mirror of
https://github.com/nvbn/thefuck.git
synced 2025-01-31 02:01:13 +00:00
#N/A Add history rule
This commit is contained in:
parent
f40b63f44b
commit
7ebc8a38af
@ -169,6 +169,7 @@ using the matched rule and runs it. Rules enabled by default are as follows:
|
|||||||
* `go_run` – appends `.go` extension when compiling/running Go programs
|
* `go_run` – appends `.go` extension when compiling/running Go programs
|
||||||
* `grep_recursive` – adds `-r` when you trying to grep directory;
|
* `grep_recursive` – adds `-r` when you trying to grep directory;
|
||||||
* `has_exists_script` – prepends `./` when script/binary exists;
|
* `has_exists_script` – prepends `./` when script/binary exists;
|
||||||
|
* `history` – tries to replace command with most similar command from history;
|
||||||
* `java` – removes `.java` extension when running Java programs;
|
* `java` – removes `.java` extension when running Java programs;
|
||||||
* `javac` – appends missing `.java` when compiling Java files;
|
* `javac` – appends missing `.java` when compiling Java files;
|
||||||
* `lein_not_task` – fixes wrong `lein` tasks like `lein rpl`;
|
* `lein_not_task` – fixes wrong `lein` tasks like `lein rpl`;
|
||||||
|
6
tests/conftest.py
Normal file
6
tests/conftest.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def no_memoize(monkeypatch):
|
||||||
|
monkeypatch.setattr('thefuck.utils.memoize.disabled', True)
|
35
tests/rules/test_history.py
Normal file
35
tests/rules/test_history.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import pytest
|
||||||
|
from thefuck.rules.history import match, get_new_command
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def history(mocker):
|
||||||
|
return mocker.patch('thefuck.rules.history.get_history',
|
||||||
|
return_value=['ls cat', 'diff x', 'nocommand x'])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def callables(mocker):
|
||||||
|
return mocker.patch('thefuck.rules.history.get_all_callables',
|
||||||
|
return_value=['diff', 'ls'])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('history', 'callables', 'no_memoize')
|
||||||
|
@pytest.mark.parametrize('script', ['ls cet', 'daff x'])
|
||||||
|
def test_match(script):
|
||||||
|
assert match(Command(script=script), None)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('history', 'callables', 'no_memoize')
|
||||||
|
@pytest.mark.parametrize('script', ['apt-get', 'nocommand y'])
|
||||||
|
def test_not_match(script):
|
||||||
|
assert not match(Command(script=script), None)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('history', 'callables', 'no_memoize')
|
||||||
|
@pytest.mark.parametrize('script, result', [
|
||||||
|
('ls cet', 'ls cat'),
|
||||||
|
('daff x', 'diff x')])
|
||||||
|
def test_get_new_command(script, result):
|
||||||
|
assert get_new_command(Command(script), None) == result
|
@ -1,36 +1,42 @@
|
|||||||
from mock import patch, Mock
|
import pytest
|
||||||
from thefuck.rules.no_command import match, get_new_command, _get_all_callables
|
from thefuck.rules.no_command import match, get_new_command, get_all_callables
|
||||||
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
@patch('thefuck.rules.no_command._safe', return_value=[])
|
@pytest.fixture(autouse=True)
|
||||||
@patch('thefuck.rules.no_command.get_aliases',
|
def _safe(mocker):
|
||||||
return_value=['vim', 'apt-get', 'fsck', 'fuck'])
|
mocker.patch('thefuck.rules.no_command._safe', return_value=[])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def get_aliases(mocker):
|
||||||
|
mocker.patch('thefuck.rules.no_command.get_aliases',
|
||||||
|
return_value=['vim', 'apt-get', 'fsck', 'fuck'])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('no_memoize')
|
||||||
def test_get_all_callables(*args):
|
def test_get_all_callables(*args):
|
||||||
all_callables = _get_all_callables()
|
all_callables = get_all_callables()
|
||||||
assert 'vim' in all_callables
|
assert 'vim' in all_callables
|
||||||
assert 'fsck' in all_callables
|
assert 'fsck' in all_callables
|
||||||
assert 'fuck' not in all_callables
|
assert 'fuck' not in all_callables
|
||||||
|
|
||||||
|
|
||||||
@patch('thefuck.rules.no_command._safe', return_value=[])
|
@pytest.mark.usefixtures('no_memoize')
|
||||||
@patch('thefuck.rules.no_command.get_aliases',
|
|
||||||
return_value=['vim', 'apt-get', 'fsck', 'fuck'])
|
|
||||||
def test_match(*args):
|
def test_match(*args):
|
||||||
assert match(Mock(stderr='vom: not found', script='vom file.py'), None)
|
assert match(Command(stderr='vom: not found', script='vom file.py'), None)
|
||||||
assert match(Mock(stderr='fucck: not found', script='fucck'), None)
|
assert match(Command(stderr='fucck: not found', script='fucck'), None)
|
||||||
assert not match(Mock(stderr='qweqwe: not found', script='qweqwe'), None)
|
assert not match(Command(stderr='qweqwe: not found', script='qweqwe'), None)
|
||||||
assert not match(Mock(stderr='some text', script='vom file.py'), None)
|
assert not match(Command(stderr='some text', script='vom file.py'), None)
|
||||||
|
|
||||||
|
|
||||||
@patch('thefuck.rules.no_command._safe', return_value=[])
|
@pytest.mark.usefixtures('no_memoize')
|
||||||
@patch('thefuck.rules.no_command.get_aliases',
|
|
||||||
return_value=['vim', 'apt-get', 'fsck', 'fuck'])
|
|
||||||
def test_get_new_command(*args):
|
def test_get_new_command(*args):
|
||||||
assert get_new_command(
|
assert get_new_command(
|
||||||
Mock(stderr='vom: not found',
|
Command(stderr='vom: not found',
|
||||||
script='vom file.py'),
|
script='vom file.py'),
|
||||||
None) == 'vim file.py'
|
None) == 'vim file.py'
|
||||||
assert get_new_command(
|
assert get_new_command(
|
||||||
Mock(stderr='fucck: not found',
|
Command(stderr='fucck: not found',
|
||||||
script='fucck'),
|
script='fucck'),
|
||||||
None) == 'fsck'
|
Command) == 'fsck'
|
||||||
|
@ -2,7 +2,7 @@ import pytest
|
|||||||
from mock import Mock
|
from mock import Mock
|
||||||
from thefuck.utils import sudo_support, wrap_settings, memoize, get_closest
|
from thefuck.utils import sudo_support, wrap_settings, memoize, get_closest
|
||||||
from thefuck.types import Settings
|
from thefuck.types import Settings
|
||||||
from tests.utils import Command, no_memoize
|
from tests.utils import Command
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('override, old, new', [
|
@pytest.mark.parametrize('override, old, new', [
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import pytest
|
|
||||||
from thefuck import types
|
from thefuck import types
|
||||||
from thefuck.conf import DEFAULT_PRIORITY
|
from thefuck.conf import DEFAULT_PRIORITY
|
||||||
|
|
||||||
@ -15,7 +14,3 @@ def Rule(name='', match=lambda *_: True,
|
|||||||
return types.Rule(name, match, get_new_command,
|
return types.Rule(name, match, get_new_command,
|
||||||
enabled_by_default, side_effect,
|
enabled_by_default, side_effect,
|
||||||
priority)
|
priority)
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def no_memoize(monkeypatch):
|
|
||||||
monkeypatch.setattr('thefuck.utils.memoize.disabled', True)
|
|
||||||
|
24
thefuck/rules/history.py
Normal file
24
thefuck/rules/history.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
from difflib import get_close_matches
|
||||||
|
from thefuck.shells import get_history
|
||||||
|
from thefuck.utils import get_closest, memoize
|
||||||
|
from thefuck.rules.no_command import get_all_callables
|
||||||
|
|
||||||
|
|
||||||
|
@memoize
|
||||||
|
def _history_of_exists_without_current(command):
|
||||||
|
callables = get_all_callables()
|
||||||
|
return [line for line in get_history()
|
||||||
|
if line != command.script
|
||||||
|
and line.split(' ')[0] in callables]
|
||||||
|
|
||||||
|
|
||||||
|
def match(command, settings):
|
||||||
|
return len(get_close_matches(command.script,
|
||||||
|
_history_of_exists_without_current(command)))
|
||||||
|
|
||||||
|
|
||||||
|
def get_new_command(command, settings):
|
||||||
|
return get_closest(command.script,
|
||||||
|
_history_of_exists_without_current(command))
|
||||||
|
|
||||||
|
priority = 9999
|
@ -1,7 +1,7 @@
|
|||||||
from difflib import get_close_matches
|
from difflib import get_close_matches
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from thefuck.utils import sudo_support
|
from thefuck.utils import sudo_support, memoize
|
||||||
from thefuck.shells import thefuck_alias, get_aliases
|
from thefuck.shells import thefuck_alias, get_aliases
|
||||||
|
|
||||||
|
|
||||||
@ -12,7 +12,8 @@ def _safe(fn, fallback):
|
|||||||
return fallback
|
return fallback
|
||||||
|
|
||||||
|
|
||||||
def _get_all_callables():
|
@memoize
|
||||||
|
def get_all_callables():
|
||||||
tf_alias = thefuck_alias()
|
tf_alias = thefuck_alias()
|
||||||
return [exe.name
|
return [exe.name
|
||||||
for path in os.environ.get('PATH', '').split(':')
|
for path in os.environ.get('PATH', '').split(':')
|
||||||
@ -25,14 +26,14 @@ def _get_all_callables():
|
|||||||
def match(command, settings):
|
def match(command, settings):
|
||||||
return 'not found' in command.stderr and \
|
return 'not found' in command.stderr and \
|
||||||
bool(get_close_matches(command.script.split(' ')[0],
|
bool(get_close_matches(command.script.split(' ')[0],
|
||||||
_get_all_callables()))
|
get_all_callables()))
|
||||||
|
|
||||||
|
|
||||||
@sudo_support
|
@sudo_support
|
||||||
def get_new_command(command, settings):
|
def get_new_command(command, settings):
|
||||||
old_command = command.script.split(' ')[0]
|
old_command = command.script.split(' ')[0]
|
||||||
new_command = get_close_matches(old_command,
|
new_command = get_close_matches(old_command,
|
||||||
_get_all_callables())[0]
|
get_all_callables())[0]
|
||||||
return ' '.join([new_command] + command.script.split(' ')[1:])
|
return ' '.join([new_command] + command.script.split(' ')[1:])
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user