diff options
-rw-r--r-- | CHANGELOG.md | 28 | ||||
-rwxr-xr-x | README.md | 22 | ||||
-rw-r--r-- | cmd2/argparse_completer.py | 6 | ||||
-rw-r--r-- | cmd2/argparse_custom.py | 14 | ||||
-rw-r--r-- | docs/features/argument_processing.rst | 5 | ||||
-rw-r--r-- | docs/features/completion.rst | 24 | ||||
-rw-r--r-- | docs/features/embedded_python_shells.rst | 2 | ||||
-rw-r--r-- | docs/features/initialization.rst | 2 | ||||
-rw-r--r-- | docs/features/os.rst | 2 | ||||
-rw-r--r-- | docs/features/scripting.rst | 4 | ||||
-rw-r--r-- | docs/features/settings.rst | 4 | ||||
-rw-r--r-- | docs/overview/installation.rst | 2 | ||||
-rw-r--r-- | examples/argparse_completion.py | 122 | ||||
-rwxr-xr-x | examples/basic_completion.py | 91 | ||||
-rwxr-xr-x | examples/python_scripting.py | 1 | ||||
-rwxr-xr-x | examples/tab_autocompletion.py | 268 | ||||
-rwxr-xr-x | examples/tab_completion.py | 81 | ||||
-rw-r--r-- | tests/conftest.py | 2 | ||||
-rwxr-xr-x | tests/test_completion.py | 14 |
19 files changed, 280 insertions, 414 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index d4e3bc0b..f9d71831 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ ## 0.10.0 (February 7, 2020) * Enhancements * Changed the default help text to make `help -v` more discoverable - * **set** command now supports tab-completion of values + * **set** command now supports tab completion of values * Added `add_settable()` and `remove_settable()` convenience methods to update `self.settable` dictionary * Added convenience `ansi.fg` and `ansi.bg` enums of foreground and background colors * `ansi.style()` `fg` argument can now either be of type `str` or `ansi.fg` @@ -185,7 +185,7 @@ `delimiter_complete`, `flag_based_complete`, `index_based_complete`, `path_complete`, `shell_cmd_complete` * Renamed history option from `--output-file` to `--output_file` * Renamed `matches_sort_key` to `default_sort_key`. This value determines the default sort ordering of string - results like alias, command, category, macro, settable, and shortcut names. Unsorted tab-completion results + results like alias, command, category, macro, settable, and shortcut names. Unsorted tab completion results also are sorted with this key. Its default value (ALPHABETICAL_SORT_KEY) performs a case-insensitive alphabetical sort, but it can be changed to a natural sort by setting the value to NATURAL_SORT_KEY. * `StatementParser` now expects shortcuts to be passed in as dictionary. This eliminates the step of converting the @@ -434,7 +434,7 @@ * ``ACHelpFormatter`` now inherits from ``argparse.RawTextHelpFormatter`` to make it easier for formatting help/description text * Aliases are now sorted alphabetically - * The **set** command now tab-completes settable parameter names + * The **set** command now tab completes settable parameter names * Added ``async_alert``, ``async_update_prompt``, and ``set_window_title`` functions * These allow you to provide feedback to the user in an asychronous fashion, meaning alerts can display when the user is still entering text at the prompt. See [async_printing.py](https://github.com/python-cmd2/cmd2/blob/master/examples/async_printing.py) @@ -468,7 +468,7 @@ * Improved implementation of lifecycle hooks to support a plugin framework, see ``docs/hooks.rst`` for details. * New dependency on ``attrs`` third party module - * Added ``matches_sorted`` member to support custom sorting of tab-completion matches + * Added ``matches_sorted`` member to support custom sorting of tab completion matches * Added [tab_autocomp_dynamic.py](https://github.com/python-cmd2/cmd2/blob/master/examples/tab_autocomp_dynamic.py) example * Demonstrates updating the argparse object during init instead of during class construction * Deprecations @@ -498,7 +498,7 @@ * Bug Fixes * Fixed issue where piping and redirecting did not work correctly with paths that had spaces * Enhancements - * Added ability to print a header above tab-completion suggestions using `completion_header` member + * Added ability to print a header above tab completion suggestions using `completion_header` member * Added ``pager`` and ``pager_chop`` attributes to the ``cmd2.Cmd`` class * ``pager`` defaults to **less -RXF** on POSIX and **more** on Windows * ``pager_chop`` defaults to **less -SRXF** on POSIX and **more** on Windows @@ -570,7 +570,7 @@ * Fixed ``AttributeError`` on Windows when running a ``select`` command cause by **pyreadline** not implementing ``remove_history_item`` * Enhancements * Added warning about **libedit** variant of **readline** not being supported on macOS - * Added tab-completion of alias names in value field of **alias** command + * Added tab completion of alias names in value field of **alias** command * Enhanced the ``py`` console in the following ways * Added tab completion of Python identifiers instead of **cmd2** commands * Separated the ``py`` console history from the **cmd2** history @@ -628,7 +628,7 @@ ## 0.8.2 (March 21, 2018) * Bug Fixes - * Fixed a bug in tab-completion of command names within sub-menus + * Fixed a bug in tab completion of command names within sub-menus * Fixed a bug when using persistent readline history in Python 2.7 * Fixed a bug where the ``AddSubmenu`` decorator didn't work with a default value for ``shared_attributes`` * Added a check to ``ppaged()`` to only use a pager when running in a real fully functional terminal @@ -685,7 +685,7 @@ and [arg_print.py](https://github.com/python-cmd2/cmd2/blob/master/examples/arg_print.py) examples * Added support for Argparse subcommands when using the **with_argument_parser** or **with_argparser_and_unknown_args** decorators * See [subcommands.py](https://github.com/python-cmd2/cmd2/blob/master/examples/subcommands.py) for an example of how to use subcommands - * Tab-completion of subcommand names is automatically supported + * Tab completion of subcommand names is automatically supported * The **__relative_load** command is now hidden from the help menu by default * This command is not intended to be called from the command line, only from within scripts * The **set** command now has an additional **-a/--all** option to also display read-only settings @@ -712,7 +712,7 @@ * Fixed a couple broken examples * Enhancements * Improved documentation for modifying shortcuts (command aliases) - * Made ``pyreadline`` a dependency on Windows to ensure tab-completion works + * Made ``pyreadline`` a dependency on Windows to ensure tab completion works * Other changes * Abandoned official support for Python 3.3. It should still work, just don't have an easy way to test it anymore. @@ -750,7 +750,7 @@ * Fixed some pyperclip clipboard interaction bugs on Linux * Fixed some timing bugs when running unit tests in parallel by using monkeypatch * Enhancements - * Enhanced tab-completion of cmd2 command names to support case-insensitive completion + * Enhanced tab completion of cmd2 command names to support case-insensitive completion * Added an example showing how to remove unused commands * Improved how transcript testing handles prompts with ANSI escape codes by stripping them * Greatly improved implementation for how command output gets piped to a shell command @@ -766,7 +766,7 @@ * Enhancements * Organized all attributes used to configure the ParserManager into a single location * Set the default value of `abbrev` to `False` (which controls whether or not abbreviated commands are allowed) - * With good tab-completion of command names, using abbreviated commands isn't particularly useful + * With good tab completion of command names, using abbreviated commands isn't particularly useful * And it can create complications if you are't careful * Improved implementation of `load` to use command queue instead of nested inner loop @@ -778,7 +778,7 @@ * Ability to pipe ``cmd2`` command output to a shell command is now more reliable, particularly on Windows * Fixed a bug in ``pyscript`` command on Windows related to ``\`` being interpreted as an escape * Enhancements - * Ensure that path and shell command tab-completion results are alphabetically sorted + * Ensure that path and shell command tab completion results are alphabetically sorted * Removed feature for load command to load scripts from URLS * It didn't work, there were no unit tests, and it felt out of place * Removed presence of a default file name and default file extension @@ -801,8 +801,8 @@ * Enhancements * Added the ability to exclude commands from the help menu (**eof** included by default) * Redundant **list** command removed and features merged into **history** command - * Added **pyscript** command which supports tab-completion and running Python scripts with arguments - * Improved tab-completion of file system paths, command names, and shell commands + * Added **pyscript** command which supports tab completion and running Python scripts with arguments + * Improved tab completion of file system paths, command names, and shell commands * Thanks to Kevin Van Brunt for all of the help with debugging and testing this * Changed default value of USE_ARG_LIST to True - this affects the beavhior of all **@options** commands * **WARNING**: This breaks backwards compatibility, to restore backwards compatibility, add this to the @@ -37,8 +37,8 @@ Main Features - Settable environment parameters - Parsing commands with arguments using `argparse`, including support for subcommands - Unicode character support -- Good tab-completion of commands, subcommands, file system paths, and shell commands -- Automatic tab-completion of `argparse` flags when using one of the `cmd2` `argparse` decorators +- Good tab completion of commands, subcommands, file system paths, and shell commands +- Automatic tab completion of `argparse` flags when using one of the `cmd2` `argparse` decorators - Support for Python 3.5+ on Windows, macOS, and Linux - Trivial to provide built-in help for all commands - Built-in regression testing framework for your applications (transcript-based testing) @@ -96,7 +96,7 @@ Instructions for implementing each feature follow. - By default the docstring for your **do_foo** method is the help for the **foo** command - NOTE: This doesn't apply if you use one of the `argparse` decorators mentioned below - Can provide more custom help by creating a **help_foo** method (except when using `argparse` decorators) - - Can provide custom tab-completion for the **foo** command by creating a **complete_foo** method + - Can provide custom tab completion for the **foo** command by creating a **complete_foo** method - Easy to upgrade an existing `cmd` app to `cmd2` - Run your `cmd2` app using the built-in REPL by executing the **cmdloop** method @@ -164,25 +164,25 @@ Instructions for implementing each feature follow. - Option to display long output using a pager with ``cmd2.Cmd.ppaged()`` - Optionally specify a startup script that end users can use to customize their environment -- Top-notch tab-completion capabilities which are easy to use but very powerful +- Top-notch tab completion capabilities which are easy to use but very powerful - For a command **foo** implement a **complete_foo** method to provide custom tab completion for that command - But the helper methods within `cmd2` discussed below mean you would rarely have to implement this from scratch - - Commands which use one of the `argparse` decorators have automatic tab-completion of `argparse` flags + - Commands which use one of the `argparse` decorators have automatic tab completion of `argparse` flags - And also provide help hints for values associated with these flags - Experiment with the [argprint.py](https://github.com/python-cmd2/cmd2/blob/master/examples/arg_print.py) example using the **oprint** and **pprint** commands to get a feel for how this works - - `path_complete` helper method provides flexible tab-completion of file system paths + - `path_complete` helper method provides flexible tab completion of file system paths - See the [paged_output.py](https://github.com/python-cmd2/cmd2/blob/master/examples/paged_output.py) example for a simple use case - See the [python_scripting.py](https://github.com/python-cmd2/cmd2/blob/master/examples/python_scripting.py) example for a more full-featured use case - `flag_based_complete` helper method for tab completion based on a particular flag preceding the token being completed - - See the [tab_completion.py](https://github.com/python-cmd2/cmd2/blob/master/examples/tab_completion.py) example for a demonstration of how to use this feature + - See the [basic_completion.py](https://github.com/python-cmd2/cmd2/blob/master/examples/basic_completion.py) example for a demonstration of how to use this feature - `index_based_complete` helper method for tab completion based on a fixed position in the input string - - See the [tab_completion.py](https://github.com/python-cmd2/cmd2/blob/master/examples/tab_completion.py) example for a demonstration of how to use this feature + - See the [basic_completion.py](https://github.com/python-cmd2/cmd2/blob/master/examples/basic_completion.py) example for a demonstration of how to use this feature - `basic_complete` helper method for tab completion against a list - `delimiter_complete` helper method for tab completion against a list but each match is split on a delimiter - - See the [tab_autocompletion.py](https://github.com/python-cmd2/cmd2/blob/master/examples/tab_autocompletion.py) example for a demonstration of how to use this feature - - `cmd2` in combination with `argparse` also provide several advanced capabilities for automatic tab-completion - - See the [tab_autocompletion.py](https://github.com/python-cmd2/cmd2/blob/master/examples/tab_autocompletion.py) example for more info + - See the [basic_completion.py](https://github.com/python-cmd2/cmd2/blob/master/examples/basic_completion.py) example for a demonstration of how to use this feature + - `cmd2` in combination with `argparse` also provide several advanced capabilities for automatic tab completion + - See the [argparse_completion.py](https://github.com/python-cmd2/cmd2/blob/master/examples/argparse_completion.py) example for more info - Multi-line commands diff --git a/cmd2/argparse_completer.py b/cmd2/argparse_completer.py index 6513fe13..185e01a2 100644 --- a/cmd2/argparse_completer.py +++ b/cmd2/argparse_completer.py @@ -444,7 +444,9 @@ class AutoCompleter: completions.sort(key=self._cmd2_app.default_sort_key) self._cmd2_app.matches_sorted = True - token_width = ansi.style_aware_wcswidth(action.dest) + # If a metavar was defined, use that instead of the dest field + destination = action.metavar if action.metavar else action.dest + token_width = ansi.style_aware_wcswidth(destination) completions_with_desc = [] for item in completions: @@ -463,7 +465,7 @@ class AutoCompleter: desc_header = getattr(action, ATTR_DESCRIPTIVE_COMPLETION_HEADER, None) if desc_header is None: desc_header = DEFAULT_DESCRIPTIVE_HEADER - header = '\n{: <{token_width}}{}'.format(action.dest.upper(), desc_header, token_width=token_width + 2) + header = '\n{: <{token_width}}{}'.format(destination.upper(), desc_header, token_width=token_width + 2) self._cmd2_app.completion_header = header self._cmd2_app.display_matches = completions_with_desc diff --git a/cmd2/argparse_custom.py b/cmd2/argparse_custom.py index a0e05ae9..a59270c3 100644 --- a/cmd2/argparse_custom.py +++ b/cmd2/argparse_custom.py @@ -62,8 +62,8 @@ Tab Completion: return my_generated_list completer_function - Pass a tab-completion function that does custom completion. Since custom tab completion operations commonly - need to modify cmd2's instance variables related to tab-completion, it will be rare to need a completer + Pass a tab completion function that does custom completion. Since custom tab completion operations commonly + need to modify cmd2's instance variables related to tab completion, it will be rare to need a completer function. completer_method should be used in those cases. Example: @@ -90,7 +90,7 @@ Tab Completion: path_filter=lambda path: os.path.isdir(path)) parser.add_argument('-o', '--options', choices_method=completer_method) - Of the 5 tab-completion parameters, choices is the only one where argparse validates user input against items + Of the 5 tab completion parameters, choices is the only one where argparse validates user input against items in the choices list. This is because the other 4 parameters are meant to tab complete data sets that are viewed as dynamic. Therefore it is up to the developer to validate if the user has typed an acceptable value for these arguments. @@ -118,7 +118,7 @@ Tab Completion: the developer to determine if the user entered the correct argument type (e.g. int) and validate their values. CompletionError Class: - Raised during tab-completion operations to report any sort of error you want printed by the AutoCompleter + Raised during tab completion operations to report any sort of error you want printed by the AutoCompleter Example use cases - Reading a database to retrieve a tab completion data set failed @@ -231,7 +231,7 @@ def generate_range_error(range_min: int, range_max: Union[int, float]) -> str: class CompletionError(Exception): """ - Raised during tab-completion operations to report any sort of error you want printed by the AutoCompleter + Raised during tab completion operations to report any sort of error you want printed by the AutoCompleter Example use cases - Reading a database to retrieve a tab completion data set failed @@ -356,8 +356,8 @@ def _add_argument_wrapper(self, *args, # Added args used by AutoCompleter :param choices_function: function that provides choices for this argument :param choices_method: cmd2-app method that provides choices for this argument - :param completer_function: tab-completion function that provides choices for this argument - :param completer_method: cmd2-app tab-completion method that provides choices for this argument + :param completer_function: tab completion function that provides choices for this argument + :param completer_method: cmd2-app tab completion method that provides choices for this argument :param suppress_tab_hint: when AutoCompleter has no results to show during tab completion, it displays the current argument's help text as a hint. Set this to True to suppress the hint. If this argument's help text is set to argparse.SUPPRESS, then tab hints will not display regardless of the diff --git a/docs/features/argument_processing.rst b/docs/features/argument_processing.rst index 9d98ea93..82244d7e 100644 --- a/docs/features/argument_processing.rst +++ b/docs/features/argument_processing.rst @@ -325,14 +325,13 @@ Subcommands are supported for commands using either the ``@with_argparser`` or is based on argparse sub-parsers. You may add multiple layers of subcommands for your command. ``cmd2`` will -automatically traverse and tab-complete subcommands for all commands using +automatically traverse and tab complete subcommands for all commands using argparse. -See the subcommands_ and tab_autocompletion_ example to learn more about how to +See the subcommands_ example to learn more about how to use subcommands in your ``cmd2`` application. .. _subcommands: https://github.com/python-cmd2/cmd2/blob/master/examples/subcommands.py -.. _tab_autocompletion: https://github.com/python-cmd2/cmd2/blob/master/examples/tab_autocompletion.py Argparse Extensions diff --git a/docs/features/completion.rst b/docs/features/completion.rst index 14a98caf..a8c1cc85 100644 --- a/docs/features/completion.rst +++ b/docs/features/completion.rst @@ -1,7 +1,7 @@ Completion ========== -``cmd2`` adds tab-completion of file system paths for all built-in commands +``cmd2`` adds tab completion of file system paths for all built-in commands where it makes sense, including: - ``edit`` @@ -9,7 +9,7 @@ where it makes sense, including: - ``run_script`` - ``shell`` -``cmd2`` also adds tab-completion of shell commands to the ``shell`` command. +``cmd2`` also adds tab completion of shell commands to the ``shell`` command. Additionally, it is trivial to add identical file system path completion to your own custom commands. Suppose you have defined a custom command ``foo`` by @@ -17,7 +17,7 @@ implementing the ``do_foo`` method. To enable path completion for the ``foo`` command, then add a line of code similar to the following to your class which inherits from ``cmd2.Cmd``:: - complete_foo = self.path_complete + complete_foo = cmd2.Cmd.path_complete This will effectively define the ``complete_foo`` readline completer method in your class and make it utilize the same path completion logic as the built-in @@ -37,9 +37,9 @@ Tab Completion Using Argparse Decorators ---------------------------------------- When using one the Argparse-based :ref:`api/decorators:Decorators`, ``cmd2`` -provides automatic tab-completion of flag names. +provides automatic tab completion of flag names. -Tab-completion of argument values can be configured by using one of five +Tab completion of argument values can be configured by using one of five parameters to ``argparse.ArgumentParser.add_argument()`` - ``choices`` @@ -47,26 +47,26 @@ parameters to ``argparse.ArgumentParser.add_argument()`` - ``completer_function`` / ``completer_method`` See the arg_decorators_ or colors_ example for a demonstration of how to -use the ``choices`` parameter. See the tab_autocompletion_ example for a +use the ``choices`` parameter. See the argparse_completion_ example for a demonstration of how to use the ``choices_function`` and ``choices_method`` -parameters. See the arg_decorators_ or tab_autocompletion_ example for a +parameters. See the arg_decorators_ or argparse_completion_ example for a demonstration of how to use the ``completer_method`` parameter. -When tab-completing flags and/or argument values for a ``cmd2`` command using +When tab completing flags and/or argument values for a ``cmd2`` command using one of these decorators, ``cmd2`` keeps track of state so that once a flag has -already previously been provided, it won't attempt to tab-complete it again. +already previously been provided, it won't attempt to tab complete it again. When no completion results exists, a hint for the current argument will be displayed to help the user. .. _arg_decorators: https://github.com/python-cmd2/cmd2/blob/master/examples/arg_decorators.py .. _colors: https://github.com/python-cmd2/cmd2/blob/master/examples/colors.py -.. _tab_autocompletion: https://github.com/python-cmd2/cmd2/blob/master/examples/tab_autocompletion.py +.. _argparse_completion: https://github.com/python-cmd2/cmd2/blob/master/examples/argparse_completion.py CompletionItem For Providing Extra Context ------------------------------------------ -When tab-completing things like a unique ID from a database, it can often be +When tab completing things like a unique ID from a database, it can often be beneficial to provide the user with some extra context about the item being completed, such as a description. To facilitate this, ``cmd2`` defines the ``CompletionItem`` class which can be returned from any of the 4 completion @@ -76,5 +76,5 @@ or ``completion_method``. .. autoclass:: cmd2.argparse_custom.CompletionItem :members: -See the tab_autocompletion_ example or the implementation of the built-in +See the argparse_completion_ example or the implementation of the built-in **set** command for demonstration of how this is used. diff --git a/docs/features/embedded_python_shells.rst b/docs/features/embedded_python_shells.rst index 68377876..70765b21 100644 --- a/docs/features/embedded_python_shells.rst +++ b/docs/features/embedded_python_shells.rst @@ -67,7 +67,7 @@ code directory for an example of how to achieve this in your own applications. Using ``py`` to run scripts directly is considered deprecated. The newer ``run_pyscript`` command is superior for doing this in two primary ways: -- it supports tab-completion of file system paths +- it supports tab completion of file system paths - it has the ability to pass command-line arguments to the scripts invoked There are no disadvantages to using ``run_pyscript`` as opposed to ``py diff --git a/docs/features/initialization.rst b/docs/features/initialization.rst index 6824c7bf..b1ca4f05 100644 --- a/docs/features/initialization.rst +++ b/docs/features/initialization.rst @@ -133,7 +133,7 @@ override: command via ``self`` (Default: ``False``) - **macros**: dictionary of macro names and their values - **max_completion_items**: max number of CompletionItems to display during - tab-completion (Default: 50) + tab completion (Default: 50) - **pager**: sets the pager command used by the ``Cmd.ppaged()`` method for displaying wrapped output using a pager - **pager_chop**: sets the pager command used by the ``Cmd.ppaged()`` method diff --git a/docs/features/os.rst b/docs/features/os.rst index 89905d17..77bc6a66 100644 --- a/docs/features/os.rst +++ b/docs/features/os.rst @@ -20,7 +20,7 @@ to type:: (Cmd) !ls -al -NOTE: ``cmd2`` provides user-friendly tab-completion throughout the process of +NOTE: ``cmd2`` provides user-friendly tab completion throughout the process of running a shell command - first for the shell command name itself, and then for file paths in the argument section. diff --git a/docs/features/scripting.rst b/docs/features/scripting.rst index 62af2e6d..1128f5e1 100644 --- a/docs/features/scripting.rst +++ b/docs/features/scripting.rst @@ -34,7 +34,7 @@ Running Command Scripts Command script files can be executed using the built-in ``run_script`` command or ``@`` shortcut. Both ASCII and UTF-8 encoded unicode text files are -supported. The ``run_script`` command supports tab-completion of file system +supported. The ``run_script`` command supports tab completion of file system paths. There is a variant ``_relative_run_script`` command or ``@@`` shortcut for use within a script which uses paths relative to the first script. @@ -73,7 +73,7 @@ using ``run_pyscript`` is shown below along with the arg_printer_ script:: arg 2: 'bar' arg 3: 'baz 23' -``run_pyscript`` supports tab-completion of file system paths, and as shown +``run_pyscript`` supports tab completion of file system paths, and as shown above it has the ability to pass command-line arguments to the scripts invoked. Python scripts executed with ``run_pyscript`` can run ``cmd2`` application diff --git a/docs/features/settings.rst b/docs/features/settings.rst index 5a4a9c0f..aa3e5cec 100644 --- a/docs/features/settings.rst +++ b/docs/features/settings.rst @@ -89,11 +89,11 @@ max_completion_items ~~~~~~~~~~~~~~~~~~~~ Maximum number of CompletionItems to display during tab completion. A -CompletionItem is a special kind of tab-completion hint which displays both a +CompletionItem is a special kind of tab completion hint which displays both a value and description and uses one line for each hint. Tab complete the ``set`` command for an example. -If the number of tab-completion hints exceeds ``max_completion_items``, then +If the number of tab completion hints exceeds ``max_completion_items``, then they will be displayed in the typical columnized format and will not include the description text of the CompletionItem. diff --git a/docs/overview/installation.rst b/docs/overview/installation.rst index d8d24ebd..6080fe90 100644 --- a/docs/overview/installation.rst +++ b/docs/overview/installation.rst @@ -119,7 +119,7 @@ macOS Considerations -------------------- macOS comes with the `libedit <http://thrysoee.dk/editline/>`_ library which is -similar, but not identical, to GNU Readline. Tab-completion for ``cmd2`` +similar, but not identical, to GNU Readline. Tab completion for ``cmd2`` applications is only tested against GNU Readline. There are several ways GNU Readline can be installed within a Python diff --git a/examples/argparse_completion.py b/examples/argparse_completion.py new file mode 100644 index 00000000..90975d3f --- /dev/null +++ b/examples/argparse_completion.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python +# coding=utf-8 +""" +A simple example demonstrating how to integrate tab completion with argparse-based commands. +""" +import argparse +from typing import Dict, List + +from cmd2 import Cmd, Cmd2ArgumentParser, with_argparser, CompletionError, CompletionItem +from cmd2.utils import basic_complete + +# Data source for argparse.choices +food_item_strs = ['Pizza', 'Ham', 'Ham Sandwich', 'Potato'] + + +def choices_function() -> List[str]: + """Choices functions are useful when the choice list is dynamically generated (e.g. from data in a database)""" + return ['a', 'dynamic', 'list', 'goes', 'here'] + + +def completer_function(text: str, line: str, begidx: int, endidx: int) -> List[str]: + """ + A tab completion function not dependent on instance data. Since custom tab completion operations commonly + need to modify cmd2's instance variables related to tab completion, it will be rare to need a completer + function. completer_method should be used in those cases. + """ + match_against = ['a', 'dynamic', 'list', 'goes', 'here'] + return basic_complete(text, line, begidx, endidx, match_against) + + +def choices_completion_item() -> List[CompletionItem]: + """Return CompletionItem instead of strings. These give more context to what's being tab completed.""" + items = \ + { + 1: "My item", + 2: "Another item", + 3: "Yet another item" + } + return [CompletionItem(item_id, description) for item_id, description in items.items()] + + +def choices_arg_tokens(arg_tokens: Dict[str, List[str]]) -> List[str]: + """ + If a choices or completer function/method takes a value called arg_tokens, then it will be + passed a dictionary that maps the command line tokens up through the one being completed + to their argparse argument name. All values of the arg_tokens dictionary are lists, even if + a particular argument expects only 1 token. + """ + # Check if choices_function flag has appeared + values = ['choices_function', 'flag'] + if 'choices_function' in arg_tokens: + values.append('is {}'.format(arg_tokens['choices_function'][0])) + else: + values.append('not supplied') + return values + + +class ArgparseCompletion(Cmd): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.sport_item_strs = ['Bat', 'Basket', 'Basketball', 'Football', 'Space Ball'] + + def choices_method(self) -> List[str]: + """Choices methods are useful when the choice list is based on instance data of your application""" + return self.sport_item_strs + + def choices_completion_error(self) -> List[str]: + """ + CompletionErrors can be raised if an error occurs while tab completing. + + Example use cases + - Reading a database to retrieve a tab completion data set failed + - A previous command line argument that determines the data set being completed is invalid + """ + if self.debug: + return self.sport_item_strs + raise CompletionError("debug must be true") + + # Parser for example command + example_parser = Cmd2ArgumentParser(description="Command demonstrating tab completion with argparse\n" + "Notice even the flags of this command tab complete") + + # Tab complete from a list using argparse choices. Set metavar if you don't + # want the entire choices list showing in the usage text for this command. + example_parser.add_argument('--choices', choices=food_item_strs, metavar="CHOICE", + help="tab complete using choices") + + # Tab complete from choices provided by a choices function and choices method + example_parser.add_argument('--choices_function', choices_function=choices_function, + help="tab complete using a choices_function") + example_parser.add_argument('--choices_method', choices_method=choices_method, + help="tab complete using a choices_method") + + # Tab complete using a completer function and completer method + example_parser.add_argument('--completer_function', completer_function=completer_function, + help="tab complete using a completer_function") + example_parser.add_argument('--completer_method', completer_method=Cmd.path_complete, + help="tab complete using a completer_method") + + # Demonstrate raising a CompletionError while tab completing + example_parser.add_argument('--completion_error', choices_method=choices_completion_error, + help="raise a CompletionError while tab completing if debug is False") + + # Demonstrate returning CompletionItems instead of strings + example_parser.add_argument('--completion_item', choices_function=choices_completion_item, metavar="ITEM_ID", + descriptive_header="Description", + help="demonstrate use of CompletionItems") + + # Demonstrate use of arg_tokens dictionary + example_parser.add_argument('--arg_tokens', choices_function=choices_arg_tokens, + help="demonstrate use of arg_tokens dictionary") + + @with_argparser(example_parser) + def do_example(self, _: argparse.Namespace) -> None: + """The example command""" + self.poutput("I do nothing") + + +if __name__ == '__main__': + import sys + app = ArgparseCompletion() + sys.exit(app.cmdloop()) diff --git a/examples/basic_completion.py b/examples/basic_completion.py new file mode 100755 index 00000000..e021828b --- /dev/null +++ b/examples/basic_completion.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +# coding=utf-8 +""" +A simple example demonstrating how to enable tab completion by assigning a completer function to do_* commands. +This also demonstrates capabilities of the following completer methods included with cmd2: +- delimiter_completer +- flag_based_complete (see note below) +- index_based_complete (see note below) + +flag_based_complete() and index_based_complete() are basic methods and should only be used if you are not +familiar with argparse. The recommended approach for tab completing positional tokens and flags is to use +argparse-based completion. For an example integrating tab completion with argparse, see argparse_completion.py +""" +import functools + +import cmd2 + +# List of strings used with completion functions +food_item_strs = ['Pizza', 'Ham', 'Ham Sandwich', 'Potato'] +sport_item_strs = ['Bat', 'Basket', 'Basketball', 'Football', 'Space Ball'] + +# This data is used to demonstrate delimiter_complete +file_strs = \ + [ + '/home/user/file.db', + '/home/user/file space.db', + '/home/user/another.db', + '/home/other user/maps.db', + '/home/other user/tests.db' + ] + + +class BasicCompletion(cmd2.Cmd): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def do_flag_based(self, statement: cmd2.Statement): + """Tab completes arguments based on a preceding flag using flag_based_complete + -f, --food [completes food items] + -s, --sport [completes sports] + -p, --path [completes local file system paths] + """ + self.poutput("Args: {}".format(statement.args)) + + def complete_flag_based(self, text, line, begidx, endidx): + """Completion function for do_flag_based""" + flag_dict = \ + { + # Tab complete food items after -f and --food flags in command line + '-f': food_item_strs, + '--food': food_item_strs, + + # Tab complete sport items after -s and --sport flags in command line + '-s': sport_item_strs, + '--sport': sport_item_strs, + + # Tab complete using path_complete function after -p and --path flags in command line + '-p': self.path_complete, + '--path': self.path_complete, + } + + return self.flag_based_complete(text, line, begidx, endidx, flag_dict=flag_dict) + + def do_index_based(self, statement: cmd2.Statement): + """Tab completes first 3 arguments using index_based_complete""" + self.poutput("Args: {}".format(statement.args)) + + def complete_index_based(self, text, line, begidx, endidx): + """Completion function for do_index_based""" + index_dict = \ + { + 1: food_item_strs, # Tab complete food items at index 1 in command line + 2: sport_item_strs, # Tab complete sport items at index 2 in command line + 3: self.path_complete, # Tab complete using path_complete function at index 3 in command line + } + + return self.index_based_complete(text, line, begidx, endidx, index_dict=index_dict) + + def do_delimiter_complete(self, statement: cmd2.Statement): + """Tab completes files from a list using delimiter_complete""" + self.poutput("Args: {}".format(statement.args)) + + # Use a partialmethod to set arguments to delimiter_complete + complete_delimiter_complete = functools.partialmethod(cmd2.Cmd.delimiter_complete, + match_against=file_strs, delimiter='/') + + +if __name__ == '__main__': + import sys + app = BasicCompletion() + sys.exit(app.cmdloop()) diff --git a/examples/python_scripting.py b/examples/python_scripting.py index fc23c562..198e784d 100755 --- a/examples/python_scripting.py +++ b/examples/python_scripting.py @@ -87,6 +87,7 @@ class CmdLineApp(cmd2.Cmd): # Enable tab completion for cd command def complete_cd(self, text, line, begidx, endidx): + # Tab complete only directories return self.path_complete(text, line, begidx, endidx, path_filter=os.path.isdir) dir_parser = argparse.ArgumentParser() diff --git a/examples/tab_autocompletion.py b/examples/tab_autocompletion.py deleted file mode 100755 index 3561f968..00000000 --- a/examples/tab_autocompletion.py +++ /dev/null @@ -1,268 +0,0 @@ -#!/usr/bin/env python3 -# coding=utf-8 -""" -A example usage of the AutoCompleter -""" -import argparse -import functools -from typing import List - -import cmd2 -from cmd2 import utils, Cmd2ArgumentParser, CompletionItem - -actors = ['Mark Hamill', 'Harrison Ford', 'Carrie Fisher', 'Alec Guinness', 'Peter Mayhew', - 'Anthony Daniels', 'Adam Driver', 'Daisy Ridley', 'John Boyega', 'Oscar Isaac', - 'Lupita Nyong\'o', 'Andy Serkis', 'Liam Neeson', 'Ewan McGregor', 'Natalie Portman', - 'Jake Lloyd', 'Hayden Christensen', 'Christopher Lee'] - - -def query_actors() -> List[str]: - """Simulating a function that queries and returns a completion values""" - return actors - - -class TabCompleteExample(cmd2.Cmd): - """ Example cmd2 application where we a base command which has a couple subcommands.""" - - CAT_AUTOCOMPLETE = 'AutoComplete Examples' - - def __init__(self): - super().__init__() - - # For mocking a data source for the example commands - ratings_types = ['G', 'PG', 'PG-13', 'R', 'NC-17'] - show_ratings = ['TV-Y', 'TV-Y7', 'TV-G', 'TV-PG', 'TV-14', 'TV-MA'] - static_list_directors = ['J. J. Abrams', 'Irvin Kershner', 'George Lucas', 'Richard Marquand', - 'Rian Johnson', 'Gareth Edwards'] - USER_MOVIE_LIBRARY = ['ROGUE1', 'SW_EP04', 'SW_EP05'] - MOVIE_DATABASE_IDS = ['SW_EP1', 'SW_EP02', 'SW_EP03', 'ROGUE1', 'SW_EP04', - 'SW_EP05', 'SW_EP06', 'SW_EP07', 'SW_EP08', 'SW_EP09'] - MOVIE_DATABASE = {'SW_EP04': {'title': 'Star Wars: Episode IV - A New Hope', - 'rating': 'PG', - 'director': ['George Lucas'], - 'actor': ['Mark Hamill', 'Harrison Ford', 'Carrie Fisher', - 'Alec Guinness', 'Peter Mayhew', 'Anthony Daniels'] - }, - 'SW_EP05': {'title': 'Star Wars: Episode V - The Empire Strikes Back', - 'rating': 'PG', - 'director': ['Irvin Kershner'], - 'actor': ['Mark Hamill', 'Harrison Ford', 'Carrie Fisher', - 'Alec Guinness', 'Peter Mayhew', 'Anthony Daniels'] - }, - 'SW_EP06': {'title': 'Star Wars: Episode VI - Return of the Jedi', - 'rating': 'PG', - 'director': ['Richard Marquand'], - 'actor': ['Mark Hamill', 'Harrison Ford', 'Carrie Fisher', - 'Alec Guinness', 'Peter Mayhew', 'Anthony Daniels'] - }, - 'SW_EP1': {'title': 'Star Wars: Episode I - The Phantom Menace', - 'rating': 'PG', - 'director': ['George Lucas'], - 'actor': ['Liam Neeson', 'Ewan McGregor', 'Natalie Portman', 'Jake Lloyd'] - }, - 'SW_EP02': {'title': 'Star Wars: Episode II - Attack of the Clones', - 'rating': 'PG', - 'director': ['George Lucas'], - 'actor': ['Liam Neeson', 'Ewan McGregor', 'Natalie Portman', - 'Hayden Christensen', 'Christopher Lee'] - }, - 'SW_EP03': {'title': 'Star Wars: Episode III - Revenge of the Sith', - 'rating': 'PG-13', - 'director': ['George Lucas'], - 'actor': ['Liam Neeson', 'Ewan McGregor', 'Natalie Portman', - 'Hayden Christensen'] - }, - - } - USER_SHOW_LIBRARY = {'SW_REB': ['S01E01', 'S02E02']} - SHOW_DATABASE_IDS = ['SW_CW', 'SW_TCW', 'SW_REB'] - SHOW_DATABASE = {'SW_CW': {'title': 'Star Wars: Clone Wars', - 'rating': 'TV-Y7', - 'seasons': {1: ['S01E01', 'S01E02', 'S01E03'], - 2: ['S02E01', 'S02E02', 'S02E03']} - }, - 'SW_TCW': {'title': 'Star Wars: The Clone Wars', - 'rating': 'TV-PG', - 'seasons': {1: ['S01E01', 'S01E02', 'S01E03'], - 2: ['S02E01', 'S02E02', 'S02E03']} - }, - 'SW_REB': {'title': 'Star Wars: Rebels', - 'rating': 'TV-Y7', - 'seasons': {1: ['S01E01', 'S01E02', 'S01E03'], - 2: ['S02E01', 'S02E02', 'S02E03']} - }, - } - - file_list = \ - [ - '/home/user/file.db', - '/home/user/file space.db', - '/home/user/another.db', - '/home/other user/maps.db', - '/home/other user/tests.db' - ] - - # noinspection PyMethodMayBeStatic - def instance_query_actors(self) -> List[str]: - """Simulating a function that queries and returns a completion values""" - return actors - - def instance_query_movie_ids(self) -> List[str]: - """Demonstrates showing tabular hinting of tab completion information""" - completions_with_desc = [] - - # Sort the movie id strings with a natural sort since they contain numbers - for movie_id in utils.natural_sort(self.MOVIE_DATABASE_IDS): - if movie_id in self.MOVIE_DATABASE: - movie_entry = self.MOVIE_DATABASE[movie_id] - completions_with_desc.append(CompletionItem(movie_id, movie_entry['title'])) - - # Mark that we already sorted the matches - self.matches_sorted = True - return completions_with_desc - - # This demonstrates a number of customizations of the AutoCompleter version of ArgumentParser - # - The help output will separately group required vs optional flags - # - The help output for arguments with multiple flags or with append=True is more concise - # - cmd2 adds the ability to specify ranges of argument counts in 'nargs' - - suggest_description = "Suggest command demonstrates argparse customizations.\n" - suggest_description += "See hybrid_suggest and orig_suggest to compare the help output." - suggest_parser = Cmd2ArgumentParser(description=suggest_description) - - suggest_parser.add_argument('-t', '--type', choices=['movie', 'show'], required=True) - suggest_parser.add_argument('-d', '--duration', nargs=(1, 2), action='append', - help='Duration constraint in minutes.\n' - '\tsingle value - maximum duration\n' - '\t[a, b] - duration range') - - @cmd2.with_category(CAT_AUTOCOMPLETE) - @cmd2.with_argparser(suggest_parser) - def do_suggest(self, args) -> None: - """Suggest command demonstrates argparse customizations""" - if not args.type: - self.do_help('suggest') - - # If you prefer the original argparse help output but would like narg ranges, it's possible - # to enable narg ranges without the help changes using this method - - suggest_parser_hybrid = argparse.ArgumentParser() - suggest_parser_hybrid.add_argument('-t', '--type', choices=['movie', 'show'], required=True) - suggest_parser_hybrid.add_argument('-d', '--duration', nargs=(1, 2), action='append', - help='Duration constraint in minutes.\n' - '\tsingle value - maximum duration\n' - '\t[a, b] - duration range') - - @cmd2.with_category(CAT_AUTOCOMPLETE) - @cmd2.with_argparser(suggest_parser_hybrid) - def do_hybrid_suggest(self, args): - if not args.type: - self.do_help('orig_suggest') - - # This variant demonstrates the AutoCompleter working with the orginial argparse. - # Base argparse is unable to specify narg ranges. Autocompleter will keep expecting additional arguments - # for the -d/--duration flag until you specify a new flag or end processing of flags with '--' - - suggest_parser_orig = argparse.ArgumentParser() - - suggest_parser_orig.add_argument('-t', '--type', choices=['movie', 'show'], required=True) - suggest_parser_orig.add_argument('-d', '--duration', nargs='+', action='append', - help='Duration constraint in minutes.\n' - '\tsingle value - maximum duration\n' - '\t[a, b] - duration range') - - @cmd2.with_argparser(suggest_parser_orig) - @cmd2.with_category(CAT_AUTOCOMPLETE) - def do_orig_suggest(self, args) -> None: - if not args.type: - self.do_help('orig_suggest') - - def _do_vid_movies(self, args) -> None: - if not args.command: - self.do_help('video movies') - elif args.command == 'list': - for movie_id in TabCompleteExample.MOVIE_DATABASE: - movie = TabCompleteExample.MOVIE_DATABASE[movie_id] - print('{}\n-----------------------------\n{} ID: {}\nDirector: {}\nCast:\n {}\n\n' - .format(movie['title'], movie['rating'], movie_id, - ', '.join(movie['director']), - '\n '.join(movie['actor']))) - - def _do_vid_shows(self, args) -> None: - if not args.command: - self.do_help('video shows') - - elif args.command == 'list': - for show_id in TabCompleteExample.SHOW_DATABASE: - show = TabCompleteExample.SHOW_DATABASE[show_id] - print('{}\n-----------------------------\n{} ID: {}' - .format(show['title'], show['rating'], show_id)) - for season in show['seasons']: - ep_list = show['seasons'][season] - print(' Season {}:\n {}' - .format(season, - '\n '.join(ep_list))) - print() - - video_parser = Cmd2ArgumentParser() - - video_types_subparsers = video_parser.add_subparsers(title='Media Types', dest='type') - - vid_movies_parser = video_types_subparsers.add_parser('movies') - vid_movies_parser.set_defaults(func=_do_vid_movies) - - vid_movies_commands_subparsers = vid_movies_parser.add_subparsers(title='Commands', dest='command') - - vid_movies_list_parser = vid_movies_commands_subparsers.add_parser('list') - - vid_movies_list_parser.add_argument('-t', '--title', help='Title Filter') - vid_movies_list_parser.add_argument('-r', '--rating', help='Rating Filter', nargs='+', - choices=ratings_types) - vid_movies_list_parser.add_argument('-d', '--director', help='Director Filter', choices=static_list_directors) - vid_movies_list_parser.add_argument('-a', '--actor', help='Actor Filter', action='append', - choices_function=query_actors) - - vid_movies_add_parser = vid_movies_commands_subparsers.add_parser('add') - vid_movies_add_parser.add_argument('title', help='Movie Title') - vid_movies_add_parser.add_argument('rating', help='Movie Rating', choices=ratings_types) - - vid_movies_add_parser.add_argument('-d', '--director', help='Director', nargs=(1, 2), required=True, - choices=static_list_directors) - vid_movies_add_parser.add_argument('actor', help='Actors', nargs='*', choices_method=instance_query_actors) - - vid_movies_load_parser = vid_movies_commands_subparsers.add_parser('load') - vid_movies_load_parser.add_argument('movie_file', help='Movie database', - completer_method=functools.partial(cmd2.Cmd.delimiter_complete, - delimiter='/', match_against=file_list)) - - vid_movies_read_parser = vid_movies_commands_subparsers.add_parser('read') - vid_movies_read_parser.add_argument('movie_file', help='Movie database', completer_method=cmd2.Cmd.path_complete) - - vid_movies_delete_parser = vid_movies_commands_subparsers.add_parser('delete') - vid_movies_delete_parser.add_argument('movie_id', help='Movie ID', choices_method=instance_query_movie_ids, - descriptive_header='Title') - - vid_shows_parser = video_types_subparsers.add_parser('shows') - vid_shows_parser.set_defaults(func=_do_vid_shows) - - vid_shows_commands_subparsers = vid_shows_parser.add_subparsers(title='Commands', dest='command') - - vid_shows_list_parser = vid_shows_commands_subparsers.add_parser('list') - - @cmd2.with_category(CAT_AUTOCOMPLETE) - @cmd2.with_argparser(video_parser) - def do_video(self, args): - """Video management command demonstrates multiple layers of subcommands being handled by AutoCompleter""" - func = getattr(args, 'func', None) - if func is not None: - # Call whatever subcommand function was selected - func(self, args) - else: - # No subcommand was provided, so call help - self.do_help('video') - - -if __name__ == '__main__': - import sys - app = TabCompleteExample() - sys.exit(app.cmdloop()) diff --git a/examples/tab_completion.py b/examples/tab_completion.py deleted file mode 100755 index 1a25238f..00000000 --- a/examples/tab_completion.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env python -# coding=utf-8 -""" -A simple example demonstrating how to use flag and index based tab-completion functions -For argparse-based tab completion, see tab_autocompletion.py -""" -import argparse - -import cmd2 - -# List of strings used with flag and index based completion functions -food_item_strs = ['Pizza', 'Ham', 'Ham Sandwich', 'Potato'] -sport_item_strs = ['Bat', 'Basket', 'Basketball', 'Football', 'Space Ball'] - - -class TabCompleteExample(cmd2.Cmd): - """ Example cmd2 application where we a base command which has a couple subcommands.""" - - def __init__(self): - super().__init__() - - add_item_parser = argparse.ArgumentParser() - add_item_group = add_item_parser.add_mutually_exclusive_group() - add_item_group.add_argument('-f', '--food', help='Adds food item') - add_item_group.add_argument('-s', '--sport', help='Adds sport item') - add_item_group.add_argument('-o', '--other', help='Adds other item') - - @cmd2.with_argparser(add_item_parser) - def do_add_item(self, args): - """Add item command help""" - if args.food: - add_item = args.food - elif args.sport: - add_item = args.sport - elif args.other: - add_item = args.other - else: - add_item = 'no items' - - self.poutput("You added {}".format(add_item)) - - # Add flag-based tab-completion to add_item command - def complete_add_item(self, text, line, begidx, endidx): - flag_dict = \ - { - # Tab-complete food items after -f and --food flags in command line - '-f': food_item_strs, - '--food': food_item_strs, - - # Tab-complete sport items after -s and --sport flags in command line - '-s': sport_item_strs, - '--sport': sport_item_strs, - - # Tab-complete using path_complete function after -o and --other flags in command line - '-o': self.path_complete, - '--other': self.path_complete, - } - - return self.flag_based_complete(text, line, begidx, endidx, flag_dict=flag_dict) - - @cmd2.with_argument_list - def do_list_item(self, args): - """List item command help""" - self.poutput("You listed {}".format(args)) - - # Add index-based tab-completion to list_item command - def complete_list_item(self, text, line, begidx, endidx): - index_dict = \ - { - 1: food_item_strs, # Tab-complete food items at index 1 in command line - 2: sport_item_strs, # Tab-complete sport items at index 2 in command line - 3: self.path_complete, # Tab-complete using path_complete function at index 3 in command line - } - - return self.index_based_complete(text, line, begidx, endidx, index_dict=index_dict) - - -if __name__ == '__main__': - import sys - app = TabCompleteExample() - sys.exit(app.cmdloop()) diff --git a/tests/conftest.py b/tests/conftest.py index 7f77a207..9ee8da19 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -185,7 +185,7 @@ def complete_tester(text: str, line: str, begidx: int, endidx: int, app) -> Opti def get_endidx(): return endidx - # Run the readline tab-completion function with readline mocks in place + # Run the readline tab completion function with readline mocks in place with mock.patch.object(readline, 'get_line_buffer', get_line): with mock.patch.object(readline, 'get_begidx', get_begidx): with mock.patch.object(readline, 'get_endidx', get_endidx): diff --git a/tests/test_completion.py b/tests/test_completion.py index 99f832a4..f545c8f9 100755 --- a/tests/test_completion.py +++ b/tests/test_completion.py @@ -1,9 +1,9 @@ # coding=utf-8 # flake8: noqa E302 """ -Unit/functional testing for readline tab-completion functions in the cmd2.py module. +Unit/functional testing for readline tab completion functions in the cmd2.py module. -These are primarily tests related to readline completer functions which handle tab-completion of cmd2/cmd commands, +These are primarily tests related to readline completer functions which handle tab completion of cmd2/cmd commands, file system paths, and shell commands. """ # Python 3.5 had some regressions in the unitest.mock module, so use 3rd party mock if available @@ -39,11 +39,11 @@ delimited_strs = \ # Dictionary used with flag based completion functions flag_dict = \ { - # Tab-complete food items after -f and --food flag in command line + # Tab complete food items after -f and --food flag in command line '-f': food_item_strs, '--food': food_item_strs, - # Tab-complete sport items after -s and --sport flag in command line + # Tab complete sport items after -s and --sport flag in command line '-s': sport_item_strs, '--sport': sport_item_strs, } @@ -51,14 +51,14 @@ flag_dict = \ # Dictionary used with index based completion functions index_dict = \ { - 1: food_item_strs, # Tab-complete food items at index 1 in command line - 2: sport_item_strs, # Tab-complete sport items at index 2 in command line + 1: food_item_strs, # Tab complete food items at index 1 in command line + 2: sport_item_strs, # Tab complete sport items at index 2 in command line } class CompletionsExample(cmd2.Cmd): """ - Example cmd2 application used to exercise tab-completion tests + Example cmd2 application used to exercise tab completion tests """ def __init__(self): cmd2.Cmd.__init__(self, multiline_commands=['test_multiline']) |