mirror of
https://github.com/nvbn/thefuck.git
synced 2025-03-14 14:48:49 +00:00
#842: add settings var to control number of close matches
This commit is contained in:
parent
087c58f21b
commit
5ae637ca34
@ -390,7 +390,8 @@ Several *The Fuck* parameters can be changed in the file `$XDG_CONFIG_HOME/thefu
|
||||
* `history_limit` – numeric value of how many history commands will be scanned, like `2000`;
|
||||
* `alter_history` – push fixed command to history, by default `True`;
|
||||
* `wait_slow_command` – max amount of time in seconds for getting previous command output if it in `slow_commands` list;
|
||||
* `slow_commands` – list of slow commands.
|
||||
* `slow_commands` – list of slow commands;
|
||||
* `num_close_matches` – maximum number of close matches to suggest, by default `3`.
|
||||
|
||||
An example of `settings.py`:
|
||||
|
||||
@ -405,6 +406,7 @@ debug = False
|
||||
history_limit = 9999
|
||||
wait_slow_command = 20
|
||||
slow_commands = ['react-native', 'gradle']
|
||||
num_close_matches = 5
|
||||
```
|
||||
|
||||
Or via environment variables:
|
||||
@ -420,7 +422,8 @@ rule with lower `priority` will be matched first;
|
||||
* `THEFUCK_HISTORY_LIMIT` – how many history commands will be scanned, like `2000`;
|
||||
* `THEFUCK_ALTER_HISTORY` – push fixed command to history `true/false`;
|
||||
* `THEFUCK_WAIT_SLOW_COMMAND` – max amount of time in seconds for getting previous command output if it in `slow_commands` list;
|
||||
* `THEFUCK_SLOW_COMMANDS` – list of slow commands, like `lein:gradle`.
|
||||
* `THEFUCK_SLOW_COMMANDS` – list of slow commands, like `lein:gradle`;
|
||||
* `THEFUCK_NUM_CLOSE_MATCHES` – maximum number of close matches to suggest, like `5`.
|
||||
|
||||
For example:
|
||||
|
||||
@ -432,6 +435,7 @@ export THEFUCK_WAIT_COMMAND=10
|
||||
export THEFUCK_NO_COLORS='false'
|
||||
export THEFUCK_PRIORITY='no_command=9999:apt_get=100'
|
||||
export THEFUCK_HISTORY_LIMIT='2000'
|
||||
export THEFUCK_NUM_CLOSE_MATCHES='5'
|
||||
```
|
||||
|
||||
## Third-party packages with rules
|
||||
|
58
tests/output_readers/test_rerun.py
Normal file
58
tests/output_readers/test_rerun.py
Normal file
@ -0,0 +1,58 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
from mock import Mock, patch
|
||||
from psutil import AccessDenied, TimeoutExpired
|
||||
|
||||
from thefuck.output_readers import rerun
|
||||
|
||||
|
||||
class TestRerun(object):
|
||||
def setup_method(self, test_method):
|
||||
self.patcher = patch('thefuck.output_readers.rerun.Process')
|
||||
process_mock = self.patcher.start()
|
||||
self.proc_mock = process_mock.return_value = Mock()
|
||||
|
||||
def teardown_method(self, test_method):
|
||||
self.patcher.stop()
|
||||
|
||||
@patch('thefuck.output_readers.rerun._wait_output', return_value=False)
|
||||
@patch('thefuck.output_readers.rerun.Popen')
|
||||
def test_get_output(self, popen_mock, wait_output_mock):
|
||||
popen_mock.return_value.stdout.read.return_value = b'output'
|
||||
assert rerun.get_output('', '') is None
|
||||
wait_output_mock.assert_called_once()
|
||||
|
||||
def test_wait_output_is_slow(self, settings):
|
||||
assert rerun._wait_output(Mock(), True)
|
||||
self.proc_mock.wait.assert_called_once_with(settings.wait_slow_command)
|
||||
|
||||
def test_wait_output_is_not_slow(self, settings):
|
||||
assert rerun._wait_output(Mock(), False)
|
||||
self.proc_mock.wait.assert_called_once_with(settings.wait_command)
|
||||
|
||||
@patch('thefuck.output_readers.rerun._kill_process')
|
||||
def test_wait_output_timeout(self, kill_process_mock):
|
||||
self.proc_mock.wait.side_effect = TimeoutExpired(3)
|
||||
self.proc_mock.children.return_value = []
|
||||
assert not rerun._wait_output(Mock(), False)
|
||||
kill_process_mock.assert_called_once_with(self.proc_mock)
|
||||
|
||||
@patch('thefuck.output_readers.rerun._kill_process')
|
||||
def test_wait_output_timeout_children(self, kill_process_mock):
|
||||
self.proc_mock.wait.side_effect = TimeoutExpired(3)
|
||||
self.proc_mock.children.return_value = [Mock()] * 2
|
||||
assert not rerun._wait_output(Mock(), False)
|
||||
assert kill_process_mock.call_count == 3
|
||||
|
||||
def test_kill_process(self):
|
||||
proc = Mock()
|
||||
rerun._kill_process(proc)
|
||||
proc.kill.assert_called_once_with()
|
||||
|
||||
@patch('thefuck.output_readers.rerun.logs')
|
||||
def test_kill_process_access_denied(self, logs_mock):
|
||||
proc = Mock()
|
||||
proc.kill.side_effect = AccessDenied()
|
||||
rerun._kill_process(proc)
|
||||
proc.kill.assert_called_once_with()
|
||||
logs_mock.debug.assert_called_once()
|
@ -53,7 +53,8 @@ class TestSettingsFromEnv(object):
|
||||
'THEFUCK_NO_COLORS': 'false',
|
||||
'THEFUCK_PRIORITY': 'bash=10:lisp=wrong:vim=15',
|
||||
'THEFUCK_WAIT_SLOW_COMMAND': '999',
|
||||
'THEFUCK_SLOW_COMMANDS': 'lein:react-native:./gradlew'})
|
||||
'THEFUCK_SLOW_COMMANDS': 'lein:react-native:./gradlew',
|
||||
'THEFUCK_NUM_CLOSE_MATCHES': '359'})
|
||||
settings.init()
|
||||
assert settings.rules == ['bash', 'lisp']
|
||||
assert settings.exclude_rules == ['git', 'vim']
|
||||
@ -63,6 +64,7 @@ class TestSettingsFromEnv(object):
|
||||
assert settings.priority == {'bash': 10, 'vim': 15}
|
||||
assert settings.wait_slow_command == 999
|
||||
assert settings.slow_commands == ['lein', 'react-native', './gradlew']
|
||||
assert settings.num_close_matches == 359
|
||||
|
||||
def test_from_env_with_DEFAULT(self, os_environ, settings):
|
||||
os_environ.update({'THEFUCK_RULES': 'DEFAULT_RULES:bash:lisp'})
|
||||
|
@ -2,11 +2,11 @@
|
||||
|
||||
import pytest
|
||||
import warnings
|
||||
from mock import Mock
|
||||
from mock import Mock, patch
|
||||
from thefuck.utils import default_settings, \
|
||||
memoize, get_closest, get_all_executables, replace_argument, \
|
||||
get_all_matched_commands, is_app, for_app, cache, \
|
||||
get_valid_history_without_current, _cache
|
||||
get_valid_history_without_current, _cache, get_close_matches
|
||||
from thefuck.types import Command
|
||||
|
||||
|
||||
@ -50,6 +50,18 @@ class TestGetClosest(object):
|
||||
fallback_to_first=False) is None
|
||||
|
||||
|
||||
class TestGetCloseMatches(object):
|
||||
@patch('thefuck.utils.difflib_get_close_matches')
|
||||
def test_call_with_n(self, difflib_mock):
|
||||
get_close_matches('', [], 1)
|
||||
assert difflib_mock.call_args[0][2] == 1
|
||||
|
||||
@patch('thefuck.utils.difflib_get_close_matches')
|
||||
def test_call_without_n(self, difflib_mock, settings):
|
||||
get_close_matches('', [])
|
||||
assert difflib_mock.call_args[0][2] == settings.get('num_close_matches')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def get_aliases(mocker):
|
||||
mocker.patch('thefuck.shells.shell.get_aliases',
|
||||
|
@ -95,7 +95,8 @@ class Settings(dict):
|
||||
return self._rules_from_env(val)
|
||||
elif attr == 'priority':
|
||||
return dict(self._priority_from_env(val))
|
||||
elif attr in ('wait_command', 'history_limit', 'wait_slow_command'):
|
||||
elif attr in ('wait_command', 'history_limit', 'wait_slow_command',
|
||||
'num_close_matches'):
|
||||
return int(val)
|
||||
elif attr in ('require_confirmation', 'no_colors', 'debug',
|
||||
'alter_history', 'instant_mode'):
|
||||
|
@ -42,6 +42,7 @@ DEFAULT_SETTINGS = {'rules': DEFAULT_RULES,
|
||||
'./gradlew', 'vagrant'],
|
||||
'repeat': False,
|
||||
'instant_mode': False,
|
||||
'num_close_matches': 3,
|
||||
'env': {'LC_ALL': 'C', 'LANG': 'C', 'GIT_TRACE': '1'}}
|
||||
|
||||
ENV_TO_ATTR = {'THEFUCK_RULES': 'rules',
|
||||
@ -56,7 +57,8 @@ ENV_TO_ATTR = {'THEFUCK_RULES': 'rules',
|
||||
'THEFUCK_WAIT_SLOW_COMMAND': 'wait_slow_command',
|
||||
'THEFUCK_SLOW_COMMANDS': 'slow_commands',
|
||||
'THEFUCK_REPEAT': 'repeat',
|
||||
'THEFUCK_INSTANT_MODE': 'instant_mode'}
|
||||
'THEFUCK_INSTANT_MODE': 'instant_mode',
|
||||
'THEFUCK_NUM_CLOSE_MATCHES': 'num_close_matches'}
|
||||
|
||||
SETTINGS_HEADER = u"""# The Fuck settings file
|
||||
#
|
||||
|
@ -2,10 +2,9 @@
|
||||
|
||||
import os
|
||||
import six
|
||||
from difflib import get_close_matches
|
||||
from thefuck.specific.sudo import sudo_support
|
||||
from thefuck.rules import cd_mkdir
|
||||
from thefuck.utils import for_app
|
||||
from thefuck.utils import for_app, get_close_matches
|
||||
|
||||
__author__ = "mmussomele"
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
from difflib import get_close_matches
|
||||
from thefuck.utils import get_close_matches
|
||||
from thefuck.specific.git import git_support
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
from difflib import get_close_matches
|
||||
from thefuck.utils import get_closest, get_valid_history_without_current
|
||||
from thefuck.utils import get_close_matches, get_closest, \
|
||||
get_valid_history_without_current
|
||||
|
||||
|
||||
def match(command):
|
||||
|
@ -1,5 +1,4 @@
|
||||
from thefuck.utils import replace_command, for_app
|
||||
from difflib import get_close_matches
|
||||
from thefuck.utils import for_app, get_close_matches, replace_command
|
||||
import re
|
||||
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
from difflib import get_close_matches
|
||||
from thefuck.utils import get_all_executables, \
|
||||
from thefuck.utils import get_all_executables, get_close_matches, \
|
||||
get_valid_history_without_current, get_closest, which
|
||||
from thefuck.specific.sudo import sudo_support
|
||||
|
||||
|
@ -5,7 +5,7 @@ import re
|
||||
import shelve
|
||||
import six
|
||||
from decorator import decorator
|
||||
from difflib import get_close_matches
|
||||
from difflib import get_close_matches as difflib_get_close_matches
|
||||
from functools import wraps
|
||||
from .logs import warn
|
||||
from .conf import settings
|
||||
@ -90,12 +90,19 @@ def get_closest(word, possibilities, n=3, cutoff=0.6, fallback_to_first=True):
|
||||
"""Returns closest match or just first from possibilities."""
|
||||
possibilities = list(possibilities)
|
||||
try:
|
||||
return get_close_matches(word, possibilities, n, cutoff)[0]
|
||||
return difflib_get_close_matches(word, possibilities, n, cutoff)[0]
|
||||
except IndexError:
|
||||
if fallback_to_first:
|
||||
return possibilities[0]
|
||||
|
||||
|
||||
def get_close_matches(word, possibilities, n=None, cutoff=0.6):
|
||||
"""Overrides `difflib.get_close_match` to controle argument `n`."""
|
||||
if n is None:
|
||||
n = settings.num_close_matches
|
||||
return difflib_get_close_matches(word, possibilities, n, cutoff)
|
||||
|
||||
|
||||
@memoize
|
||||
def get_all_executables():
|
||||
from thefuck.shells import shell
|
||||
|
Loading…
x
Reference in New Issue
Block a user