Skip to content

Commit a39c06d

Browse files
committed
docs: Propagate tmuxp PR #1011 changes
- feat(docs): Render argparse metadata as semantic definition list Replace pipe-separated format with <dl>/<dt>/<dd> structure - style(css): Use var(--code-font-size) for all argparse elements Add font-size to inline roles, pre.argparse-usage, .argparse-argument-name Add new .argparse-argument-meta flexbox styles - fix(lexer): Include underscores in lowercase metavar patterns Change [a-z][-a-z0-9]* to [a-z][-a-z0-9_]* in 6 locations - test(lexer): Add underscore metavar regression test Add fixtures and test for socket_name, config_file patterns
1 parent 27674f8 commit a39c06d

6 files changed

Lines changed: 941 additions & 36 deletions

File tree

docs/_ext/argparse_lexer.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,14 @@ class ArgparseUsageLexer(RegexLexer):
6767
(r"\.\.\.", Punctuation),
6868
# Long options with = value (e.g., --log-level=VALUE)
6969
(
70-
r"(--[a-zA-Z0-9][-a-zA-Z0-9]*)(=)([A-Z][A-Z0-9_]*|[a-z][-a-z0-9]*)",
70+
r"(--[a-zA-Z0-9][-a-zA-Z0-9]*)(=)([A-Z][A-Z0-9_]*|[a-z][-a-z0-9_]*)",
7171
bygroups(Name.Tag, Operator, Name.Variable), # type: ignore[no-untyped-call]
7272
),
7373
# Long options standalone
7474
(r"--[a-zA-Z0-9][-a-zA-Z0-9]*", Name.Tag),
7575
# Short options with space-separated value (e.g., -S socket-path)
7676
(
77-
r"(-[a-zA-Z0-9])(\s+)([A-Z][A-Z0-9_]*|[a-z][-a-z0-9]*)",
77+
r"(-[a-zA-Z0-9])(\s+)([A-Z][A-Z0-9_]*|[a-z][-a-z0-9_]*)",
7878
bygroups(Name.Attribute, Whitespace, Name.Variable), # type: ignore[no-untyped-call]
7979
),
8080
# Short options standalone
@@ -94,7 +94,7 @@ class ArgparseUsageLexer(RegexLexer):
9494
# UPPERCASE meta-variables (COMMAND, FILE, PATH)
9595
(r"\b[A-Z][A-Z0-9_]*\b", Name.Variable),
9696
# Subcommand/positional names (Name.Function for distinct styling)
97-
(r"\b[a-z][-a-z0-9]*\b", Name.Function),
97+
(r"\b[a-z][-a-z0-9_]*\b", Name.Function),
9898
# Catch-all for any other text
9999
(r"[^\s\[\]|(){},]+", Text),
100100
],
@@ -105,14 +105,14 @@ class ArgparseUsageLexer(RegexLexer):
105105
(r"\.\.\.", Punctuation),
106106
# Long options with = value (e.g., --log-level=VALUE)
107107
(
108-
r"(--[a-zA-Z0-9][-a-zA-Z0-9]*)(=)([A-Z][A-Z0-9_]*|[a-z][-a-z0-9]*)",
108+
r"(--[a-zA-Z0-9][-a-zA-Z0-9]*)(=)([A-Z][A-Z0-9_]*|[a-z][-a-z0-9_]*)",
109109
bygroups(Name.Tag, Operator, Name.Variable), # type: ignore[no-untyped-call]
110110
),
111111
# Long options standalone
112112
(r"--[a-zA-Z0-9][-a-zA-Z0-9]*", Name.Tag),
113113
# Short options with space-separated value (e.g., -S socket-path)
114114
(
115-
r"(-[a-zA-Z0-9])(\s+)([A-Z][A-Z0-9_]*|[a-z][-a-z0-9]*)",
115+
r"(-[a-zA-Z0-9])(\s+)([A-Z][A-Z0-9_]*|[a-z][-a-z0-9_]*)",
116116
bygroups(Name.Attribute, Whitespace, Name.Variable), # type: ignore[no-untyped-call]
117117
),
118118
# Short options standalone
@@ -132,7 +132,7 @@ class ArgparseUsageLexer(RegexLexer):
132132
# UPPERCASE meta-variables (COMMAND, FILE, PATH)
133133
(r"\b[A-Z][A-Z0-9_]*\b", Name.Variable),
134134
# Positional/command names (lowercase with dashes)
135-
(r"\b[a-z][-a-z0-9]*\b", Name.Label),
135+
(r"\b[a-z][-a-z0-9_]*\b", Name.Label),
136136
# Catch-all for any other text
137137
(r"[^\s\[\]|(){},]+", Text),
138138
],
@@ -234,14 +234,14 @@ class ArgparseHelpLexer(RegexLexer):
234234
(r"\.\.\.", Punctuation),
235235
# Long options with = value
236236
(
237-
r"(--[a-zA-Z0-9][-a-zA-Z0-9]*)(=)([A-Z][A-Z0-9_]*|[a-z][-a-z0-9]*)",
237+
r"(--[a-zA-Z0-9][-a-zA-Z0-9]*)(=)([A-Z][A-Z0-9_]*|[a-z][-a-z0-9_]*)",
238238
bygroups(Name.Tag, Operator, Name.Variable), # type: ignore[no-untyped-call]
239239
),
240240
# Long options standalone
241241
(r"--[a-zA-Z0-9][-a-zA-Z0-9]*", Name.Tag),
242242
# Short options with value
243243
(
244-
r"(-[a-zA-Z0-9])(\s+)([A-Z][A-Z0-9_]*|[a-z][-a-z0-9]*)",
244+
r"(-[a-zA-Z0-9])(\s+)([A-Z][A-Z0-9_]*|[a-z][-a-z0-9_]*)",
245245
bygroups(Name.Attribute, Whitespace, Name.Variable), # type: ignore[no-untyped-call]
246246
),
247247
# Short options standalone
@@ -259,7 +259,7 @@ class ArgparseHelpLexer(RegexLexer):
259259
# UPPERCASE metavars
260260
(r"\b[A-Z][A-Z0-9_]*\b", Name.Variable),
261261
# Subcommand/positional names (Name.Function for distinct styling)
262-
(r"\b[a-z][-a-z0-9]*\b", Name.Function),
262+
(r"\b[a-z][-a-z0-9_]*\b", Name.Function),
263263
# Other text
264264
(r"[^\s\[\]|(){},\n]+", Text),
265265
],

docs/_ext/sphinx_argparse_neo/nodes.py

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -518,30 +518,46 @@ def depart_argparse_argument_html(
518518
node : argparse_argument
519519
The argument node being departed.
520520
"""
521-
# Add metadata (default, choices, type)
522-
metadata: list[str] = []
523-
521+
# Build metadata as definition list items
524522
default = node.get("default_string")
525-
if default is not None:
526-
# Wrap default value in nv span for yellow/italic styling
527-
metadata.append(f'Default: <span class="nv">{self.encode(default)}</span>')
528-
529523
choices = node.get("choices")
530-
if choices:
531-
choices_str = ", ".join(str(c) for c in choices)
532-
metadata.append(f"Choices: {self.encode(choices_str)}")
533-
534524
type_name = node.get("type_name")
535-
if type_name:
536-
metadata.append(f"Type: {self.encode(type_name)}")
537-
538525
required = node.get("required", False)
539-
if required:
540-
metadata.append("Required")
541526

542-
if metadata:
543-
meta_str = " | ".join(metadata)
544-
self.body.append(f'<p class="argparse-argument-meta">{meta_str}</p>')
527+
if default is not None or choices or type_name or required:
528+
self.body.append('<dl class="argparse-argument-meta">\n')
529+
530+
if default is not None:
531+
self.body.append('<div class="argparse-meta-item">')
532+
self.body.append('<dt class="argparse-meta-key">Default</dt>')
533+
self.body.append(
534+
f'<dd class="argparse-meta-value">'
535+
f'<span class="nv">{self.encode(default)}</span></dd>'
536+
)
537+
self.body.append("</div>\n")
538+
539+
if type_name:
540+
self.body.append('<div class="argparse-meta-item">')
541+
self.body.append('<dt class="argparse-meta-key">Type</dt>')
542+
self.body.append(
543+
f'<dd class="argparse-meta-value">'
544+
f'<span class="nv">{self.encode(type_name)}</span></dd>'
545+
)
546+
self.body.append("</div>\n")
547+
548+
if choices:
549+
choices_str = ", ".join(str(c) for c in choices)
550+
self.body.append('<div class="argparse-meta-item">')
551+
self.body.append('<dt class="argparse-meta-key">Choices</dt>')
552+
self.body.append(
553+
f'<dd class="argparse-meta-value">{self.encode(choices_str)}</dd>'
554+
)
555+
self.body.append("</div>\n")
556+
557+
if required:
558+
self.body.append('<dt class="argparse-meta-tag">Required</dt>\n')
559+
560+
self.body.append("</dl>\n")
545561

546562
self.body.append("</dd>\n")
547563
# Close wrapper div

docs/_static/css/argparse-highlight.css

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@
2222
========================================================================== */
2323

2424
/*
25-
* Shared monospace font for all CLI inline roles
25+
* Shared monospace font and code font-size for all CLI inline roles
2626
*/
2727
.cli-option,
2828
.cli-metavar,
2929
.cli-command,
3030
.cli-default,
3131
.cli-choice {
3232
font-family: var(--font-stack--monospace);
33+
font-size: var(--code-font-size);
3334
}
3435

3536
/*
@@ -191,6 +192,7 @@
191192
/* Usage block container - match Pygments monokai background and code block styling */
192193
pre.argparse-usage {
193194
background: var(--argparse-code-background);
195+
font-size: var(--code-font-size);
194196
padding: 0.625rem 0.875rem;
195197
line-height: 1.5;
196198
border-radius: 0.2rem;
@@ -289,6 +291,7 @@ pre.argparse-usage {
289291
border-radius: 0.2rem;
290292
padding: 0.485rem 0.875rem;
291293
font-family: var(--font-stack--monospace);
294+
font-size: var(--code-font-size);
292295
width: fit-content;
293296
position: relative;
294297
}
@@ -348,18 +351,65 @@ body:not([data-theme="dark"]) .argparse-argument-name .headerlink {
348351
}
349352

350353
/*
351-
* Default value styling in metadata
352-
* Styled like inline code with monokai background.
354+
* Argument metadata definition list
355+
*
356+
* Renders metadata (Default, Type, Choices, Required) as a horizontal
357+
* flexbox of key-value pairs and standalone tags.
353358
*/
354-
.argparse-argument-meta .nv {
359+
.argparse-argument-meta {
360+
margin: 0.5rem 0 0 0;
361+
padding: 0;
362+
display: flex;
363+
flex-wrap: wrap;
364+
gap: 0.5rem 1rem;
365+
align-items: center;
366+
}
367+
368+
.argparse-meta-item {
369+
display: flex;
370+
align-items: center;
371+
gap: 0.25rem;
372+
}
373+
374+
.argparse-meta-key {
375+
color: var(--color-foreground-secondary, #6c757d);
376+
font-size: var(--code-font-size);
377+
}
378+
379+
.argparse-meta-key::after {
380+
content: ":";
381+
}
382+
383+
.argparse-meta-value .nv {
355384
background: var(--argparse-code-background);
356385
border-radius: 0.2rem;
357-
padding: 0.1405rem 0.3rem;
386+
padding: 0.1rem 0.3rem;
358387
font-family: var(--font-stack--monospace);
359-
font-size: var(--font-size--small);
388+
font-size: var(--code-font-size);
360389
color: #e5c07b;
361390
}
362391

392+
/*
393+
* Meta tag (e.g., "Required") - follows Furo's guilabel pattern
394+
* Uses semi-transparent amber background with border for visibility
395+
* without the harshness of solid fills. Amber conveys "needs attention".
396+
*/
397+
.argparse-meta-tag {
398+
background-color: #fef3c780;
399+
border: 1px solid #fcd34d80;
400+
color: var(--color-foreground-primary);
401+
font-size: var(--code-font-size);
402+
padding: 0.1rem 0.4rem;
403+
border-radius: 0.2rem;
404+
font-weight: 500;
405+
}
406+
407+
/* Dark mode: darker amber with adjusted border */
408+
body[data-theme="dark"] .argparse-meta-tag {
409+
background-color: #78350f60;
410+
border-color: #b4530980;
411+
}
412+
363413
/*
364414
* Help text description
365415
* Adds spacing above for visual separation from argument name.

tests/docs/_ext/conftest.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
"""Fixtures and configuration for docs extension tests."""
2+
3+
from __future__ import annotations
4+
5+
import pathlib
6+
import sys
7+
8+
# Add docs/_ext to path so we can import the extension module
9+
docs_ext_path = pathlib.Path(__file__).parent.parent.parent.parent / "docs" / "_ext"
10+
if str(docs_ext_path) not in sys.path:
11+
sys.path.insert(0, str(docs_ext_path))

tests/docs/_ext/sphinx_argparse_neo/test_nodes.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,9 @@ class ArgumentHTMLCase(t.NamedTuple):
332332
r'<span class="na">-L</span>',
333333
r'<span class="nv">socket-name</span>',
334334
r'<a class="headerlink" href="#shell-L">¶</a>',
335-
r'Default: <span class="nv">None</span>',
335+
r'<dl class="argparse-argument-meta">',
336+
r'<dt class="argparse-meta-key">Default</dt>',
337+
r'<dd class="argparse-meta-value"><span class="nv">None</span></dd>',
336338
r"</div>",
337339
],
338340
),
@@ -492,7 +494,8 @@ def test_default_value_styled() -> None:
492494
id_prefix="",
493495
)
494496

495-
assert 'Default: <span class="nv">json</span>' in html
497+
assert '<dt class="argparse-meta-key">Default</dt>' in html
498+
assert '<dd class="argparse-meta-value"><span class="nv">json</span></dd>' in html
496499

497500

498501
def test_wrapper_div_closed() -> None:

0 commit comments

Comments
 (0)