docs: Working cmdref groups

Also adds note on source location if available.
This commit is contained in:
Krystine Sherwin 2025-01-17 17:44:49 +13:00
parent f7b168a2a1
commit e1c7dfbacb
No known key found for this signature in database
3 changed files with 35 additions and 72 deletions

View File

@ -115,12 +115,11 @@ class CommandUsageNode(TocNode):
] ]
def handle_signature(self, sig: str, signode: addnodes.desc_signature): def handle_signature(self, sig: str, signode: addnodes.desc_signature):
try: parts = sig.split('::')
cmd, use = sig.split('::') if len(parts) > 2: parts.pop(0)
except ValueError: use = parts[-1]
cmd, use = sig, '' signode['fullname'] = '::'.join(parts)
signode['fullname'] = sig usage = self.options.get('usage', use)
usage = self.options.get('usage', use or sig)
if usage: if usage:
signode['tocname'] = usage signode['tocname'] = usage
signode += addnodes.desc_name(text=usage) signode += addnodes.desc_name(text=usage)
@ -145,47 +144,17 @@ class CommandUsageNode(TocNode):
idx, idx,
1)) 1))
class CommandOptionGroupNode(TocNode): class CommandOptionGroupNode(CommandUsageNode):
"""A custom node that describes a group of related options""" """A custom node that describes a group of related options"""
name = 'cmdoptiongroup' name = 'cmdoptiongroup'
option_spec = TocNode.option_spec option_spec = CommandUsageNode.option_spec
doc_field_types = [ doc_field_types = [
Field('opt', ('option',), label='', rolename='option') Field('opt', ('option',), label='', rolename='option')
] ]
def handle_signature(self, sig: str, signode: addnodes.desc_signature):
try:
cmd, name = sig.split('::')
except ValueError:
cmd, name = '', sig
signode['fullname'] = sig
if name:
signode['tocname'] = name
signode += addnodes.desc_name(text=name)
return signode['fullname']
def add_target_and_index(
self,
name: str,
sig: str,
signode: addnodes.desc_signature
) -> None:
idx = ".".join(name.split("::"))
signode['ids'].append(idx)
if 'noindex' not in self.options:
tocname: str = signode.get('tocname', name)
objs = self.env.domaindata[self.domain]['objects']
# (name, sig, typ, docname, anchor, prio)
objs.append((name,
tocname,
type(self).name,
self.env.docname,
idx,
1))
def transform_content(self, contentnode: addnodes.desc_content) -> None: def transform_content(self, contentnode: addnodes.desc_content) -> None:
"""hack `:option -thing: desc` into a proper option list""" """hack `:option -thing: desc` into a proper option list"""
newchildren = [] newchildren = []

View File

@ -16,7 +16,8 @@ logger = logging.getLogger(__name__)
# cmd signature # cmd signature
cmd_ext_sig_re = re.compile( cmd_ext_sig_re = re.compile(
r'''^ ([\w$._]+?) # module name r'''^ ([\w/]+::)? # optional group
([\w$._]+?) # module name
(?:\.([\w_]+))? # optional: thing name (?:\.([\w_]+))? # optional: thing name
(::[\w_]+)? # attribute (::[\w_]+)? # attribute
\s* $ # and nothing more \s* $ # and nothing more
@ -47,23 +48,22 @@ class YosysCmd:
name: str name: str
title: str title: str
content: list[YosysCmdContentListing] content: list[YosysCmdContentListing]
source_file: str
experimental_flag: bool experimental_flag: bool
def __init__( def __init__(
self, self,
name:str = "", title:str = "", name:str = "", title:str = "",
content: list[dict[str]] = [], content: list[dict[str]] = [],
source_file:str = 'unknown',
experimental_flag: bool = False experimental_flag: bool = False
) -> None: ) -> None:
self.name = name self.name = name
self.title = title self.title = title
self.content = [YosysCmdContentListing(**c) for c in content] self.content = [YosysCmdContentListing(**c) for c in content]
self.source_file = source_file
self.experimental_flag = experimental_flag self.experimental_flag = experimental_flag
@property
def source_file(self) -> str:
return ""
@property @property
def source_line(self) -> int: def source_line(self) -> int:
return 0 return 0
@ -86,7 +86,7 @@ class YosysCmdGroupDocumenter(Documenter):
def cmd_lib(self) -> dict[str, list[str] | dict[str]]: def cmd_lib(self) -> dict[str, list[str] | dict[str]]:
if not self.__cmd_lib: if not self.__cmd_lib:
self.__cmd_lib = {} self.__cmd_lib = {}
cmds_obj: dict[str, dict[str, list[str] | dict[str]]] cmds_obj: dict[str, dict[str, dict[str]]]
try: try:
with open(self.config.cmds_json, "r") as f: with open(self.config.cmds_json, "r") as f:
cmds_obj = json.loads(f.read()) cmds_obj = json.loads(f.read())
@ -96,8 +96,19 @@ class YosysCmdGroupDocumenter(Documenter):
type = 'cmdref', type = 'cmdref',
subtype = 'cmd_lib' subtype = 'cmd_lib'
) )
else: cmds_obj = {}
for (name, obj) in cmds_obj.get(self.lib_key, {}).items(): for (name, obj) in cmds_obj.get('cmds', {}).items():
if self.lib_key == 'groups':
source_file: str = obj.get('source_file', 'unknown')
if source_file == 'unknown':
source_group = 'unknown'
else:
source_group = str(Path(source_file).parent)
try:
self.__cmd_lib[source_group].append(name)
except KeyError:
self.__cmd_lib[source_group] = [name,]
else:
self.__cmd_lib[name] = obj self.__cmd_lib[name] = obj
return self.__cmd_lib return self.__cmd_lib
@ -139,25 +150,10 @@ class YosysCmdGroupDocumenter(Documenter):
return self.modname return self.modname
def add_directive_header(self, sig: str) -> None: def add_directive_header(self, sig: str) -> None:
domain = getattr(self, 'domain', 'cmd') pass
directive = getattr(self, 'directivetype', 'group')
name = self.format_name()
sourcename = self.get_sourcename()
cmd_list = self.object
# cmd definition
self.add_line(f'.. {domain}:{directive}:: {sig}', sourcename)
self.add_line(f' :caption: {name}', sourcename)
if self.options.noindex:
self.add_line(' :noindex:', sourcename)
def add_content(self, more_content: Any | None) -> None: def add_content(self, more_content: Any | None) -> None:
# groups have no native content pass
# add additional content (e.g. from document), if present
if more_content:
for line, src in zip(more_content.data, more_content.items):
self.add_line(line, src[0], src[1])
def filter_members( def filter_members(
self, self,
@ -290,13 +286,14 @@ class YosysCmdDocumenter(YosysCmdGroupDocumenter):
def parse_name(self) -> bool: def parse_name(self) -> bool:
try: try:
matched = cmd_ext_sig_re.match(self.name) matched = cmd_ext_sig_re.match(self.name)
modname, thing, attribute = matched.groups() group, modname, thing, attribute = matched.groups()
except AttributeError: except AttributeError:
logger.warning(('invalid signature for auto%s (%r)') % (self.objtype, self.name), logger.warning(('invalid signature for auto%s (%r)') % (self.objtype, self.name),
type='cmdref') type='cmdref')
return False return False
self.modname = modname self.modname = modname
self.groupname = group or ''
self.attribute = attribute or '' self.attribute = attribute or ''
self.fullname = ((self.modname) + (thing or '')) self.fullname = ((self.modname) + (thing or ''))
@ -364,19 +361,15 @@ class YosysCmdDocumenter(YosysCmdGroupDocumenter):
for content in self.object.content: for content in self.object.content:
render(content) render(content)
if self.get_sourcename() != 'unknown':
self.add_line('\n', source_name)
self.add_line(f'.. note:: Help text automatically generated from :file:`{source_name}`', source_name)
# add additional content (e.g. from document), if present # add additional content (e.g. from document), if present
if more_content: if more_content:
for line, src in zip(more_content.data, more_content.items): for line, src in zip(more_content.data, more_content.items):
self.add_line(line, src[0], src[1]) self.add_line(line, src[0], src[1])
# fields
self.add_line('\n', source_name)
field_attrs = ["properties", ]
for field in field_attrs:
attr = getattr(self.object, field, [])
for val in attr:
self.add_line(f':{field} {val}:', source_name)
def get_object_members( def get_object_members(
self, self,
want_all: bool want_all: bool

View File

@ -1045,6 +1045,7 @@ struct HelpPass : public Pass {
for (auto content : cmd_help.get_content()) for (auto content : cmd_help.get_content())
json.value(content->to_json()); json.value(content->to_json());
json.end_array(); json.end_array();
json.entry("source_file", cmd_help.source_file());
json.entry("experimental_flag", experimental_flag); json.entry("experimental_flag", experimental_flag);
json.end_object(); json.end_object();
} }