@@ -115,6 +115,37 @@ def __init__(
115115 self .config = config or RenderConfig ()
116116 self .state = state
117117
118+ @staticmethod
119+ def _extract_id_prefix (prog : str ) -> str :
120+ """Extract subcommand from prog for unique section IDs.
121+
122+ Parameters
123+ ----------
124+ prog : str
125+ The program name, potentially with subcommand (e.g., "tmuxp load").
126+
127+ Returns
128+ -------
129+ str
130+ The subcommand part for use as ID prefix, or empty string if none.
131+
132+ Examples
133+ --------
134+ >>> ArgparseRenderer._extract_id_prefix("tmuxp load")
135+ 'load'
136+ >>> ArgparseRenderer._extract_id_prefix("tmuxp")
137+ ''
138+ >>> ArgparseRenderer._extract_id_prefix("vcspull sync")
139+ 'sync'
140+ >>> ArgparseRenderer._extract_id_prefix("myapp sub cmd")
141+ 'sub-cmd'
142+ """
143+ parts = prog .split ()
144+ if len (parts ) <= 1 :
145+ return ""
146+ # Join remaining parts with hyphen for multi-level subcommands
147+ return "-" .join (parts [1 :])
148+
118149 def render (self , parser_info : ParserInfo ) -> list [nodes .Node ]:
119150 """Render a complete parser to docutils nodes.
120151
@@ -159,13 +190,17 @@ def render(self, parser_info: ParserInfo) -> list[nodes.Node]:
159190
160191 result .append (program_node )
161192
193+ # Extract ID prefix from prog for unique section IDs
194+ # e.g., "tmuxp load" -> "load", "myapp" -> ""
195+ id_prefix = self ._extract_id_prefix (parser_info .prog )
196+
162197 # Add Usage section as sibling (for TOC visibility)
163- usage_section = self .render_usage_section (parser_info )
198+ usage_section = self .render_usage_section (parser_info , id_prefix = id_prefix )
164199 result .append (usage_section )
165200
166201 # Add argument groups as sibling sections (for TOC visibility)
167202 for group in parser_info .argument_groups :
168- group_section = self .render_group_section (group )
203+ group_section = self .render_group_section (group , id_prefix = id_prefix )
169204 result .append (group_section )
170205
171206 # Add subcommands
@@ -197,7 +232,9 @@ def render_usage(self, parser_info: ParserInfo) -> argparse_usage:
197232 usage_node ["usage" ] = parser_info .bare_usage
198233 return usage_node
199234
200- def render_usage_section (self , parser_info : ParserInfo ) -> nodes .section :
235+ def render_usage_section (
236+ self , parser_info : ParserInfo , * , id_prefix : str = ""
237+ ) -> nodes .section :
201238 """Render usage as a section with heading for TOC visibility.
202239
203240 Creates a proper section node with "Usage" heading containing the
@@ -208,6 +245,10 @@ def render_usage_section(self, parser_info: ParserInfo) -> nodes.section:
208245 ----------
209246 parser_info : ParserInfo
210247 The parser information.
248+ id_prefix : str
249+ Optional prefix for the section ID (e.g., "load" -> "load-usage").
250+ Used to ensure unique IDs when multiple argparse directives exist
251+ on the same page.
211252
212253 Returns
213254 -------
@@ -231,11 +272,18 @@ def render_usage_section(self, parser_info: ParserInfo) -> nodes.section:
231272 >>> section = renderer.render_usage_section(info)
232273 >>> section["ids"]
233274 ['usage']
275+
276+ With prefix for subcommand pages:
277+
278+ >>> section = renderer.render_usage_section(info, id_prefix="load")
279+ >>> section["ids"]
280+ ['load-usage']
234281 >>> section.children[0].astext()
235282 'Usage'
236283 """
284+ section_id = f"{ id_prefix } -usage" if id_prefix else "usage"
237285 section = nodes .section ()
238- section ["ids" ] = ["usage" ]
286+ section ["ids" ] = [section_id ]
239287 section ["names" ] = [nodes .fully_normalize_name ("Usage" )]
240288 section += nodes .title ("Usage" , "Usage" )
241289
@@ -245,7 +293,9 @@ def render_usage_section(self, parser_info: ParserInfo) -> nodes.section:
245293
246294 return section
247295
248- def render_group_section (self , group : ArgumentGroup ) -> nodes .section :
296+ def render_group_section (
297+ self , group : ArgumentGroup , * , id_prefix : str = ""
298+ ) -> nodes .section :
249299 """Render an argument group wrapped in a section for TOC visibility.
250300
251301 Creates a proper section node with the group title as heading,
@@ -256,6 +306,10 @@ def render_group_section(self, group: ArgumentGroup) -> nodes.section:
256306 ----------
257307 group : ArgumentGroup
258308 The argument group to render.
309+ id_prefix : str
310+ Optional prefix for the section ID (e.g., "load" -> "load-options").
311+ Used to ensure unique IDs when multiple argparse directives exist
312+ on the same page.
259313
260314 Returns
261315 -------
@@ -275,6 +329,12 @@ def render_group_section(self, group: ArgumentGroup) -> nodes.section:
275329 >>> section = renderer.render_group_section(group)
276330 >>> section["ids"]
277331 ['positional-arguments']
332+
333+ With prefix for subcommand pages:
334+
335+ >>> section = renderer.render_group_section(group, id_prefix="load")
336+ >>> section["ids"]
337+ ['load-positional-arguments']
278338 >>> section.children[0].astext()
279339 'Positional Arguments'
280340 """
@@ -285,8 +345,9 @@ def render_group_section(self, group: ArgumentGroup) -> nodes.section:
285345 if self .config .group_title_prefix :
286346 title = f"{ self .config .group_title_prefix } { title } "
287347
288- # Generate section ID from title
289- section_id = title .lower ().replace (" " , "-" )
348+ # Generate section ID from title (with optional prefix for uniqueness)
349+ base_id = title .lower ().replace (" " , "-" )
350+ section_id = f"{ id_prefix } -{ base_id } " if id_prefix else base_id
290351
291352 # Create section wrapper for TOC discovery
292353 section = nodes .section ()
0 commit comments