diff options
author | Matthew Woehlke <matthew.woehlke@kitware.com> | 2023-02-24 20:01:14 (GMT) |
---|---|---|
committer | Matthew Woehlke <matthew.woehlke@kitware.com> | 2023-03-03 22:05:02 (GMT) |
commit | 74e3c1d313616b5faf83ff423c8e8ef3f2010a41 (patch) | |
tree | 7f24ecc7db552a3e658a742848cdc0f408c06c7a /Utilities/Sphinx | |
parent | c09b7604841448b0c949e5c98ea791c9dc9d477e (diff) | |
download | CMake-74e3c1d313616b5faf83ff423c8e8ef3f2010a41.zip CMake-74e3c1d313616b5faf83ff423c8e8ef3f2010a41.tar.gz CMake-74e3c1d313616b5faf83ff423c8e8ef3f2010a41.tar.bz2 |
Utilities/Sphinx: Add a directive to document command signatures
Add a `signature` directive to offer a CMake version of Sphinx's
`function` directive, similar to that found in other domains (py, cpp,
etc.). Like others, this takes one or more signatures as arguments and
creates dt/dd nodes from the signatures and the directive contents.
Diffstat (limited to 'Utilities/Sphinx')
-rw-r--r-- | Utilities/Sphinx/cmake.py | 85 | ||||
-rw-r--r-- | Utilities/Sphinx/static/cmake.css | 23 |
2 files changed, 105 insertions, 3 deletions
diff --git a/Utilities/Sphinx/cmake.py b/Utilities/Sphinx/cmake.py index e9f0dc5..9043709 100644 --- a/Utilities/Sphinx/cmake.py +++ b/Utilities/Sphinx/cmake.py @@ -16,6 +16,9 @@ from pygments.lexers import CMakeLexer from pygments.token import Name, Operator, Punctuation, String, Text, Comment, Generic, Whitespace, Number from pygments.lexer import bygroups +# RE to split multiple command signatures +sig_end_re = re.compile(r'(?<=[)])\n') + # Notes on regular expressions below: # - [\.\+-] are needed for string constants like gtk+-2.0 # - Unix paths are recognized by '/'; support for Windows paths may be added if needed @@ -57,14 +60,16 @@ CMakeLexer.tokens["root"] = [ # (r'[^<>\])\}\|$"# \t\n]+', Name.Exception), # fallback, for debugging only ] +from docutils.utils.code_analyzer import Lexer, LexerError from docutils.parsers.rst import Directive, directives from docutils.transforms import Transform from docutils import io, nodes -from sphinx.directives import ObjectDescription +from sphinx.directives import ObjectDescription, nl_escape_re from sphinx.domains import Domain, ObjType from sphinx.roles import XRefRole from sphinx.util.nodes import make_refnode +from sphinx.util import ws_re from sphinx import addnodes sphinx_before_1_4 = False @@ -286,9 +291,9 @@ class CMakeObject(ObjectDescription): def add_target_and_index(self, name, sig, signode): if self.objtype == 'command': - targetname = name.lower() + targetname = name.lower() else: - targetname = name + targetname = name targetid = '%s:%s' % (self.objtype, targetname) if targetid not in self.state.document.ids: signode['names'].append(targetid) @@ -302,6 +307,79 @@ class CMakeObject(ObjectDescription): if make_index_entry: self.indexnode['entries'].append(make_index_entry(name, targetid)) +class CMakeSignatureObject(CMakeObject): + object_type = 'signature' + + option_spec = { + 'target': directives.unchanged, + } + + def get_signatures(self): + content = nl_escape_re.sub('', self.arguments[0]) + lines = sig_end_re.split(content) + return [ws_re.sub(' ', line.strip()) for line in lines] + + def handle_signature(self, sig, signode): + language = 'cmake' + classes = ['code', 'cmake', 'highlight'] + + node = addnodes.desc_name(sig, '', classes=classes) + + try: + tokens = Lexer(sig, language, 'short') + except LexerError as error: + if self.state.document.settings.report_level > 2: + # Silently insert without syntax highlighting. + tokens = Lexer(sig, language, 'none') + else: + raise self.warning(error) + + for classes, value in tokens: + if classes: + node += nodes.inline(value, value, classes=classes) + else: + node += nodes.Text(value) + + signode.clear() + signode += node + + return sig + + def __init__(self, *args, **kwargs): + self.targetnames = {} + super().__init__(*args, **kwargs) + + def add_target_and_index(self, name, sig, signode): + if name in self.targetnames: + targetname = self.targetnames[name].lower() + else: + def extract_keywords(params): + for p in params: + if p[0].isalpha(): + yield p + else: + return + + keywords = extract_keywords(name.split('(')[1].split()) + targetname = ' '.join(keywords).lower() + targetid = nodes.make_id(targetname) + + if targetid not in self.state.document.ids: + signode['names'].append(targetname) + signode['ids'].append(targetid) + signode['first'] = (not self.names) + self.state.document.note_explicit_target(signode) + + def run(self): + targets = self.options.get('target') + if targets is not None: + signatures = self.get_signatures() + targets = [t.strip() for t in targets.split('\n')] + for signature, target in zip(signatures, targets): + self.targetnames[signature] = target + + return super().run() + class CMakeXRefRole(XRefRole): # See sphinx.util.nodes.explicit_title_re; \x00 escapes '<'. @@ -411,6 +489,7 @@ class CMakeDomain(Domain): 'command': CMakeObject, 'envvar': CMakeObject, 'genex': CMakeObject, + 'signature': CMakeSignatureObject, 'variable': CMakeObject, # Other `object_types` cannot be created except by the `CMakeTransform` } diff --git a/Utilities/Sphinx/static/cmake.css b/Utilities/Sphinx/static/cmake.css index 324cd92..dd0dd02 100644 --- a/Utilities/Sphinx/static/cmake.css +++ b/Utilities/Sphinx/static/cmake.css @@ -17,6 +17,29 @@ div.sphinxsidebarwrapper { background-color: #dfdfdf; } +/* Apply <pre> style (from classic.css) to signature directive argument. */ +.signature .sig { + padding: 5px; + background-color: #eeeeee; + color: #333333; + line-height: 120%; + border: 1px solid #ac9; + border-left: none; + border-right: none; +} + +/* Add additional styling to signature directive argument. */ +.signature .sig { + margin-bottom: 5px; + padding-left: calc(5px + 3em); + text-indent: -3em; + font-family: monospace; +} + +.signature .sig .code.sig-name { + font-weight: normal; +} + /* Remove unwanted margin in case list item contains a div-wrapping directive like `.. versionadded` or `.. deprecated`. */ dd > :first-child > p { |