diff --git a/CHANGELOG.md b/CHANGELOG.md index f08e1c17..f1a944ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,8 +31,7 @@ time reading the [rich documentation](https://rich.readthedocs.io/). - `descriptive_header: str` replaced with `descriptive_headers: Sequence[str | rich.Column]` - Applies to parameter name when adding an argument to a parser as well as `set_descriptive_headers` and `get_descriptive_headers` - - `CompletionItem.description: str` changed to - `CompletionItem.descriptive_data: Sequence[str | rich.Column]` + - `CompletionItem.description` type expanded from `str` to `str | Sequence[Any]` - `decorators` module breaking changes: - `_set_parser_prog` renamed to `set_parser_prog` (without the leading underscore) and moved to `argparse_custom` module diff --git a/cmd2/argparse_completer.py b/cmd2/argparse_completer.py index 523afad4..69f8de77 100644 --- a/cmd2/argparse_completer.py +++ b/cmd2/argparse_completer.py @@ -582,7 +582,7 @@ def _format_completions(self, arg_state: _ArgumentState, completions: list[str] border_style=Cmd2Style.TABLE_BORDER, ) for item in completion_items: - hint_table.add_row(item, *item.descriptive_data) + hint_table.add_row(item, *item.description) # Generate the hint table string console = Cmd2GeneralConsole() diff --git a/cmd2/argparse_custom.py b/cmd2/argparse_custom.py index 68541f31..fe70c05f 100644 --- a/cmd2/argparse_custom.py +++ b/cmd2/argparse_custom.py @@ -139,7 +139,7 @@ def my_completer(self, text, line, begidx, endidx, arg_tokens) that value's name. The right column header is defined using the ``descriptive_headers`` parameter of add_argument(), which is a list of header names that defaults to ["Description"]. The right column values come from the -``CompletionItem.descriptive_data`` member, which is a list with the same number +``CompletionItem.description`` member, which is a list with the same number of items as columns defined in descriptive_headers. To use CompletionItems, just return them from your choices_provider or @@ -166,7 +166,7 @@ def my_completer(self, text, line, begidx, endidx, arg_tokens) def get_items(self) -> list[CompletionItems]: \"\"\"choices_provider which returns CompletionItems\"\"\" - # CompletionItem's second argument is descriptive_data. + # CompletionItem's second argument is description. # Its item count should match that of descriptive_headers. return [ CompletionItem(1, ["My item", True, "02/02/2022"]), @@ -194,14 +194,14 @@ def get_items(self) -> list[CompletionItems]: truncated with an ellipsis at the end. You can override this and other settings when you create the ``Column``. -``descriptive_data`` items can include Rich objects, including styled Text and Tables. +``description`` items can include Rich objects, including styled Text and Tables. To avoid printing a excessive information to the screen at once when a user presses tab, there is a maximum threshold for the number of CompletionItems that will be shown. Its value is defined in ``cmd2.Cmd.max_completion_items``. It defaults to 50, but can be changed. If the number of completion suggestions exceeds this number, they will be displayed in the typical columnized format -and will not include the descriptive_data of the CompletionItems. +and will not include the description of the CompletionItems. **Patched argparse functions** @@ -384,22 +384,26 @@ def __new__(cls, value: object, *_args: Any, **_kwargs: Any) -> 'CompletionItem' """Responsible for creating and returning a new instance, called before __init__ when an object is instantiated.""" return super().__new__(cls, value) - def __init__(self, value: object, descriptive_data: Sequence[Any], *args: Any) -> None: + def __init__(self, value: object, description: str | Sequence[Any], *args: Any) -> None: """CompletionItem Initializer. :param value: the value being tab completed - :param descriptive_data: a list of descriptive data to display in the columns that follow - the completion value. The number of items in this list must equal + :param description: a string or sequence of descriptive data to display in the columns that follow + the completion value. If a sequence, the number of items in this sequence must equal the number of descriptive headers defined for the argument. :param args: args for str __init__ """ super().__init__(*args) + # If description is a string, wrap it in a list + if isinstance(description, str): + description = [description] + # Make sure all objects are renderable by a Rich table. - renderable_data = [obj if is_renderable(obj) else str(obj) for obj in descriptive_data] + renderable_data = [obj if is_renderable(obj) else str(obj) for obj in description] # Convert strings containing ANSI style sequences to Rich Text objects for correct display width. - self.descriptive_data = ru.prepare_objects_for_rendering(*renderable_data) + self.description = ru.prepare_objects_for_rendering(*renderable_data) # Save the original value to support CompletionItems as argparse choices. # cmd2 has patched argparse so input is compared to this value instead of the CompletionItem instance. diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py index 070046b1..355ce397 100644 --- a/tests/test_cmd2.py +++ b/tests/test_cmd2.py @@ -2306,7 +2306,7 @@ def test_get_alias_completion_items(base_app) -> None: for cur_res in results: assert cur_res in base_app.aliases # Strip trailing spaces from table output - assert cur_res.descriptive_data[0].rstrip() == base_app.aliases[cur_res] + assert cur_res.description[0].rstrip() == base_app.aliases[cur_res] def test_get_macro_completion_items(base_app) -> None: @@ -2319,7 +2319,7 @@ def test_get_macro_completion_items(base_app) -> None: for cur_res in results: assert cur_res in base_app.macros # Strip trailing spaces from table output - assert cur_res.descriptive_data[0].rstrip() == base_app.macros[cur_res].value + assert cur_res.description[0].rstrip() == base_app.macros[cur_res].value def test_get_settable_completion_items(base_app) -> None: @@ -2333,11 +2333,11 @@ def test_get_settable_completion_items(base_app) -> None: # These CompletionItem descriptions are a two column table (Settable Value and Settable Description) # First check if the description text starts with the value str_value = str(cur_settable.value) - assert cur_res.descriptive_data[0].startswith(str_value) + assert cur_res.description[0].startswith(str_value) # The second column is likely to have wrapped long text. So we will just examine the # first couple characters to look for the Settable's description. - assert cur_settable.description[0:10] in cur_res.descriptive_data[1] + assert cur_settable.description[0:10] in cur_res.description[1] def test_alias_no_subcommand(base_app) -> None: