diff --git a/README.md b/README.md index dbfac51..e41c6c7 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,10 @@ [![fair-software badge](https://img.shields.io/badge/fair--software.eu-%E2%97%8F%20%20%E2%97%8F%20%20%E2%97%8F%20%20%E2%97%8F%20%20%E2%97%8B-yellow)](https://fair-software.eu) [![CI](https://github.com/i-VRESSE/mkdocs_rich_argparse/actions/workflows/build.yml/badge.svg)](https://github.com/i-VRESSE/mkdocs_rich_argparse/actions/workflows/build.yml) -An MkDocs plugin to generate documentation for a [rich argparse parser](https://pypi.org/project/rich-argparse/). -It renders commands, sub commands and sub-sub commands which can have rich help messages. +An MkDocs plugin to generate documentation for any argparse parser with [rich-argparse](https://pypi.org/project/rich-argparse/) styling. +It renders commands, sub commands and sub-sub commands with colored output. + +The plugin works with **any** `argparse.ArgumentParser` - you don't need to modify your parser to use `RichHelpFormatter`. ## Installation @@ -40,6 +42,25 @@ See the [example/](example/) directory for a minimal example and a custom styled [![Screenshot of example](https://github.com/i-VRESSE/mkdocs_rich_argparse/raw/main/example/screenshot.png)](https://github.com/i-VRESSE/mkdocs_rich_argparse/raw/main/example/screenshot.png) +### Custom Styles + +You can customize the colors used in the generated documentation: + +```yaml +plugins: + - mkdocs-rich-argparse: + module: my_module + factory: my_factory_function + styles: + prog: "#00ff00" # Program name in usage + args: "#ff0000" # Arguments and options + groups: "#00ffff" # Group headers + metavar: "#ff00ff" # Metavariables (e.g., FILE) + help: white # Help text + text: white # Description text + default: grey50 # Default values +``` + ### Colors in Continuous Integration If you are building the mkdocs site in a Continuous Integration (CI) environment, the colors might not render correctly. To fix this add [TTY_COMPATIBLE=1 and TTY_INTERACTIVE=0 environment variables](https://rich.readthedocs.io/en/stable/console.html#environment-variables) to your CI configuration. diff --git a/src/mkdocs_rich_argparse/__init__.py b/src/mkdocs_rich_argparse/__init__.py index acee52f..3fcdb2c 100644 --- a/src/mkdocs_rich_argparse/__init__.py +++ b/src/mkdocs_rich_argparse/__init__.py @@ -6,6 +6,7 @@ import sys from collections.abc import Callable from textwrap import dedent +from typing import cast import mkdocs.config.base import mkdocs.config.config_options import mkdocs.plugins @@ -27,7 +28,14 @@ def _capture_help(parser: argparse.ArgumentParser) -> str: # Based on https://github.com/hamdanal/rich-argparse/blob/e28584ac56ddd46f4079d037c27f24f0ec4eccb4/rich_argparse/_argparse.py#L545 # but with export instead of save - text = Text.from_ansi(parser.format_help()) + # Temporarily set RichHelpFormatter to get colored output + original_formatter = parser.formatter_class + parser.formatter_class = RichHelpFormatter + try: + text = Text.from_ansi(parser.format_help()) + finally: + parser.formatter_class = original_formatter + console = Console(file=io.StringIO(), record=True) console.print(text, crop=False) code_format = dedent("""\ @@ -58,7 +66,8 @@ def argparser_to_markdown(parser: argparse.ArgumentParser, heading: str = "CLI R subparsers_actions = [action for action in parser._actions if isinstance(action, argparse._SubParsersAction)] current_subparsers_action = subparsers_actions[0] - for sub_cmd_name, sub_cmd_parser in current_subparsers_action.choices.items(): + for sub_cmd_name, _sub_cmd_parser in current_subparsers_action.choices.items(): + sub_cmd_parser = cast("argparse.ArgumentParser", _sub_cmd_parser) sub_cmd_help_text = _capture_help(sub_cmd_parser) lines.extend( @@ -77,7 +86,8 @@ def argparser_to_markdown(parser: argparse.ArgumentParser, heading: str = "CLI R ] if sub_subparsers_actions: sub_current_subparsers_action = sub_subparsers_actions[0] - for sub_sub_cmd_name, sub_sub_cmd_parser in sub_current_subparsers_action.choices.items(): + for sub_sub_cmd_name, _sub_sub_cmd_parser in sub_current_subparsers_action.choices.items(): + sub_sub_cmd_parser = cast("argparse.ArgumentParser", _sub_sub_cmd_parser) sub_sub_cmd_help_text = _capture_help(sub_sub_cmd_parser) lines.extend( @@ -133,6 +143,7 @@ def _load_obj(module: str, attribute: str, path: str | None) -> Callable: class RichArgparseStyles(mkdocs.config.base.Config): """Configuration for styles applied to the generated documentation.""" + prog = mkdocs.config.config_options.Optional(mkdocs.config.config_options.Type(str)) args = mkdocs.config.config_options.Optional(mkdocs.config.config_options.Type(str)) groups = mkdocs.config.config_options.Optional(mkdocs.config.config_options.Type(str)) # Overwrite default colors as on mkdocs black text is not visible in dark mode diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 338ca52..252b7b4 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -2,6 +2,7 @@ from textwrap import dedent import pytest from rich_argparse import RichHelpFormatter +from mkdocs_rich_argparse import RichArgparseStyles from mkdocs_rich_argparse import argparser_to_markdown @@ -93,3 +94,75 @@ def test_argparser_to_markdown_with_color(monkeypatch: pytest.MonkeyPatch, sampl assert len(result) > 3500 assert '' in result + + +@pytest.fixture +def plain_parser(): + """Parser using default HelpFormatter (the common case).""" + parser = argparse.ArgumentParser(prog="plainprog", description="A plain parser.") + parser.add_argument("--verbose", action="store_true", help="Enable verbose mode") + subparsers = parser.add_subparsers(title="commands", dest="command") + sub = subparsers.add_parser("run", help="Run something") + sub.add_argument("target", help="Target to run") + return parser + + +def test_plain_parser_gets_colors(monkeypatch: pytest.MonkeyPatch, plain_parser: argparse.ArgumentParser): + """Verify parsers without RichHelpFormatter still get colored output.""" + monkeypatch.setenv("FORCE_COLOR", "1") + + result = argparser_to_markdown(plain_parser) + + # Should have color spans from RichHelpFormatter + assert '