From 37ec7b99139766bb916e49a2bc1687f41badd94b Mon Sep 17 00:00:00 2001
From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Date: Tue, 8 Oct 2024 10:38:02 +0200
Subject: [PATCH] DOC: Format role and directive cross-references in ReST
 format

---
 sphinx/domains/rst.py | 4 ++--
 sphinx/roles.py       | 7 +++++++
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/sphinx/domains/rst.py b/sphinx/domains/rst.py
index 9eec281f3e6..4593f9f3172 100644
--- a/sphinx/domains/rst.py
+++ b/sphinx/domains/rst.py
@@ -230,8 +230,8 @@ class ReSTDomain(Domain):
         'role':      ReSTRole,
     }
     roles = {
-        'dir':  XRefRole(),
-        'role': XRefRole(),
+        'dir':  XRefRole(title_fmt=".. {title}::"),
+        'role': XRefRole(title_fmt=":{title}:"),
     }
     initial_data: dict[str, dict[tuple[str, str], str]] = {
         'objects': {},  # fullname -> docname, objtype
diff --git a/sphinx/roles.py b/sphinx/roles.py
index 27ceed29532..26504a7911f 100644
--- a/sphinx/roles.py
+++ b/sphinx/roles.py
@@ -61,6 +61,9 @@ class XRefRole(ReferenceRole):
       * `lowercase` to lowercase the target
       * `nodeclass` and `innernodeclass` select the node classes for
         the reference and the content node
+      * `title_fmt`: an optional format string using one ``{title}`` variable
+        that can be used to customize the rendered text, e.g.
+        ``title_fmt=":{title}:"`
 
     * Subclassing and overwriting `process_link()` and/or `result_nodes()`.
     """
@@ -75,6 +78,7 @@ def __init__(
         nodeclass: type[Element] | None = None,
         innernodeclass: type[TextElement] | None = None,
         warn_dangling: bool = False,
+        title_fmt: str | None = None,
     ) -> None:
         self.fix_parens = fix_parens
         self.lowercase = lowercase
@@ -83,6 +87,7 @@ def __init__(
             self.nodeclass = nodeclass
         if innernodeclass is not None:
             self.innernodeclass = innernodeclass
+        self.title_fmt = title_fmt
 
         super().__init__()
 
@@ -145,6 +150,8 @@ def create_xref_node(self) -> tuple[list[Node], list[system_message]]:
             self.env, refnode, self.has_explicit_title, title, target
         )
         refnode['reftarget'] = target
+        if self.title_fmt is not None:
+            title = self.title_fmt.format(title=title)
         refnode += self.innernodeclass(self.rawtext, title, classes=self.classes)
 
         return self.result_nodes(self.inliner.document, self.env, refnode, is_ref=True)