mirror of
https://github.com/YosysHQ/yosys
synced 2025-07-27 14:37:55 +00:00
Revert "Add groups to command reference"
This commit is contained in:
parent
2223d7848b
commit
81f87ce6ed
124 changed files with 474 additions and 2035 deletions
|
@ -1,443 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
import json
|
||||
from pathlib import Path, PosixPath, WindowsPath
|
||||
import re
|
||||
|
||||
from typing import Any
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.ext import autodoc
|
||||
from sphinx.ext.autodoc import Documenter
|
||||
from sphinx.util import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# cmd signature
|
||||
cmd_ext_sig_re = re.compile(
|
||||
r'''^ ([\w/]+::)? # optional group
|
||||
([\w$._]+?) # module name
|
||||
(?:\.([\w_]+))? # optional: thing name
|
||||
(::[\w_]+)? # attribute
|
||||
\s* $ # and nothing more
|
||||
''', re.VERBOSE)
|
||||
|
||||
class YosysCmdContentListing:
|
||||
type: str
|
||||
body: str
|
||||
source_file: str
|
||||
source_line: int
|
||||
options: dict[str, str]
|
||||
content: list[YosysCmdContentListing]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
type: str = "",
|
||||
body: str = "",
|
||||
source_file: str = "unknown",
|
||||
source_line: int = 0,
|
||||
options: dict[str, str] = {},
|
||||
content: list[dict[str]] = [],
|
||||
):
|
||||
self.type = type
|
||||
self.body = body
|
||||
self.source_file = source_file
|
||||
self.source_line = source_line
|
||||
self.options = options
|
||||
self.content = [YosysCmdContentListing(**c) for c in content]
|
||||
|
||||
class YosysCmd:
|
||||
name: str
|
||||
title: str
|
||||
content: list[YosysCmdContentListing]
|
||||
group: str
|
||||
source_file: str
|
||||
source_line: int
|
||||
source_func: str
|
||||
experimental_flag: bool
|
||||
internal_flag: bool
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name:str = "", title:str = "",
|
||||
content: list[dict[str]] = [],
|
||||
group: str = 'unknown',
|
||||
source_file: str = "",
|
||||
source_line: int = 0,
|
||||
source_func: str = "",
|
||||
experimental_flag: bool = False,
|
||||
internal_flag: bool = False,
|
||||
) -> None:
|
||||
self.name = name
|
||||
self.title = title
|
||||
self.content = [YosysCmdContentListing(**c) for c in content]
|
||||
self.group = group
|
||||
self.source_file = source_file
|
||||
self.source_line = source_line
|
||||
self.source_func = source_func
|
||||
self.experimental_flag = experimental_flag
|
||||
self.internal_flag = internal_flag
|
||||
|
||||
class YosysCmdGroupDocumenter(Documenter):
|
||||
objtype = 'cmdgroup'
|
||||
priority = 10
|
||||
object: tuple[str, list[str]]
|
||||
lib_key = 'groups'
|
||||
|
||||
option_spec = Documenter.option_spec.copy()
|
||||
option_spec.update({
|
||||
'caption': autodoc.annotation_option,
|
||||
'members': autodoc.members_option,
|
||||
'source': autodoc.bool_option,
|
||||
'linenos': autodoc.bool_option,
|
||||
})
|
||||
|
||||
__cmd_lib: dict[str, list[str] | dict[str]] | None = None
|
||||
@property
|
||||
def cmd_lib(self) -> dict[str, list[str] | dict[str]]:
|
||||
if not self.__cmd_lib:
|
||||
self.__cmd_lib = {}
|
||||
cmds_obj: dict[str, dict[str, dict[str]]]
|
||||
try:
|
||||
with open(self.config.cmds_json, "r") as f:
|
||||
cmds_obj = json.loads(f.read())
|
||||
except FileNotFoundError:
|
||||
logger.warning(
|
||||
f"unable to find cmd lib at {self.config.cmds_json}",
|
||||
type = 'cmdref',
|
||||
subtype = 'cmd_lib'
|
||||
)
|
||||
cmds_obj = {}
|
||||
for (name, obj) in cmds_obj.get(self.lib_key, {}).items():
|
||||
self.__cmd_lib[name] = obj
|
||||
return self.__cmd_lib
|
||||
|
||||
@classmethod
|
||||
def can_document_member(
|
||||
cls,
|
||||
member: Any,
|
||||
membername: str,
|
||||
isattr: bool,
|
||||
parent: Any
|
||||
) -> bool:
|
||||
return False
|
||||
|
||||
def parse_name(self) -> bool:
|
||||
if not self.options.caption:
|
||||
self.content_indent = ''
|
||||
self.fullname = self.modname = self.name
|
||||
return True
|
||||
|
||||
def import_object(self, raiseerror: bool = False) -> bool:
|
||||
# get cmd
|
||||
try:
|
||||
self.object = (self.modname, self.cmd_lib[self.modname])
|
||||
except KeyError:
|
||||
if raiseerror:
|
||||
raise
|
||||
return False
|
||||
|
||||
self.real_modname = self.modname
|
||||
return True
|
||||
|
||||
def get_sourcename(self) -> str:
|
||||
return self.env.doc2path(self.env.docname)
|
||||
|
||||
def format_name(self) -> str:
|
||||
return self.options.caption or ''
|
||||
|
||||
def format_signature(self, **kwargs: Any) -> str:
|
||||
return self.modname
|
||||
|
||||
def add_directive_header(self, sig: str) -> None:
|
||||
pass
|
||||
|
||||
def add_content(self, more_content: Any | None) -> None:
|
||||
pass
|
||||
|
||||
def filter_members(
|
||||
self,
|
||||
members: list[tuple[str, Any]],
|
||||
want_all: bool
|
||||
) -> list[tuple[str, Any, bool]]:
|
||||
return [(x[0], x[1], False) for x in members]
|
||||
|
||||
def get_object_members(
|
||||
self,
|
||||
want_all: bool
|
||||
) -> tuple[bool, list[tuple[str, Any]]]:
|
||||
ret: list[tuple[str, str]] = []
|
||||
|
||||
if want_all:
|
||||
for member in self.object[1]:
|
||||
ret.append((member, self.modname))
|
||||
else:
|
||||
memberlist = self.options.members or []
|
||||
for name in memberlist:
|
||||
if name in self.object:
|
||||
ret.append((name, self.modname))
|
||||
else:
|
||||
logger.warning(('unknown module mentioned in :members: option: '
|
||||
f'group {self.modname}, module {name}'),
|
||||
type='cmdref')
|
||||
|
||||
return False, ret
|
||||
|
||||
def document_members(self, all_members: bool = False) -> None:
|
||||
want_all = (all_members or
|
||||
self.options.inherited_members or
|
||||
self.options.members is autodoc.ALL)
|
||||
# find out which members are documentable
|
||||
members_check_module, members = self.get_object_members(want_all)
|
||||
|
||||
# document non-skipped members
|
||||
memberdocumenters: list[tuple[Documenter, bool]] = []
|
||||
for (mname, member, isattr) in self.filter_members(members, want_all):
|
||||
classes = [cls for cls in self.documenters.values()
|
||||
if cls.can_document_member(member, mname, isattr, self)]
|
||||
if not classes:
|
||||
# don't know how to document this member
|
||||
continue
|
||||
# prefer the documenter with the highest priority
|
||||
classes.sort(key=lambda cls: cls.priority)
|
||||
# give explicitly separated module name, so that members
|
||||
# of inner classes can be documented
|
||||
full_mname = self.format_signature() + '::' + mname
|
||||
documenter = classes[-1](self.directive, full_mname, self.indent)
|
||||
memberdocumenters.append((documenter, isattr))
|
||||
|
||||
member_order = self.options.member_order or self.config.autodoc_member_order
|
||||
memberdocumenters = self.sort_members(memberdocumenters, member_order)
|
||||
|
||||
for documenter, isattr in memberdocumenters:
|
||||
documenter.generate(
|
||||
all_members=True, real_modname=self.real_modname,
|
||||
check_module=members_check_module and not isattr)
|
||||
|
||||
def generate(
|
||||
self,
|
||||
more_content: Any | None = None,
|
||||
real_modname: str | None = None,
|
||||
check_module: bool = False,
|
||||
all_members: bool = False
|
||||
) -> None:
|
||||
if not self.parse_name():
|
||||
# need a cmd lib to import from
|
||||
logger.warning(
|
||||
f"don't know which cmd lib to import for autodocumenting {self.name}",
|
||||
type = 'cmdref'
|
||||
)
|
||||
return
|
||||
|
||||
sourcename = self.get_sourcename()
|
||||
|
||||
imported_object = self.import_object();
|
||||
if self.lib_key == 'groups' and self.name == 'unknown':
|
||||
if imported_object:
|
||||
logger.warning(f"Found commands assigned to group {self.name}: {[x[0] for x in self.object]}", type='cmdref')
|
||||
else:
|
||||
return
|
||||
elif not imported_object:
|
||||
log_msg = f"unable to load {self.name} with {type(self)}"
|
||||
if self.lib_key == 'groups':
|
||||
logger.info(log_msg, type = 'cmdref')
|
||||
self.add_line(f'.. warning:: No commands found for group {self.name!r}', sourcename)
|
||||
self.add_line('', sourcename)
|
||||
self.add_line(' Documentation may have been built without ``source_location`` support.', sourcename)
|
||||
self.add_line(' Try check :doc:`/cmd/index_other`.', sourcename)
|
||||
else:
|
||||
logger.warning(log_msg, type = 'cmdref')
|
||||
return
|
||||
|
||||
# check __module__ of object (for members not given explicitly)
|
||||
# if check_module:
|
||||
# if not self.check_module():
|
||||
# return
|
||||
|
||||
self.add_line('', sourcename)
|
||||
|
||||
# format the object's signature, if any
|
||||
try:
|
||||
sig = self.format_signature()
|
||||
except Exception as exc:
|
||||
logger.warning(('error while formatting signature for %s: %s'),
|
||||
self.fullname, exc, type='cmdref')
|
||||
return
|
||||
|
||||
# generate the directive header and options, if applicable
|
||||
self.add_directive_header(sig)
|
||||
self.add_line('', sourcename)
|
||||
|
||||
# e.g. the module directive doesn't have content
|
||||
self.indent += self.content_indent
|
||||
|
||||
# add all content (from docstrings, attribute docs etc.)
|
||||
self.add_content(more_content)
|
||||
|
||||
# document members, if possible
|
||||
self.document_members(all_members)
|
||||
|
||||
class YosysCmdDocumenter(YosysCmdGroupDocumenter):
|
||||
objtype = 'cmd'
|
||||
priority = 15
|
||||
object: YosysCmd
|
||||
lib_key = 'cmds'
|
||||
|
||||
@classmethod
|
||||
def can_document_member(
|
||||
cls,
|
||||
member: Any,
|
||||
membername: str,
|
||||
isattr: bool,
|
||||
parent: Any
|
||||
) -> bool:
|
||||
if membername.startswith('$'):
|
||||
return False
|
||||
return isinstance(parent, YosysCmdGroupDocumenter)
|
||||
|
||||
def parse_name(self) -> bool:
|
||||
try:
|
||||
matched = cmd_ext_sig_re.match(self.name)
|
||||
group, modname, thing, attribute = matched.groups()
|
||||
except AttributeError:
|
||||
logger.warning(('invalid signature for auto%s (%r)') % (self.objtype, self.name),
|
||||
type='cmdref')
|
||||
return False
|
||||
|
||||
self.modname = modname
|
||||
self.groupname = group or ''
|
||||
self.attribute = attribute or ''
|
||||
self.fullname = ((self.modname) + (thing or ''))
|
||||
|
||||
return True
|
||||
|
||||
def import_object(self, raiseerror: bool = False) -> bool:
|
||||
if super().import_object(raiseerror):
|
||||
self.object = YosysCmd(self.modname, **self.object[1])
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_sourcename(self) -> str:
|
||||
try:
|
||||
return self.object.source_file
|
||||
except AttributeError:
|
||||
return super().get_sourcename()
|
||||
|
||||
def format_name(self) -> str:
|
||||
return self.object.name
|
||||
|
||||
def format_signature(self, **kwargs: Any) -> str:
|
||||
return self.fullname + self.attribute
|
||||
|
||||
def add_directive_header(self, sig: str) -> None:
|
||||
domain = getattr(self, 'domain', self.objtype)
|
||||
directive = getattr(self, 'directivetype', 'def')
|
||||
source_name = self.object.source_file
|
||||
source_line = self.object.source_line
|
||||
|
||||
title = f'{self.object.name} - {self.object.title}'
|
||||
self.add_line(title, source_name, source_line)
|
||||
self.add_line('#' * len(title), source_name, source_line)
|
||||
|
||||
# cmd definition
|
||||
self.add_line(f'.. {domain}:{directive}:: {sig}', source_name, source_line)
|
||||
if self.object.title:
|
||||
self.add_line(f' :title: {self.object.title}', source_name, source_line)
|
||||
|
||||
if self.options.noindex:
|
||||
self.add_line(' :noindex:', source_name)
|
||||
|
||||
def add_content(self, more_content: Any | None) -> None:
|
||||
# set sourcename and add content from attribute documentation
|
||||
domain = getattr(self, 'domain', self.objtype)
|
||||
source_name = self.object.source_file
|
||||
source_line = self.object.source_line
|
||||
|
||||
if self.object.experimental_flag:
|
||||
self.add_line(f'.. warning:: This command is experimental', source_name, source_line)
|
||||
self.add_line('\n', source_name)
|
||||
|
||||
if self.object.internal_flag:
|
||||
self.add_line(f'.. warning:: This command is intended for internal developer use only', source_name, source_line)
|
||||
self.add_line('\n', source_name)
|
||||
|
||||
def render(content_list: YosysCmdContentListing, indent: int=0):
|
||||
content_source = content_list.source_file or source_name
|
||||
indent_str = ' '*indent
|
||||
if content_list.type == 'usage':
|
||||
if content_list.body:
|
||||
self.add_line(f'{indent_str}.. {domain}:{content_list.type}:: {self.name}::{content_list.body}', content_source)
|
||||
else:
|
||||
self.add_line(f'{indent_str}.. {domain}:{content_list.type}:: {self.name}::', content_source)
|
||||
self.add_line(f'{indent_str} :noindex:', source_name)
|
||||
self.add_line('', source_name)
|
||||
elif content_list.type == 'option':
|
||||
self.add_line(f'{indent_str}:{content_list.type} {content_list.body}:', content_source)
|
||||
elif content_list.type == 'text':
|
||||
self.add_line(f'{indent_str}{content_list.body}', content_source)
|
||||
self.add_line('', source_name)
|
||||
elif content_list.type == 'code':
|
||||
language_str = content_list.options.get('language', '')
|
||||
self.add_line(f'{indent_str}.. code-block:: {language_str}', source_name)
|
||||
self.add_line('', source_name)
|
||||
for body_line in content_list.body.splitlines():
|
||||
self.add_line(f'{indent_str} {body_line}', content_source)
|
||||
self.add_line('', source_name)
|
||||
else:
|
||||
logger.warning(f"unknown content type '{content_list.type}'")
|
||||
for content in content_list.content:
|
||||
render(content, indent+1)
|
||||
|
||||
for content in self.object.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_line}`', source_name)
|
||||
|
||||
# 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 get_object_members(
|
||||
self,
|
||||
want_all: bool
|
||||
) -> tuple[bool, list[tuple[str, Any]]]:
|
||||
|
||||
return False, []
|
||||
|
||||
class YosysCmdRstDocumenter(YosysCmdDocumenter):
|
||||
objtype = 'cmd_rst'
|
||||
priority = 0
|
||||
|
||||
@classmethod
|
||||
def can_document_member(cls, *args) -> bool:
|
||||
return False
|
||||
|
||||
def add_directive_header(self, sig):
|
||||
source_name = self.object.source_file
|
||||
cmd = self.object.name
|
||||
self.add_line(f'.. code-block:: rst', source_name)
|
||||
self.add_line(f' :caption: Generated rst for ``.. autocmd:: {cmd}``', source_name)
|
||||
|
||||
def add_content(self, more_content):
|
||||
source_name = self.object.source_file
|
||||
cmd = self.object.name
|
||||
self.domain = 'cmd'
|
||||
super().add_directive_header(cmd)
|
||||
self.add_line('', source_name)
|
||||
self.indent += self.content_indent
|
||||
super().add_content(more_content)
|
||||
|
||||
def setup(app: Sphinx) -> dict[str, Any]:
|
||||
app.add_config_value('cmds_json', False, 'html', [Path, PosixPath, WindowsPath])
|
||||
app.setup_extension('sphinx.ext.autodoc')
|
||||
app.add_autodocumenter(YosysCmdGroupDocumenter)
|
||||
app.add_autodocumenter(YosysCmdDocumenter)
|
||||
app.add_autodocumenter(YosysCmdRstDocumenter)
|
||||
return {
|
||||
'version': '2',
|
||||
'parallel_read_safe': True,
|
||||
}
|
|
@ -4,21 +4,20 @@ from __future__ import annotations
|
|||
|
||||
import re
|
||||
from typing import cast
|
||||
import warnings
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Node, Element, Text
|
||||
from docutils.nodes import Node, Element, system_message
|
||||
from docutils.parsers.rst import directives
|
||||
from docutils.parsers.rst.states import Inliner
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.domains import Domain, Index
|
||||
from sphinx.domains.std import StandardDomain
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.roles import XRefRole, SphinxRole
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.directives import ObjectDescription
|
||||
from sphinx.directives.code import container_wrapper
|
||||
from sphinx.util.nodes import make_refnode
|
||||
from sphinx.util.docfields import Field, GroupedField
|
||||
from sphinx.util.docfields import Field
|
||||
from sphinx import addnodes
|
||||
|
||||
class TocNode(ObjectDescription):
|
||||
|
@ -32,7 +31,7 @@ class TocNode(ObjectDescription):
|
|||
signode['ids'].append(idx)
|
||||
|
||||
def _object_hierarchy_parts(self, sig_node: addnodes.desc_signature) -> tuple[str, ...]:
|
||||
if 'tocname' not in sig_node:
|
||||
if 'fullname' not in sig_node:
|
||||
return ()
|
||||
|
||||
modname = sig_node.get('module')
|
||||
|
@ -58,56 +57,16 @@ class TocNode(ObjectDescription):
|
|||
return '.'.join(parents + [name])
|
||||
return ''
|
||||
|
||||
class NodeWithOptions(TocNode):
|
||||
"""A custom node with options."""
|
||||
|
||||
doc_field_types = [
|
||||
GroupedField('opts', label='Options', names=('option', 'options', 'opt', 'opts')),
|
||||
]
|
||||
|
||||
def transform_content(self, contentnode: addnodes.desc_content) -> None:
|
||||
"""hack `:option -thing: desc` into a proper option list with yoscrypt highlighting"""
|
||||
newchildren = []
|
||||
for node in contentnode:
|
||||
newnode = node
|
||||
if isinstance(node, nodes.field_list):
|
||||
newnode = nodes.option_list()
|
||||
for field in node:
|
||||
is_option = False
|
||||
option_list_item = nodes.option_list_item()
|
||||
for child in field:
|
||||
if isinstance(child, nodes.field_name):
|
||||
option_group = nodes.option_group()
|
||||
option_list_item += option_group
|
||||
option = nodes.option()
|
||||
option_group += option
|
||||
name, text = child.rawsource.split(' ', 1)
|
||||
is_option = name == 'option'
|
||||
literal = nodes.literal(text=text)
|
||||
literal['classes'] += ['code', 'highlight', 'yoscrypt']
|
||||
literal['language'] = 'yoscrypt'
|
||||
option += literal
|
||||
if not is_option: warnings.warn(f'unexpected option \'{name}\' in {field.source}')
|
||||
elif isinstance(child, nodes.field_body):
|
||||
description = nodes.description()
|
||||
description += child.children
|
||||
option_list_item += description
|
||||
if is_option:
|
||||
newnode += option_list_item
|
||||
newchildren.append(newnode)
|
||||
contentnode.children = newchildren
|
||||
|
||||
class CommandNode(NodeWithOptions):
|
||||
class CommandNode(TocNode):
|
||||
"""A custom node that describes a command."""
|
||||
|
||||
name = 'cmd'
|
||||
required_arguments = 1
|
||||
|
||||
option_spec = NodeWithOptions.option_spec.copy()
|
||||
option_spec.update({
|
||||
option_spec = {
|
||||
'title': directives.unchanged,
|
||||
'tags': directives.unchanged
|
||||
})
|
||||
}
|
||||
|
||||
def handle_signature(self, sig, signode: addnodes.desc_signature):
|
||||
signode['fullname'] = sig
|
||||
|
@ -134,46 +93,6 @@ class CommandNode(NodeWithOptions):
|
|||
idx,
|
||||
0))
|
||||
|
||||
class CommandUsageNode(NodeWithOptions):
|
||||
"""A custom node that describes command usages"""
|
||||
|
||||
name = 'cmdusage'
|
||||
|
||||
option_spec = NodeWithOptions.option_spec
|
||||
option_spec.update({
|
||||
'usage': directives.unchanged,
|
||||
})
|
||||
|
||||
def handle_signature(self, sig: str, signode: addnodes.desc_signature):
|
||||
parts = sig.split('::')
|
||||
if len(parts) > 2: parts.pop(0)
|
||||
use = parts[-1]
|
||||
signode['fullname'] = '::'.join(parts)
|
||||
usage = self.options.get('usage', use)
|
||||
if usage:
|
||||
signode['tocname'] = usage
|
||||
signode += addnodes.desc_name(text=usage)
|
||||
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))
|
||||
|
||||
class PropNode(TocNode):
|
||||
name = 'prop'
|
||||
fieldname = 'props'
|
||||
|
@ -474,7 +393,7 @@ class TagIndex(Index):
|
|||
lis.append((
|
||||
dispname, 0, docname,
|
||||
anchor,
|
||||
'', '', ''
|
||||
docname, '', typ
|
||||
))
|
||||
ret = [(k, v) for k, v in sorted(content.items())]
|
||||
|
||||
|
@ -513,19 +432,18 @@ class CommandIndex(Index):
|
|||
Qualifier and description are not rendered e.g. in LaTeX output.
|
||||
"""
|
||||
|
||||
content: dict[str, list[tuple]] = {}
|
||||
content = {}
|
||||
items = ((name, dispname, typ, docname, anchor)
|
||||
for name, dispname, typ, docname, anchor, prio
|
||||
in self.domain.get_objects()
|
||||
if typ == self.name)
|
||||
items = sorted(items, key=lambda item: item[0])
|
||||
for name, dispname, typ, docname, anchor in items:
|
||||
title = self.domain.data['obj2title'].get(name)
|
||||
lis = content.setdefault(self.shortname, [])
|
||||
lis.append((
|
||||
dispname, 0, docname,
|
||||
anchor,
|
||||
'', '', title
|
||||
'', '', typ
|
||||
))
|
||||
ret = [(k, v) for k, v in sorted(content.items())]
|
||||
|
||||
|
@ -589,27 +507,16 @@ class PropIndex(TagIndex):
|
|||
|
||||
return (ret, True)
|
||||
|
||||
class TitleRefRole(XRefRole):
|
||||
"""XRefRole used which has the cmd title as the displayed text."""
|
||||
pass
|
||||
|
||||
class OptionRole(SphinxRole):
|
||||
def run(self) -> tuple[list[Node], list]:
|
||||
return self.inliner.interpreted(self.rawtext, self.text, 'yoscrypt', self.lineno)
|
||||
|
||||
class CommandDomain(Domain):
|
||||
name = 'cmd'
|
||||
label = 'Yosys commands'
|
||||
|
||||
roles = {
|
||||
'ref': XRefRole(),
|
||||
'title': TitleRefRole(),
|
||||
'option': OptionRole(),
|
||||
'ref': XRefRole()
|
||||
}
|
||||
|
||||
directives = {
|
||||
'def': CommandNode,
|
||||
'usage': CommandUsageNode,
|
||||
}
|
||||
|
||||
indices = {
|
||||
|
@ -635,7 +542,7 @@ class CommandDomain(Domain):
|
|||
|
||||
def resolve_xref(self, env, fromdocname, builder, typ,
|
||||
target, node, contnode):
|
||||
|
||||
|
||||
match = [(docname, anchor, name)
|
||||
for name, sig, typ, docname, anchor, prio
|
||||
in self.get_objects() if sig == target]
|
||||
|
@ -645,17 +552,9 @@ class CommandDomain(Domain):
|
|||
targ = match[0][1]
|
||||
qual_name = match[0][2]
|
||||
title = self.data['obj2title'].get(qual_name, targ)
|
||||
|
||||
if typ == 'title':
|
||||
# caller wants the title in the content of the node
|
||||
cmd = contnode.astext()
|
||||
contnode = Text(f'{cmd} - {title}')
|
||||
return make_refnode(builder, fromdocname, todocname,
|
||||
targ, contnode)
|
||||
else:
|
||||
# cmd title as hover text
|
||||
return make_refnode(builder, fromdocname, todocname,
|
||||
targ, contnode, title)
|
||||
|
||||
return make_refnode(builder,fromdocname,todocname,
|
||||
targ, contnode, title)
|
||||
else:
|
||||
print(f"Missing ref for {target} in {fromdocname} ")
|
||||
return None
|
||||
|
@ -693,18 +592,10 @@ class CellDomain(CommandDomain):
|
|||
|
||||
def autoref(name, rawtext: str, text: str, lineno, inliner: Inliner,
|
||||
options=None, content=None):
|
||||
words = text.split(' ')
|
||||
if len(words) == 2 and words[0] == "help":
|
||||
IsLinkable = True
|
||||
thing = words[1]
|
||||
else:
|
||||
IsLinkable = len(words) == 1 and words[0][0] != '-'
|
||||
thing = words[0]
|
||||
if IsLinkable:
|
||||
role = 'cell:ref' if thing[0] == '$' else 'cmd:ref'
|
||||
text = f'{text} <{thing}>'
|
||||
else:
|
||||
role = 'yoscrypt'
|
||||
role = 'cell:ref' if text[0] == '$' else 'cmd:ref'
|
||||
if text.startswith("help ") and text.count(' ') == 1:
|
||||
_, cmd = text.split(' ', 1)
|
||||
text = f'{text} <{cmd}>'
|
||||
return inliner.interpreted(rawtext, text, role, lineno)
|
||||
|
||||
def setup(app: Sphinx):
|
||||
|
@ -731,7 +622,4 @@ def setup(app: Sphinx):
|
|||
|
||||
app.add_role('autoref', autoref)
|
||||
|
||||
return {
|
||||
'version': '0.3',
|
||||
'parallel_read_safe': False,
|
||||
}
|
||||
return {'version': '0.2'}
|
Loading…
Add table
Add a link
Reference in a new issue