From abce1569397d4542b7d0948f3b4632dd8ed84e9f Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 6 Feb 2019 01:06:07 +0900 Subject: [PATCH 1/2] Add SphinxRole --- sphinx/util/docutils.py | 43 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index e55cd016e..ba5a9d0ea 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -23,7 +23,7 @@ from docutils import nodes from docutils.io import FileOutput from docutils.parsers.rst import Directive, directives, roles, convert_directive_function from docutils.statemachine import StateMachine -from docutils.utils import Reporter +from docutils.utils import Reporter, unescape from sphinx.deprecation import RemovedInSphinx30Warning from sphinx.errors import ExtensionError @@ -36,7 +36,8 @@ report_re = re.compile('^(.+?:(?:\\d+)?): \\((DEBUG|INFO|WARNING|ERROR|SEVERE)/( if False: # For type annotation from types import ModuleType # NOQA - from typing import Any, Callable, Generator, List, Set, Tuple, Type # NOQA + from typing import Any, Callable, Dict, Generator, List, Set, Tuple, Type # NOQA + from docutils.parsers.rst.states import Inliner # NOQA from docutils.statemachine import State, StringList # NOQA from sphinx.builders import Builder # NOQA from sphinx.config import Config # NOQA @@ -383,6 +384,44 @@ class SphinxDirective(Directive): return self.env.config +class SphinxRole: + """A base class for Sphinx roles. + + This class provides helper methods for Sphinx roles. + + .. note:: The subclasses of this class might not work with docutils. + This class is strongly coupled with Sphinx. + """ + + def __call__(self, typ, rawtext, text, lineno, inliner, options={}, content=[]): + # type: (str, str, str, int, Inliner, Dict, List[str]) -> Tuple[List[nodes.Node], List[nodes.system_message]] # NOQA + self.type = typ + self.rawtext = rawtext + self.text = unescape(text) + self.lineno = lineno + self.inliner = inliner + self.options = options + self.content = content + + return self.run() + + def run(self): + # type: () -> Tuple[List[nodes.Node], List[nodes.system_message]] + raise NotImplementedError + + @property + def env(self): + # type: () -> BuildEnvironment + """Reference to the :class:`.BuildEnvironment` object.""" + return self.inliner.document.settings.env + + @property + def config(self): + # type: () -> Config + """Reference to the :class:`.Config` object.""" + return self.env.config + + class SphinxTranslator(nodes.NodeVisitor): """A base class for Sphinx translators. From ac70a4dd91fbfeaaf0a525a6802685273b67bf35 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 6 Feb 2019 01:03:48 +0900 Subject: [PATCH 2/2] Replace :abbr: role by class based implementation --- CHANGES | 1 + doc/extdev/index.rst | 5 +++++ sphinx/roles.py | 22 +++++++++++++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 35d5d0900..4af1f6542 100644 --- a/CHANGES +++ b/CHANGES @@ -104,6 +104,7 @@ Deprecated * ``sphinx.io.SphinxFileInput.supported`` * ``sphinx.io.SphinxRSTFileInput`` * ``sphinx.registry.SphinxComponentRegistry.add_source_input()`` +* ``sphinx.roles.abbr_role()`` * ``sphinx.testing.util.remove_unicode_literal()`` * ``sphinx.util.attrdict`` * ``sphinx.util.force_decode()`` diff --git a/doc/extdev/index.rst b/doc/extdev/index.rst index 56f2e7cee..08b9a9e65 100644 --- a/doc/extdev/index.rst +++ b/doc/extdev/index.rst @@ -365,6 +365,11 @@ The following is a list of deprecated interfaces. - 4.0 - ``sphinxcontrib.jsmath`` + * - ``sphinx.roles.abbr_role()`` + - 2.0 + - 4.0 + - ``sphinx.roles.Abbreviation`` + * - ``sphinx.testing.util.remove_unicode_literal()`` - 2.0 - 4.0 diff --git a/sphinx/roles.py b/sphinx/roles.py index 53ea144d8..e9a8786ca 100644 --- a/sphinx/roles.py +++ b/sphinx/roles.py @@ -9,13 +9,16 @@ """ import re +import warnings from docutils import nodes, utils from sphinx import addnodes +from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.errors import SphinxError from sphinx.locale import _ from sphinx.util import ws_re +from sphinx.util.docutils import SphinxRole from sphinx.util.nodes import split_explicit_title, process_index_entry, \ set_role_source_info @@ -338,6 +341,8 @@ _abbr_re = re.compile(r'\((.*)\)$', re.S) def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): # type: (str, str, str, int, Inliner, Dict, List[str]) -> Tuple[List[nodes.Node], List[nodes.system_message]] # NOQA + warnings.warn('abbr_role() is deprecated. Please use Abbrevation class instead.', + RemovedInSphinx40Warning, stacklevel=2) text = utils.unescape(text) m = _abbr_re.search(text) if m is None: @@ -349,6 +354,21 @@ def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): return [nodes.abbreviation(abbr, abbr, **options)], [] +class Abbreviation(SphinxRole): + abbr_re = re.compile(r'\((.*)\)$', re.S) + + def run(self): + # type: () -> Tuple[List[nodes.Node], List[nodes.system_message]] + matched = self.abbr_re.search(self.text) + if matched: + text = self.text[:matched.start()].strip() + self.options['explanation'] = matched.group(1) + else: + text = self.text + + return [nodes.abbreviation(self.rawtext, text, **self.options)], [] + + def index_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): # type: (str, str, str, int, Inliner, Dict, List[str]) -> Tuple[List[nodes.Node], List[nodes.system_message]] # NOQA # create new reference target @@ -390,7 +410,7 @@ specific_docroles = { 'menuselection': menusel_role, 'file': emph_literal_role, 'samp': emph_literal_role, - 'abbr': abbr_role, + 'abbr': Abbreviation(), 'index': index_role, } # type: Dict[str, RoleFunction]