Skip to content

Conversation

@tony
Copy link
Member

@tony tony commented Jan 11, 2026

Summary

  • Port CLI documentation extensions from tmuxp v1.63.0
  • Add custom Pygments lexer for CLI usage syntax highlighting
  • Add enhanced sphinx-argparse wrapper with ANSI stripping and examples transformation
  • Include comprehensive test suite (88 tests)

Changes

Commit 1: Sphinx extensions and tests

  • docs/_ext/cli_usage_lexer.py - Pygments lexer for CLI usage patterns
  • docs/_ext/pretty_argparse.py - Enhanced sphinx-argparse directive
  • tests/docs/_ext/ - Comprehensive test suite adapted for vcspull

Commit 2: Type stubs

  • Add types-docutils and types-Pygments to dependencies

Commit 3: Coverage config

  • Exclude docs/_ext/* from coverage reporting

Test plan

  • All 401 tests pass (uv run py.test --reruns 0 -vvv)
  • Ruff linting passes
  • Mypy type checking passes
  • Build docs and verify CLI pages render correctly

tony added 8 commits January 11, 2026 06:12
why: Enhanced CLI documentation with syntax highlighting and ANSI stripping
what:
- Add cli_usage_lexer.py: Pygments lexer for CLI usage patterns
- Add pretty_argparse.py: Enhanced sphinx-argparse wrapper
- Add comprehensive tests for both extensions (88 tests)
- Update docs/conf.py to register pretty_argparse extension
- Update pyproject.toml with mypy overrides and doctest config
- Fix pre-existing doctest issue in config_reader.py
why: Type stubs for docutils and Pygments libraries used in docs extensions
what:
- Add types-docutils to dev and typings groups
- Add types-Pygments to dev and typings groups
why: Sphinx extensions are documentation utilities, not core code
what:
- Add docs/_ext/* to coverage.run.omit
why: CLI examples from --help weren't appearing in generated docs
what:
- Remove :nodescription: from all CLI argparse directives
- Allows sphinx-argparse to include description with examples
- pretty_argparse transforms examples into proper sections
…ions

why: Asterisks in patterns like "django-*" trigger docutils emphasis
     parsing warnings when sphinx-argparse renders help text as RST
what:
- Add escape_rst_emphasis() to escape asterisks preceded by delimiters
- Override _nested_parse_paragraph() to pre-escape descriptions
- Fixes "Inline emphasis start-string without end-string" warnings
why: Ensure RST emphasis escaping works correctly for argparse patterns
what:
- Add 13 parameterized test cases covering:
  - Glob patterns like "django-*" are escaped
  - Multiple patterns in one string
  - Already escaped patterns unchanged
  - Valid emphasis (*text*) unchanged
  - Various edge cases (empty, underscore, dot)
why: Documentation code blocks showing vcspull CLI output need semantic
highlighting to match the colors used in the actual CLI.

what:
- Create vcspull_output_lexer.py with VcspullOutputLexer RegexLexer
- Map semantic colors to Pygments tokens (SUCCESS→Generic.Inserted,
  WARNING→Name.Exception, ERROR→Generic.Error, INFO→Name.Function)
- Handle list, status, sync, summary outputs and workspace headers
- Register lexer with Sphinx in pretty_argparse.py setup()
- Add 17 parameterized tests for all output patterns
… import

why: mypy cannot resolve sibling module imports in docs/_ext/ directory.

what:
- Add type: ignore[import-not-found] to vcspull_output_lexer import
@codecov
Copy link

codecov bot commented Jan 11, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.52%. Comparing base (b523f6b) to head (0de58df).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #496      +/-   ##
==========================================
+ Coverage   80.42%   80.52%   +0.09%     
==========================================
  Files          16       16              
  Lines        2192     2192              
  Branches      454      454              
==========================================
+ Hits         1763     1765       +2     
+ Misses        278      277       -1     
+ Partials      151      150       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

tony added 6 commits January 11, 2026 07:59
why: Console code blocks use BashSessionLexer which hardcodes output as
Generic.Output, losing semantic highlighting for vcspull command output.

what:
- Create vcspull_console_lexer.py extending ShellSessionBaseLexer pattern
- Delegate output lines to VcspullOutputLexer for semantic coloring
- Register as 'vcspull-console' alias in pretty_argparse.py
- Update docs/cli/list.md to use vcspull-console for output blocks
- Add 8 tests for console session tokenization
why: mypy reports errors for missing type stubs and return type annotation.

what:
- Add type: ignore[attr-defined] for do_insertions and line_re imports
- Add type: ignore[no-untyped-def] for generator method
- Remove explicit type annotations that conflict with Pygments internals
why: Plain HTTPS URLs in parentheses were incorrectly tokenized as repo
names, and interactive prompts like [y/N] had no special highlighting.

what:
- Add pattern for plain HTTPS/HTTP URLs (Name.Tag)
- Add pattern for interactive prompt options [y/N] (Comment)
- Add pattern for question mark prompt indicator (Generic.Prompt)
- Add 3 tests for new patterns
Update CLI documentation to use vcspull-console lexer for code blocks
that display vcspull command output with bullets, checkmarks, and
other semantic symbols.

Files updated:
- discover.md: basic usage, unattended mode, dry run, warnings, existing entries
- status.md: basic usage, filtering, detailed status
- sync.md: dry run, error handling
- search.md: basic usage, field-scoped queries
…highlighting

why: Generic "name:" pattern matched false positives like "add:" in
"Would add:" and "complete:" in "Dry run complete:".
what:
- Remove generic "name:" pattern that caused false positives
- Add ":" to success symbol lookahead for "✓ repo:" status output
- Add vcspull command and subcommand highlighting (Name.Builtin)
- Add more labels: Remote:, Repository:, Note:, Usage:
- Use vcspull-output for pure output blocks in discover.md
@tony
Copy link
Member Author

tony commented Jan 11, 2026

Code review

Found 2 issues:

  1. Import style violation - CLAUDE.md says "Use namespace imports: import enum instead of from enum import Enum". The new files use from ... import ... style extensively (e.g., from pygments.lexer import RegexLexer, from docutils import nodes).

from pygments.lexer import RegexLexer, bygroups, include
from pygments.token import Generic, Name, Operator, Punctuation, Text, Whitespace
class CLIUsageLexer(RegexLexer):
"""Lexer for CLI usage/help text (argparse, etc.).
Highlights usage patterns including options, arguments, and meta-variables.
Examples

  1. Duplicate Sphinx labels - The make_section_id() function generates identical "examples" IDs across all CLI documentation pages, causing 6 Sphinx warnings during just build-docs. The function has a counter parameter for uniqueness but it's always called with counter=0.

def make_section_id(
term_text: str, counter: int = 0, *, is_subsection: bool = False
) -> str:
"""Generate a section ID from an examples term.
Parameters
----------
term_text : str
The examples term text (e.g., "Machine-readable output: examples:")
counter : int
Counter for uniqueness if multiple examples sections exist.
is_subsection : bool
If True, omit "-examples" suffix for cleaner nested IDs.
Returns
-------
str
A normalized section ID.
Examples
--------
>>> make_section_id("examples:")
'examples'
>>> make_section_id("Machine-readable output examples:")
'machine-readable-output-examples'
>>> make_section_id("Field-scoped examples:", is_subsection=True)
'field-scoped'
>>> make_section_id("examples:", counter=1)
'examples-1'
"""
# Extract prefix before "examples" (e.g., "Machine-readable output")
lower_text = term_text.lower().rstrip(":")
if "examples" in lower_text:
prefix = lower_text.rsplit("examples", 1)[0].strip()
# Remove trailing colon from prefix (handles ": examples" pattern)
prefix = prefix.rstrip(":").strip()
if prefix:
normalized_prefix = prefix.replace(" ", "-")
# Subsections don't need "-examples" suffix
if is_subsection:
section_id = normalized_prefix
else:
section_id = f"{normalized_prefix}-examples"
else:
section_id = "examples"
else:
section_id = "examples"
# Add counter suffix for uniqueness
if counter > 0:
section_id = f"{section_id}-{counter}"
return section_id
def make_section_title(term_text: str, *, is_subsection: bool = False) -> str:

Generated with Claude Code

- If this code review was useful, please react with a thumbs up. Otherwise, react with a thumbs down.

@tony
Copy link
Member Author

tony commented Jan 11, 2026

Correction to issue #1: The import style concern was over-applied. The CLAUDE.md examples (import enum, import typing as t) target stdlib imports. The flagged imports are all third-party packages (pygments, docutils, sphinxarg) where direct imports are idiomatic - especially for Pygments token types in lexers.

Issue #1 is withdrawn. Only issue #2 (duplicate Sphinx labels) remains valid.

tony added 3 commits January 11, 2026 09:49
why: The namespace import guideline was being misapplied to third-party
packages like pygments, where direct imports are idiomatic.
what:
- Clarify that namespace imports apply to standard library modules
- Add explicit note that third-party packages use idiomatic styles
- Reorganize section with clear headers for each rule
why: The make_section_id() function generated identical "examples" IDs
across all CLI documentation pages, causing 6 Sphinx duplicate label
warnings during docs build.
what:
- Add page_prefix parameter to make_section_id() for cross-page uniqueness
- Thread page_prefix through _create_example_section(), transform_definition_list()
- Extract docname in CleanArgParseDirective.run() and pass to process_node()
- Section IDs now include page name: "sync-examples", "add-examples", etc.
- Add test for page_prefix functionality
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants