From patchwork Tue May 6 12:57:14 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Alex_Benn=C3=A9e?= X-Patchwork-Id: 887766 Delivered-To: patch@linaro.org Received: by 2002:a5d:430f:0:b0:38f:210b:807b with SMTP id h15csp2531956wrq; Tue, 6 May 2025 06:02:46 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCUCL2nw8oT8lQMI4HHMsP9kPpIXK96yARuWbFPOZdsraRULrsJJcaEnUPB6W6wDU3l7hZrP+w==@linaro.org X-Google-Smtp-Source: AGHT+IGEf//0rsGse/h6JDyfGpH0vDUuOZuBi0Cz8yab5S4YY8AQP/V/0xJR5VFGE4uwEt6SZ+pe X-Received: by 2002:ac8:5806:0:b0:47a:e49c:dc05 with SMTP id d75a77b69052e-490f149dd48mr51164991cf.11.1746536566392; Tue, 06 May 2025 06:02:46 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1746536566; cv=none; d=google.com; s=arc-20240605; b=YmRRI/ReZI5bEqfRRkE3xrOj6s5GMFv2SFZa/QQP01zftF5orL1N+jg8towUiumgwe 6X/N4kgmfi2z4QHpS21IiN3uz79hOkuRsAqpDzD4MMALZh9N6AtLawfHnea1YSR0eY6A 2qWxHVk3vClsxcL3ogSTGh+SbADvJxFqYWRIcSaihnhieL5wcqtsP0O0/mqdnazfh+pu Mr8g1SHBcL4SBquKyFbQ8ak6jnVAbk6hl7A47339s4GOEZa7+LZ1xZI6sckMO/57ocIB sVf/AcC8nod+Op6VOecafcPlKrPBE5TW4eOSVJtT/UMNNW2ZqOMFs+SIbcV0bixx5U1x y9Fg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=uuMngEWgGAO0nBl3buL5NTmX355UjBOo6woNVhHbqxY=; fh=VwaCX7udfecFJRCCfDJILJbxRRdCzThaa1bWgu6/gTU=; b=APOMECGVNoKA4gHmqsdnfCRhmIcVg5ZxDTeWmhI+MKC3ctWkNjBRREP2kS+809HZpg bUo/PuUmFsiXTBfHj6NZEbJeFfN4/tqOMZUTqKmsbijnFvjhK9J68itwijp1MpN277uG gzHBEkWtYYbB3rcYZtKKni4Yl2URyuGXLx/KgxthGNm68McNwZZXvzWqnK/yjGArQT5z gAeoBJOpI3QNWpYo/CNJ18E0l1PSMOtLCblGvh5XPyNSI490DRsRRXYeA/P5+iuYc1KN m70Ya2hSghwLP5Z7K+E87xHfpqTVOd3RhRzHU6VoTd6u9uDzU26zA5KOMya7yIdMUuui i6bw==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=opVi1yZQ; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org; dara=neutral header.i=@linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [209.51.188.17]) by mx.google.com with ESMTPS id d75a77b69052e-48b990fba85si115195161cf.622.2025.05.06.06.02.46 for (version=TLS1_2 cipher=ECDHE-ECDSA-CHACHA20-POLY1305 bits=256/256); Tue, 06 May 2025 06:02:46 -0700 (PDT) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=opVi1yZQ; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org; dara=neutral header.i=@linaro.org Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uCHru-0004DT-JT; Tue, 06 May 2025 08:57:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uCHrY-0003XP-QP for qemu-devel@nongnu.org; Tue, 06 May 2025 08:57:34 -0400 Received: from mail-ej1-x630.google.com ([2a00:1450:4864:20::630]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1uCHrS-0003sX-8C for qemu-devel@nongnu.org; Tue, 06 May 2025 08:57:31 -0400 Received: by mail-ej1-x630.google.com with SMTP id a640c23a62f3a-acb2faa9f55so746822266b.3 for ; Tue, 06 May 2025 05:57:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1746536244; x=1747141044; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=uuMngEWgGAO0nBl3buL5NTmX355UjBOo6woNVhHbqxY=; b=opVi1yZQLAMAQoHaOtTH3WSahSVMQaH6z0upy+2mjcMSwAoVmds9CfMm3Mc1+oMu/t E61dAdY88SaCX9JVIOptzVDH5u0GlZ1KZ/wixAJb5KTkbVpvTc1l0puYCrWx49+sGBxv 7gTw/p9TsBL4//D+Vhy3pMqmYd+XPqYBa+nMjEZC/2N0L4lSqMkzAB28yBhhvNLd0tVV mb2vhJDHVgB0s3sCTEwy6dsdENv/XrUloMqjWsqbQgrlzTD2cSiueQy/J1QmistLuNHq Om2b1J4iI8dsB5x0WqQlbH1XO63TAH+oIO9o6j1fLoyk7pmQfzuYmJdAuzKwV+rak9Zj pOpA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746536244; x=1747141044; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=uuMngEWgGAO0nBl3buL5NTmX355UjBOo6woNVhHbqxY=; b=bfjElUQHtcYDdx47+9LWlKRMSqJ6pQschShKKVOlXHjlENrMSBYPYptNA6P6daQiKI oPT+rNtxmklBZ8ZJwW74h2/+uLASEXFeGpPSGeFkmkz7l18iYeK/hHmw3NK7n7DXHBM2 XaJ1ByD/NAQ0Ig5iEdV4BpwJaPeh3qxv5dVXqa0h78LUL/cML7zQ/TzJxFihpptt/ITz LPYzrXRJieLE02b59MxRaCFZvP5c5Xwbu6HrVoE5RoQ+q3+XCf43eefA6lEab0hCoRfv +6f5ebLGth8nwIoYJKWFZkYg/ihu6y+w5xQpgPCf6nCWD3a8kA3JbP4Jk14WqTbYvowk rELA== X-Gm-Message-State: AOJu0Ywo9znt44aYOyCJWIoX8AOX4ZGuLuySpAYdmwQPitKqPTXUisFr lg0aM07ECuRvWQT4f/ghQFDrGgxaoRcsFW5iaKl8mXoeK0vOL83sKnHNFDvQcKM= X-Gm-Gg: ASbGncs4jtTnfz5ZFHadax5xBz+3ucT+0mhrzVcycFqCGlkcey1jLhKwkGrdm4yrT8P UJRhh9hqvbB/XcVUhBlXKHtW6BRR6f2+5Idyiu5N37DHDjp3fJWP5A9Z0p/1dUba4VuhXZ1XWGJ 2aa5imba2gIpZ7eAeUvnx9YjKJEjmFolOp9bugMeMXxPou0/qlhjjzpajX3cGHv6shl4tg3xUv1 BdxxhFGxKT89sTJA/tChUB3mrDCZVdp2xcR1DZ5BiDosApmC85zPoHHTXm1Y0htnnENENDT2rj3 TJiS3oKTNZWxSePayzCYBVZZlbnYKRSUEezCIom5T1g= X-Received: by 2002:a17:907:a2c8:b0:ac1:e6bd:a568 with SMTP id a640c23a62f3a-ad1d355c7fcmr285773166b.37.1746536244393; Tue, 06 May 2025 05:57:24 -0700 (PDT) Received: from draig.lan ([185.126.160.109]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ad1895095d7sm697433266b.151.2025.05.06.05.57.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 May 2025 05:57:22 -0700 (PDT) Received: from draig.lan (localhost [IPv6:::1]) by draig.lan (Postfix) with ESMTP id 598C25FADE; Tue, 6 May 2025 13:57:16 +0100 (BST) From: =?utf-8?q?Alex_Benn=C3=A9e?= To: qemu-devel@nongnu.org Cc: =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , David Hildenbrand , Akihiko Odaki , Dmitry Osipenko , Laurent Vivier , qemu-arm@nongnu.org, Mahmoud Mandour , Markus Armbruster , Pierrick Bouvier , Paolo Bonzini , Sriram Yagnaraman , =?utf-8?q?Marc-Andr?= =?utf-8?q?=C3=A9_Lureau?= , Peter Xu , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , John Snow , "Michael S. Tsirkin" , =?utf-8?q?Alex_Benn=C3=A9e?= , Thomas Huth , Fabiano Rosas , Peter Maydell , Alexandre Iooss Subject: [PATCH v2 13/14] docs: Create a uniquelabel Sphinx extension Date: Tue, 6 May 2025 13:57:14 +0100 Message-Id: <20250506125715.232872-14-alex.bennee@linaro.org> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250506125715.232872-1-alex.bennee@linaro.org> References: <20250506125715.232872-1-alex.bennee@linaro.org> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::630; envelope-from=alex.bennee@linaro.org; helo=mail-ej1-x630.google.com X-Spam_score_int: 12 X-Spam_score: 1.2 X-Spam_bar: + X-Spam_report: (1.2 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_SBL_CSS=3.335, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: qemu-devel-bounces+patch=linaro.org@nongnu.org From: Peter Maydell Sphinx requires that labels within documents are unique across the whole manual. This is because the "create a hyperlink" directive specifies only the name of the label, not a filename+label. Some Sphinx versions will warn about duplicate labels, but even if there is no warning there is still an ambiguity and no guarantee that the hyperlink will be created to the right target. For QEMU this is awkward, because we have various .rst.inc fragments which we include into multiple .rst files. If you define a label in the .rst.inc file then it will be a duplicate label. We have mostly worked around this by not putting labels into those .rst.inc files, or by adding "insert a label" functionality into the hxtool extension (see commit 1eeb432a953b0 "doc/sphinx/hxtool.py: add optional label argument to SRST directive"). This Sphinx extension adds a "uniquelabel" directive, which creates a label which is made unique by adding the name of the document to the label. The name of the generated label is "dir/file-labelname"; this is patterned on the generated label names that the hxtool SRST(label) directive creates. Signed-off-by: Peter Maydell Message-Id: <20250429163212.618953-2-peter.maydell@linaro.org> Signed-off-by: Alex Bennée --- docs/conf.py | 1 + docs/sphinx/uniquelabel.py | 74 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 docs/sphinx/uniquelabel.py diff --git a/docs/conf.py b/docs/conf.py index 7b5712e122..562db95bbf 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -67,6 +67,7 @@ 'qapi_domain', 'qapidoc', 'qmp_lexer', + 'uniquelabel', ] if sphinx.version_info[:3] > (4, 0, 0): diff --git a/docs/sphinx/uniquelabel.py b/docs/sphinx/uniquelabel.py new file mode 100644 index 0000000000..cc4ab7f31c --- /dev/null +++ b/docs/sphinx/uniquelabel.py @@ -0,0 +1,74 @@ +# coding=utf-8 +# +# Copyright (c) 2025 Linaro +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Sphinx extension to create a unique label by concatenating +# the name of the origin document with the label text. +# +# Sphinx requires that labels within documents are unique across +# the whole manual. This is because the "create a hyperlink" directive +# specifies only the name of the label, not a filename+label. +# Some Sphinx versions will warn about duplicate labels, but +# even if there is no warning there is still an ambiguity and no +# guarantee that the hyperlink will be created to the right target. +# +# For QEMU this is awkward, because we have various .rst.inc fragments +# which we include into multiple .rst files. If you define a label in +# the .rst.inc file then it will be a duplicate label. +# +# The uniquelabel directive is our fix for this: it creates a label +# whose name includes the name of the top level .rst file. This is then +# unique even if the .rst.inc file is included in multiple places, and +# when we create a hyperlink we can explicitly specify which label we +# are targeting. +# +# Concretely, if you have a foo/bar.rst and a foo/baz.rst that +# both include wat.rst.inc, then in wat.rst.inc you can write +# .. uniquelabel:: mylabel +# and it will be as if you had written a reference label: +# .. _foo/bar-mylabel +# or +# .. _foo/baz-mylabel +# depending on which file included wat.rst.inc, and you can link to +# whichever one you intend via any of the usual markup, e.g. +# `documentation of the thing in bar `. + +"""uniquelabel is a Sphinx extension that implements the uniquelabel directive""" + +from docutils import nodes +from docutils.statemachine import ViewList +from docutils.parsers.rst import directives, Directive +import sphinx + +__version__ = '1.0' + +class UniqueLabelDocDirective(Directive): + """Create a unique label by including the docname""" + required_arguments = 1 + optional_arguments = 0 + has_content = False + + def run(self): + env = self.state.document.settings.env + label = self.arguments[0] + + refline = ".. _" + env.docname + "-" + label + ":" + + rstlist = ViewList() + rstlist.append(refline, "generated text", 0) + + node = nodes.paragraph() + self.state.nested_parse(rstlist, 0, node) + return node.children + +def setup(app): + """ Register uniquelabel directive with Sphinx""" + app.add_directive('uniquelabel', UniqueLabelDocDirective) + + return dict( + version = __version__, + parallel_read_safe = True, + parallel_write_safe = True + )