mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-21 23:00:50 +08:00
Utilities/Sphinx: Make signatures linkable
Add signatures to the collection of observed objects (which can be referenced elsewhere). Don't automatically strip parameters from a :command: reference, as these may now link signatures. (Do, however, munge them into 'text <ref>' form if they aren't already, as not doing so adds an extra '()' for some reason.) Correspondingly, change xref resolution to try to match 'command' when a ref like 'command(args)' is not matched, so that existing links to commands that have not been converted to use the new signature directive don't immediately break.
This commit is contained in:
@@ -270,8 +270,7 @@ The ``signature`` directive requires one argument, the signature summary:
|
|||||||
abbreviate it in the ``signature`` directive argument and specify the full
|
abbreviate it in the ``signature`` directive argument and specify the full
|
||||||
signature in a ``code-block`` in the description.
|
signature in a ``code-block`` in the description.
|
||||||
|
|
||||||
The ``signature`` directive generates a document-local hyperlink target
|
The ``signature`` directive generates a hyperlink target for each signature:
|
||||||
for each signature:
|
|
||||||
|
|
||||||
* Default target names are automatically extracted from leading "keyword"
|
* Default target names are automatically extracted from leading "keyword"
|
||||||
arguments in the signatures, where a keyword is any sequence of
|
arguments in the signatures, where a keyword is any sequence of
|
||||||
@@ -299,7 +298,8 @@ for each signature:
|
|||||||
|
|
||||||
* The targets may be referenced from within the same document using
|
* The targets may be referenced from within the same document using
|
||||||
```REF`_`` or ```TEXT <REF_>`_`` syntax. Like reStructuredText section
|
```REF`_`` or ```TEXT <REF_>`_`` syntax. Like reStructuredText section
|
||||||
headers, the targets do not work with Sphinx ``:ref:`` syntax.
|
headers, the targets do not work with Sphinx ``:ref:`` syntax, however
|
||||||
|
they can be globally referenced using e.g. ``:command:`string(APPEND)```.
|
||||||
|
|
||||||
The directive treats its content as the documentation of the signature(s).
|
The directive treats its content as the documentation of the signature(s).
|
||||||
Indent the signature documentation accordingly.
|
Indent the signature documentation accordingly.
|
||||||
|
@@ -360,7 +360,7 @@ class CMakeSignatureObject(CMakeObject):
|
|||||||
|
|
||||||
def add_target_and_index(self, name, sig, signode):
|
def add_target_and_index(self, name, sig, signode):
|
||||||
if name in self.targetnames:
|
if name in self.targetnames:
|
||||||
targetname = self.targetnames[name].lower()
|
sigargs = self.targetnames[name]
|
||||||
else:
|
else:
|
||||||
def extract_keywords(params):
|
def extract_keywords(params):
|
||||||
for p in params:
|
for p in params:
|
||||||
@@ -370,7 +370,8 @@ class CMakeSignatureObject(CMakeObject):
|
|||||||
return
|
return
|
||||||
|
|
||||||
keywords = extract_keywords(name.split('(')[1].split())
|
keywords = extract_keywords(name.split('(')[1].split())
|
||||||
targetname = ' '.join(keywords).lower()
|
sigargs = ' '.join(keywords)
|
||||||
|
targetname = sigargs.lower()
|
||||||
targetid = nodes.make_id(targetname)
|
targetid = nodes.make_id(targetname)
|
||||||
|
|
||||||
if targetid not in self.state.document.ids:
|
if targetid not in self.state.document.ids:
|
||||||
@@ -379,6 +380,15 @@ class CMakeSignatureObject(CMakeObject):
|
|||||||
signode['first'] = (not self.names)
|
signode['first'] = (not self.names)
|
||||||
self.state.document.note_explicit_target(signode)
|
self.state.document.note_explicit_target(signode)
|
||||||
|
|
||||||
|
# Register the signature as a command object.
|
||||||
|
command = name.split('(')[0].lower()
|
||||||
|
refname = f'{command}({sigargs})'
|
||||||
|
refid = f'command:{command}({targetname})'
|
||||||
|
|
||||||
|
domain = cast(CMakeDomain, self.env.get_domain('cmake'))
|
||||||
|
domain.note_object('command', name=refname, target_id=refid,
|
||||||
|
node_id=targetid, location=signode)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
targets = self.options.get('target')
|
targets = self.options.get('target')
|
||||||
if targets is not None:
|
if targets is not None:
|
||||||
@@ -393,19 +403,15 @@ class CMakeXRefRole(XRefRole):
|
|||||||
|
|
||||||
# See sphinx.util.nodes.explicit_title_re; \x00 escapes '<'.
|
# See sphinx.util.nodes.explicit_title_re; \x00 escapes '<'.
|
||||||
_re = re.compile(r'^(.+?)(\s*)(?<!\x00)<(.*?)>$', re.DOTALL)
|
_re = re.compile(r'^(.+?)(\s*)(?<!\x00)<(.*?)>$', re.DOTALL)
|
||||||
_re_sub = re.compile(r'^([^()\s]+)\s*\(([^()]*)\)$', re.DOTALL)
|
_re_ref = re.compile(r'^.*\s<\w+([(][\w\s]+[)])?>$', re.DOTALL)
|
||||||
_re_genex = re.compile(r'^\$<([^<>:]+)(:[^<>]+)?>$', re.DOTALL)
|
_re_genex = re.compile(r'^\$<([^<>:]+)(:[^<>]+)?>$', re.DOTALL)
|
||||||
_re_guide = re.compile(r'^([^<>/]+)/([^<>]*)$', re.DOTALL)
|
_re_guide = re.compile(r'^([^<>/]+)/([^<>]*)$', re.DOTALL)
|
||||||
|
|
||||||
def __call__(self, typ, rawtext, text, *args, **keys):
|
def __call__(self, typ, rawtext, text, *args, **keys):
|
||||||
# Translate CMake command cross-references of the form:
|
|
||||||
# `command_name(SUB_COMMAND)`
|
|
||||||
# to have an explicit target:
|
|
||||||
# `command_name(SUB_COMMAND) <command_name>`
|
|
||||||
if typ == 'cmake:command':
|
if typ == 'cmake:command':
|
||||||
m = CMakeXRefRole._re_sub.match(text)
|
m = CMakeXRefRole._re_ref.match(text)
|
||||||
if m:
|
if m is None:
|
||||||
text = '%s <%s>' % (text, m.group(1))
|
text = f'{text} <{text}>'
|
||||||
elif typ == 'cmake:genex':
|
elif typ == 'cmake:genex':
|
||||||
m = CMakeXRefRole._re_genex.match(text)
|
m = CMakeXRefRole._re_genex.match(text)
|
||||||
if m:
|
if m:
|
||||||
@@ -461,6 +467,10 @@ class CMakeXRefTransform(Transform):
|
|||||||
# Do not index cross-references to guide sections.
|
# Do not index cross-references to guide sections.
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if objtype == 'command':
|
||||||
|
# Index signature references to their parent command.
|
||||||
|
objname = objname.split('(')[0].lower()
|
||||||
|
|
||||||
targetnum = env.new_serialno('index-%s:%s' % (objtype, objname))
|
targetnum = env.new_serialno('index-%s:%s' % (objtype, objname))
|
||||||
|
|
||||||
targetid = 'index-%s-%s:%s' % (targetnum, objtype, objname)
|
targetid = 'index-%s-%s:%s' % (targetnum, objtype, objname)
|
||||||
@@ -537,6 +547,15 @@ class CMakeDomain(Domain):
|
|||||||
typ, target, node, contnode):
|
typ, target, node, contnode):
|
||||||
targetid = f'{typ}:{target}'
|
targetid = f'{typ}:{target}'
|
||||||
obj = self.data['objects'].get(targetid)
|
obj = self.data['objects'].get(targetid)
|
||||||
|
|
||||||
|
if obj is None and typ == 'command':
|
||||||
|
# If 'command(args)' wasn't found, try just 'command'.
|
||||||
|
# TODO: remove this fallback? warn?
|
||||||
|
# logger.warning(f'no match for {targetid}')
|
||||||
|
command = target.split('(')[0]
|
||||||
|
targetid = f'{typ}:{command}'
|
||||||
|
obj = self.data['objects'].get(targetid)
|
||||||
|
|
||||||
if obj is None:
|
if obj is None:
|
||||||
# TODO: warn somehow?
|
# TODO: warn somehow?
|
||||||
return None
|
return None
|
||||||
|
Reference in New Issue
Block a user