1
0
mirror of https://github.com/nvbn/thefuck.git synced 2025-02-21 20:38:54 +00:00

#620: Add support of arguments to fuck, like fuck -y on zsh

This commit is contained in:
Vladimir Iakovlev 2017-03-28 11:31:06 +02:00
parent d28567bb31
commit ec37998a10
8 changed files with 129 additions and 49 deletions

View File

@ -40,17 +40,17 @@ class TestZsh(object):
'll': 'ls -alF'}
def test_app_alias(self, shell):
assert 'alias fuck' in shell.app_alias('fuck')
assert 'alias FUCK' in shell.app_alias('FUCK')
assert 'fuck () {' in shell.app_alias('fuck')
assert 'FUCK () {' in shell.app_alias('FUCK')
assert 'thefuck' in shell.app_alias('fuck')
assert 'PYTHONIOENCODING' in shell.app_alias('fuck')
def test_app_alias_variables_correctly_set(self, shell):
alias = shell.app_alias('fuck')
assert "alias fuck='TF_CMD=$(TF_ALIAS" in alias
assert '$(TF_ALIAS=fuck PYTHONIOENCODING' in alias
assert 'PYTHONIOENCODING=utf-8 TF_SHELL_ALIASES' in alias
assert 'ALIASES=$(alias) thefuck' in alias
assert "fuck () {" in alias
assert "TF_ALIAS=fuck" in alias
assert 'PYTHONIOENCODING=utf-8' in alias
assert 'TF_SHELL_ALIASES=$(alias)' in alias
def test_get_history(self, history_lines, shell):
history_lines([': 1432613911:0;ls', ': 1432613916:0;rm'])

View File

@ -0,0 +1,26 @@
import pytest
from thefuck.argument_parser import Parser
from thefuck.const import ARGUMENT_PLACEHOLDER
@pytest.mark.parametrize('argv, result', [
(['thefuck'], {'alias': None, 'command': [], 'yes': False,
'help': False, 'version': False}),
(['thefuck', '-a'], {'alias': 'fuck', 'command': [], 'yes': False,
'help': False, 'version': False}),
(['thefuck', '-a', 'fix'], {'alias': 'fix', 'command': [], 'yes': False,
'help': False, 'version': False}),
(['thefuck', 'git', 'branch', ARGUMENT_PLACEHOLDER, '-y'],
{'alias': None, 'command': ['git', 'branch'], 'yes': True,
'help': False, 'version': False}),
(['thefuck', 'git', 'branch', '-a', ARGUMENT_PLACEHOLDER, '-y'],
{'alias': None, 'command': ['git', 'branch', '-a'], 'yes': True,
'help': False, 'version': False}),
(['thefuck', ARGUMENT_PLACEHOLDER, '-v'],
{'alias': None, 'command': [], 'yes': False, 'help': False,
'version': True}),
(['thefuck', ARGUMENT_PLACEHOLDER, '--help'],
{'alias': None, 'command': [], 'yes': False, 'help': True,
'version': False})])
def test_parse(argv, result):
assert vars(Parser().parse(argv)) == result

View File

@ -0,0 +1,48 @@
import sys
from argparse import ArgumentParser
from .const import ARGUMENT_PLACEHOLDER
from .utils import get_alias
class Parser(object):
def __init__(self):
self._parser = ArgumentParser(prog='thefuck', add_help=False)
self._parser.add_argument(
'-v', '--version',
action='store_true',
help="show program's version number and exit")
self._parser.add_argument(
'-a', '--alias',
nargs='?',
const=get_alias(),
help='[custom-alias-name] prints alias for current shell')
self._parser.add_argument(
'-h', '--help',
action='store_true',
help='show this help message and exit')
self._parser.add_argument(
'-y', '--yes',
action='store_true',
help='execute fixed command without confirmation')
self._parser.add_argument('command',
nargs='*',
help='command that should be fixed')
def _get_arguments(self, argv):
if ARGUMENT_PLACEHOLDER in argv:
index = argv.index(ARGUMENT_PLACEHOLDER)
return argv[index + 1:] + ['--'] + argv[:index]
elif argv and not argv[0].startswith('-') and argv[0] != '--':
return ['--'] + argv
else:
return argv
def parse(self, argv):
arguments = self._get_arguments(argv[1:])
return self._parser.parse_args(arguments)
def print_usage(self):
self._parser.print_usage(sys.stderr)
def print_help(self):
self._parser.print_help(sys.stderr)

View File

@ -14,7 +14,7 @@ class Settings(dict):
def __setattr__(self, key, value):
self[key] = value
def init(self):
def init(self, args=None):
"""Fills `settings` with values from `settings.py` and env."""
from .logs import exception
@ -31,6 +31,8 @@ class Settings(dict):
except Exception:
exception("Can't load settings from env", sys.exc_info())
self.update(self._settings_from_args(args))
def _init_settings_file(self):
settings_path = self.user_dir.joinpath('settings.py')
if not settings_path.is_file():
@ -109,5 +111,12 @@ class Settings(dict):
for env, attr in const.ENV_TO_ATTR.items()
if env in os.environ}
def _settings_from_args(self, args):
"""Loads settings from args."""
if args and args.yes:
return {'require_confirmation': False}
else:
return {}
settings = Settings(const.DEFAULT_SETTINGS)

View File

@ -59,3 +59,5 @@ SETTINGS_HEADER = u"""# The Fuck settings file
#
"""
ARGUMENT_PLACEHOLDER = 'THEFUCK_ARGUMENT_PLACEHOLDER'

View File

@ -121,3 +121,9 @@ def configured_successfully(configuration_details):
bold=color(colorama.Style.BRIGHT),
reset=color(colorama.Style.RESET_ALL),
reload=configuration_details.reload))
def version(thefuck_version, python_version):
print(u'The Fuck {} using Python {}'.format(thefuck_version,
python_version),
file=sys.stderr)

View File

@ -3,7 +3,6 @@ from .system import init_output
init_output()
from argparse import ArgumentParser # noqa: E402
from pprint import pformat # noqa: E402
import sys # noqa: E402
from . import logs, types # noqa: E402
@ -11,18 +10,19 @@ from .shells import shell # noqa: E402
from .conf import settings # noqa: E402
from .corrector import get_corrected_commands # noqa: E402
from .exceptions import EmptyCommand # noqa: E402
from .utils import get_installation_info, get_alias # noqa: E402
from .ui import select_command # noqa: E402
from .argument_parser import Parser # noqa: E402
from .utils import get_installation_info # noqa: E402
def fix_command():
def fix_command(known_args):
"""Fixes previous command. Used when `thefuck` called without arguments."""
settings.init()
settings.init(known_args)
with logs.debug_time('Total'):
logs.debug(u'Run with settings: {}'.format(pformat(settings)))
try:
command = types.Command.from_raw_script(sys.argv[1:])
command = types.Command.from_raw_script(known_args.command)
except EmptyCommand:
logs.debug('Empty command, nothing to do')
return
@ -36,34 +36,18 @@ def fix_command():
sys.exit(1)
def print_alias():
"""Prints alias for current shell."""
try:
alias = sys.argv[2]
except IndexError:
alias = get_alias()
print(shell.app_alias(alias))
def main():
parser = ArgumentParser(prog='thefuck')
version = get_installation_info().version
parser.add_argument('-v', '--version',
action='version',
version='The Fuck {} using Python {}'.format(
version, sys.version.split()[0]))
parser.add_argument('-a', '--alias',
action='store_true',
help='[custom-alias-name] prints alias for current shell')
parser.add_argument('command',
nargs='*',
help='command that should be fixed')
known_args = parser.parse_args(sys.argv[1:2])
parser = Parser()
known_args = parser.parse(sys.argv)
if known_args.alias:
print_alias()
if known_args.help:
parser.print_help()
elif known_args.version:
logs.version(get_installation_info().version,
sys.version.split()[0])
elif known_args.command:
fix_command()
fix_command(known_args)
elif known_args.alias:
print(shell.app_alias(known_args.alias))
else:
parser.print_usage()

View File

@ -1,23 +1,28 @@
from time import time
import os
from ..conf import settings
from ..const import ARGUMENT_PLACEHOLDER
from ..utils import memoize
from .generic import Generic
class Zsh(Generic):
def app_alias(self, alias_name):
# It is VERY important to have the variables declared WITHIN the alias
alias = "alias {0}='TF_CMD=$(TF_ALIAS={0}" \
" PYTHONIOENCODING=utf-8" \
" TF_SHELL_ALIASES=$(alias)" \
" thefuck $(fc -ln -1 | tail -n 1)) &&" \
" eval $TF_CMD".format(alias_name)
if settings.alter_history:
return alias + " ; test -n \"$TF_CMD\" && print -s $TF_CMD'"
else:
return alias + "'"
# It is VERY important to have the variables declared WITHIN the function
return '''
{name} () {{
TF_ALIAS={name};
PYTHONIOENCODING=utf-8;
TF_SHELL_ALIASES=$(alias);
TF_PREVIOUS=$(fc -ln -1 | tail -n 1);
TF_CMD=$(thefuck $TF_PREVIOUS {argument_placeholder} $*) && eval $TF_CMD;
{alter_history}
}}
'''.format(
name=alias_name,
argument_placeholder=ARGUMENT_PLACEHOLDER,
alter_history=('test -n "$TF_CMD" && print -s $TF_CMD'
if settings.alter_history else ''))
def _parse_alias(self, alias):
name, value = alias.split('=', 1)