Adding custom domain for cmdref

This commit is contained in:
Krystine Sherwin 2023-08-08 11:51:57 +12:00
parent d8b8880ad6
commit 8203a01ba9
No known key found for this signature in database
6 changed files with 256 additions and 8 deletions

View File

@ -63,10 +63,13 @@ latex_elements = {
extensions.append('sphinx.ext.todo')
todo_include_todos = True
# custom cmd-ref parsing/linking
sys.path += [os.path.dirname(__file__) + "/../"]
extensions.append('util.cmdref')
def setup(sphinx):
sys.path += [os.path.dirname(__file__) + "/../util"]
from RtlilLexer import RtlilLexer
from util.RtlilLexer import RtlilLexer
sphinx.add_lexer("RTLIL", RtlilLexer)
from YoscryptLexer import YoscryptLexer
from util.YoscryptLexer import YoscryptLexer
sphinx.add_lexer("yoscrypt", YoscryptLexer)

View File

@ -13,6 +13,12 @@ Yosys Open SYnthesis Suite
appendix
Indices
-------
- :ref:`commandindex`
- :ref:`tagindex`
TODOs
-----

View File

@ -63,12 +63,12 @@ p {
color: #6ecbd7 !important;
}
.cmdref .highlight-yoscrypt .highlight pre {
.cmd.def .highlight-yoscrypt, .cmd.def .highlight pre {
padding: 0%;
margin: 0%;
}
.cmdref .highlight-none .highlight pre {
.cmd.def .highlight-none, .cmd.def .highlight pre {
padding-top: 0%;
margin-top: 0%;
}

0
docs/util/__init__.py Normal file
View File

240
docs/util/cmdref.py Normal file
View File

@ -0,0 +1,240 @@
# based on https://github.com/ofosos/sphinxrecipes/blob/master/sphinxrecipes/sphinxrecipes.py
# license:
# Copyright 2019 Mark Meyer
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import docutils
from docutils import nodes
import sphinx
from docutils.parsers import rst
from docutils.parsers.rst import directives
from sphinx.domains import Domain, Index
from sphinx.domains.std import StandardDomain
from sphinx.roles import XRefRole
from sphinx.directives import ObjectDescription
from sphinx.util.nodes import make_refnode
from sphinx import addnodes
class CommandNode(ObjectDescription):
"""A custom node that describes a command."""
required_arguments = 1
option_spec = {
'title': directives.unchanged_required,
'tags': directives.unchanged
}
def handle_signature(self, sig, signode: addnodes.desc_signature):
signode += addnodes.desc_addname(text="yosys> help ")
signode += addnodes.desc_name(text=sig)
return sig
def add_target_and_index(self, name_cls, sig, signode):
signode['ids'].append('cmd' + '-' + sig)
if 'noindex' not in self.options:
name = "{}.{}.{}".format('cmd', type(self).__name__, sig)
tmap = self.env.domaindata['cmd']['obj2tag']
tmap[name] = list(self.options.get('tags', '').split(' '))
objs = self.env.domaindata['cmd']['objects']
objs.append((name,
sig,
self.options.get('title'),
self.env.docname,
'cmd' + '-' + sig,
0))
class TagIndex(Index):
"""A custom directive that creates an tag matrix."""
name = 'tag'
localname = 'Tag Index'
shortname = 'Tag'
def __init__(self, *args, **kwargs):
super(TagIndex, self).__init__(*args, **kwargs)
def generate(self, docnames=None):
"""Return entries for the index given by *name*. If *docnames* is
given, restrict to entries referring to these docnames.
The return value is a tuple of ``(content, collapse)``, where
* collapse* is a boolean that determines if sub-entries should
start collapsed (for output formats that support collapsing
sub-entries).
*content* is a sequence of ``(letter, entries)`` tuples, where *letter*
is the "heading" for the given *entries*, usually the starting letter.
*entries* is a sequence of single entries, where a single entry is a
sequence ``[name, subtype, docname, anchor, extra, qualifier, descr]``.
The items in this sequence have the following meaning:
- `name` -- the name of the index entry to be displayed
- `subtype` -- sub-entry related type:
0 -- normal entry
1 -- entry with sub-entries
2 -- sub-entry
- `docname` -- docname where the entry is located
- `anchor` -- anchor for the entry within `docname`
- `extra` -- extra info for the entry
- `qualifier` -- qualifier for the description
- `descr` -- description for the entry
Qualifier and description are not rendered e.g. in LaTeX output.
"""
content = {}
objs = {name: (dispname, typ, docname, anchor)
for name, dispname, typ, docname, anchor, prio
in self.domain.get_objects()}
tmap = {}
tags = self.domain.data['obj2tag']
for name, tags in tags.items():
for tag in tags:
tmap.setdefault(tag,[])
tmap[tag].append(name)
for tag in tmap.keys():
lis = content.setdefault(tag, [])
objlis = tmap[tag]
for objname in objlis:
dispname, typ, docname, anchor = objs[objname]
lis.append((
dispname, 0, docname,
anchor,
docname, '', typ
))
re = [(k, v) for k, v in sorted(content.items())]
return (re, True)
class CommandIndex(Index):
name = 'cmd'
localname = 'Command Reference'
shortname = 'Command'
def __init__(self, *args, **kwargs):
super(CommandIndex, self).__init__(*args, **kwargs)
def generate(self, docnames=None):
"""Return entries for the index given by *name*. If *docnames* is
given, restrict to entries referring to these docnames.
The return value is a tuple of ``(content, collapse)``, where
* collapse* is a boolean that determines if sub-entries should
start collapsed (for output formats that support collapsing
sub-entries).
*content* is a sequence of ``(letter, entries)`` tuples, where *letter*
is the "heading" for the given *entries*, usually the starting letter.
*entries* is a sequence of single entries, where a single entry is a
sequence ``[name, subtype, docname, anchor, extra, qualifier, descr]``.
The items in this sequence have the following meaning:
- `name` -- the name of the index entry to be displayed
- `subtype` -- sub-entry related type:
0 -- normal entry
1 -- entry with sub-entries
2 -- sub-entry
- `docname` -- docname where the entry is located
- `anchor` -- anchor for the entry within `docname`
- `extra` -- extra info for the entry
- `qualifier` -- qualifier for the description
- `descr` -- description for the entry
Qualifier and description are not rendered e.g. in LaTeX output.
"""
content = {}
items = ((name, dispname, typ, docname, anchor)
for name, dispname, typ, docname, anchor, prio
in self.domain.get_objects())
items = sorted(items, key=lambda item: item[0])
for name, dispname, typ, docname, anchor in items:
lis = content.setdefault('Command', [])
lis.append((
dispname, 0, docname,
anchor,
'', '', typ
))
re = [(k, v) for k, v in sorted(content.items())]
return (re, True)
class CommandDomain(Domain):
name = 'cmd'
label = 'Command Sample'
roles = {
'ref': XRefRole()
}
directives = {
'def': CommandNode,
}
indices = {
CommandIndex,
TagIndex
}
initial_data = {
'objects': [], # object list
'obj2tag': {}, # name -> object
}
def get_full_qualified_name(self, node):
"""Return full qualified name for a given node"""
return "{}.{}.{}".format('cmd',
type(node).__name__,
node.arguments[0])
def get_objects(self):
for obj in self.data['objects']:
yield(obj)
def resolve_xref(self, env, fromdocname, builder, typ,
target, node, contnode):
match = [(docname, anchor)
for name, sig, typ, docname, anchor, prio
in self.get_objects() if sig == target]
if len(match) > 0:
todocname = match[0][0]
targ = match[0][1]
return make_refnode(builder,fromdocname,todocname,
targ, contnode, targ)
else:
print("Awww, found nothing")
return None
def setup(app):
app.add_domain(CommandDomain)
StandardDomain.initial_data['labels']['commandindex'] =\
('cmd-cmd', '', 'Command Reference')
StandardDomain.initial_data['labels']['tagindex'] =\
('cmd-tag', '', 'Tag Index')
StandardDomain.initial_data['anonlabels']['commandindex'] =\
('cmd-cmd', '')
StandardDomain.initial_data['anonlabels']['tagindex'] =\
('cmd-tag', '')
return {'version': '0.1'}

View File

@ -786,9 +786,8 @@ struct HelpPass : public Pass {
fprintf(f, ".. raw:: latex\n\n \\begin{comment}\n\n");
// render html
fprintf(f, ":code:`yosys> help %s`\n", cmd.c_str());
fprintf(f, "--------------------------------------------------------------------------------\n\n");
fprintf(f, ".. container:: cmdref\n");
fprintf(f, ".. cmd:def:: %s\n", cmd.c_str());
fprintf(f, " :title: %s\n\n", title.c_str());
std::stringstream ss;
std::string textcp = text;
ss << text;