From 18207f62d4f70240e79935507bcde7cbb22212a7 Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Mon, 1 Jul 2019 12:30:08 -0400 Subject: Small refactor and documentation updates --- cmd2/cmd2.py | 4 ---- 1 file changed, 4 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index a10219b1..0ca9f358 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -1617,11 +1617,7 @@ class Cmd(cmd.Cmd): argparser: argparse.ArgumentParser) -> List[str]: """Default completion function for argparse commands.""" completer = AutoCompleter(argparser, self) - tokens, _ = self.tokens_for_completion(line, begidx, endidx) - if not tokens: - return [] - return completer.complete_command(tokens, text, line, begidx, endidx) def get_all_commands(self) -> List[str]: -- cgit v1.2.1 From b7fa4e46593151086a4186c9d90dc72b809c9b45 Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Tue, 2 Jul 2019 10:47:52 -0400 Subject: Moved basic_complete to utils --- cmd2/cmd2.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 0ca9f358..d6fc78eb 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -910,7 +910,7 @@ class Cmd(cmd.Cmd): :param delimiter: what delimits each portion of the matches (ex: paths are delimited by a slash) :return: a list of possible tab completions """ - matches = self.basic_complete(text, line, begidx, endidx, match_against) + matches = utils.basic_complete(text, line, begidx, endidx, match_against) # Display only the portion of the match that's being completed based on delimiter if matches: @@ -971,7 +971,7 @@ class Cmd(cmd.Cmd): # Perform tab completion using a Collection if isinstance(match_against, Collection): - completions_matches = self.basic_complete(text, line, begidx, endidx, match_against) + completions_matches = utils.basic_complete(text, line, begidx, endidx, match_against) # Perform tab completion using a function elif callable(match_against): @@ -1015,7 +1015,7 @@ class Cmd(cmd.Cmd): # Perform tab completion using a Collection if isinstance(match_against, Collection): - matches = self.basic_complete(text, line, begidx, endidx, match_against) + matches = utils.basic_complete(text, line, begidx, endidx, match_against) # Perform tab completion using a function elif callable(match_against): @@ -1567,8 +1567,8 @@ class Cmd(cmd.Cmd): else: # Complete token against anything a user can run - self.completion_matches = self.basic_complete(text, line, begidx, endidx, - self._get_commands_aliases_and_macros_for_completion()) + self.completion_matches = utils.basic_complete(text, line, begidx, endidx, + self._get_commands_aliases_and_macros_for_completion()) # Handle single result if len(self.completion_matches) == 1: @@ -2648,7 +2648,7 @@ class Cmd(cmd.Cmd): topics = set(self.get_help_topics()) visible_commands = set(self.get_visible_commands()) strs_to_match = list(topics | visible_commands) - return self.basic_complete(text, line, begidx, endidx, strs_to_match) + return utils.basic_complete(text, line, begidx, endidx, strs_to_match) def complete_help_subcommand(self, text: str, line: str, begidx: int, endidx: int) -> List[str]: """Completes the subcommand argument of help""" -- cgit v1.2.1 From 479cab00b4c0bd6a2ce20605f97a8f904dc0136f Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Tue, 2 Jul 2019 10:50:19 -0400 Subject: Removed cmd2.basic_complete function since it was added to utils --- cmd2/cmd2.py | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index d6fc78eb..d65b750c 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -861,21 +861,6 @@ class Cmd(cmd.Cmd): return tokens, raw_tokens - # noinspection PyUnusedLocal - @staticmethod - def basic_complete(text: str, line: str, begidx: int, endidx: int, match_against: Iterable) -> List[str]: - """ - Performs tab completion against a list - - :param text: the string prefix we are attempting to match (all returned matches must begin with it) - :param line: the current input line with leading whitespace removed - :param begidx: the beginning index of the prefix text - :param endidx: the ending index of the prefix text - :param match_against: the list being matched against - :return: a list of possible tab completions - """ - return [cur_match for cur_match in match_against if cur_match.startswith(text)] - def delimiter_complete(self, text: str, line: str, begidx: int, endidx: int, match_against: Iterable, delimiter: str) -> List[str]: """ -- cgit v1.2.1 From b10cc8f39e94e60d9d6adbd4f2ca19f1866cd9ca Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Tue, 2 Jul 2019 13:23:16 -0400 Subject: Added functions to enable tab completion and choices provider functions to argparse argument values --- cmd2/cmd2.py | 111 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 56 insertions(+), 55 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index d65b750c..da2e83b3 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -46,7 +46,7 @@ from . import ansi from . import constants from . import plugin from . import utils -from .argparse_completer import AutoCompleter, ACArgumentParser, ACTION_ARG_CHOICES +from .argparse_completer import AutoCompleter, ACArgumentParser, set_arg_choices_method, set_arg_completer_method from .clipboard import can_clip, get_paste_buffer, write_to_paste_buffer from .history import History, HistoryItem from .parsing import StatementParser, Statement, Macro, MacroArg, shlex_split @@ -617,7 +617,8 @@ class Cmd(cmd.Cmd): if self.broken_pipe_warning: sys.stderr.write(self.broken_pipe_warning) - def perror(self, msg: Any, *, end: str = '\n', apply_style: bool = True) -> None: + @staticmethod + def perror(msg: Any, *, end: str = '\n', apply_style: bool = True) -> None: """Print message to sys.stderr :param msg: message to print (anything convertible to a str with '{}'.format() is OK) @@ -2380,11 +2381,11 @@ class Cmd(cmd.Cmd): description=alias_create_description, epilog=alias_create_epilog) alias_create_parser.add_argument('name', help='name of this alias') - setattr(alias_create_parser.add_argument('command', help='what the alias resolves to'), - ACTION_ARG_CHOICES, _get_commands_aliases_and_macros_for_completion) - setattr(alias_create_parser.add_argument('command_args', nargs=argparse.REMAINDER, - help='arguments to pass to command'), - ACTION_ARG_CHOICES, ('path_complete',)) + set_arg_choices_method(alias_create_parser.add_argument('command', help='what the alias resolves to'), + _get_commands_aliases_and_macros_for_completion) + set_arg_completer_method(alias_create_parser.add_argument('command_args', nargs=argparse.REMAINDER, + help='arguments to pass to command'), + path_complete) alias_create_parser.set_defaults(func=_alias_create) # alias -> delete @@ -2392,8 +2393,8 @@ class Cmd(cmd.Cmd): alias_delete_description = "Delete specified aliases or all aliases if --all is used" alias_delete_parser = alias_subparsers.add_parser('delete', help=alias_delete_help, description=alias_delete_description) - setattr(alias_delete_parser.add_argument('name', nargs='*', help='alias to delete'), - ACTION_ARG_CHOICES, _get_alias_names) + set_arg_choices_method(alias_delete_parser.add_argument('name', nargs='*', help='alias to delete'), + _get_alias_names) alias_delete_parser.add_argument('-a', '--all', action='store_true', help="delete all aliases") alias_delete_parser.set_defaults(func=_alias_delete) @@ -2406,8 +2407,8 @@ class Cmd(cmd.Cmd): alias_list_parser = alias_subparsers.add_parser('list', help=alias_list_help, description=alias_list_description) - setattr(alias_list_parser.add_argument('name', nargs="*", help='alias to list'), - ACTION_ARG_CHOICES, _get_alias_names) + set_arg_choices_method(alias_list_parser.add_argument('name', nargs="*", help='alias to list'), + _get_alias_names) alias_list_parser.set_defaults(func=_alias_list) # Preserve quotes since we are passing strings to other commands @@ -2585,11 +2586,11 @@ class Cmd(cmd.Cmd): description=macro_create_description, epilog=macro_create_epilog) macro_create_parser.add_argument('name', help='name of this macro') - setattr(macro_create_parser.add_argument('command', help='what the macro resolves to'), - ACTION_ARG_CHOICES, _get_commands_aliases_and_macros_for_completion) - setattr(macro_create_parser.add_argument('command_args', nargs=argparse.REMAINDER, - help='arguments to pass to command'), - ACTION_ARG_CHOICES, ('path_complete',)) + set_arg_choices_method(macro_create_parser.add_argument('command', help='what the macro resolves to'), + _get_commands_aliases_and_macros_for_completion) + set_arg_completer_method(macro_create_parser.add_argument('command_args', nargs=argparse.REMAINDER, + help='arguments to pass to command'), + path_complete) macro_create_parser.set_defaults(func=_macro_create) # macro -> delete @@ -2597,8 +2598,8 @@ class Cmd(cmd.Cmd): macro_delete_description = "Delete specified macros or all macros if --all is used" macro_delete_parser = macro_subparsers.add_parser('delete', help=macro_delete_help, description=macro_delete_description) - setattr(macro_delete_parser.add_argument('name', nargs='*', help='macro to delete'), - ACTION_ARG_CHOICES, _get_macro_names) + set_arg_choices_method(macro_delete_parser.add_argument('name', nargs='*', help='macro to delete'), + _get_macro_names) macro_delete_parser.add_argument('-a', '--all', action='store_true', help="delete all macros") macro_delete_parser.set_defaults(func=_macro_delete) @@ -2610,8 +2611,8 @@ class Cmd(cmd.Cmd): "Without arguments, all macros will be listed.") macro_list_parser = macro_subparsers.add_parser('list', help=macro_list_help, description=macro_list_description) - setattr(macro_list_parser.add_argument('name', nargs="*", help='macro to list'), - ACTION_ARG_CHOICES, _get_macro_names) + set_arg_choices_method(macro_list_parser.add_argument('name', nargs="*", help='macro to list'), + _get_macro_names) macro_list_parser.set_defaults(func=_macro_list) # Preserve quotes since we are passing strings to other commands @@ -2670,12 +2671,11 @@ class Cmd(cmd.Cmd): return matches help_parser = ACArgumentParser() - - setattr(help_parser.add_argument('command', help="command to retrieve help for", nargs="?"), - ACTION_ARG_CHOICES, ('complete_help_command',)) - setattr(help_parser.add_argument('subcommand', help="sub-command to retrieve help for", - nargs=argparse.REMAINDER), - ACTION_ARG_CHOICES, ('complete_help_subcommand',)) + set_arg_completer_method(help_parser.add_argument('command', nargs="?", help="command to retrieve help for"), + complete_help_command) + set_arg_completer_method(help_parser.add_argument('subcommand', nargs=argparse.REMAINDER, + help="sub-command to retrieve help for"), + complete_help_subcommand) help_parser.add_argument('-v', '--verbose', action='store_true', help="print a list of all commands with descriptions of each") @@ -2944,8 +2944,8 @@ class Cmd(cmd.Cmd): set_parser = ACArgumentParser(description=set_description) set_parser.add_argument('-a', '--all', action='store_true', help='display read-only settings as well') set_parser.add_argument('-l', '--long', action='store_true', help='describe function of parameter') - setattr(set_parser.add_argument('param', nargs='?', help='parameter to set or view'), - ACTION_ARG_CHOICES, _get_settable_names) + set_arg_choices_method(set_parser.add_argument('param', nargs='?', help='parameter to set or view'), + _get_settable_names) set_parser.add_argument('value', nargs='?', help='the new value for settable') @with_argparser(set_parser) @@ -2987,11 +2987,11 @@ class Cmd(cmd.Cmd): onchange_hook(old=orig_value, new=new_value) shell_parser = ACArgumentParser() - setattr(shell_parser.add_argument('command', help='the command to run'), - ACTION_ARG_CHOICES, ('shell_cmd_complete',)) - setattr(shell_parser.add_argument('command_args', nargs=argparse.REMAINDER, - help='arguments to pass to command'), - ACTION_ARG_CHOICES, ('path_complete',)) + set_arg_completer_method(shell_parser.add_argument('command', help='the command to run'), + shell_cmd_complete) + set_arg_completer_method(shell_parser.add_argument('command_args', nargs=argparse.REMAINDER, + help='arguments to pass to command'), + path_complete) # Preserve quotes since we are passing these strings to the shell @with_argparser(shell_parser, preserve_quotes=True) @@ -3052,8 +3052,8 @@ class Cmd(cmd.Cmd): "by providing no arguments to py and run more complex statements there.") py_parser = ACArgumentParser(description=py_description) - py_parser.add_argument('command', help="command to run", nargs='?') - py_parser.add_argument('remainder', help="remainder of command", nargs=argparse.REMAINDER) + py_parser.add_argument('command', nargs='?', help="command to run") + py_parser.add_argument('remainder', nargs=argparse.REMAINDER, help="remainder of command") # Preserve quotes since we are passing these strings to Python @with_argparser(py_parser, preserve_quotes=True) @@ -3238,11 +3238,11 @@ class Cmd(cmd.Cmd): return bridge.stop run_pyscript_parser = ACArgumentParser() - setattr(run_pyscript_parser.add_argument('script_path', help='path to the script file'), - ACTION_ARG_CHOICES, ('path_complete',)) - setattr(run_pyscript_parser.add_argument('script_arguments', nargs=argparse.REMAINDER, - help='arguments to pass to script'), - ACTION_ARG_CHOICES, ('path_complete',)) + set_arg_completer_method(run_pyscript_parser.add_argument('script_path', help='path to the script file'), + path_complete) + set_arg_completer_method(run_pyscript_parser.add_argument('script_arguments', nargs=argparse.REMAINDER, + help='arguments to pass to script'), + path_complete) @with_argparser(run_pyscript_parser) def do_run_pyscript(self, args: argparse.Namespace) -> bool: @@ -3300,13 +3300,13 @@ class Cmd(cmd.Cmd): history_action_group.add_argument('-r', '--run', action='store_true', help='run selected history items') history_action_group.add_argument('-e', '--edit', action='store_true', help='edit and then run selected history items') - setattr(history_action_group.add_argument('-o', '--output-file', metavar='FILE', - help='output commands to a script file, implies -s'), - ACTION_ARG_CHOICES, ('path_complete',)) - setattr(history_action_group.add_argument('-t', '--transcript', - help='output commands and results to a transcript file,\n' - 'implies -s'), - ACTION_ARG_CHOICES, ('path_complete',)) + set_arg_completer_method(history_action_group.add_argument('-o', '--output-file', metavar='FILE', + help='output commands to a script file, implies -s'), + path_complete) + set_arg_completer_method(history_action_group.add_argument('-t', '--transcript', + help='output commands and results to a transcript\n' + 'file, implies -s'), + path_complete) history_action_group.add_argument('-c', '--clear', action='store_true', help='clear all history') history_format_group = history_parser.add_argument_group(title='formatting') @@ -3596,8 +3596,8 @@ class Cmd(cmd.Cmd): " set editor (program-name)") edit_parser = ACArgumentParser(description=edit_description) - setattr(edit_parser.add_argument('file_path', help="path to a file to open in editor", nargs="?"), - ACTION_ARG_CHOICES, ('path_complete',)) + set_arg_completer_method(edit_parser.add_argument('file_path', nargs="?", help="path to a file to open in editor"), + path_complete) @with_argparser(edit_parser) def do_edit(self, args: argparse.Namespace) -> None: @@ -3629,11 +3629,11 @@ class Cmd(cmd.Cmd): ) run_script_parser = ACArgumentParser(description=run_script_description) - setattr(run_script_parser.add_argument('-t', '--transcript', - help='record the output of the script as a transcript file'), - ACTION_ARG_CHOICES, ('path_complete',)) - setattr(run_script_parser.add_argument('script_path', help="path to the script file"), - ACTION_ARG_CHOICES, ('path_complete',)) + set_arg_completer_method(run_script_parser.add_argument('-t', '--transcript', help='record the output of the ' + 'script as a transcript file'), + path_complete) + set_arg_completer_method(run_script_parser.add_argument('script_path', help="path to the script file"), + path_complete) @with_argparser(run_script_parser) def do_run_script(self, args: argparse.Namespace) -> Optional[bool]: @@ -3962,7 +3962,8 @@ class Cmd(cmd.Cmd): self.disable_command(cmd_name, message_to_print) # noinspection PyUnusedLocal - def _report_disabled_command_usage(self, *args, message_to_print: str, **kwargs) -> None: + @staticmethod + def _report_disabled_command_usage(*args, message_to_print: str, **kwargs) -> None: """ Report when a disabled command has been run or had help called on it :param args: not used -- cgit v1.2.1 From 5014fecf58bb546a453c57eaff7a226f29bfba46 Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Tue, 2 Jul 2019 19:30:50 -0400 Subject: Patched argparse._ActionsContainer.add_argument() to support more settings like enabling tab completion and providing choice generating functions --- cmd2/cmd2.py | 88 +++++++++++++++++++++++++----------------------------------- 1 file changed, 36 insertions(+), 52 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index da2e83b3..0272a7c4 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -46,7 +46,7 @@ from . import ansi from . import constants from . import plugin from . import utils -from .argparse_completer import AutoCompleter, ACArgumentParser, set_arg_choices_method, set_arg_completer_method +from .argparse_completer import AutoCompleter, ACArgumentParser from .clipboard import can_clip, get_paste_buffer, write_to_paste_buffer from .history import History, HistoryItem from .parsing import StatementParser, Statement, Macro, MacroArg, shlex_split @@ -2381,11 +2381,10 @@ class Cmd(cmd.Cmd): description=alias_create_description, epilog=alias_create_epilog) alias_create_parser.add_argument('name', help='name of this alias') - set_arg_choices_method(alias_create_parser.add_argument('command', help='what the alias resolves to'), - _get_commands_aliases_and_macros_for_completion) - set_arg_completer_method(alias_create_parser.add_argument('command_args', nargs=argparse.REMAINDER, - help='arguments to pass to command'), - path_complete) + alias_create_parser.add_argument('command', help='what the alias resolves to', + choices_method=_get_commands_aliases_and_macros_for_completion) + alias_create_parser.add_argument('command_args', nargs=argparse.REMAINDER, help='arguments to pass to command', + completer_method=path_complete) alias_create_parser.set_defaults(func=_alias_create) # alias -> delete @@ -2393,8 +2392,7 @@ class Cmd(cmd.Cmd): alias_delete_description = "Delete specified aliases or all aliases if --all is used" alias_delete_parser = alias_subparsers.add_parser('delete', help=alias_delete_help, description=alias_delete_description) - set_arg_choices_method(alias_delete_parser.add_argument('name', nargs='*', help='alias to delete'), - _get_alias_names) + alias_delete_parser.add_argument('name', nargs='*', help='alias to delete', choices_method=_get_alias_names) alias_delete_parser.add_argument('-a', '--all', action='store_true', help="delete all aliases") alias_delete_parser.set_defaults(func=_alias_delete) @@ -2407,8 +2405,7 @@ class Cmd(cmd.Cmd): alias_list_parser = alias_subparsers.add_parser('list', help=alias_list_help, description=alias_list_description) - set_arg_choices_method(alias_list_parser.add_argument('name', nargs="*", help='alias to list'), - _get_alias_names) + alias_list_parser.add_argument('name', nargs="*", help='alias to list', choices_method=_get_alias_names) alias_list_parser.set_defaults(func=_alias_list) # Preserve quotes since we are passing strings to other commands @@ -2586,11 +2583,10 @@ class Cmd(cmd.Cmd): description=macro_create_description, epilog=macro_create_epilog) macro_create_parser.add_argument('name', help='name of this macro') - set_arg_choices_method(macro_create_parser.add_argument('command', help='what the macro resolves to'), - _get_commands_aliases_and_macros_for_completion) - set_arg_completer_method(macro_create_parser.add_argument('command_args', nargs=argparse.REMAINDER, - help='arguments to pass to command'), - path_complete) + macro_create_parser.add_argument('command', help='what the macro resolves to', + choices_method=_get_commands_aliases_and_macros_for_completion) + macro_create_parser.add_argument('command_args', nargs=argparse.REMAINDER, + help='arguments to pass to command', completer_method=path_complete) macro_create_parser.set_defaults(func=_macro_create) # macro -> delete @@ -2598,8 +2594,7 @@ class Cmd(cmd.Cmd): macro_delete_description = "Delete specified macros or all macros if --all is used" macro_delete_parser = macro_subparsers.add_parser('delete', help=macro_delete_help, description=macro_delete_description) - set_arg_choices_method(macro_delete_parser.add_argument('name', nargs='*', help='macro to delete'), - _get_macro_names) + macro_delete_parser.add_argument('name', nargs='*', help='macro to delete', choices_method=_get_macro_names) macro_delete_parser.add_argument('-a', '--all', action='store_true', help="delete all macros") macro_delete_parser.set_defaults(func=_macro_delete) @@ -2611,8 +2606,7 @@ class Cmd(cmd.Cmd): "Without arguments, all macros will be listed.") macro_list_parser = macro_subparsers.add_parser('list', help=macro_list_help, description=macro_list_description) - set_arg_choices_method(macro_list_parser.add_argument('name', nargs="*", help='macro to list'), - _get_macro_names) + macro_list_parser.add_argument('name', nargs="*", help='macro to list', choices_method=_get_macro_names) macro_list_parser.set_defaults(func=_macro_list) # Preserve quotes since we are passing strings to other commands @@ -2671,11 +2665,10 @@ class Cmd(cmd.Cmd): return matches help_parser = ACArgumentParser() - set_arg_completer_method(help_parser.add_argument('command', nargs="?", help="command to retrieve help for"), - complete_help_command) - set_arg_completer_method(help_parser.add_argument('subcommand', nargs=argparse.REMAINDER, - help="sub-command to retrieve help for"), - complete_help_subcommand) + help_parser.add_argument('command', nargs="?", help="command to retrieve help for", + completer_method=complete_help_command) + help_parser.add_argument('subcommand', nargs=argparse.REMAINDER, help="sub-command to retrieve help for", + completer_method=complete_help_subcommand) help_parser.add_argument('-v', '--verbose', action='store_true', help="print a list of all commands with descriptions of each") @@ -2944,8 +2937,7 @@ class Cmd(cmd.Cmd): set_parser = ACArgumentParser(description=set_description) set_parser.add_argument('-a', '--all', action='store_true', help='display read-only settings as well') set_parser.add_argument('-l', '--long', action='store_true', help='describe function of parameter') - set_arg_choices_method(set_parser.add_argument('param', nargs='?', help='parameter to set or view'), - _get_settable_names) + set_parser.add_argument('param', nargs='?', help='parameter to set or view', choices_method=_get_settable_names) set_parser.add_argument('value', nargs='?', help='the new value for settable') @with_argparser(set_parser) @@ -2987,11 +2979,9 @@ class Cmd(cmd.Cmd): onchange_hook(old=orig_value, new=new_value) shell_parser = ACArgumentParser() - set_arg_completer_method(shell_parser.add_argument('command', help='the command to run'), - shell_cmd_complete) - set_arg_completer_method(shell_parser.add_argument('command_args', nargs=argparse.REMAINDER, - help='arguments to pass to command'), - path_complete) + shell_parser.add_argument('command', help='the command to run', completer_method=shell_cmd_complete) + shell_parser.add_argument('command_args', nargs=argparse.REMAINDER, help='arguments to pass to command', + completer_method=path_complete) # Preserve quotes since we are passing these strings to the shell @with_argparser(shell_parser, preserve_quotes=True) @@ -3238,11 +3228,9 @@ class Cmd(cmd.Cmd): return bridge.stop run_pyscript_parser = ACArgumentParser() - set_arg_completer_method(run_pyscript_parser.add_argument('script_path', help='path to the script file'), - path_complete) - set_arg_completer_method(run_pyscript_parser.add_argument('script_arguments', nargs=argparse.REMAINDER, - help='arguments to pass to script'), - path_complete) + run_pyscript_parser.add_argument('script_path', help='path to the script file', completer_method=path_complete) + run_pyscript_parser.add_argument('script_arguments', nargs=argparse.REMAINDER, + help='arguments to pass to script', completer_method=path_complete) @with_argparser(run_pyscript_parser) def do_run_pyscript(self, args: argparse.Namespace) -> bool: @@ -3300,13 +3288,12 @@ class Cmd(cmd.Cmd): history_action_group.add_argument('-r', '--run', action='store_true', help='run selected history items') history_action_group.add_argument('-e', '--edit', action='store_true', help='edit and then run selected history items') - set_arg_completer_method(history_action_group.add_argument('-o', '--output-file', metavar='FILE', - help='output commands to a script file, implies -s'), - path_complete) - set_arg_completer_method(history_action_group.add_argument('-t', '--transcript', - help='output commands and results to a transcript\n' - 'file, implies -s'), - path_complete) + history_action_group.add_argument('-o', '--output-file', metavar='FILE', + help='output commands to a script file, implies -s', + completer_method=path_complete) + history_action_group.add_argument('-t', '--transcript', help='output commands and results to a transcript file,\n' + 'implies -s', + completer_method=path_complete) history_action_group.add_argument('-c', '--clear', action='store_true', help='clear all history') history_format_group = history_parser.add_argument_group(title='formatting') @@ -3596,8 +3583,8 @@ class Cmd(cmd.Cmd): " set editor (program-name)") edit_parser = ACArgumentParser(description=edit_description) - set_arg_completer_method(edit_parser.add_argument('file_path', nargs="?", help="path to a file to open in editor"), - path_complete) + edit_parser.add_argument('file_path', nargs="?", + help="path to a file to open in editor", completer_method=path_complete) @with_argparser(edit_parser) def do_edit(self, args: argparse.Namespace) -> None: @@ -3625,15 +3612,12 @@ class Cmd(cmd.Cmd): "typed in the console.\n" "\n" "If the -r/--record_transcript flag is used, this command instead records\n" - "the output of the script commands to a transcript for testing purposes.\n" - ) + "the output of the script commands to a transcript for testing purposes.\n") run_script_parser = ACArgumentParser(description=run_script_description) - set_arg_completer_method(run_script_parser.add_argument('-t', '--transcript', help='record the output of the ' - 'script as a transcript file'), - path_complete) - set_arg_completer_method(run_script_parser.add_argument('script_path', help="path to the script file"), - path_complete) + run_script_parser.add_argument('-t', '--transcript', help='record the output of the script as a transcript file', + completer_method=path_complete) + run_script_parser.add_argument('script_path', help="path to the script file", completer_method=path_complete) @with_argparser(run_script_parser) def do_run_script(self, args: argparse.Namespace) -> Optional[bool]: -- cgit v1.2.1 From 5208170c694c027008ba4bca8a09476a01e0dc50 Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Wed, 3 Jul 2019 15:08:14 -0400 Subject: Moved cmd2 custom argparse types to argparse_custom.py Rename ACArgumentParser to Cmd2ArgParser --- cmd2/cmd2.py | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index ac9cdb6a..24e57f98 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -46,7 +46,8 @@ from . import ansi from . import constants from . import plugin from . import utils -from .argparse_completer import AutoCompleter, ACArgumentParser +from .argparse_completer import AutoCompleter +from .argparse_custom import Cmd2ArgParser from .clipboard import can_clip, get_paste_buffer, write_to_paste_buffer from .history import History, HistoryItem from .parsing import StatementParser, Statement, Macro, MacroArg, shlex_split @@ -2333,7 +2334,7 @@ class Cmd(cmd.Cmd): "An alias is a command that enables replacement of a word by another string.") alias_epilog = ("See also:\n" " macro") - alias_parser = ACArgumentParser(description=alias_description, epilog=alias_epilog, prog='alias') + alias_parser = Cmd2ArgParser(description=alias_description, epilog=alias_epilog, prog='alias') # Add sub-commands to alias alias_subparsers = alias_parser.add_subparsers() @@ -2512,7 +2513,7 @@ class Cmd(cmd.Cmd): "A macro is similar to an alias, but it can contain argument placeholders.") macro_epilog = ("See also:\n" " alias") - macro_parser = ACArgumentParser(description=macro_description, epilog=macro_epilog, prog='macro') + macro_parser = Cmd2ArgParser(description=macro_description, epilog=macro_epilog, prog='macro') # Add sub-commands to macro macro_subparsers = macro_parser.add_subparsers() @@ -2641,7 +2642,7 @@ class Cmd(cmd.Cmd): return matches - help_parser = ACArgumentParser() + help_parser = Cmd2ArgParser() help_parser.add_argument('command', nargs="?", help="command to retrieve help for", completer_method=complete_help_command) help_parser.add_argument('subcommand', nargs=argparse.REMAINDER, help="sub-command to retrieve help for", @@ -2804,19 +2805,19 @@ class Cmd(cmd.Cmd): command = '' self.stdout.write("\n") - @with_argparser(ACArgumentParser()) + @with_argparser(Cmd2ArgParser()) def do_shortcuts(self, _: argparse.Namespace) -> None: """List available shortcuts""" result = "\n".join('%s: %s' % (sc[0], sc[1]) for sc in sorted(self._statement_parser.shortcuts)) self.poutput("Shortcuts for other commands:\n{}".format(result)) - @with_argparser(ACArgumentParser(epilog=INTERNAL_COMMAND_EPILOG)) + @with_argparser(Cmd2ArgParser(epilog=INTERNAL_COMMAND_EPILOG)) def do_eof(self, _: argparse.Namespace) -> bool: """Called when -D is pressed""" # Return True to stop the command loop return True - @with_argparser(ACArgumentParser()) + @with_argparser(Cmd2ArgParser()) def do_quit(self, _: argparse.Namespace) -> bool: """Exit this application""" # Return True to stop the command loop @@ -2911,7 +2912,7 @@ class Cmd(cmd.Cmd): "Accepts abbreviated parameter names so long as there is no ambiguity.\n" "Call without arguments for a list of settable parameters with their values.") - set_parser = ACArgumentParser(description=set_description) + set_parser = Cmd2ArgParser(description=set_description) set_parser.add_argument('-a', '--all', action='store_true', help='display read-only settings as well') set_parser.add_argument('-l', '--long', action='store_true', help='describe function of parameter') set_parser.add_argument('param', nargs='?', help='parameter to set or view', choices_method=_get_settable_names) @@ -2955,7 +2956,7 @@ class Cmd(cmd.Cmd): if onchange_hook is not None: onchange_hook(old=orig_value, new=new_value) - shell_parser = ACArgumentParser() + shell_parser = Cmd2ArgParser() shell_parser.add_argument('command', help='the command to run', completer_method=shell_cmd_complete) shell_parser.add_argument('command_args', nargs=argparse.REMAINDER, help='arguments to pass to command', completer_method=path_complete) @@ -3018,7 +3019,7 @@ class Cmd(cmd.Cmd): "If you see strange parsing behavior, it's best to just open the Python shell\n" "by providing no arguments to py and run more complex statements there.") - py_parser = ACArgumentParser(description=py_description) + py_parser = Cmd2ArgParser(description=py_description) py_parser.add_argument('command', nargs='?', help="command to run") py_parser.add_argument('remainder', nargs=argparse.REMAINDER, help="remainder of command") @@ -3204,7 +3205,7 @@ class Cmd(cmd.Cmd): return bridge.stop - run_pyscript_parser = ACArgumentParser() + run_pyscript_parser = Cmd2ArgParser() run_pyscript_parser.add_argument('script_path', help='path to the script file', completer_method=path_complete) run_pyscript_parser.add_argument('script_arguments', nargs=argparse.REMAINDER, help='arguments to pass to script', completer_method=path_complete) @@ -3237,7 +3238,7 @@ class Cmd(cmd.Cmd): # Only include the do_ipy() method if IPython is available on the system if ipython_available: # pragma: no cover - @with_argparser(ACArgumentParser()) + @with_argparser(Cmd2ArgParser()) def do_ipy(self, _: argparse.Namespace) -> None: """Enter an interactive IPython shell""" from .pyscript_bridge import PyscriptBridge @@ -3260,7 +3261,7 @@ class Cmd(cmd.Cmd): history_description = "View, run, edit, save, or clear previously entered commands" - history_parser = ACArgumentParser(description=history_description) + history_parser = Cmd2ArgParser(description=history_description) history_action_group = history_parser.add_mutually_exclusive_group() history_action_group.add_argument('-r', '--run', action='store_true', help='run selected history items') history_action_group.add_argument('-e', '--edit', action='store_true', @@ -3559,7 +3560,7 @@ class Cmd(cmd.Cmd): "\n" " set editor (program-name)") - edit_parser = ACArgumentParser(description=edit_description) + edit_parser = Cmd2ArgParser(description=edit_description) edit_parser.add_argument('file_path', nargs="?", help="path to a file to open in editor", completer_method=path_complete) @@ -3591,7 +3592,7 @@ class Cmd(cmd.Cmd): "If the -r/--record_transcript flag is used, this command instead records\n" "the output of the script commands to a transcript for testing purposes.\n") - run_script_parser = ACArgumentParser(description=run_script_description) + run_script_parser = Cmd2ArgParser(description=run_script_description) run_script_parser.add_argument('-t', '--transcript', help='record the output of the script as a transcript file', completer_method=path_complete) run_script_parser.add_argument('script_path', help="path to the script file", completer_method=path_complete) @@ -3657,8 +3658,8 @@ class Cmd(cmd.Cmd): relative_run_script_epilog = ("Notes:\n" " This command is intended to only be used within text file scripts.") - relative_run_script_parser = ACArgumentParser(description=relative_run_script_description, - epilog=relative_run_script_epilog) + relative_run_script_parser = Cmd2ArgParser(description=relative_run_script_description, + epilog=relative_run_script_epilog) relative_run_script_parser.add_argument('file_path', help='a file path pointing to a script') @with_argparser(relative_run_script_parser) -- cgit v1.2.1 From 39127e6a16b8e7ef8da82f45a25e19e2545d820b Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Thu, 4 Jul 2019 13:21:51 -0400 Subject: Made optional args on completers keyword-only --- cmd2/cmd2.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 24e57f98..5893ef03 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -840,8 +840,8 @@ class Cmd(cmd.Cmd): return tokens, raw_tokens - def delimiter_complete(self, text: str, line: str, begidx: int, endidx: int, match_against: Iterable, - delimiter: str) -> List[str]: + def delimiter_complete(self, text: str, line: str, begidx: int, endidx: int, + match_against: Iterable, delimiter: str) -> List[str]: """ Performs tab completion against a list but each match is split on a delimiter and only the portion of the match being tab completed is shown as the completion suggestions. @@ -902,7 +902,7 @@ class Cmd(cmd.Cmd): return matches def flag_based_complete(self, text: str, line: str, begidx: int, endidx: int, - flag_dict: Dict[str, Union[Iterable, Callable]], + flag_dict: Dict[str, Union[Iterable, Callable]], *, all_else: Union[None, Iterable, Callable] = None) -> List[str]: """ Tab completes based on a particular flag preceding the token being completed @@ -944,7 +944,7 @@ class Cmd(cmd.Cmd): return completions_matches def index_based_complete(self, text: str, line: str, begidx: int, endidx: int, - index_dict: Mapping[int, Union[Iterable, Callable]], + index_dict: Mapping[int, Union[Iterable, Callable]], *, all_else: Union[None, Iterable, Callable] = None) -> List[str]: """ Tab completes based on a fixed position in the input string @@ -988,7 +988,7 @@ class Cmd(cmd.Cmd): return matches # noinspection PyUnusedLocal - def path_complete(self, text: str, line: str, begidx: int, endidx: int, + def path_complete(self, text: str, line: str, begidx: int, endidx: int, *, path_filter: Optional[Callable[[str], bool]] = None) -> List[str]: """Performs completion of local file system paths @@ -1132,7 +1132,7 @@ class Cmd(cmd.Cmd): return matches - def shell_cmd_complete(self, text: str, line: str, begidx: int, endidx: int, + def shell_cmd_complete(self, text: str, line: str, begidx: int, endidx: int, *, complete_blank: bool = False) -> List[str]: """Performs completion of executables either in a user's path or a given path :param text: the string prefix we are attempting to match (all returned matches must begin with it) @@ -1155,7 +1155,7 @@ class Cmd(cmd.Cmd): # Otherwise look for executables in the given path else: return self.path_complete(text, line, begidx, endidx, - lambda path: os.path.isdir(path) or os.access(path, os.X_OK)) + path_filter=lambda path: os.path.isdir(path) or os.access(path, os.X_OK)) def _redirect_complete(self, text: str, line: str, begidx: int, endidx: int, compfunc: Callable) -> List[str]: """Called by complete() as the first tab completion function for all commands -- cgit v1.2.1 From 4f2d1ba0b1aec77116d660ae8315c74491098a79 Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Thu, 4 Jul 2019 14:23:06 -0400 Subject: Using argparse constants instead of hardcoded strings --- cmd2/cmd2.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 5893ef03..eaae5de7 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -2370,7 +2370,8 @@ class Cmd(cmd.Cmd): alias_delete_description = "Delete specified aliases or all aliases if --all is used" alias_delete_parser = alias_subparsers.add_parser('delete', help=alias_delete_help, description=alias_delete_description) - alias_delete_parser.add_argument('name', nargs='*', help='alias to delete', choices_method=_get_alias_names) + alias_delete_parser.add_argument('name', nargs=argparse.ZERO_OR_MORE, + help='alias to delete', choices_method=_get_alias_names) alias_delete_parser.add_argument('-a', '--all', action='store_true', help="delete all aliases") alias_delete_parser.set_defaults(func=_alias_delete) @@ -2383,7 +2384,8 @@ class Cmd(cmd.Cmd): alias_list_parser = alias_subparsers.add_parser('list', help=alias_list_help, description=alias_list_description) - alias_list_parser.add_argument('name', nargs="*", help='alias to list', choices_method=_get_alias_names) + alias_list_parser.add_argument('name', nargs=argparse.ZERO_OR_MORE, + help='alias to list', choices_method=_get_alias_names) alias_list_parser.set_defaults(func=_alias_list) # Preserve quotes since we are passing strings to other commands @@ -2572,7 +2574,8 @@ class Cmd(cmd.Cmd): macro_delete_description = "Delete specified macros or all macros if --all is used" macro_delete_parser = macro_subparsers.add_parser('delete', help=macro_delete_help, description=macro_delete_description) - macro_delete_parser.add_argument('name', nargs='*', help='macro to delete', choices_method=_get_macro_names) + macro_delete_parser.add_argument('name', nargs=argparse.ZERO_OR_MORE, + help='macro to delete', choices_method=_get_macro_names) macro_delete_parser.add_argument('-a', '--all', action='store_true', help="delete all macros") macro_delete_parser.set_defaults(func=_macro_delete) @@ -2584,7 +2587,8 @@ class Cmd(cmd.Cmd): "Without arguments, all macros will be listed.") macro_list_parser = macro_subparsers.add_parser('list', help=macro_list_help, description=macro_list_description) - macro_list_parser.add_argument('name', nargs="*", help='macro to list', choices_method=_get_macro_names) + macro_list_parser.add_argument('name', nargs=argparse.ZERO_OR_MORE, + help='macro to list', choices_method=_get_macro_names) macro_list_parser.set_defaults(func=_macro_list) # Preserve quotes since we are passing strings to other commands @@ -2643,7 +2647,7 @@ class Cmd(cmd.Cmd): return matches help_parser = Cmd2ArgParser() - help_parser.add_argument('command', nargs="?", help="command to retrieve help for", + help_parser.add_argument('command', nargs=argparse.OPTIONAL, help="command to retrieve help for", completer_method=complete_help_command) help_parser.add_argument('subcommand', nargs=argparse.REMAINDER, help="sub-command to retrieve help for", completer_method=complete_help_subcommand) @@ -2915,8 +2919,9 @@ class Cmd(cmd.Cmd): set_parser = Cmd2ArgParser(description=set_description) set_parser.add_argument('-a', '--all', action='store_true', help='display read-only settings as well') set_parser.add_argument('-l', '--long', action='store_true', help='describe function of parameter') - set_parser.add_argument('param', nargs='?', help='parameter to set or view', choices_method=_get_settable_names) - set_parser.add_argument('value', nargs='?', help='the new value for settable') + set_parser.add_argument('param', nargs=argparse.OPTIONAL, help='parameter to set or view', + choices_method=_get_settable_names) + set_parser.add_argument('value', nargs=argparse.OPTIONAL, help='the new value for settable') @with_argparser(set_parser) def do_set(self, args: argparse.Namespace) -> None: @@ -3020,7 +3025,7 @@ class Cmd(cmd.Cmd): "by providing no arguments to py and run more complex statements there.") py_parser = Cmd2ArgParser(description=py_description) - py_parser.add_argument('command', nargs='?', help="command to run") + py_parser.add_argument('command', nargs=argparse.OPTIONAL, help="command to run") py_parser.add_argument('remainder', nargs=argparse.REMAINDER, help="remainder of command") # Preserve quotes since we are passing these strings to Python @@ -3293,7 +3298,7 @@ class Cmd(cmd.Cmd): "a..b, a:b, a:, ..b items by indices (inclusive)\n" "string items containing string\n" "/regex/ items matching regular expression") - history_parser.add_argument('arg', nargs='?', help=history_arg_help) + history_parser.add_argument('arg', nargs=argparse.OPTIONAL, help=history_arg_help) @with_argparser(history_parser) def do_history(self, args: argparse.Namespace) -> Optional[bool]: @@ -3561,7 +3566,7 @@ class Cmd(cmd.Cmd): " set editor (program-name)") edit_parser = Cmd2ArgParser(description=edit_description) - edit_parser.add_argument('file_path', nargs="?", + edit_parser.add_argument('file_path', nargs=argparse.OPTIONAL, help="path to a file to open in editor", completer_method=path_complete) @with_argparser(edit_parser) -- cgit v1.2.1 From 5ef4267360e87d8c2af13d0b7f6a6cd8d80fd016 Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Sat, 6 Jul 2019 10:39:56 -0400 Subject: Made alias and macro tab completion lookup results use CompletionItems --- cmd2/cmd2.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index eaae5de7..364f18f9 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -46,7 +46,7 @@ from . import ansi from . import constants from . import plugin from . import utils -from .argparse_completer import AutoCompleter +from .argparse_completer import AutoCompleter, CompletionItem from .argparse_custom import Cmd2ArgParser from .clipboard import can_clip, get_paste_buffer, write_to_paste_buffer from .history import History, HistoryItem @@ -1605,13 +1605,13 @@ class Cmd(cmd.Cmd): return commands - def _get_alias_names(self) -> List[str]: + def _get_alias_completion_items(self) -> List[CompletionItem]: """Return list of current alias names""" - return list(self.aliases) + return [CompletionItem(cur_key, self.aliases[cur_key]) for cur_key in self.aliases] - def _get_macro_names(self) -> List[str]: - """Return list of current macro names""" - return list(self.macros) + def _get_macro_completion_items(self) -> List[CompletionItem]: + """Return list of current alias names""" + return [CompletionItem(cur_key, self.macros[cur_key].value) for cur_key in self.macros] def _get_settable_names(self) -> List[str]: """Return list of current settable names""" @@ -1620,8 +1620,8 @@ class Cmd(cmd.Cmd): def _get_commands_aliases_and_macros_for_completion(self) -> List[str]: """Return a list of visible commands, aliases, and macros for tab completion""" visible_commands = set(self.get_visible_commands()) - alias_names = set(self._get_alias_names()) - macro_names = set(self._get_macro_names()) + alias_names = set(self.aliases) + macro_names = set(self.macros) return list(visible_commands | alias_names | macro_names) def get_help_topics(self) -> List[str]: @@ -2370,8 +2370,8 @@ class Cmd(cmd.Cmd): alias_delete_description = "Delete specified aliases or all aliases if --all is used" alias_delete_parser = alias_subparsers.add_parser('delete', help=alias_delete_help, description=alias_delete_description) - alias_delete_parser.add_argument('name', nargs=argparse.ZERO_OR_MORE, - help='alias to delete', choices_method=_get_alias_names) + alias_delete_parser.add_argument('name', nargs=argparse.ZERO_OR_MORE, help='alias to delete', + choices_method=_get_alias_completion_items, descriptive_header='Value') alias_delete_parser.add_argument('-a', '--all', action='store_true', help="delete all aliases") alias_delete_parser.set_defaults(func=_alias_delete) @@ -2384,8 +2384,8 @@ class Cmd(cmd.Cmd): alias_list_parser = alias_subparsers.add_parser('list', help=alias_list_help, description=alias_list_description) - alias_list_parser.add_argument('name', nargs=argparse.ZERO_OR_MORE, - help='alias to list', choices_method=_get_alias_names) + alias_list_parser.add_argument('name', nargs=argparse.ZERO_OR_MORE, help='alias to list', + choices_method=_get_alias_completion_items, descriptive_header='Value') alias_list_parser.set_defaults(func=_alias_list) # Preserve quotes since we are passing strings to other commands @@ -2574,8 +2574,8 @@ class Cmd(cmd.Cmd): macro_delete_description = "Delete specified macros or all macros if --all is used" macro_delete_parser = macro_subparsers.add_parser('delete', help=macro_delete_help, description=macro_delete_description) - macro_delete_parser.add_argument('name', nargs=argparse.ZERO_OR_MORE, - help='macro to delete', choices_method=_get_macro_names) + macro_delete_parser.add_argument('name', nargs=argparse.ZERO_OR_MORE, help='macro to delete', + choices_method=_get_macro_completion_items, descriptive_header='Value') macro_delete_parser.add_argument('-a', '--all', action='store_true', help="delete all macros") macro_delete_parser.set_defaults(func=_macro_delete) @@ -2587,8 +2587,8 @@ class Cmd(cmd.Cmd): "Without arguments, all macros will be listed.") macro_list_parser = macro_subparsers.add_parser('list', help=macro_list_help, description=macro_list_description) - macro_list_parser.add_argument('name', nargs=argparse.ZERO_OR_MORE, - help='macro to list', choices_method=_get_macro_names) + macro_list_parser.add_argument('name', nargs=argparse.ZERO_OR_MORE, help='macro to list', + choices_method=_get_macro_completion_items, descriptive_header='Value') macro_list_parser.set_defaults(func=_macro_list) # Preserve quotes since we are passing strings to other commands -- cgit v1.2.1 From 67445d49af8db72f9e27a8d47449d0b5ed1e6b9c Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Sat, 6 Jul 2019 11:28:05 -0400 Subject: Display set command tab-completion results as CompletionItems --- cmd2/cmd2.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 364f18f9..46d996ea 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -1606,16 +1606,16 @@ class Cmd(cmd.Cmd): return commands def _get_alias_completion_items(self) -> List[CompletionItem]: - """Return list of current alias names""" + """Return list of current alias names and values as CompletionItems""" return [CompletionItem(cur_key, self.aliases[cur_key]) for cur_key in self.aliases] def _get_macro_completion_items(self) -> List[CompletionItem]: - """Return list of current alias names""" + """Return list of current macro names and values as CompletionItems""" return [CompletionItem(cur_key, self.macros[cur_key].value) for cur_key in self.macros] - def _get_settable_names(self) -> List[str]: - """Return list of current settable names""" - return list(self.settable) + def _get_settable_completion_items(self) -> List[CompletionItem]: + """Return list of current settable names and descriptions as CompletionItems""" + return [CompletionItem(cur_key, self.settable[cur_key]) for cur_key in self.settable] def _get_commands_aliases_and_macros_for_completion(self) -> List[str]: """Return a list of visible commands, aliases, and macros for tab completion""" @@ -2920,7 +2920,7 @@ class Cmd(cmd.Cmd): set_parser.add_argument('-a', '--all', action='store_true', help='display read-only settings as well') set_parser.add_argument('-l', '--long', action='store_true', help='describe function of parameter') set_parser.add_argument('param', nargs=argparse.OPTIONAL, help='parameter to set or view', - choices_method=_get_settable_names) + choices_method=_get_settable_completion_items, descriptive_header='Description') set_parser.add_argument('value', nargs=argparse.OPTIONAL, help='the new value for settable') @with_argparser(set_parser) -- cgit v1.2.1 From 53f6c07559f2c15656423dbbb92471758e8c6d20 Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Sat, 6 Jul 2019 13:22:41 -0400 Subject: Added ability to limit how many CompletionItems display at a time --- cmd2/cmd2.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 46d996ea..e6d4ae47 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -468,6 +468,11 @@ class Cmd(cmd.Cmd): # Otherwise it can be set to any custom key to meet your needs. self.matches_sort_key = ALPHABETICAL_SORT_KEY + # The maximum number of CompletionItems to display during tab completion. If the number of possible + # completions exceeds this number, suggestions will be displayed in the typical columnized format and + # will not include the description value of the CompletionItems. + self.max_completion_items = 50 + ############################################################################################################ # The following variables are used by tab-completion functions. They are reset each time complete() is run # in reset_completion_defaults() and it is up to completer functions to set them before returning results. -- cgit v1.2.1 From f8f06bff169dca1f0c6ee1dbb2d61c347490b3bb Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Sat, 6 Jul 2019 18:03:12 -0400 Subject: More unit tests --- cmd2/cmd2.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index e6d4ae47..009b1359 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -1584,18 +1584,18 @@ class Cmd(cmd.Cmd): def _autocomplete_default(self, text: str, line: str, begidx: int, endidx: int, argparser: argparse.ArgumentParser) -> List[str]: - """Default completion function for argparse commands.""" + """Default completion function for argparse commands""" completer = AutoCompleter(argparser, self) tokens, _ = self.tokens_for_completion(line, begidx, endidx) return completer.complete_command(tokens, text, line, begidx, endidx) def get_all_commands(self) -> List[str]: - """Returns a list of all commands.""" + """Return a list of all commands""" return [name[len(COMMAND_FUNC_PREFIX):] for name in self.get_names() if name.startswith(COMMAND_FUNC_PREFIX) and callable(getattr(self, name))] def get_visible_commands(self) -> List[str]: - """Returns a list of commands that have not been hidden or disabled.""" + """Return a list of commands that have not been hidden or disabled""" commands = self.get_all_commands() # Remove the hidden commands -- cgit v1.2.1 From bb2dd69bd04f5dccff9474c018eb6b6eea74c6af Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Sun, 7 Jul 2019 21:45:52 -0400 Subject: Moved all custom argparse classes intended for normal development to argparse_custom.py. Lazy loading AutoCompleter in cmd2 instance methods to allow argparse_completer.py to import cmd2.Cmd class. This Architecture makes more sense because AutoCompleter depends on cmd2.Cmd. --- cmd2/cmd2.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index bfda6ae2..0d14d5ad 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -46,8 +46,7 @@ from . import ansi from . import constants from . import plugin from . import utils -from .argparse_completer import AutoCompleter, CompletionItem -from .argparse_custom import Cmd2ArgParser +from .argparse_custom import Cmd2ArgParser, CompletionItem from .clipboard import can_clip, get_paste_buffer, write_to_paste_buffer from .history import History, HistoryItem from .parsing import StatementParser, Statement, Macro, MacroArg, shlex_split @@ -1582,6 +1581,7 @@ class Cmd(cmd.Cmd): def _autocomplete_default(self, text: str, line: str, begidx: int, endidx: int, argparser: argparse.ArgumentParser) -> List[str]: """Default completion function for argparse commands""" + from .argparse_completer import AutoCompleter completer = AutoCompleter(argparser, self) tokens, _ = self.tokens_for_completion(line, begidx, endidx) return completer.complete_command(tokens, text, line, begidx, endidx) @@ -2643,6 +2643,7 @@ class Cmd(cmd.Cmd): # Check if this is a command with an argparse function func = self.cmd_func(command) if func and hasattr(func, 'argparser'): + from .argparse_completer import AutoCompleter completer = AutoCompleter(getattr(func, 'argparser'), self) matches = completer.complete_command_help(tokens[cmd_index:], text, line, begidx, endidx) @@ -2673,6 +2674,7 @@ class Cmd(cmd.Cmd): # If the command function uses argparse, then use argparse's help if func and hasattr(func, 'argparser'): + from .argparse_completer import AutoCompleter completer = AutoCompleter(getattr(func, 'argparser'), self) tokens = [args.command] + args.subcommand self.poutput(completer.format_help(tokens)) -- cgit v1.2.1 From 1c2dc43a982eada206975f97e8e49c5ea95d9dd5 Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Wed, 10 Jul 2019 11:51:06 -0400 Subject: Small refactoring to simplify code --- cmd2/cmd2.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 0d14d5ad..4ac63a07 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -1926,8 +1926,6 @@ class Cmd(cmd.Cmd): :param statement: the parsed statement from the command line :return: the resolved macro or None on error """ - from itertools import islice - if statement.command not in self.macros.keys(): raise KeyError('{} is not a macro'.format(statement.command)) @@ -1960,7 +1958,7 @@ class Cmd(cmd.Cmd): resolved = parts[0] + replacement + parts[1] # Append extra arguments and use statement.arg_list since these arguments need their quotes preserved - for arg in islice(statement.arg_list, macro.minimum_arg_count, None): + for arg in statement.arg_list[macro.minimum_arg_count:]: resolved += ' ' + arg # Restore any terminator, suffix, redirection, etc. -- cgit v1.2.1 From c1312cadba42f273179a6bc08ec5a8d22ca23891 Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Thu, 11 Jul 2019 15:16:38 -0400 Subject: Updated documentation --- cmd2/cmd2.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 14107f5b..ee40d79d 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -467,9 +467,9 @@ class Cmd(cmd.Cmd): # Otherwise it can be set to any custom key to meet your needs. self.matches_sort_key = ALPHABETICAL_SORT_KEY - # The maximum number of CompletionItems to display during tab completion. If the number of possible - # completions exceeds this number, suggestions will be displayed in the typical columnized format and - # will not include the description value of the CompletionItems. + # The maximum number of CompletionItems to display during tab completion. If the number of completion + # suggestions exceeds this number, they will be displayed in the typical columnized format and will + # not include the description value of the CompletionItems. self.max_completion_items = 50 ############################################################################################################ -- cgit v1.2.1 From 9bb6b84608b6262d228c021c7115e1389eed33e3 Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Fri, 12 Jul 2019 12:42:04 -0400 Subject: Renamed Cmd2ArgParser to ArgParser --- cmd2/cmd2.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index ee40d79d..ee7cc449 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -42,11 +42,11 @@ from collections import namedtuple from contextlib import redirect_stdout from typing import Any, Callable, Dict, Iterable, List, Mapping, Optional, Tuple, Type, Union +from . import ArgParser, CompletionItem from . import ansi from . import constants from . import plugin from . import utils -from .argparse_custom import Cmd2ArgParser, CompletionItem from .clipboard import can_clip, get_paste_buffer, write_to_paste_buffer from .history import History, HistoryItem from .parsing import StatementParser, Statement, Macro, MacroArg, shlex_split @@ -2334,7 +2334,7 @@ class Cmd(cmd.Cmd): "An alias is a command that enables replacement of a word by another string.") alias_epilog = ("See also:\n" " macro") - alias_parser = Cmd2ArgParser(description=alias_description, epilog=alias_epilog, prog='alias') + alias_parser = ArgParser(description=alias_description, epilog=alias_epilog, prog='alias') # Add sub-commands to alias alias_subparsers = alias_parser.add_subparsers() @@ -2515,7 +2515,7 @@ class Cmd(cmd.Cmd): "A macro is similar to an alias, but it can contain argument placeholders.") macro_epilog = ("See also:\n" " alias") - macro_parser = Cmd2ArgParser(description=macro_description, epilog=macro_epilog, prog='macro') + macro_parser = ArgParser(description=macro_description, epilog=macro_epilog, prog='macro') # Add sub-commands to macro macro_subparsers = macro_parser.add_subparsers() @@ -2647,7 +2647,7 @@ class Cmd(cmd.Cmd): return matches - help_parser = Cmd2ArgParser() + help_parser = ArgParser() help_parser.add_argument('command', nargs=argparse.OPTIONAL, help="command to retrieve help for", completer_method=complete_help_command) help_parser.add_argument('subcommand', nargs=argparse.REMAINDER, help="sub-command to retrieve help for", @@ -2811,19 +2811,19 @@ class Cmd(cmd.Cmd): command = '' self.stdout.write("\n") - @with_argparser(Cmd2ArgParser()) + @with_argparser(ArgParser()) def do_shortcuts(self, _: argparse.Namespace) -> None: """List available shortcuts""" result = "\n".join('%s: %s' % (sc[0], sc[1]) for sc in sorted(self.statement_parser.shortcuts)) self.poutput("Shortcuts for other commands:\n{}".format(result)) - @with_argparser(Cmd2ArgParser(epilog=INTERNAL_COMMAND_EPILOG)) + @with_argparser(ArgParser(epilog=INTERNAL_COMMAND_EPILOG)) def do_eof(self, _: argparse.Namespace) -> bool: """Called when -D is pressed""" # Return True to stop the command loop return True - @with_argparser(Cmd2ArgParser()) + @with_argparser(ArgParser()) def do_quit(self, _: argparse.Namespace) -> bool: """Exit this application""" # Return True to stop the command loop @@ -2918,7 +2918,7 @@ class Cmd(cmd.Cmd): "Accepts abbreviated parameter names so long as there is no ambiguity.\n" "Call without arguments for a list of settable parameters with their values.") - set_parser = Cmd2ArgParser(description=set_description) + set_parser = ArgParser(description=set_description) set_parser.add_argument('-a', '--all', action='store_true', help='display read-only settings as well') set_parser.add_argument('-l', '--long', action='store_true', help='describe function of parameter') set_parser.add_argument('param', nargs=argparse.OPTIONAL, help='parameter to set or view', @@ -2963,7 +2963,7 @@ class Cmd(cmd.Cmd): if onchange_hook is not None: onchange_hook(old=orig_value, new=new_value) - shell_parser = Cmd2ArgParser() + shell_parser = ArgParser() shell_parser.add_argument('command', help='the command to run', completer_method=shell_cmd_complete) shell_parser.add_argument('command_args', nargs=argparse.REMAINDER, help='arguments to pass to command', completer_method=path_complete) @@ -3026,7 +3026,7 @@ class Cmd(cmd.Cmd): "If you see strange parsing behavior, it's best to just open the Python shell\n" "by providing no arguments to py and run more complex statements there.") - py_parser = Cmd2ArgParser(description=py_description) + py_parser = ArgParser(description=py_description) py_parser.add_argument('command', nargs=argparse.OPTIONAL, help="command to run") py_parser.add_argument('remainder', nargs=argparse.REMAINDER, help="remainder of command") @@ -3212,7 +3212,7 @@ class Cmd(cmd.Cmd): return bridge.stop - run_pyscript_parser = Cmd2ArgParser() + run_pyscript_parser = ArgParser() run_pyscript_parser.add_argument('script_path', help='path to the script file', completer_method=path_complete) run_pyscript_parser.add_argument('script_arguments', nargs=argparse.REMAINDER, help='arguments to pass to script', completer_method=path_complete) @@ -3245,7 +3245,7 @@ class Cmd(cmd.Cmd): # Only include the do_ipy() method if IPython is available on the system if ipython_available: # pragma: no cover - @with_argparser(Cmd2ArgParser()) + @with_argparser(ArgParser()) def do_ipy(self, _: argparse.Namespace) -> None: """Enter an interactive IPython shell""" from .pyscript_bridge import PyscriptBridge @@ -3268,7 +3268,7 @@ class Cmd(cmd.Cmd): history_description = "View, run, edit, save, or clear previously entered commands" - history_parser = Cmd2ArgParser(description=history_description) + history_parser = ArgParser(description=history_description) history_action_group = history_parser.add_mutually_exclusive_group() history_action_group.add_argument('-r', '--run', action='store_true', help='run selected history items') history_action_group.add_argument('-e', '--edit', action='store_true', @@ -3567,7 +3567,7 @@ class Cmd(cmd.Cmd): "\n" " set editor (program-name)") - edit_parser = Cmd2ArgParser(description=edit_description) + edit_parser = ArgParser(description=edit_description) edit_parser.add_argument('file_path', nargs=argparse.OPTIONAL, help="path to a file to open in editor", completer_method=path_complete) @@ -3599,7 +3599,7 @@ class Cmd(cmd.Cmd): "If the -r/--record_transcript flag is used, this command instead records\n" "the output of the script commands to a transcript for testing purposes.\n") - run_script_parser = Cmd2ArgParser(description=run_script_description) + run_script_parser = ArgParser(description=run_script_description) run_script_parser.add_argument('-t', '--transcript', help='record the output of the script as a transcript file', completer_method=path_complete) run_script_parser.add_argument('script_path', help="path to the script file", completer_method=path_complete) @@ -3665,7 +3665,7 @@ class Cmd(cmd.Cmd): relative_run_script_epilog = ("Notes:\n" " This command is intended to only be used within text file scripts.") - relative_run_script_parser = Cmd2ArgParser(description=relative_run_script_description, + relative_run_script_parser = ArgParser(description=relative_run_script_description, epilog=relative_run_script_epilog) relative_run_script_parser.add_argument('file_path', help='a file path pointing to a script') -- cgit v1.2.1 From fdbd9d5bd17f8b3de278ee867919a3103b523d91 Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Fri, 12 Jul 2019 15:00:00 -0400 Subject: Fixed flake8 warning --- cmd2/cmd2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index ee7cc449..6667911a 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -3666,7 +3666,7 @@ class Cmd(cmd.Cmd): " This command is intended to only be used within text file scripts.") relative_run_script_parser = ArgParser(description=relative_run_script_description, - epilog=relative_run_script_epilog) + epilog=relative_run_script_epilog) relative_run_script_parser.add_argument('file_path', help='a file path pointing to a script') @with_argparser(relative_run_script_parser) -- cgit v1.2.1 From bff6e04607ea9bede7bc981755cdf41740c15462 Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Mon, 15 Jul 2019 11:39:16 -0400 Subject: Make max_completion_items settable --- cmd2/cmd2.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'cmd2/cmd2.py') diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 6667911a..4ba2e83e 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -352,6 +352,12 @@ class Cmd(cmd.Cmd): self.editor = self.DEFAULT_EDITOR self.feedback_to_output = False # Do not include nonessentials in >, | output by default (things like timing) self.locals_in_py = False + + # The maximum number of CompletionItems to display during tab completion. If the number of completion + # suggestions exceeds this number, they will be displayed in the typical columnized format and will + # not include the description value of the CompletionItems. + self.max_completion_items = 50 + self.quiet = False # Do not suppress nonessential output self.timing = False # Prints elapsed time for each command @@ -369,6 +375,7 @@ class Cmd(cmd.Cmd): 'editor': 'Program used by ``edit``', 'feedback_to_output': 'Include nonessentials in `|`, `>` results', 'locals_in_py': 'Allow access to your application in py via self', + 'max_completion_items': 'Maximum number of CompletionItems to display during tab completion', 'prompt': 'The prompt issued to solicit input', 'quiet': "Don't print nonessential feedback", 'timing': 'Report execution times' @@ -467,11 +474,6 @@ class Cmd(cmd.Cmd): # Otherwise it can be set to any custom key to meet your needs. self.matches_sort_key = ALPHABETICAL_SORT_KEY - # The maximum number of CompletionItems to display during tab completion. If the number of completion - # suggestions exceeds this number, they will be displayed in the typical columnized format and will - # not include the description value of the CompletionItems. - self.max_completion_items = 50 - ############################################################################################################ # The following variables are used by tab-completion functions. They are reset each time complete() is run # in reset_completion_defaults() and it is up to completer functions to set them before returning results. -- cgit v1.2.1