summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2023-03-15 13:54:10 +0000
committerKitware Robot <kwrobot@kitware.com>2023-03-15 09:54:18 -0400
commit1ec4c6579117634ddb20962cdb63313dbf79887e (patch)
tree75bdb05c13eb92ae2a4d08bdf0845505bd1977b2
parentd34c98b06adfb0c82080a244e24abd450dc40904 (diff)
parent302f5171d8bc9877fc1e9b34024d5c0322f53a69 (diff)
downloadcmake-1ec4c6579117634ddb20962cdb63313dbf79887e.tar.gz
Merge topic 'sphinx-cref'
302f5171d8 Utilities/Sphinx: Add 'cref' role bc77ddb90c Utilities/Sphinx: Factor out part of CMakeXRefRole Acked-by: Kitware Robot <kwrobot@kitware.com> Acked-by: buildbot <buildbot@kitware.com> Merge-request: !8313
-rw-r--r--Help/dev/documentation.rst4
-rw-r--r--Source/cmRST.cxx1
-rw-r--r--Tests/CMakeLib/testRST.expect7
-rw-r--r--Tests/CMakeLib/testRST.rst7
-rw-r--r--Utilities/Sphinx/cmake.py59
5 files changed, 63 insertions, 15 deletions
diff --git a/Help/dev/documentation.rst b/Help/dev/documentation.rst
index b7a77c9b21..c6fb7a653c 100644
--- a/Help/dev/documentation.rst
+++ b/Help/dev/documentation.rst
@@ -395,6 +395,10 @@ object names like ``OUTPUT_NAME_<CONFIG>``. The form ``a <b>``,
with a space preceding ``<``, is still interpreted as a link text
with an explicit target.
+Additionally, the ``cref`` role may be used to create references
+to local targets that have literal styling. This is especially
+useful for referencing a subcommand in the command's documentation.
+
.. _`list()`: https://cmake.org/cmake/help/latest/command/list.html
.. _`list(APPEND)`: https://cmake.org/cmake/help/latest/command/list.html
.. _`list(APPEND) sub-command`: https://cmake.org/cmake/help/latest/command/list.html
diff --git a/Source/cmRST.cxx b/Source/cmRST.cxx
index 5ff70097df..f48330d5e1 100644
--- a/Source/cmRST.cxx
+++ b/Source/cmRST.cxx
@@ -33,6 +33,7 @@ cmRST::cmRST(std::ostream& os, std::string docroot)
, VersionDirective("^.. version(added|changed)::[ \t]*(.*)$")
, ModuleRST(R"(^#\[(=*)\[\.rst:$)")
, CMakeRole("(:cmake)?:("
+ "cref|"
"command|cpack_gen|generator|genex|"
"variable|envvar|module|policy|"
"prop_cache|prop_dir|prop_gbl|prop_inst|prop_sf|"
diff --git a/Tests/CMakeLib/testRST.expect b/Tests/CMakeLib/testRST.expect
index 483e2208b7..424b7d419a 100644
--- a/Tests/CMakeLib/testRST.expect
+++ b/Tests/CMakeLib/testRST.expect
@@ -26,10 +26,15 @@ Generator expression ``$<SOME_GENEX:...>`` with brackets and parameter.
Generator expression ``some genex`` with space and target.
Generator expression ``$<SOME_GENEX>`` with brackets, space, and target.
Generator expression ``$<SOME_GENEX:...>`` with brackets, parameter, space, and target.
-Inline literal ``~!@#$%^&*( )_+-=\\[]{}'":;,<>.?/``.
+Inline cref ``Link Dest``.
+Inline cref ``Link_Dest_<Placeholder>``.
+Inline cref ``Link Text``.
+Inline cref ``Link_Text_<Placeholder>``.
+Inline link Link Dest.
Inline link Link Text.
Inline link Link Text <With \-escaped Brackets>.
Inline literal ``__`` followed by inline link Link Text.
+Inline literal ``~!@#$%^&*( )_+-=\\[]{}'":;,<>.?/``.
First TOC entry.
diff --git a/Tests/CMakeLib/testRST.rst b/Tests/CMakeLib/testRST.rst
index c23b69a281..3a384077cf 100644
--- a/Tests/CMakeLib/testRST.rst
+++ b/Tests/CMakeLib/testRST.rst
@@ -33,10 +33,15 @@ Generator expression :genex:`$<SOME_GENEX:...>` with brackets and parameter.
Generator expression :genex:`some genex <SOME_GENEX>` with space and target.
Generator expression :genex:`$<SOME_GENEX> <SOME_GENEX>` with brackets, space, and target.
Generator expression :genex:`$<SOME_GENEX:...> <SOME_GENEX>` with brackets, parameter, space, and target.
-Inline literal ``~!@#$%^&*( )_+-=\\[]{}'":;,<>.?/``.
+Inline cref :cref:`Link Dest`.
+Inline cref :cref:`Link_Dest_<Placeholder>`.
+Inline cref :cref:`Link Text <ExternalDest>`.
+Inline cref :cref:`Link_Text_<Placeholder> <ExternalDest>`.
+Inline link `Link Dest`_.
Inline link `Link Text <ExternalDest>`_.
Inline link `Link Text \<With \\-escaped Brackets\> <ExternalDest>`_.
Inline literal ``__`` followed by inline link `Link Text <InternalDest_>`_.
+Inline literal ``~!@#$%^&*( )_+-=\\[]{}'":;,<>.?/``.
.. |not replaced| replace:: not replaced through toctree
.. |not replaced in literal| replace:: replaced in parsed literal
diff --git a/Utilities/Sphinx/cmake.py b/Utilities/Sphinx/cmake.py
index ba1fa4a9f5..5990f8a616 100644
--- a/Utilities/Sphinx/cmake.py
+++ b/Utilities/Sphinx/cmake.py
@@ -5,7 +5,7 @@ import os
import re
from dataclasses import dataclass
-from typing import Any, List, cast
+from typing import Any, List, Tuple, Type, cast
# Override much of pygments' CMakeLexer.
# We need to parse CMake syntax definitions, not CMake code.
@@ -66,11 +66,13 @@ CMakeLexer.tokens["root"] = [
from docutils.utils.code_analyzer import Lexer, LexerError
from docutils.parsers.rst import Directive, directives
from docutils.transforms import Transform
+from docutils.nodes import Element, Node, TextElement, system_message
from docutils import io, nodes
from sphinx.directives import ObjectDescription, nl_escape_re
from sphinx.domains import Domain, ObjType
from sphinx.roles import XRefRole
+from sphinx.util.docutils import ReferenceRole
from sphinx.util.nodes import make_refnode
from sphinx.util import logging, ws_re
from sphinx import addnodes
@@ -482,15 +484,53 @@ class CMakeSignatureObject(CMakeObject):
return super().run()
-class CMakeXRefRole(XRefRole):
-
+class CMakeReferenceRole:
# See sphinx.util.nodes.explicit_title_re; \x00 escapes '<'.
_re = re.compile(r'^(.+?)(\s*)(?<!\x00)<(.*?)>$', re.DOTALL)
+
+ @staticmethod
+ def _escape_angle_brackets(text: str) -> str:
+ # CMake cross-reference targets frequently contain '<' so escape
+ # any explicit `<target>` with '<' not preceded by whitespace.
+ while True:
+ m = CMakeReferenceRole._re.match(text)
+ if m and len(m.group(2)) == 0:
+ text = f'{m.group(1)}\x00<{m.group(3)}>'
+ else:
+ break
+ return text
+
+ def __class_getitem__(cls, parent: Any):
+ class Class(parent):
+ def __call__(self, name: str, rawtext: str, text: str,
+ *args, **kwargs
+ ) -> Tuple[List[Node], List[system_message]]:
+ text = CMakeReferenceRole._escape_angle_brackets(text)
+ return super().__call__(name, rawtext, text, *args, **kwargs)
+ return Class
+
+class CMakeCRefRole(CMakeReferenceRole[ReferenceRole]):
+ nodeclass: Type[Element] = nodes.reference
+ innernodeclass: Type[TextElement] = nodes.literal
+ classes: List[str] = ['cmake', 'literal']
+
+ def run(self) -> Tuple[List[Node], List[system_message]]:
+ refnode = self.nodeclass(self.rawtext)
+ self.set_source_info(refnode)
+
+ refnode['refid'] = nodes.make_id(self.target)
+ refnode += self.innernodeclass(self.rawtext, self.title,
+ classes=self.classes)
+
+ return [refnode], []
+
+class CMakeXRefRole(CMakeReferenceRole[XRefRole]):
+
_re_sub = re.compile(r'^([^()\s]+)\s*\(([^()]*)\)$', re.DOTALL)
_re_genex = 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, **kwargs):
if typ == 'cmake:command':
# Translate a CMake command cross-reference of the form:
# `command_name(SUB_COMMAND)`
@@ -508,15 +548,7 @@ class CMakeXRefRole(XRefRole):
m = CMakeXRefRole._re_guide.match(text)
if m:
text = '%s <%s>' % (m.group(2), text)
- # CMake cross-reference targets frequently contain '<' so escape
- # any explicit `<target>` with '<' not preceded by whitespace.
- while True:
- m = CMakeXRefRole._re.match(text)
- if m and len(m.group(2)) == 0:
- text = '%s\x00<%s>' % (m.group(1), m.group(3))
- else:
- break
- return XRefRole.__call__(self, typ, rawtext, text, *args, **keys)
+ return super().__call__(typ, rawtext, text, *args, **kwargs)
# We cannot insert index nodes using the result_nodes method
# because CMakeXRefRole is processed before substitution_reference
@@ -601,6 +633,7 @@ class CMakeDomain(Domain):
# Other `object_types` cannot be created except by the `CMakeTransform`
}
roles = {
+ 'cref': CMakeCRefRole(),
'command': CMakeXRefRole(fix_parens = True, lowercase = True),
'cpack_gen': CMakeXRefRole(),
'envvar': CMakeXRefRole(),