From 22968d29f5fd8f1ca04b10f7f616d31b880cab0a Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sun, 17 Mar 2024 10:55:04 +0100 Subject: [PATCH] [manpage] emit OSC 8 hyperlinks via groff (#12108) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- CHANGES.rst | 6 ++++++ sphinx/writers/manpage.py | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 85cd47881..20ebaf073 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -35,6 +35,12 @@ Features added * #11981: Improve rendering of signatures using ``slice`` syntax, e.g., ``def foo(arg: np.float64[:,:]) -> None: ...``. +* The manpage builder now adds `OSC 8`_ anchors to hyperlinks, using + the `groff`_ device control command. + + .. _OSC 8: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda + .. _groff: https://lists.gnu.org/archive/html/groff/2021-10/msg00000.html + Bugs fixed ---------- diff --git a/sphinx/writers/manpage.py b/sphinx/writers/manpage.py index 902f29ca2..e3dca81ed 100644 --- a/sphinx/writers/manpage.py +++ b/sphinx/writers/manpage.py @@ -308,13 +308,17 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator): # overwritten -- don't visit inner marked up nodes def visit_reference(self, node: Element) -> None: + uri = node.get('refuri', '') + if uri: + # OSC 8 link start (using groff's device control directive). + self.body.append(fr"\X'tty: link {uri}'") + self.body.append(self.defs['reference'][0]) # avoid repeating escaping code... fine since # visit_Text calls astext() and only works on that afterwards self.visit_Text(node) # type: ignore[arg-type] self.body.append(self.defs['reference'][1]) - uri = node.get('refuri', '') if uri.startswith(('mailto:', 'http:', 'https:', 'ftp:')): # if configured, put the URL after the link if self.config.man_show_urls and node.astext() != uri: @@ -324,6 +328,9 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator): ' <', self.defs['strong'][0], uri, self.defs['strong'][1], '>']) + if uri: + # OSC 8 link end. + self.body.append(r"\X'tty: link'") raise nodes.SkipNode def visit_number_reference(self, node: Element) -> None: