Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 23 additions & 19 deletions cmd2/cmd2.py
Original file line number Diff line number Diff line change
Expand Up @@ -4079,14 +4079,23 @@ def do_help(self, args: argparse.Namespace) -> None:
self.poutput(self.doc_leader, style=Cmd2Style.HELP_LEADER)
self.poutput()

if not cmds_cats:
# No categories found, fall back to standard behavior
self._print_documented_command_topics(self.doc_header, cmds_doc, args.verbose)
else:
# Categories found, Organize all commands by category
for category in sorted(cmds_cats.keys(), key=self.default_sort_key):
self._print_documented_command_topics(category, cmds_cats[category], args.verbose)
self._print_documented_command_topics(self.default_category, cmds_doc, args.verbose)
# Print any categories first and then the default category.
sorted_categories = sorted(cmds_cats.keys(), key=self.default_sort_key)
all_cmds = {category: cmds_cats[category] for category in sorted_categories}
all_cmds[self.doc_header] = cmds_doc

# Used to provide verbose table separation for better readability.
previous_table_printed = False

for category, commands in all_cmds.items():
if previous_table_printed:
self.poutput()

self._print_documented_command_topics(category, commands, args.verbose)
previous_table_printed = bool(commands) and args.verbose

if previous_table_printed and (help_topics or cmds_undoc):
self.poutput()

self.print_topics(self.misc_header, help_topics, 15, 80)
self.print_topics(self.undoc_header, cmds_undoc, 15, 80)
Expand All @@ -4102,7 +4111,7 @@ def do_help(self, args: argparse.Namespace) -> None:
completer = argparse_completer.DEFAULT_AP_COMPLETER(argparser, self)
completer.print_help(args.subcommands, self.stdout)

# If there is a help func delegate to do_help
# If the command has a custom help function, then call it
elif help_func is not None:
help_func()

Expand Down Expand Up @@ -5617,11 +5626,9 @@ def async_alert(self, alert_msg: str, new_prompt: str | None = None) -> None: #
cursor_offset=rl_get_point(),
alert_msg=alert_msg,
)
if rl_type == RlType.GNU:
sys.stderr.write(terminal_str)
sys.stderr.flush()
elif rl_type == RlType.PYREADLINE:
readline.rl.mode.console.write(terminal_str)

sys.stdout.write(terminal_str)
sys.stdout.flush()

# Redraw the prompt and input lines below the alert
rl_force_redisplay()
Expand Down Expand Up @@ -5679,9 +5686,6 @@ def need_prompt_refresh(self) -> bool: # pragma: no cover
def set_window_title(title: str) -> None: # pragma: no cover
"""Set the terminal window title.

NOTE: This function writes to stderr. Therefore, if you call this during a command run by a pyscript,
the string which updates the title will appear in that command's CommandResult.stderr data.

:param title: the new window title
"""
if not vt100_support:
Expand All @@ -5690,8 +5694,8 @@ def set_window_title(title: str) -> None: # pragma: no cover
from .terminal_utils import set_title_str

try:
sys.stderr.write(set_title_str(title))
sys.stderr.flush()
sys.stdout.write(set_title_str(title))
sys.stdout.flush()
except AttributeError:
# Debugging in Pycharm has issues with setting terminal title
pass
Expand Down
27 changes: 23 additions & 4 deletions cmd2/styles.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
"""Defines custom Rich styles and their corresponding names for cmd2.

This module provides a centralized and discoverable way to manage Rich styles used
within the cmd2 framework. It defines a StrEnum for style names and a dictionary
that maps these names to their default style objects.
This module provides a centralized and discoverable way to manage Rich styles
used within the cmd2 framework. It defines a StrEnum for style names and a
dictionary that maps these names to their default style objects.

**Notes**

Cmd2 uses Rich for its terminal output, and while this module defines a set of
cmd2-specific styles, it's important to understand that these aren't the only
styles that can appear. Components like Rich tracebacks and the rich-argparse
library, which cmd2 uses for its help output, also apply their own built-in
styles. Additionally, app developers may use other Rich objects that have
their own default styles.

For a complete theming experience, you can create a custom theme that includes
styles from Rich and rich-argparse. The `cmd2.rich_utils.set_theme()` function
automatically updates rich-argparse's styles with any custom styles provided in
your theme dictionary, so you don't have to modify them directly.

You can find Rich's default styles in the `rich.default_styles` module.
For rich-argparse, the style names are defined in the
`rich_argparse.RichHelpFormatter.styles` dictionary.

"""

import sys
Expand All @@ -26,7 +45,7 @@ class Cmd2Style(StrEnum):
Using this enum allows for autocompletion and prevents typos when
referencing cmd2-specific styles.

This StrEnum is tightly coupled with DEFAULT_CMD2_STYLES. Any name
This StrEnum is tightly coupled with `DEFAULT_CMD2_STYLES`. Any name
added here must have a corresponding style definition there.
"""

Expand Down
5 changes: 3 additions & 2 deletions tests/test_argparse_completer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from typing import cast

import pytest
from rich.text import Text

import cmd2
import cmd2.string_utils as su
Expand Down Expand Up @@ -115,7 +116,7 @@ def do_pos_and_flag(self, args: argparse.Namespace) -> None:
CompletionItem('choice_1', ['Description 1']),
# Make this the longest description so we can test display width.
CompletionItem('choice_2', [su.stylize("String with style", style=cmd2.Color.BLUE)]),
CompletionItem('choice_3', [su.stylize("Text with style", style=cmd2.Color.RED)]),
CompletionItem('choice_3', [Text("Text with style", style=cmd2.Color.RED)]),
)

# This tests that CompletionItems created with numerical values are sorted as numbers.
Expand Down Expand Up @@ -739,7 +740,7 @@ def test_completion_items(ac_app) -> None:
assert lines[3].endswith("\x1b[34mString with style\x1b[0m ")

# Verify that the styled Rich Text also rendered.
assert lines[4].endswith("\x1b[31mText with style\x1b[0m ")
assert lines[4].endswith("\x1b[31mText with style \x1b[0m ")

# Now test CompletionItems created from numbers
text = ''
Expand Down
Loading