From 4d467cce95de7e7679330460ce1b5321ba8e31de Mon Sep 17 00:00:00 2001 From: mcarton Date: Fri, 31 Jul 2015 20:57:51 +0200 Subject: [PATCH 1/5] #324 Remove arrows in case there is only one match --- tests/test_ui.py | 7 +++++++ thefuck/logs.py | 12 +++++++++--- thefuck/ui.py | 7 ++++--- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/tests/test_ui.py b/tests/test_ui.py index 578abce2..7843dea3 100644 --- a/tests/test_ui.py +++ b/tests/test_ui.py @@ -92,6 +92,13 @@ class TestSelectCommand(object): require_confirmation=True)) == commands[0] assert capsys.readouterr() == ('', u'\x1b[1K\rls [enter/↑/↓/ctrl+c]\n') + def test_with_confirmation_one_match(self, capsys, patch_getch, commands): + patch_getch(['\n']) + assert ui.select_command((commands[0],), + Mock(debug=False, no_color=True, + require_confirmation=True)) == commands[0] + assert capsys.readouterr() == ('', u'\x1b[1K\rls [enter/ctrl+c]\n') + def test_with_confirmation_abort(self, capsys, patch_getch, commands): patch_getch([KeyboardInterrupt]) assert ui.select_command(commands, diff --git a/thefuck/logs.py b/thefuck/logs.py index 08781024..18154f13 100644 --- a/thefuck/logs.py +++ b/thefuck/logs.py @@ -45,12 +45,18 @@ def show_corrected_command(corrected_command, settings): reset=color(colorama.Style.RESET_ALL, settings))) -def confirm_text(corrected_command, settings): +def confirm_text(corrected_command, multiple_cmds, settings): + if multiple_cmds: + arrows = '{blue}↑{reset}/{blue}↓{reset}/' + else: + arrows = '' + sys.stderr.write( - '\033[1K\r{bold}{script}{reset}{side_effect} ' - '[{green}enter{reset}/{blue}↑{reset}/{blue}↓{reset}/{red}ctrl+c{reset}]'.format( + ('{clear}{bold}{script}{reset}{side_effect} ' + '[{green}enter{reset}/' + arrows + '{red}ctrl+c{reset}]').format( script=corrected_command.script, side_effect=' (+side effect)' if corrected_command.side_effect else '', + clear='\033[1K\r', bold=color(colorama.Style.BRIGHT, settings), green=color(colorama.Fore.GREEN, settings), red=color(colorama.Fore.RED, settings), diff --git a/thefuck/ui.py b/thefuck/ui.py index f0b49793..18684b46 100644 --- a/thefuck/ui.py +++ b/thefuck/ui.py @@ -44,8 +44,7 @@ def read_actions(): if buffer == ['\x1b', '[', 'A']: # ↑ yield PREVIOUS - - if buffer == ['\x1b', '[', 'B']: # ↓ + elif buffer == ['\x1b', '[', 'B']: # ↓ yield NEXT @@ -89,7 +88,9 @@ def select_command(corrected_commands, settings): logs.show_corrected_command(selector.value, settings) return selector.value - selector.on_change(lambda val: logs.confirm_text(val, settings)) + multiple_cmds = len(corrected_commands) > 1 + + selector.on_change(lambda val: logs.confirm_text(val, multiple_cmds, settings)) for action in read_actions(): if action == SELECT: sys.stderr.write('\n') From 3ae01ac65d541e9a34b55abaecfb071d1906fb15 Mon Sep 17 00:00:00 2001 From: mcarton Date: Fri, 31 Jul 2015 21:41:07 +0200 Subject: [PATCH 2/5] Adapt the `man` rule to #324 --- tests/rules/test_man.py | 2 +- thefuck/rules/man.py | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/rules/test_man.py b/tests/rules/test_man.py index 883d7366..7be54687 100644 --- a/tests/rules/test_man.py +++ b/tests/rules/test_man.py @@ -23,7 +23,7 @@ def test_not_match(command): @pytest.mark.parametrize('command, new_command', [ - (Command('man read'), 'man 3 read'), + (Command('man read'), ['man 3 read', 'man 2 read']), (Command('man 2 read'), 'man 3 read'), (Command('man 3 read'), 'man 2 read'), (Command('man -s2 read'), 'man -s3 read'), diff --git a/thefuck/rules/man.py b/thefuck/rules/man.py index 0b15c5fc..869350c7 100644 --- a/thefuck/rules/man.py +++ b/thefuck/rules/man.py @@ -8,6 +8,10 @@ def get_new_command(command, settings): if '2' in command.script: return command.script.replace("2", "3") - split_cmd = command.script.split() - split_cmd.insert(1, ' 3 ') - return "".join(split_cmd) + split_cmd2 = command.script.split() + split_cmd3 = split_cmd2[:] + + split_cmd2.insert(1, ' 2 ') + split_cmd3.insert(1, ' 3 ') + + return ["".join(split_cmd3), "".join(split_cmd2)] From 8374be0872e32e57d650c97e15aad37bcd5ad0a5 Mon Sep 17 00:00:00 2001 From: mcarton Date: Fri, 31 Jul 2015 21:41:49 +0200 Subject: [PATCH 3/5] Adapt the `pacman` rule to #324 --- tests/rules/test_pacman.py | 41 ++++++++++++++++++++++++-------------- thefuck/rules/pacman.py | 11 ++++++---- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/tests/rules/test_pacman.py b/tests/rules/test_pacman.py index 90ee2591..73413589 100644 --- a/tests/rules/test_pacman.py +++ b/tests/rules/test_pacman.py @@ -7,17 +7,13 @@ from tests.utils import Command pacman_cmd = getattr(pacman, 'pacman', 'pacman') -PKGFILE_OUTPUT_CONVERT = ''' -extra/imagemagick 6.9.1.0-1\t/usr/bin/convert -''' +PKGFILE_OUTPUT_CONVERT = 'extra/imagemagick 6.9.1.0-1\t/usr/bin/convert' -PKGFILE_OUTPUT_VIM = ''' -extra/gvim 7.4.712-1 \t/usr/bin/vim +PKGFILE_OUTPUT_VIM = '''extra/gvim 7.4.712-1 \t/usr/bin/vim extra/gvim-python3 7.4.712-1\t/usr/bin/vim extra/vim 7.4.712-1 \t/usr/bin/vim extra/vim-minimal 7.4.712-1 \t/usr/bin/vim -extra/vim-python3 7.4.712-1 \t/usr/bin/vim -''' +extra/vim-python3 7.4.712-1 \t/usr/bin/vim''' @pytest.mark.skipif(not getattr(pacman, 'enabled_by_default', True), @@ -46,22 +42,37 @@ def test_not_match(command): assert not match(command, None) +sudo_vim_possibilities = ['{} -S extra/gvim && sudo vim', + '{} -S extra/gvim-python3 && sudo vim', + '{} -S extra/vim && sudo vim', + '{} -S extra/vim-minimal && sudo vim', + '{} -S extra/vim-python3 && sudo vim'] +sudo_vim_possibilities = [s.format(pacman_cmd) for s in sudo_vim_possibilities] + +vim_possibilities = ['{} -S extra/gvim && vim', + '{} -S extra/gvim-python3 && vim', + '{} -S extra/vim && vim', + '{} -S extra/vim-minimal && vim', + '{} -S extra/vim-python3 && vim'] +vim_possibilities = [s.format(pacman_cmd) for s in vim_possibilities] + + @pytest.mark.skipif(not getattr(pacman, 'enabled_by_default', True), reason='Skip if pacman is not available') @pytest.mark.parametrize('command, new_command', [ - (Command('vim'), '{} -S extra/gvim && vim'.format(pacman_cmd)), - (Command('sudo vim'), '{} -S extra/gvim && sudo vim'.format(pacman_cmd)), - (Command('convert'), '{} -S extra/imagemagick && convert'.format(pacman_cmd)), - (Command('sudo convert'), '{} -S extra/imagemagick && sudo convert'.format(pacman_cmd))]) + (Command('vim'), vim_possibilities), + (Command('sudo vim'), sudo_vim_possibilities), + (Command('convert'), ['{} -S extra/imagemagick && convert'.format(pacman_cmd)]), + (Command('sudo convert'), ['{} -S extra/imagemagick && sudo convert'.format(pacman_cmd)])]) def test_get_new_command(command, new_command, mocker): assert get_new_command(command, None) == new_command @pytest.mark.parametrize('command, new_command, return_value', [ - (Command('vim'), '{} -S extra/gvim && vim'.format(pacman_cmd), PKGFILE_OUTPUT_VIM), - (Command('sudo vim'), '{} -S extra/gvim && sudo vim'.format(pacman_cmd), PKGFILE_OUTPUT_VIM), - (Command('convert'), '{} -S extra/imagemagick && convert'.format(pacman_cmd), PKGFILE_OUTPUT_CONVERT), - (Command('sudo convert'), '{} -S extra/imagemagick && sudo convert'.format(pacman_cmd), PKGFILE_OUTPUT_CONVERT)]) + (Command('vim'), vim_possibilities, PKGFILE_OUTPUT_VIM), + (Command('sudo vim'), sudo_vim_possibilities, PKGFILE_OUTPUT_VIM), + (Command('convert'), ['{} -S extra/imagemagick && convert'.format(pacman_cmd)], PKGFILE_OUTPUT_CONVERT), + (Command('sudo convert'), ['{} -S extra/imagemagick && sudo convert'.format(pacman_cmd)], PKGFILE_OUTPUT_CONVERT)]) @patch('thefuck.rules.pacman.subprocess') @patch.multiple(pacman, create=True, pacman=pacman_cmd) def test_get_new_command_mocked(subp_mock, command, new_command, return_value): diff --git a/thefuck/rules/pacman.py b/thefuck/rules/pacman.py index 1272827b..2bf64b30 100644 --- a/thefuck/rules/pacman.py +++ b/thefuck/rules/pacman.py @@ -14,10 +14,12 @@ def __get_pkgfile(command): command = command.split(" ")[0] - return subprocess.check_output( + packages = subprocess.check_output( ['pkgfile', '-b', '-v', command], universal_newlines=True, stderr=DEVNULL - ).split() + ).splitlines() + + return [package.split()[0] for package in packages] except subprocess.CalledProcessError: return None @@ -27,10 +29,11 @@ def match(command, settings): def get_new_command(command, settings): - package = __get_pkgfile(command)[0] + packages = __get_pkgfile(command) formatme = shells.and_('{} -S {}', '{}') - return formatme.format(pacman, package, command.script) + return [formatme.format(pacman, package, command.script) + for package in packages] if not which('pkgfile'): From 88732a608e71e1af42f8dd73030d90c6d8aaba34 Mon Sep 17 00:00:00 2001 From: mcarton Date: Fri, 31 Jul 2015 21:48:14 +0200 Subject: [PATCH 4/5] Adapt the `tmux` rule to #324 --- tests/rules/test_tmux.py | 2 +- thefuck/rules/tmux.py | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/rules/test_tmux.py b/tests/rules/test_tmux.py index ebbe6736..963e9f1d 100644 --- a/tests/rules/test_tmux.py +++ b/tests/rules/test_tmux.py @@ -16,4 +16,4 @@ def test_match(tmux_ambiguous): def test_get_new_command(tmux_ambiguous): assert get_new_command(Command('tmux list', stderr=tmux_ambiguous), None)\ - == 'tmux list-keys' + == ['tmux list-keys', 'tmux list-panes', 'tmux list-windows'] diff --git a/thefuck/rules/tmux.py b/thefuck/rules/tmux.py index 719e8208..d58ae37a 100644 --- a/thefuck/rules/tmux.py +++ b/thefuck/rules/tmux.py @@ -1,4 +1,4 @@ -from thefuck.utils import get_closest, replace_argument +from thefuck.utils import get_closest, replace_command import re @@ -15,6 +15,4 @@ def get_new_command(command, settings): old_cmd = cmd.group(1) suggestions = [cmd.strip() for cmd in cmd.group(2).split(',')] - new_cmd = get_closest(old_cmd, suggestions) - - return replace_argument(command.script, old_cmd, new_cmd) + return replace_command(command, old_cmd, suggestions) From fc48e69921fc625c1e66446ed0402addd9995470 Mon Sep 17 00:00:00 2001 From: mcarton Date: Fri, 31 Jul 2015 22:12:10 +0200 Subject: [PATCH 5/5] Adapt the `whois` rule to #342 --- tests/rules/test_whois.py | 7 +++++-- thefuck/rules/whois.py | 5 +++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/rules/test_whois.py b/tests/rules/test_whois.py index 18548ce5..bb64b1b8 100644 --- a/tests/rules/test_whois.py +++ b/tests/rules/test_whois.py @@ -6,7 +6,7 @@ from tests.utils import Command @pytest.mark.parametrize('command', [ Command(script='whois https://en.wikipedia.org/wiki/Main_Page'), Command(script='whois https://en.wikipedia.org/'), - Command(script='whois en.wikipedia.org')]) + Command(script='whois meta.unix.stackexchange.com')]) def test_match(command): assert match(command, None) @@ -15,9 +15,12 @@ def test_not_match(): assert not match(Command(script='whois'), None) +# `whois com` actually makes sense @pytest.mark.parametrize('command, new_command', [ (Command('whois https://en.wikipedia.org/wiki/Main_Page'), 'whois en.wikipedia.org'), (Command('whois https://en.wikipedia.org/'), 'whois en.wikipedia.org'), - (Command('whois en.wikipedia.org'), 'whois wikipedia.org')]) + (Command('whois meta.unix.stackexchange.com'), ['whois unix.stackexchange.com', + 'whois stackexchange.com', + 'whois com'])]) def test_get_new_command(command, new_command): assert get_new_command(command, None) == new_command diff --git a/thefuck/rules/whois.py b/thefuck/rules/whois.py index d27ecc16..79487c38 100644 --- a/thefuck/rules/whois.py +++ b/thefuck/rules/whois.py @@ -19,7 +19,7 @@ def match(command, settings): - www.google.fr → subdomain: www, domain: 'google.fr'; - google.co.uk → subdomain: None, domain; 'google.co.uk'. """ - return 'whois' in command.script and len(command.script.split()) > 1 + return 'whois ' in command.script.strip() def get_new_command(command, settings): @@ -28,4 +28,5 @@ def get_new_command(command, settings): if '/' in command.script: return 'whois ' + urlparse(url).netloc elif '.' in command.script: - return 'whois ' + '.'.join(urlparse(url).path.split('.')[1:]) + path = urlparse(url).path.split('.') + return ['whois ' + '.'.join(path[n:]) for n in range(1, len(path))]