mirror of
				https://github.com/nvbn/thefuck.git
				synced 2025-10-31 15:12:20 +00:00 
			
		
		
		
	Add excluded_search_path_prefixes setting (#1165)
Improves performance in WSL Fix #1036 * Add excluded_search_path_prefixes setting Allows filtering the paths used to search for commands Can be useful to filter out /mnt/ in WSL for performance * Add test for excluded_search_path_prefixes * Apply suggestions from code review Co-authored-by: Pablo Aguiar <scorphus@gmail.com> Co-authored-by: Pablo Aguiar <scorphus@gmail.com>
This commit is contained in:
		| @@ -434,6 +434,7 @@ Several *The Fuck* parameters can be changed in the file `$XDG_CONFIG_HOME/thefu | ||||
| * `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; | ||||
| * `num_close_matches` – maximum number of close matches to suggest, by default `3`. | ||||
| * `excluded_search_path_prefixes` – path prefixes to ignore when searching for commands, by default `[]`. | ||||
|  | ||||
| An example of `settings.py`: | ||||
|  | ||||
| @@ -466,6 +467,7 @@ rule with lower `priority` will be matched first; | ||||
| * `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_NUM_CLOSE_MATCHES` – maximum number of close matches to suggest, like `5`. | ||||
| * `THEFUCK_EXCLUDED_SEARCH_PATH_PREFIXES` – path prefixes to ignore when searching for commands, by default `[]`. | ||||
|  | ||||
| For example: | ||||
|  | ||||
|   | ||||
| @@ -54,7 +54,8 @@ class TestSettingsFromEnv(object): | ||||
|                            'THEFUCK_PRIORITY': 'bash=10:lisp=wrong:vim=15', | ||||
|                            'THEFUCK_WAIT_SLOW_COMMAND': '999', | ||||
|                            'THEFUCK_SLOW_COMMANDS': 'lein:react-native:./gradlew', | ||||
|                            'THEFUCK_NUM_CLOSE_MATCHES': '359'}) | ||||
|                            'THEFUCK_NUM_CLOSE_MATCHES': '359', | ||||
|                            'THEFUCK_EXCLUDED_SEARCH_PATH_PREFIXES': '/media/:/mnt/'}) | ||||
|         settings.init() | ||||
|         assert settings.rules == ['bash', 'lisp'] | ||||
|         assert settings.exclude_rules == ['git', 'vim'] | ||||
| @@ -65,6 +66,7 @@ class TestSettingsFromEnv(object): | ||||
|         assert settings.wait_slow_command == 999 | ||||
|         assert settings.slow_commands == ['lein', 'react-native', './gradlew'] | ||||
|         assert settings.num_close_matches == 359 | ||||
|         assert settings.excluded_search_path_prefixes == ['/media/', '/mnt/'] | ||||
|  | ||||
|     def test_from_env_with_DEFAULT(self, os_environ, settings): | ||||
|         os_environ.update({'THEFUCK_RULES': 'DEFAULT_RULES:bash:lisp'}) | ||||
|   | ||||
| @@ -94,6 +94,20 @@ def test_get_all_executables_pathsep(path, pathsep): | ||||
|         Path_mock.assert_has_calls([call(p) for p in path.split(pathsep)], True) | ||||
|  | ||||
|  | ||||
| @pytest.mark.usefixtures('no_memoize', 'os_environ_pathsep') | ||||
| @pytest.mark.parametrize('path, pathsep, excluded', [ | ||||
|     ('/foo:/bar:/baz:/foo/bar:/mnt/foo', ':', '/mnt/foo'), | ||||
|     (r'C:\\foo;C:\\bar;C:\\baz;C:\\foo\\bar;Z:\\foo', ';', r'Z:\\foo')]) | ||||
| def test_get_all_executables_exclude_paths(path, pathsep, excluded, settings): | ||||
|     settings.init() | ||||
|     settings.excluded_search_path_prefixes = [excluded] | ||||
|     with patch('thefuck.utils.Path') as Path_mock: | ||||
|         get_all_executables() | ||||
|         path_list = path.split(pathsep) | ||||
|         assert call(path_list[-1]) not in Path_mock.mock_calls | ||||
|         assert all(call(p) in Path_mock.mock_calls for p in path_list[:-1]) | ||||
|  | ||||
|  | ||||
| @pytest.mark.parametrize('args, result', [ | ||||
|     (('apt-get instol vim', 'instol', 'install'), 'apt-get install vim'), | ||||
|     (('git brnch', 'brnch', 'branch'), 'git branch')]) | ||||
|   | ||||
| @@ -101,7 +101,7 @@ class Settings(dict): | ||||
|         elif attr in ('require_confirmation', 'no_colors', 'debug', | ||||
|                       'alter_history', 'instant_mode'): | ||||
|             return val.lower() == 'true' | ||||
|         elif attr == 'slow_commands': | ||||
|         elif attr in ('slow_commands', 'excluded_search_path_prefixes'): | ||||
|             return val.split(':') | ||||
|         else: | ||||
|             return val | ||||
|   | ||||
| @@ -43,7 +43,8 @@ DEFAULT_SETTINGS = {'rules': DEFAULT_RULES, | ||||
|                     'repeat': False, | ||||
|                     'instant_mode': False, | ||||
|                     'num_close_matches': 3, | ||||
|                     'env': {'LC_ALL': 'C', 'LANG': 'C', 'GIT_TRACE': '1'}} | ||||
|                     'env': {'LC_ALL': 'C', 'LANG': 'C', 'GIT_TRACE': '1'}, | ||||
|                     'excluded_search_path_prefixes': []} | ||||
|  | ||||
| ENV_TO_ATTR = {'THEFUCK_RULES': 'rules', | ||||
|                'THEFUCK_EXCLUDE_RULES': 'exclude_rules', | ||||
| @@ -58,7 +59,8 @@ ENV_TO_ATTR = {'THEFUCK_RULES': 'rules', | ||||
|                'THEFUCK_SLOW_COMMANDS': 'slow_commands', | ||||
|                'THEFUCK_REPEAT': 'repeat', | ||||
|                'THEFUCK_INSTANT_MODE': 'instant_mode', | ||||
|                'THEFUCK_NUM_CLOSE_MATCHES': 'num_close_matches'} | ||||
|                'THEFUCK_NUM_CLOSE_MATCHES': 'num_close_matches', | ||||
|                'THEFUCK_EXCLUDED_SEARCH_PATH_PREFIXES': 'excluded_search_path_prefixes'} | ||||
|  | ||||
| SETTINGS_HEADER = u"""# The Fuck settings file | ||||
| # | ||||
|   | ||||
| @@ -104,6 +104,10 @@ def get_close_matches(word, possibilities, n=None, cutoff=0.6): | ||||
|     return difflib_get_close_matches(word, possibilities, n, cutoff) | ||||
|  | ||||
|  | ||||
| def include_path_in_search(path): | ||||
|     return not any(path.startswith(x) for x in settings.excluded_search_path_prefixes) | ||||
|  | ||||
|  | ||||
| @memoize | ||||
| def get_all_executables(): | ||||
|     from thefuck.shells import shell | ||||
| @@ -119,6 +123,7 @@ def get_all_executables(): | ||||
|  | ||||
|     bins = [exe.name.decode('utf8') if six.PY2 else exe.name | ||||
|             for path in os.environ.get('PATH', '').split(os.pathsep) | ||||
|             if include_path_in_search(path) | ||||
|             for exe in _safe(lambda: list(Path(path).iterdir()), []) | ||||
|             if not _safe(exe.is_dir, True) | ||||
|             and exe.name not in tf_entry_points] | ||||
|   | ||||
		Reference in New Issue
	
	Block a user