mirror of
https://github.com/nvbn/thefuck.git
synced 2025-01-19 04:21:14 +00:00
Merge pull request #323 from mcarton/fix-file
#320 Add the `fix_file` rule
This commit is contained in:
commit
b16de9c7c2
@ -146,6 +146,7 @@ using the matched rule and runs it. Rules enabled by default are as follows:
|
||||
* `docker_not_command` – fixes wrong docker commands like `docker tags`;
|
||||
* `dry` – fixes repetitions like `git git push`;
|
||||
* `fix_alt_space` – replaces Alt+Space with Space character;
|
||||
* `fix_file` – opens a file with an error in your `$EDITOR`;
|
||||
* `git_add` – fixes *"Did you forget to 'git add'?"*;
|
||||
* `git_branch_delete` – changes `git branch -d` to `git branch -D`;
|
||||
* `git_branch_list` – catches `git branch list` in place of `git branch` and removes created branch;
|
||||
|
188
tests/rules/test_fix_file.py
Normal file
188
tests/rules/test_fix_file.py
Normal file
@ -0,0 +1,188 @@
|
||||
import pytest
|
||||
import os
|
||||
from thefuck.rules.fix_file import match, get_new_command
|
||||
from tests.utils import Command
|
||||
|
||||
|
||||
# (script, file, line, col (or None), stderr)
|
||||
tests = (
|
||||
('gcc a.c', 'a.c', 3, 1,
|
||||
"""
|
||||
a.c: In function 'main':
|
||||
a.c:3:1: error: expected expression before '}' token
|
||||
}
|
||||
^
|
||||
"""),
|
||||
|
||||
('clang a.c', 'a.c', 3, 1,
|
||||
"""
|
||||
a.c:3:1: error: expected expression
|
||||
}
|
||||
^
|
||||
"""),
|
||||
|
||||
('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,
|
||||
"""
|
||||
Search pattern not terminated at a.pl line 2.
|
||||
"""),
|
||||
|
||||
('sh a.sh', 'a.sh', 2, None,
|
||||
"""
|
||||
a.sh: line 2: foo: command not found
|
||||
"""),
|
||||
|
||||
('zsh a.sh', 'a.sh', 2, None,
|
||||
"""
|
||||
a.sh:2: command not found: foo
|
||||
"""),
|
||||
|
||||
('bash a.sh', 'a.sh', 2, None,
|
||||
"""
|
||||
a.sh: line 2: foo: command not found
|
||||
"""),
|
||||
|
||||
('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,
|
||||
"""
|
||||
Compiling test v0.1.0 (file:///tmp/fix-error/test)
|
||||
src/lib.rs:3:5: 3:6 error: unexpected token: `+`
|
||||
src/lib.rs:3 +
|
||||
^
|
||||
Could not compile `test`.
|
||||
|
||||
To learn more, run the command again with --verbose.
|
||||
"""),
|
||||
|
||||
('python a.py', 'a.py', 2, None,
|
||||
"""
|
||||
File "a.py", line 2
|
||||
+
|
||||
^
|
||||
SyntaxError: invalid syntax
|
||||
"""),
|
||||
|
||||
('python a.py', 'a.py', 8, None,
|
||||
"""
|
||||
Traceback (most recent call last):
|
||||
File "a.py", line 8, in <module>
|
||||
match("foo")
|
||||
File "a.py", line 5, in match
|
||||
m = re.search(None, command)
|
||||
File "/usr/lib/python3.4/re.py", line 170, in search
|
||||
return _compile(pattern, flags).search(string)
|
||||
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,
|
||||
"""
|
||||
a.rb:3: syntax error, unexpected keyword_end
|
||||
"""),
|
||||
|
||||
('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: Unknown command 'foo'
|
||||
/tmp/fix-error/a.sh (line 2): foo
|
||||
^
|
||||
"""),
|
||||
|
||||
('./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:1:1: error: expected top-level entity
|
||||
+
|
||||
^
|
||||
"""),
|
||||
|
||||
('go build a.go', 'a.go', 1, None,
|
||||
"""
|
||||
can't load package:
|
||||
a.go:1:1: expected 'package', found '+'
|
||||
"""),
|
||||
|
||||
('make', 'Makefile', 2, None,
|
||||
"""
|
||||
bidule
|
||||
make: bidule: Command not found
|
||||
Makefile:2: recipe for target 'target' failed
|
||||
make: *** [target] Error 127
|
||||
"""),
|
||||
|
||||
('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,
|
||||
"""
|
||||
/Users/pablo/Workspace/barebones/fuck.js:2
|
||||
conole.log(arg); // this should read console.log(arg);
|
||||
^
|
||||
ReferenceError: conole is not defined
|
||||
at /Users/pablo/Workspace/barebones/fuck.js:2:5
|
||||
at Array.forEach (native)
|
||||
at Object.<anonymous> (/Users/pablo/Workspace/barebones/fuck.js:1:85)
|
||||
at Module._compile (module.js:460:26)
|
||||
at Object.Module._extensions..js (module.js:478:10)
|
||||
at Module.load (module.js:355:32)
|
||||
at Function.Module._load (module.js:310:12)
|
||||
at Function.Module.runMain (module.js:501:10)
|
||||
at startup (node.js:129:16)
|
||||
at node.js:814:3
|
||||
"""),
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('test', tests)
|
||||
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)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('test', tests)
|
||||
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)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('test', tests)
|
||||
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)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('test', tests)
|
||||
def test_get_new_command(monkeypatch, test):
|
||||
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]))
|
67
thefuck/rules/fix_file.py
Normal file
67
thefuck/rules/fix_file.py
Normal file
@ -0,0 +1,67 @@
|
||||
import re
|
||||
import os
|
||||
from thefuck.utils import memoize
|
||||
from thefuck import shells
|
||||
|
||||
|
||||
patterns = (
|
||||
# js, node:
|
||||
'^ at {file}:{line}:{col}',
|
||||
# cargo:
|
||||
'^ {file}:{line}:{col}',
|
||||
# python, thefuck:
|
||||
'^ File "{file}", line {line}',
|
||||
# awk:
|
||||
'^awk: {file}:{line}:',
|
||||
# git
|
||||
'^fatal: bad config file line {line} in {file}',
|
||||
# llc:
|
||||
'^llc: {file}:{line}:{col}:',
|
||||
# lua:
|
||||
'^lua: {file}:{line}:',
|
||||
# fish:
|
||||
'^{file} \(line {line}\):',
|
||||
# bash, sh, ssh:
|
||||
'^{file}: line {line}: ',
|
||||
# ghc, make, ruby, zsh:
|
||||
'^{file}:{line}:',
|
||||
# cargo, clang, gcc, go, rustc:
|
||||
'^{file}:{line}:{col}',
|
||||
# perl:
|
||||
'at {file} line {line}',
|
||||
)
|
||||
|
||||
|
||||
# for the sake of readability do not use named groups above
|
||||
def _make_pattern(pattern):
|
||||
pattern = pattern.replace('{file}', '(?P<file>[^:\n]+)')
|
||||
pattern = pattern.replace('{line}', '(?P<line>[0-9]+)')
|
||||
pattern = pattern.replace('{col}', '(?P<col>[0-9]+)')
|
||||
return re.compile(pattern, re.MULTILINE)
|
||||
patterns = [_make_pattern(p) for p in patterns]
|
||||
|
||||
|
||||
@memoize
|
||||
def _search(stderr):
|
||||
for pattern in patterns:
|
||||
m = re.search(pattern, stderr)
|
||||
if m:
|
||||
return m
|
||||
|
||||
|
||||
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'))
|
||||
|
||||
|
||||
def get_new_command(command, settings):
|
||||
m = _search(command.stderr)
|
||||
|
||||
# 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)
|
Loading…
x
Reference in New Issue
Block a user