mirror of
				https://github.com/nvbn/thefuck.git
				synced 2025-10-31 07:04:12 +00:00 
			
		
		
		
	#620: Add support of arguments to fuck, like fuck -y on zsh
				
					
				
			This commit is contained in:
		| @@ -40,17 +40,17 @@ class TestZsh(object): | |||||||
|             'll': 'ls -alF'} |             'll': 'ls -alF'} | ||||||
|  |  | ||||||
|     def test_app_alias(self, shell): |     def test_app_alias(self, shell): | ||||||
|         assert 'alias fuck' in shell.app_alias('fuck') |         assert 'fuck () {' in shell.app_alias('fuck') | ||||||
|         assert 'alias FUCK' in shell.app_alias('FUCK') |         assert 'FUCK () {' in shell.app_alias('FUCK') | ||||||
|         assert 'thefuck' in shell.app_alias('fuck') |         assert 'thefuck' in shell.app_alias('fuck') | ||||||
|         assert 'PYTHONIOENCODING' in shell.app_alias('fuck') |         assert 'PYTHONIOENCODING' in shell.app_alias('fuck') | ||||||
|  |  | ||||||
|     def test_app_alias_variables_correctly_set(self, shell): |     def test_app_alias_variables_correctly_set(self, shell): | ||||||
|         alias = shell.app_alias('fuck') |         alias = shell.app_alias('fuck') | ||||||
|         assert "alias fuck='TF_CMD=$(TF_ALIAS" in alias |         assert "fuck () {" in alias | ||||||
|         assert '$(TF_ALIAS=fuck PYTHONIOENCODING' in alias |         assert "TF_ALIAS=fuck" in alias | ||||||
|         assert 'PYTHONIOENCODING=utf-8 TF_SHELL_ALIASES' in alias |         assert 'PYTHONIOENCODING=utf-8' in alias | ||||||
|         assert 'ALIASES=$(alias) thefuck' in alias |         assert 'TF_SHELL_ALIASES=$(alias)' in alias | ||||||
|  |  | ||||||
|     def test_get_history(self, history_lines, shell): |     def test_get_history(self, history_lines, shell): | ||||||
|         history_lines([': 1432613911:0;ls', ': 1432613916:0;rm']) |         history_lines([': 1432613911:0;ls', ': 1432613916:0;rm']) | ||||||
|   | |||||||
							
								
								
									
										26
									
								
								tests/test_argument_parser.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								tests/test_argument_parser.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | import pytest | ||||||
|  | from thefuck.argument_parser import Parser | ||||||
|  | from thefuck.const import ARGUMENT_PLACEHOLDER | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('argv, result', [ | ||||||
|  |     (['thefuck'], {'alias': None, 'command': [], 'yes': False, | ||||||
|  |                    'help': False, 'version': False}), | ||||||
|  |     (['thefuck', '-a'], {'alias': 'fuck', 'command': [], 'yes': False, | ||||||
|  |                          'help': False, 'version': False}), | ||||||
|  |     (['thefuck', '-a', 'fix'], {'alias': 'fix', 'command': [], 'yes': False, | ||||||
|  |                                 'help': False, 'version': False}), | ||||||
|  |     (['thefuck', 'git', 'branch', ARGUMENT_PLACEHOLDER, '-y'], | ||||||
|  |      {'alias': None, 'command': ['git', 'branch'], 'yes': True, | ||||||
|  |       'help': False, 'version': False}), | ||||||
|  |     (['thefuck', 'git', 'branch', '-a', ARGUMENT_PLACEHOLDER, '-y'], | ||||||
|  |      {'alias': None, 'command': ['git', 'branch', '-a'], 'yes': True, | ||||||
|  |       'help': False, 'version': False}), | ||||||
|  |     (['thefuck', ARGUMENT_PLACEHOLDER, '-v'], | ||||||
|  |      {'alias': None, 'command': [], 'yes': False, 'help': False, | ||||||
|  |       'version': True}), | ||||||
|  |     (['thefuck', ARGUMENT_PLACEHOLDER, '--help'], | ||||||
|  |      {'alias': None, 'command': [], 'yes': False, 'help': True, | ||||||
|  |       'version': False})]) | ||||||
|  | def test_parse(argv, result): | ||||||
|  |     assert vars(Parser().parse(argv)) == result | ||||||
							
								
								
									
										48
									
								
								thefuck/argument_parser.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								thefuck/argument_parser.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | import sys | ||||||
|  | from argparse import ArgumentParser | ||||||
|  | from .const import ARGUMENT_PLACEHOLDER | ||||||
|  | from .utils import get_alias | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Parser(object): | ||||||
|  |     def __init__(self): | ||||||
|  |         self._parser = ArgumentParser(prog='thefuck', add_help=False) | ||||||
|  |         self._parser.add_argument( | ||||||
|  |             '-v', '--version', | ||||||
|  |             action='store_true', | ||||||
|  |             help="show program's version number and exit") | ||||||
|  |         self._parser.add_argument( | ||||||
|  |             '-a', '--alias', | ||||||
|  |             nargs='?', | ||||||
|  |             const=get_alias(), | ||||||
|  |             help='[custom-alias-name] prints alias for current shell') | ||||||
|  |         self._parser.add_argument( | ||||||
|  |             '-h', '--help', | ||||||
|  |             action='store_true', | ||||||
|  |             help='show this help message and exit') | ||||||
|  |         self._parser.add_argument( | ||||||
|  |             '-y', '--yes', | ||||||
|  |             action='store_true', | ||||||
|  |             help='execute fixed command without confirmation') | ||||||
|  |         self._parser.add_argument('command', | ||||||
|  |                                   nargs='*', | ||||||
|  |                                   help='command that should be fixed') | ||||||
|  |  | ||||||
|  |     def _get_arguments(self, argv): | ||||||
|  |         if ARGUMENT_PLACEHOLDER in argv: | ||||||
|  |             index = argv.index(ARGUMENT_PLACEHOLDER) | ||||||
|  |             return argv[index + 1:] + ['--'] + argv[:index] | ||||||
|  |         elif argv and not argv[0].startswith('-') and argv[0] != '--': | ||||||
|  |             return ['--'] + argv | ||||||
|  |         else: | ||||||
|  |             return argv | ||||||
|  |  | ||||||
|  |     def parse(self, argv): | ||||||
|  |         arguments = self._get_arguments(argv[1:]) | ||||||
|  |         return self._parser.parse_args(arguments) | ||||||
|  |  | ||||||
|  |     def print_usage(self): | ||||||
|  |         self._parser.print_usage(sys.stderr) | ||||||
|  |  | ||||||
|  |     def print_help(self): | ||||||
|  |         self._parser.print_help(sys.stderr) | ||||||
| @@ -14,7 +14,7 @@ class Settings(dict): | |||||||
|     def __setattr__(self, key, value): |     def __setattr__(self, key, value): | ||||||
|         self[key] = value |         self[key] = value | ||||||
|  |  | ||||||
|     def init(self): |     def init(self, args=None): | ||||||
|         """Fills `settings` with values from `settings.py` and env.""" |         """Fills `settings` with values from `settings.py` and env.""" | ||||||
|         from .logs import exception |         from .logs import exception | ||||||
|  |  | ||||||
| @@ -31,6 +31,8 @@ class Settings(dict): | |||||||
|         except Exception: |         except Exception: | ||||||
|             exception("Can't load settings from env", sys.exc_info()) |             exception("Can't load settings from env", sys.exc_info()) | ||||||
|  |  | ||||||
|  |         self.update(self._settings_from_args(args)) | ||||||
|  |  | ||||||
|     def _init_settings_file(self): |     def _init_settings_file(self): | ||||||
|         settings_path = self.user_dir.joinpath('settings.py') |         settings_path = self.user_dir.joinpath('settings.py') | ||||||
|         if not settings_path.is_file(): |         if not settings_path.is_file(): | ||||||
| @@ -109,5 +111,12 @@ class Settings(dict): | |||||||
|                 for env, attr in const.ENV_TO_ATTR.items() |                 for env, attr in const.ENV_TO_ATTR.items() | ||||||
|                 if env in os.environ} |                 if env in os.environ} | ||||||
|  |  | ||||||
|  |     def _settings_from_args(self, args): | ||||||
|  |         """Loads settings from args.""" | ||||||
|  |         if args and args.yes: | ||||||
|  |             return {'require_confirmation': False} | ||||||
|  |         else: | ||||||
|  |             return {} | ||||||
|  |  | ||||||
|  |  | ||||||
| settings = Settings(const.DEFAULT_SETTINGS) | settings = Settings(const.DEFAULT_SETTINGS) | ||||||
|   | |||||||
| @@ -59,3 +59,5 @@ SETTINGS_HEADER = u"""# The Fuck settings file | |||||||
| # | # | ||||||
|  |  | ||||||
| """ | """ | ||||||
|  |  | ||||||
|  | ARGUMENT_PLACEHOLDER = 'THEFUCK_ARGUMENT_PLACEHOLDER' | ||||||
|   | |||||||
| @@ -121,3 +121,9 @@ def configured_successfully(configuration_details): | |||||||
|             bold=color(colorama.Style.BRIGHT), |             bold=color(colorama.Style.BRIGHT), | ||||||
|             reset=color(colorama.Style.RESET_ALL), |             reset=color(colorama.Style.RESET_ALL), | ||||||
|             reload=configuration_details.reload)) |             reload=configuration_details.reload)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def version(thefuck_version, python_version): | ||||||
|  |     print(u'The Fuck {} using Python {}'.format(thefuck_version, | ||||||
|  |                                                 python_version), | ||||||
|  |           file=sys.stderr) | ||||||
|   | |||||||
| @@ -3,7 +3,6 @@ from .system import init_output | |||||||
|  |  | ||||||
| init_output() | init_output() | ||||||
|  |  | ||||||
| from argparse import ArgumentParser  # noqa: E402 |  | ||||||
| from pprint import pformat  # noqa: E402 | from pprint import pformat  # noqa: E402 | ||||||
| import sys  # noqa: E402 | import sys  # noqa: E402 | ||||||
| from . import logs, types  # noqa: E402 | from . import logs, types  # noqa: E402 | ||||||
| @@ -11,18 +10,19 @@ from .shells import shell  # noqa: E402 | |||||||
| from .conf import settings  # noqa: E402 | from .conf import settings  # noqa: E402 | ||||||
| from .corrector import get_corrected_commands  # noqa: E402 | from .corrector import get_corrected_commands  # noqa: E402 | ||||||
| from .exceptions import EmptyCommand  # noqa: E402 | from .exceptions import EmptyCommand  # noqa: E402 | ||||||
| from .utils import get_installation_info, get_alias  # noqa: E402 |  | ||||||
| from .ui import select_command  # noqa: E402 | from .ui import select_command  # noqa: E402 | ||||||
|  | from .argument_parser import Parser  # noqa: E402 | ||||||
|  | from .utils import get_installation_info  # noqa: E402 | ||||||
|  |  | ||||||
|  |  | ||||||
| def fix_command(): | def fix_command(known_args): | ||||||
|     """Fixes previous command. Used when `thefuck` called without arguments.""" |     """Fixes previous command. Used when `thefuck` called without arguments.""" | ||||||
|     settings.init() |     settings.init(known_args) | ||||||
|     with logs.debug_time('Total'): |     with logs.debug_time('Total'): | ||||||
|         logs.debug(u'Run with settings: {}'.format(pformat(settings))) |         logs.debug(u'Run with settings: {}'.format(pformat(settings))) | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
|             command = types.Command.from_raw_script(sys.argv[1:]) |             command = types.Command.from_raw_script(known_args.command) | ||||||
|         except EmptyCommand: |         except EmptyCommand: | ||||||
|             logs.debug('Empty command, nothing to do') |             logs.debug('Empty command, nothing to do') | ||||||
|             return |             return | ||||||
| @@ -36,34 +36,18 @@ def fix_command(): | |||||||
|             sys.exit(1) |             sys.exit(1) | ||||||
|  |  | ||||||
|  |  | ||||||
| def print_alias(): |  | ||||||
|     """Prints alias for current shell.""" |  | ||||||
|     try: |  | ||||||
|         alias = sys.argv[2] |  | ||||||
|     except IndexError: |  | ||||||
|         alias = get_alias() |  | ||||||
|  |  | ||||||
|     print(shell.app_alias(alias)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def main(): | def main(): | ||||||
|     parser = ArgumentParser(prog='thefuck') |     parser = Parser() | ||||||
|     version = get_installation_info().version |     known_args = parser.parse(sys.argv) | ||||||
|     parser.add_argument('-v', '--version', |  | ||||||
|                         action='version', |  | ||||||
|                         version='The Fuck {} using Python {}'.format( |  | ||||||
|                             version, sys.version.split()[0])) |  | ||||||
|     parser.add_argument('-a', '--alias', |  | ||||||
|                         action='store_true', |  | ||||||
|                         help='[custom-alias-name] prints alias for current shell') |  | ||||||
|     parser.add_argument('command', |  | ||||||
|                         nargs='*', |  | ||||||
|                         help='command that should be fixed') |  | ||||||
|     known_args = parser.parse_args(sys.argv[1:2]) |  | ||||||
|  |  | ||||||
|     if known_args.alias: |     if known_args.help: | ||||||
|         print_alias() |         parser.print_help() | ||||||
|  |     elif known_args.version: | ||||||
|  |         logs.version(get_installation_info().version, | ||||||
|  |                      sys.version.split()[0]) | ||||||
|     elif known_args.command: |     elif known_args.command: | ||||||
|         fix_command() |         fix_command(known_args) | ||||||
|  |     elif known_args.alias: | ||||||
|  |         print(shell.app_alias(known_args.alias)) | ||||||
|     else: |     else: | ||||||
|         parser.print_usage() |         parser.print_usage() | ||||||
|   | |||||||
| @@ -1,23 +1,28 @@ | |||||||
| from time import time | from time import time | ||||||
| import os | import os | ||||||
| from ..conf import settings | from ..conf import settings | ||||||
|  | from ..const import ARGUMENT_PLACEHOLDER | ||||||
| from ..utils import memoize | from ..utils import memoize | ||||||
| from .generic import Generic | from .generic import Generic | ||||||
|  |  | ||||||
|  |  | ||||||
| class Zsh(Generic): | class Zsh(Generic): | ||||||
|     def app_alias(self, alias_name): |     def app_alias(self, alias_name): | ||||||
|         # It is VERY important to have the variables declared WITHIN the alias |         # It is VERY important to have the variables declared WITHIN the function | ||||||
|         alias = "alias {0}='TF_CMD=$(TF_ALIAS={0}" \ |         return ''' | ||||||
|                 " PYTHONIOENCODING=utf-8" \ |             {name} () {{ | ||||||
|                 " TF_SHELL_ALIASES=$(alias)" \ |                 TF_ALIAS={name}; | ||||||
|                 " thefuck $(fc -ln -1 | tail -n 1)) &&" \ |                 PYTHONIOENCODING=utf-8; | ||||||
|                 " eval $TF_CMD".format(alias_name) |                 TF_SHELL_ALIASES=$(alias); | ||||||
|  |                 TF_PREVIOUS=$(fc -ln -1 | tail -n 1); | ||||||
|         if settings.alter_history: |                 TF_CMD=$(thefuck $TF_PREVIOUS {argument_placeholder} $*) && eval $TF_CMD; | ||||||
|             return alias + " ; test -n \"$TF_CMD\" && print -s $TF_CMD'" |                 {alter_history} | ||||||
|         else: |             }} | ||||||
|             return alias + "'" |         '''.format( | ||||||
|  |             name=alias_name, | ||||||
|  |             argument_placeholder=ARGUMENT_PLACEHOLDER, | ||||||
|  |             alter_history=('test -n "$TF_CMD" && print -s $TF_CMD' | ||||||
|  |                            if settings.alter_history else '')) | ||||||
|  |  | ||||||
|     def _parse_alias(self, alias): |     def _parse_alias(self, alias): | ||||||
|         name, value = alias.split('=', 1) |         name, value = alias.split('=', 1) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user