docs(cli) Custom argparse documentation engine with syntax highlighting#1009
docs(cli) Custom argparse documentation engine with syntax highlighting#1009
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1009 +/- ##
=======================================
Coverage 80.11% 80.11%
=======================================
Files 28 28
Lines 2409 2409
Branches 457 457
=======================================
Hits 1930 1930
Misses 356 356
Partials 123 123 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. 🤖 Generated with Claude Code |
why: Custom extensions provide better control over CLI documentation rendering and eliminate external dependency on sphinx-argparse. what: - Add docs/_ext/sphinx_argparse_neo/ module for argparse rendering - Add docs/_ext/argparse_exemplar.py extension (replaces sphinxarg.ext) - Add syntax highlighting lexers and roles for CLI documentation - Replace pretty_argparse.py with argparse_exemplar.py - Keep aafig.py extension (tmuxp-specific ASCII art rendering) - Add comprehensive test suite for all Sphinx extensions - Remove sphinx-argparse from dependencies - Update docs/conf.py to use argparse_exemplar extension - Update mypy overrides for new extension modules
Add argparse-highlight.css with "One Dark" color palette to style the CLI usage lines with semantic colorization: - Blue: "usage:" heading - Purple: program name - Green: subcommands - Teal: options (-h, --tree) - Yellow: metavars Also strip ANSI codes and disable colors during doc builds to ensure clean parsing by the argparse lexer.
Add intro paragraphs, wrap argparse directives in `## Command` sections, and rename generic `## Usage` to descriptive section names for consistent documentation structure across projects.
ca2f0e8 to
5a79fc6
Compare
The sphinx_argparse_neo module is in mypy's ignore_missing_imports, causing strip_ansi's return type to be treated as Any. Adding explicit str annotation ensures mypy knows the variable type throughout the function.
Code reviewFound 1 issue:
Affected files include:
Example of a function missing doctests: tmuxp/docs/_ext/sphinx_argparse_neo/nodes.py Lines 310 to 322 in f879f92 tmuxp/docs/_ext/sphinx_argparse_neo/renderer.py Lines 499 to 521 in f879f92 🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
Direct assignment to node.children bypasses docutils' setup_child() mechanism which maintains parent-child relationships, document references, and source tracking. Replace with clear() + extend() pattern to properly invoke the docutils protocol.
Glob patterns like "django-*" in argparse help text trigger RST "Inline emphasis start-string without end-string" warnings. Add escape_rst_emphasis() utility that escapes problematic asterisks (e.g., "django-*" → "django-\*") and apply it in the renderer's _parse_text() method.
Document sphinx_argparse_neo migration and related fixes for v1.64.0.
Replace .clear() + .extend() with slice assignment (node[:] = children) to fix mypy errors about Sequence[Node] having no .clear() method and Node having no .extend() method. This is the idiomatic pattern used in Sphinx's codebase for modifying node children.
Document when doctests are NOT required: - Sphinx/docutils visit_*/depart_* methods (tested via integration) - Sphinx setup() functions (entry points not testable in isolation) - Complex recursive traversal functions (extract helpers instead) This clarifies the doctest policy for docs/_ext/ Sphinx extensions where visitor patterns don't have doctests across docutils, Sphinx, or CPython's ast.NodeVisitor.
Add working doctests demonstrating: - Basic section creation from definition nodes - Page prefix for unique section IDs across docs - Category-prefixed examples with descriptive IDs/titles This helper function creates docutils section nodes and is straightforward to test, unlike complex visitor traversals.
Add working doctests demonstrating: - Extracting mutex groups from ArgumentParser - Verifying actions map to same MutuallyExclusiveGroup instance - Empty mapping for parsers without mutex groups Uses identity checks (is) instead of set() since dataclasses aren't hashable by default.
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. 🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
Add consistent styling to pre.argparse-usage to match code blocks: - background: #272822 (Monokai, same as .highlight) - padding, line-height, border-radius - thin scrollbars using Furo CSS variable
Extract subcommand from parser_info.prog to generate unique section IDs: - "tmuxp load" -> prefix "load" -> IDs like "load-usage", "load-options" - "tmuxp" -> no prefix -> IDs like "usage", "options" (backwards compatible) This prevents duplicate ID warnings when multiple argparse directives exist on the same documentation page (e.g., documenting subcommands). Changes: - Add _extract_id_prefix() static method - Add id_prefix parameter to render_usage_section() - Add id_prefix parameter to render_group_section() - Pass prefix from render() to section methods
Summary
Replace external
sphinx-argparsedependency with customsphinx_argparse_neoextensions, ported from vcspull project. Adds comprehensive documentation infrastructure for CLI commands.Changes
New Extensions
docs/_ext/sphinx_argparse_neo/- Complete argparse documentation enginedocs/_ext/argparse_exemplar.py- Transforms epilog examples into TOC sectionsdocs/_ext/argparse_lexer.py- Pygments lexers for CLI syntax highlightingdocs/_ext/argparse_roles.py- RST roles for inline CLI formattingdocs/_static/css/argparse-highlight.css- Styling for usage blocks and codeBug Fixes
no-any-returnerrorDocumentation
_create_example_section()and_extract_mutex_groups()Removed
pretty_argparse.py(replaced by new extensions)sphinx-argparsedependencyTest plan
uv run ruff check . --fix --show-fixespassesuv run ruff format .passesuv run mypypassesuv run py.testpasses (997 tests, 313 for docs/_ext)cd docs && sphinx-build -b html . _build/htmlbuilds successfully