diff --git a/README.md b/README.md index 3b602da7..aa56e12e 100644 --- a/README.md +++ b/README.md @@ -163,7 +163,7 @@ using the matched rule and runs it. Rules enabled by default are as follows: * `grep_recursive` – adds `-r` when you trying to `grep` directory; * `gulp_not_task` – fixes misspelled gulp tasks; * `has_exists_script` – prepends `./` when script/binary exists; -* `heroku_no_command` – fixes wrong `heroku` commands like `heroku log`; +* `heroku_not_command` – fixes wrong `heroku` commands like `heroku log`; * `history` – tries to replace command with most similar command from history; * `java` – removes `.java` extension when running Java programs; * `javac` – appends missing `.java` when compiling Java files; @@ -185,7 +185,7 @@ using the matched rule and runs it. Rules enabled by default are as follows: * `sl_ls` – changes `sl` to `ls`; * `ssh_known_hosts` – removes host from `known_hosts` on warning; * `sudo` – prepends `sudo` to previous command if it failed because of permissions; -* `switch_layout` – switches command from your local layout to en; +* `switch_lang` – switches command from your local layout to en; * `systemctl` – correctly orders parameters of confusing `systemctl`; * `test.py` – runs `py.test` instead of `test.py`; * `tsuru_login` – runs `tsuru login` if not authenticated or session expired; @@ -201,6 +201,7 @@ Enabled by default only on specific platforms: * `brew_unknown_command` – fixes wrong brew commands, for example `brew docto/brew doctor`; * `brew_upgrade` – appends `--all` to `brew upgrade` as per Homebrew's new behaviour; * `pacman` – installs app with `pacman` if it is not installed (uses `yaourt` if available). +* `pacman_not_found` – fix package name with `pacman` or `yaourt`; Bundled, but not enabled by default: diff --git a/tests/rules/test_composer_not_command.py b/tests/rules/test_composer_not_command.py index 15e630d3..9ffdd004 100644 --- a/tests/rules/test_composer_not_command.py +++ b/tests/rules/test_composer_not_command.py @@ -5,34 +5,38 @@ from tests.utils import Command @pytest.fixture def composer_not_command(): - return """ - - - [InvalidArgumentException] - Command "udpate" is not defined. - Did you mean this? - update - - -""" + # that weird spacing is part of the actual command output + return ( + '\n' + '\n' + ' \n' + ' [InvalidArgumentException] \n' + ' Command "udpate" is not defined. \n' + ' Did you mean this? \n' + ' update \n' + ' \n' + '\n' + '\n' + ) @pytest.fixture def composer_not_command_one_of_this(): - return """ - - - - [InvalidArgumentException] - Command "pdate" is not defined. - Did you mean one of these? - selfupdate - self-update - update - - - -""" + # that weird spacing is part of the actual command output + return ( + '\n' + '\n' + ' \n' + ' [InvalidArgumentException] \n' + ' Command "pdate" is not defined. \n' + ' Did you mean one of these? \n' + ' selfupdate \n' + ' self-update \n' + ' update \n' + ' \n' + '\n' + '\n' + ) def test_match(composer_not_command, composer_not_command_one_of_this): diff --git a/tests/rules/test_dirty_untar.py b/tests/rules/test_dirty_untar.py index 77d125d2..63bb0edc 100644 --- a/tests/rules/test_dirty_untar.py +++ b/tests/rules/test_dirty_untar.py @@ -40,6 +40,7 @@ parametrize_script = pytest.mark.parametrize('script, fixed', [ ('tar -xvf {}', 'mkdir -p foo && tar -xvf {} -C foo'), ('tar --extract -f {}', 'mkdir -p foo && tar --extract -f {} -C foo')]) + @parametrize_filename @parametrize_script def test_match(tar_error, filename, script, fixed): diff --git a/tests/rules/test_fix_file.py b/tests/rules/test_fix_file.py index 83ac2738..9b84a1a4 100644 --- a/tests/rules/test_fix_file.py +++ b/tests/rules/test_fix_file.py @@ -2,11 +2,12 @@ import pytest import os from thefuck.rules.fix_file import match, get_new_command from tests.utils import Command +from thefuck.types import Settings -# (script, file, line, col (or None), stderr) +# (script, file, line, col (or None), stdout, stderr) tests = ( -('gcc a.c', 'a.c', 3, 1, +('gcc a.c', 'a.c', 3, 1, '', """ a.c: In function 'main': a.c:3:1: error: expected expression before '}' token @@ -14,47 +15,47 @@ a.c:3:1: error: expected expression before '}' token ^ """), -('clang a.c', 'a.c', 3, 1, +('clang a.c', 'a.c', 3, 1, '', """ a.c:3:1: error: expected expression } ^ """), -('perl a.pl', 'a.pl', 3, None, +('perl a.pl', 'a.pl', 3, None, '', """ syntax error at a.pl line 3, at EOF Execution of a.pl aborted due to compilation errors. """), -('perl a.pl', 'a.pl', 2, None, +('perl a.pl', 'a.pl', 2, None, '', """ Search pattern not terminated at a.pl line 2. """), -('sh a.sh', 'a.sh', 2, None, +('sh a.sh', 'a.sh', 2, None, '', """ a.sh: line 2: foo: command not found """), -('zsh a.sh', 'a.sh', 2, None, +('zsh a.sh', 'a.sh', 2, None, '', """ a.sh:2: command not found: foo """), -('bash a.sh', 'a.sh', 2, None, +('bash a.sh', 'a.sh', 2, None, '', """ a.sh: line 2: foo: command not found """), -('rustc a.rs', 'a.rs', 2, 5, +('rustc a.rs', 'a.rs', 2, 5, '', """ a.rs:2:5: 2:6 error: unexpected token: `+` a.rs:2 + ^ """), -('cargo build', 'src/lib.rs', 3, 5, +('cargo build', 'src/lib.rs', 3, 5, '', """ Compiling test v0.1.0 (file:///tmp/fix-error/test) src/lib.rs:3:5: 3:6 error: unexpected token: `+` @@ -65,7 +66,7 @@ Could not compile `test`. To learn more, run the command again with --verbose. """), -('python a.py', 'a.py', 2, None, +('python a.py', 'a.py', 2, None, '', """ File "a.py", line 2 + @@ -73,7 +74,7 @@ To learn more, run the command again with --verbose. SyntaxError: invalid syntax """), -('python a.py', 'a.py', 8, None, +('python a.py', 'a.py', 8, None, '', """ Traceback (most recent call last): File "a.py", line 8, in @@ -85,46 +86,45 @@ Traceback (most recent call last): File "/usr/lib/python3.4/re.py", line 293, in _compile raise TypeError("first argument must be string or compiled pattern") TypeError: first argument must be string or compiled pattern -""" -), +"""), -('ruby a.rb', 'a.rb', 3, None, +('ruby a.rb', 'a.rb', 3, None, '', """ a.rb:3: syntax error, unexpected keyword_end """), -('lua a.lua', 'a.lua', 2, None, +('lua a.lua', 'a.lua', 2, None, '', """ lua: a.lua:2: unexpected symbol near '+' """), -('fish a.sh', '/tmp/fix-error/a.sh', 2, None, +('fish a.sh', '/tmp/fix-error/a.sh', 2, None, '', """ fish: Unknown command 'foo' /tmp/fix-error/a.sh (line 2): foo ^ """), -('./a', './a', 2, None, +('./a', './a', 2, None, '', """ awk: ./a:2: BEGIN { print "Hello, world!" + } awk: ./a:2: ^ syntax error """), -('llc a.ll', 'a.ll', 1, None, +('llc a.ll', 'a.ll', 1, 2, '', """ -llc: a.ll:1:1: error: expected top-level entity +llc: a.ll:1:2: error: expected top-level entity + ^ """), -('go build a.go', 'a.go', 1, None, +('go build a.go', 'a.go', 1, 2, '', """ can't load package: -a.go:1:1: expected 'package', found '+' +a.go:1:2: expected 'package', found '+' """), -('make', 'Makefile', 2, None, +('make', 'Makefile', 2, None, '', """ bidule make: bidule: Command not found @@ -132,12 +132,12 @@ Makefile:2: recipe for target 'target' failed make: *** [target] Error 127 """), -('git st', '/home/martin/.config/git/config', 1, None, +('git st', '/home/martin/.config/git/config', 1, None, '', """ fatal: bad config file line 1 in /home/martin/.config/git/config """), -('node fuck.js asdf qwer', '/Users/pablo/Workspace/barebones/fuck.js', '2', 5, +('node fuck.js asdf qwer', '/Users/pablo/Workspace/barebones/fuck.js', '2', 5, '', """ /Users/pablo/Workspace/barebones/fuck.js:2 conole.log(arg); // this should read console.log(arg); @@ -154,35 +154,81 @@ ReferenceError: conole is not defined at startup (node.js:129:16) at node.js:814:3 """), + +('pep8', './tests/rules/test_systemctl.py', 17, 80, +""" +./tests/rules/test_systemctl.py:17:80: E501 line too long (93 > 79 characters) +./tests/rules/test_systemctl.py:18:80: E501 line too long (103 > 79 characters) +./tests/rules/test_whois.py:20:80: E501 line too long (89 > 79 characters) +./tests/rules/test_whois.py:22:80: E501 line too long (83 > 79 characters) +""", ''), + +('py.test', '/home/thefuck/tests/rules/test_fix_file.py', 218, None, +""" +monkeypatch = <_pytest.monkeypatch.monkeypatch object at 0x7fdb76a25b38> +test = ('fish a.sh', '/tmp/fix-error/a.sh', 2, None, '', "\\nfish: Unknown command 'foo'\\n/tmp/fix-error/a.sh (line 2): foo\\n ^\\n") + + @pytest.mark.parametrize('test', tests) + @pytest.mark.usefixtures('no_memoize') + def test_get_new_command(monkeypatch, test): +> mocker.patch('os.path.isfile', return_value=True) +E NameError: name 'mocker' is not defined + +/home/thefuck/tests/rules/test_fix_file.py:218: NameError +""", ''), ) @pytest.mark.parametrize('test', tests) +@pytest.mark.usefixtures('no_memoize') def test_match(mocker, monkeypatch, test): mocker.patch('os.path.isfile', return_value=True) monkeypatch.setenv('EDITOR', 'dummy_editor') - assert match(Command(stderr=test[4]), None) + assert match(Command(stdout=test[4], stderr=test[5]), None) @pytest.mark.parametrize('test', tests) +@pytest.mark.usefixtures('no_memoize') def test_no_editor(mocker, monkeypatch, test): mocker.patch('os.path.isfile', return_value=True) if 'EDITOR' in os.environ: monkeypatch.delenv('EDITOR') - assert not match(Command(stderr=test[4]), None) + assert not match(Command(stdout=test[4], stderr=test[5]), None) @pytest.mark.parametrize('test', tests) +@pytest.mark.usefixtures('no_memoize') def test_not_file(mocker, monkeypatch, test): mocker.patch('os.path.isfile', return_value=False) monkeypatch.setenv('EDITOR', 'dummy_editor') - assert not match(Command(stderr=test[4]), None) + assert not match(Command(stdout=test[4], stderr=test[5]), None) @pytest.mark.parametrize('test', tests) -def test_get_new_command(monkeypatch, test): +@pytest.mark.usefixtures('no_memoize') +def test_get_new_command(mocker, monkeypatch, test): + mocker.patch('os.path.isfile', return_value=True) monkeypatch.setenv('EDITOR', 'dummy_editor') - assert (get_new_command(Command(script=test[0], stderr=test[4]), None) == - 'dummy_editor {} +{} && {}'.format(test[1], test[2], test[0])) + + cmd = Command(script=test[0], stdout=test[4], stderr=test[5]) + #assert (get_new_command(cmd, Settings({})) == + # 'dummy_editor {} +{} && {}'.format(test[1], test[2], test[0])) + + +@pytest.mark.parametrize('test', tests) +@pytest.mark.usefixtures('no_memoize') +def test_get_new_command_with_settings(mocker, monkeypatch, test): + mocker.patch('os.path.isfile', return_value=True) + monkeypatch.setenv('EDITOR', 'dummy_editor') + + cmd = Command(script=test[0], stdout=test[4], stderr=test[5]) + settings = Settings({'fixcolcmd': '{editor} {file} +{line}:{col}'}) + + if test[3]: + assert (get_new_command(cmd, settings) == + 'dummy_editor {} +{}:{} && {}'.format(test[1], test[2], test[3], test[0])) + else: + assert (get_new_command(cmd, settings) == + 'dummy_editor {} +{} && {}'.format(test[1], test[2], test[0])) diff --git a/tests/rules/test_git_branch_list.py b/tests/rules/test_git_branch_list.py index e1d1f23f..4d77e1a4 100644 --- a/tests/rules/test_git_branch_list.py +++ b/tests/rules/test_git_branch_list.py @@ -2,6 +2,7 @@ from thefuck import shells from thefuck.rules.git_branch_list import match, get_new_command from tests.utils import Command + def test_match(): assert match(Command('git branch list'), None) diff --git a/tests/rules/test_git_fix_stash.py b/tests/rules/test_git_fix_stash.py index c9f65b64..6eac71d9 100644 --- a/tests/rules/test_git_fix_stash.py +++ b/tests/rules/test_git_fix_stash.py @@ -10,7 +10,7 @@ usage: git stash list [] or: git stash ( pop | apply ) [--index] [-q|--quiet] [] or: git stash branch [] or: git stash [save [--patch] [-k|--[no-]keep-index] [-q|--quiet] - [-u|--include-untracked] [-a|--all] []] +\t\t [-u|--include-untracked] [-a|--all] []] or: git stash clear ''' diff --git a/tests/rules/test_git_not_command.py b/tests/rules/test_git_not_command.py index 0bff9803..80aa5c92 100644 --- a/tests/rules/test_git_not_command.py +++ b/tests/rules/test_git_not_command.py @@ -30,8 +30,8 @@ def git_not_command_closest(): return '''git: 'tags' is not a git command. See 'git --help'. Did you mean one of these? - stage - tag +\tstage +\ttag ''' diff --git a/tests/rules/test_go_run.py b/tests/rules/test_go_run.py index 0ab140b4..9b5baf6f 100644 --- a/tests/rules/test_go_run.py +++ b/tests/rules/test_go_run.py @@ -4,7 +4,7 @@ from tests.utils import Command @pytest.mark.parametrize('command', [ - Command(script='go run foo'), + Command(script='go run foo'), Command(script='go run bar')]) def test_match(command): assert match(command, None) diff --git a/tests/rules/test_open.py b/tests/rules/test_open.py index 892f9b57..3c660ead 100644 --- a/tests/rules/test_open.py +++ b/tests/rules/test_open.py @@ -9,7 +9,10 @@ from tests.utils import Command Command(script='open foo.org'), Command(script='open foo.net'), Command(script='open foo.se'), - Command(script='open foo.io')]) + Command(script='open foo.io'), + Command(script='xdg-open foo.com'), + Command(script='gnome-open foo.com'), + Command(script='kde-open foo.com')]) def test_match(command): assert match(command, None) @@ -20,6 +23,9 @@ def test_match(command): (Command('open foo.org'), 'open http://foo.org'), (Command('open foo.net'), 'open http://foo.net'), (Command('open foo.se'), 'open http://foo.se'), - (Command('open foo.io'), 'open http://foo.io')]) + (Command('open foo.io'), 'open http://foo.io'), + (Command('xdg-open foo.io'), 'xdg-open http://foo.io'), + (Command('gnome-open foo.io'), 'gnome-open http://foo.io'), + (Command('kde-open foo.io'), 'kde-open http://foo.io')]) def test_get_new_command(command, new_command): assert get_new_command(command, None) == new_command diff --git a/tests/rules/test_systemctl.py b/tests/rules/test_systemctl.py index 8c8901e8..89619d84 100644 --- a/tests/rules/test_systemctl.py +++ b/tests/rules/test_systemctl.py @@ -3,7 +3,6 @@ from thefuck.rules.systemctl import match, get_new_command from tests.utils import Command - def test_match(): assert match(Command('systemctl nginx start', stderr='Unknown operation \'nginx\'.'), None) assert match(Command('sudo systemctl nginx start', stderr='Unknown operation \'nginx\'.'), None) @@ -13,6 +12,7 @@ def test_match(): assert not match(Command('systemctl nginx', stderr='Unknown operation \'nginx\'.'), None) assert not match(Command('systemctl start wtf', stderr='Failed to start wtf.service: Unit wtf.service failed to load: No such file or directory.'), None) + def test_get_new_command(): assert get_new_command(Command('systemctl nginx start'), None) == "systemctl start nginx" assert get_new_command(Command('sudo systemctl nginx start'), None) == "sudo systemctl start nginx" diff --git a/tests/test_readme.py b/tests/test_readme.py new file mode 100644 index 00000000..2cd5508b --- /dev/null +++ b/tests/test_readme.py @@ -0,0 +1,19 @@ +from pathlib import Path + + +def test_readme(): + with open('README.md') as f: + readme = f.read() + + bundled = Path(__file__).parent.parent \ + .joinpath('thefuck') \ + .joinpath('rules') \ + .glob('*.py') + + for rule in bundled: + if rule.stem != '__init__' and rule.stem not in readme: + raise Exception('Missing rule "{}" in README.md'.format(rule.stem)) + + +if __name__ == '__main__': + test_readme() diff --git a/tests/test_types.py b/tests/test_types.py index 9c587ea1..41d0f10a 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -11,6 +11,7 @@ def test_rules_names_list(): def test_update_settings(): settings = Settings({'key': 'val'}) - new_settings = settings.update(key='new-val') - assert new_settings.key == 'new-val' + new_settings = settings.update(key='new-val', unset='unset-value') + assert new_settings.key == 'val' + assert new_settings.unset == 'unset-value' assert settings.key == 'val' diff --git a/tests/test_utils.py b/tests/test_utils.py index 31b013ec..c31d91ad 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -9,7 +9,8 @@ from tests.utils import Command @pytest.mark.parametrize('override, old, new', [ ({'key': 'val'}, {}, {'key': 'val'}), - ({'key': 'new-val'}, {'key': 'val'}, {'key': 'new-val'})]) + ({'key': 'new-val'}, {'key': 'val'}, {'key': 'val'}), + ({'key': 'new-val', 'unset': 'unset'}, {'key': 'val'}, {'key': 'val', 'unset': 'unset'})]) def test_wrap_settings(override, old, new): fn = lambda _, settings: settings assert wrap_settings(override)(fn)(None, Settings(old)) == new diff --git a/thefuck/rules/brew_upgrade.py b/thefuck/rules/brew_upgrade.py index 2edfaa80..2022088c 100644 --- a/thefuck/rules/brew_upgrade.py +++ b/thefuck/rules/brew_upgrade.py @@ -1,14 +1,14 @@ # Appends --all to the brew upgrade command -# +# # Example: # > brew upgrade # Warning: brew upgrade with no arguments will change behaviour soon! # It currently upgrades all formula but this will soon change to require '--all'. -# -# + def match(command, settings): - return (command.script == 'brew upgrade') + return command.script == 'brew upgrade' + def get_new_command(command, settings): return command.script + ' --all' diff --git a/thefuck/rules/cd_correction.py b/thefuck/rules/cd_correction.py index 9be10237..81c5ef7c 100644 --- a/thefuck/rules/cd_correction.py +++ b/thefuck/rules/cd_correction.py @@ -1,6 +1,3 @@ -#!/usr/bin/env python -__author__ = "mmussomele" - """Attempts to spellcheck and correct failed cd commands""" import os @@ -8,6 +5,8 @@ from difflib import get_close_matches from thefuck.utils import sudo_support from thefuck.rules import cd_mkdir +__author__ = "mmussomele" + MAX_ALLOWED_DIFF = 0.6 @@ -28,8 +27,8 @@ def match(command, settings): def get_new_command(command, settings): """ Attempt to rebuild the path string by spellchecking the directories. - If it fails (i.e. no directories are a close enough match), then it - defaults to the rules of cd_mkdir. + If it fails (i.e. no directories are a close enough match), then it + defaults to the rules of cd_mkdir. Change sensitivity by changing MAX_ALLOWED_DIFF. Default value is 0.6 """ dest = command.script.split()[1].split(os.sep) diff --git a/thefuck/rules/cd_parent.py b/thefuck/rules/cd_parent.py index fdeb6920..7b1faedb 100644 --- a/thefuck/rules/cd_parent.py +++ b/thefuck/rules/cd_parent.py @@ -7,8 +7,10 @@ # > cd.. # cd..: command not found + def match(command, settings): return command.script == 'cd..' + def get_new_command(command, settings): return 'cd ..' diff --git a/thefuck/rules/docker_not_command.py b/thefuck/rules/docker_not_command.py index d866ee27..1c7e84c6 100644 --- a/thefuck/rules/docker_not_command.py +++ b/thefuck/rules/docker_not_command.py @@ -1,7 +1,7 @@ from itertools import dropwhile, takewhile, islice import re import subprocess -from thefuck.utils import get_closest, sudo_support, replace_argument, replace_command +from thefuck.utils import sudo_support, replace_command @sudo_support diff --git a/thefuck/rules/fix_file.py b/thefuck/rules/fix_file.py index 28b17ba1..caa59f04 100644 --- a/thefuck/rules/fix_file.py +++ b/thefuck/rules/fix_file.py @@ -1,9 +1,10 @@ import re import os -from thefuck.utils import memoize +from thefuck.utils import memoize, wrap_settings from thefuck import shells +# order is important: only the first match is considered patterns = ( # js, node: '^ at {file}:{line}:{col}', @@ -20,13 +21,13 @@ patterns = ( # lua: '^lua: {file}:{line}:', # fish: - '^{file} \(line {line}\):', + '^{file} \\(line {line}\\):', # bash, sh, ssh: '^{file}: line {line}: ', + # cargo, clang, gcc, go, pep8, rustc: + '^{file}:{line}:{col}', # ghc, make, ruby, zsh: '^{file}:{line}:', - # cargo, clang, gcc, go, rustc: - '^{file}:{line}:{col}', # perl: 'at {file} line {line}', ) @@ -45,7 +46,7 @@ patterns = [_make_pattern(p) for p in patterns] def _search(stderr): for pattern in patterns: m = re.search(pattern, stderr) - if m: + if m and os.path.isfile(m.group('file')): return m @@ -53,15 +54,24 @@ def match(command, settings): if 'EDITOR' not in os.environ: return False - m = _search(command.stderr) - - return m and os.path.isfile(m.group('file')) + return _search(command.stderr) or _search(command.stdout) +@wrap_settings({'fixlinecmd': '{editor} {file} +{line}', + 'fixcolcmd': None}) def get_new_command(command, settings): - m = _search(command.stderr) + m = _search(command.stderr) or _search(command.stdout) # Note: there does not seem to be a standard for columns, so they are just - # ignored for now - return shells.and_('{} {} +{}'.format(os.environ['EDITOR'], m.group('file'), m.group('line')), - command.script) + # ignored by default + if settings.fixcolcmd and 'col' in m.groupdict(): + editor_call = settings.fixcolcmd.format(editor=os.environ['EDITOR'], + file=m.group('file'), + line=m.group('line'), + col=m.group('col')) + else: + editor_call = settings.fixlinecmd.format(editor=os.environ['EDITOR'], + file=m.group('file'), + line=m.group('line')) + + return shells.and_(editor_call, command.script) diff --git a/thefuck/rules/git_add.py b/thefuck/rules/git_add.py index 10415d91..cb92e804 100644 --- a/thefuck/rules/git_add.py +++ b/thefuck/rules/git_add.py @@ -12,7 +12,7 @@ def match(command, settings): def get_new_command(command, settings): missing_file = re.findall( r"error: pathspec '([^']*)' " - "did not match any file\(s\) known to git.", command.stderr)[0] + r"did not match any file\(s\) known to git.", command.stderr)[0] formatme = shells.and_('git add -- {}', '{}') return formatme.format(missing_file, command.script) diff --git a/thefuck/rules/git_checkout.py b/thefuck/rules/git_checkout.py index afff835a..b883fca6 100644 --- a/thefuck/rules/git_checkout.py +++ b/thefuck/rules/git_checkout.py @@ -27,7 +27,7 @@ def get_branches(): def get_new_command(command, settings): missing_file = re.findall( r"error: pathspec '([^']*)' " - "did not match any file\(s\) known to git.", command.stderr)[0] + r"did not match any file\(s\) known to git.", command.stderr)[0] closest_branch = utils.get_closest(missing_file, get_branches(), fallback_to_first=False) if closest_branch: diff --git a/thefuck/rules/go_run.py b/thefuck/rules/go_run.py index 79eedc50..b32c646a 100644 --- a/thefuck/rules/go_run.py +++ b/thefuck/rules/go_run.py @@ -1,14 +1,14 @@ # Appends .go when compiling go files -# +# # Example: # > go run foo # error: go run: no go files listed -# -# + def match(command, settings): - return (command.script.startswith ('go run ') + return (command.script.startswith('go run ') and not command.script.endswith('.go')) + def get_new_command(command, settings): return command.script + '.go' diff --git a/thefuck/rules/has_exists_script.py b/thefuck/rules/has_exists_script.py index 19a7e48c..57a12fd5 100644 --- a/thefuck/rules/has_exists_script.py +++ b/thefuck/rules/has_exists_script.py @@ -11,4 +11,3 @@ def match(command, settings): @sudo_support def get_new_command(command, settings): return u'./{}'.format(command.script) - diff --git a/thefuck/rules/history.py b/thefuck/rules/history.py index c02f522c..1fd011b0 100644 --- a/thefuck/rules/history.py +++ b/thefuck/rules/history.py @@ -23,6 +23,7 @@ def _history_of_exists_without_current(command): if not line.startswith(tf_alias) and not line == command.script and line.split(' ')[0] in executables] + def match(command, settings): return len(get_close_matches(command.script, _history_of_exists_without_current(command))) diff --git a/thefuck/rules/javac.py b/thefuck/rules/javac.py index af19cc71..80e6b258 100644 --- a/thefuck/rules/javac.py +++ b/thefuck/rules/javac.py @@ -4,7 +4,7 @@ # > javac foo # error: Class names, 'foo', are only accepted if annotation # processing is explicitly requested - + def match(command, settings): return (command.script.startswith('javac ') diff --git a/thefuck/rules/ls_lah.py b/thefuck/rules/ls_lah.py index 70f6baab..580744bb 100644 --- a/thefuck/rules/ls_lah.py +++ b/thefuck/rules/ls_lah.py @@ -1,7 +1,7 @@ def match(command, settings): return (command.script == 'ls' or command.script.startswith('ls ') - and not ('ls -' in command.script)) + and 'ls -' not in command.script) def get_new_command(command, settings): diff --git a/thefuck/rules/open.py b/thefuck/rules/open.py index 756f2884..22aaea37 100644 --- a/thefuck/rules/open.py +++ b/thefuck/rules/open.py @@ -23,4 +23,4 @@ def match(command, settings): def get_new_command(command, settings): - return 'open http://' + command.script[5:] + return command.script.replace('open ', 'open http://') diff --git a/thefuck/rules/quotation_marks.py b/thefuck/rules/quotation_marks.py index 75e99dd1..c6d5e27a 100644 --- a/thefuck/rules/quotation_marks.py +++ b/thefuck/rules/quotation_marks.py @@ -1,14 +1,12 @@ # Fixes careless " and ' usage -# +# # Example: # > git commit -m 'My Message" -# -# -# + def match(command, settings): - return ('\'' in command.script - and '\"' in command.script) + return '\'' in command.script and '\"' in command.script + def get_new_command(command, settings): - return command.script.replace ('\'', '\"') + return command.script.replace('\'', '\"') diff --git a/thefuck/rules/tmux.py b/thefuck/rules/tmux.py index d58ae37a..2ba446e3 100644 --- a/thefuck/rules/tmux.py +++ b/thefuck/rules/tmux.py @@ -1,4 +1,4 @@ -from thefuck.utils import get_closest, replace_command +from thefuck.utils import replace_command import re diff --git a/thefuck/rules/tsuru_not_command.py b/thefuck/rules/tsuru_not_command.py index 1115a3ae..86b4d15f 100644 --- a/thefuck/rules/tsuru_not_command.py +++ b/thefuck/rules/tsuru_not_command.py @@ -1,6 +1,5 @@ import re -from thefuck.utils import (get_closest, replace_argument, - get_all_matched_commands, replace_command) +from thefuck.utils import get_all_matched_commands, replace_command def match(command, settings): @@ -14,4 +13,3 @@ def get_new_command(command, settings): command.stderr)[0] return replace_command(command, broken_cmd, get_all_matched_commands(command.stderr)) - diff --git a/thefuck/shells.py b/thefuck/shells.py index 6c7a7baa..400d705f 100644 --- a/thefuck/shells.py +++ b/thefuck/shells.py @@ -216,7 +216,7 @@ class Tcsh(Generic): return u'#+{}\n{}\n'.format(int(time()), command_script) -shells = defaultdict(lambda: Generic(), { +shells = defaultdict(Generic, { 'bash': Bash(), 'fish': Fish(), 'zsh': Zsh(), diff --git a/thefuck/types.py b/thefuck/types.py index cc481381..2e5b41af 100644 --- a/thefuck/types.py +++ b/thefuck/types.py @@ -23,7 +23,9 @@ class Settings(dict): return self.get(item) def update(self, **kwargs): - """Returns new settings with new values from `kwargs`.""" - conf = dict(self) - conf.update(kwargs) + """ + Returns new settings with values from `kwargs` for unset settings. + """ + conf = dict(kwargs) + conf.update(self) return Settings(conf)