Received: by 2002:a25:4158:0:0:0:0:0 with SMTP id o85csp2244124yba; Thu, 25 Apr 2019 13:04:40 -0700 (PDT) X-Google-Smtp-Source: APXvYqwBwf7UEy0FL+BV3ruZahpHrZBNcrLba1/t9LyoNkzQqxXICv4e2WSduynzOd/4GKiUaILX X-Received: by 2002:a65:6108:: with SMTP id z8mr39128680pgu.106.1556222680540; Thu, 25 Apr 2019 13:04:40 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1556222680; cv=none; d=google.com; s=arc-20160816; b=GzToUdx8haujF8X0ITTbO8Ia+GDi/OwNwGwmk1C7pPGqdMXfrStrcKHXr/M/yMIxi5 +pPbMP5Km1nC4Ejt7UTiiNyVjcdA8pmbCQDquRxDHzoysVwX2r0Ufe2BoKPdGYByVwGt Nir2GGeCykSNEuDATsdDykGaNojl6Y1MNEn1A8mwou6n38BvwiUGepmvIQtz6n62qpJB q2KS0XRbhxB9wpnrb6Tww275D3umCMFPIoBofAhmpty9ZHBT1M4SmAasCI8S7ZTE5ugT 6KCm5h9m0a9ZENLTfLpypkNJDR1olnO2tFM5/K+8m5DNzkZoNoWsV/8r+mK5vHLbpbA/ vPbQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=PJpok+D+tx4uIEBr0d1/V4NI+vn1J4CwaCyUTuoFGXk=; b=aWsfArxdBLjJIHLkRuqCkqHYOuiqKOotfsVo1KprAe+7QffgaXWXyQ1JCjsKjGEHxn Eiq4e2Mf+7i+asy0bKci9o4TRf/Qv77WKHR9kATgrbp0GOYAJwbsyWS4FjK41THzTPub 5ADjSdVJYErDIr8j/Q3WmKCxwND2jm6w1J2YuMUW859sy9kBLrmKqgIzJZHmC0SO224E HCqJVxtXSgNG4RzX8EbJmiqSU5kbAaGR9XSlq7R9uz41nC0uiiPingUG4pHZSe9/mABk WZVPjDtr315uuwJcSk2csDsy1ujCigwA3yNjBZpRc+TOu3vIPsXzoUe5ANzxowS8R4YS vaMg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l86si24134203pfb.182.2019.04.25.13.04.23; Thu, 25 Apr 2019 13:04:40 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730976AbfDYUBx (ORCPT + 99 others); Thu, 25 Apr 2019 16:01:53 -0400 Received: from ms.lwn.net ([45.79.88.28]:43880 "EHLO ms.lwn.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729259AbfDYUBm (ORCPT ); Thu, 25 Apr 2019 16:01:42 -0400 Received: from meer.lwn.net (localhost [127.0.0.1]) by ms.lwn.net (Postfix) with ESMTPA id 3515D7DC; Thu, 25 Apr 2019 20:01:41 +0000 (UTC) From: Jonathan Corbet To: linux-doc@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Matthew Wilcox , Mauro Carvalho Chehab , Jonathan Corbet Subject: [PATCH 1/2] Docs: An initial automarkup extension for sphinx Date: Thu, 25 Apr 2019 14:01:24 -0600 Message-Id: <20190425200125.12302-2-corbet@lwn.net> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190425200125.12302-1-corbet@lwn.net> References: <20190425200125.12302-1-corbet@lwn.net> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Rather than fill our text files with :c:func:`function()` syntax, just do the markup via a hook into the sphinx build process. As is always the case, the real problem is detecting the situations where this markup should *not* be done. Signed-off-by: Jonathan Corbet --- Documentation/conf.py | 3 +- Documentation/sphinx/automarkup.py | 90 ++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 Documentation/sphinx/automarkup.py diff --git a/Documentation/conf.py b/Documentation/conf.py index 72647a38b5c2..ba7b2846b1c5 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -34,7 +34,8 @@ needs_sphinx = '1.3' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'cdomain', 'kfigure', 'sphinx.ext.ifconfig'] +extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'cdomain', + 'kfigure', 'sphinx.ext.ifconfig', 'automarkup'] # The name of the math extension changed on Sphinx 1.4 if major == 1 and minor > 3: diff --git a/Documentation/sphinx/automarkup.py b/Documentation/sphinx/automarkup.py new file mode 100644 index 000000000000..c47469372bae --- /dev/null +++ b/Documentation/sphinx/automarkup.py @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# This is a little Sphinx extension that tries to apply certain kinds +# of markup automatically so we can keep it out of the text files +# themselves. +# +# It's possible that this could be done better by hooking into the build +# much later and traversing through the doctree. That would eliminate the +# need to duplicate some RST parsing and perhaps be less fragile, at the +# cost of some more complexity and the need to generate the cross-reference +# links ourselves. +# +# Copyright 2019 Jonathan Corbet +# +from __future__ import print_function +import re +import sphinx + +# +# Regex nastiness. Of course. +# Try to identify "function()" that's not already marked up some +# other way. Sphinx doesn't like a lot of stuff right after a +# :c:func: block (i.e. ":c:func:`mmap()`s" flakes out), so the last +# bit tries to restrict matches to things that won't create trouble. +# +RE_function = re.compile(r'(^|\s+)([\w\d_]+\(\))([.,/\s]|$)') +# +# Lines consisting of a single underline character. +# +RE_underline = re.compile(r'^([-=~])\1+$') +# +# Starting a literal block. +# +RE_literal = re.compile(r'^(\s*)(.*::\s*|\.\.\s+code-block::.*)$') +# +# Just get the white space beginning a line. +# +RE_whitesp = re.compile(r'^(\s*)') + +def MangleFile(app, docname, text): + ret = [ ] + previous = '' + literal = False + for line in text[0].split('\n'): + # + # See if we might be ending a literal block, as denoted by + # an indent no greater than when we started. + # + if literal and len(line) > 0: + m = RE_whitesp.match(line) # Should always match + if len(m.group(1).expandtabs()) <= lit_indent: + literal = False + # + # Blank lines, directives, and lines within literal blocks + # should not be messed with. + # + if literal or len(line) == 0 or line[0] == '.': + ret.append(line) + # + # Is this an underline line? If so, and it is the same length + # as the previous line, we may have mangled a heading line in + # error, so undo it. + # + elif RE_underline.match(line): + if len(line) == len(previous): + ret[-1] = previous + ret.append(line) + # + # Normal line - perform substitutions. + # + else: + ret.append(RE_function.sub(r'\1:c:func:`\2`\3', line)) + # + # Might we be starting a literal block? If so make note of + # the fact. + # + m = RE_literal.match(line) + if m: + literal = True + lit_indent = len(m.group(1).expandtabs()) + previous = line + text[0] = '\n'.join(ret) + +def setup(app): + app.connect('source-read', MangleFile) + + return dict( + parallel_read_safe = True, + parallel_write_safe = True + ) -- 2.21.0