diff --git a/CHANGES b/CHANGES index b3e2dcfdf..1ac66ced4 100644 --- a/CHANGES +++ b/CHANGES @@ -18,6 +18,9 @@ New features Bugs fixed ---------- +* #1174: Fix smart quotes being applied inside roles like :rst:role:`program` or + :rst:role:`makevar`. + * #1335: Fix autosummary template overloading with exclamation prefix like ``{% extends "!autosummary/class.rst" %}`` cause infinite recursive function call. This caused by PR#181. diff --git a/doc/ext/appapi.rst b/doc/ext/appapi.rst index a6393d408..156dede8c 100644 --- a/doc/ext/appapi.rst +++ b/doc/ext/appapi.rst @@ -199,10 +199,13 @@ the following public API: .. index:: pair: function; directive The reference node will be of class ``literal`` (so it will be rendered in a - proportional font, as appropriate for code) unless you give the *ref_nodeclass* - argument, which must be a docutils node class (most useful are - ``docutils.nodes.emphasis`` or ``docutils.nodes.strong`` -- you can also use - ``docutils.nodes.generated`` if you want no further text decoration). + proportional font, as appropriate for code) unless you give the + *ref_nodeclass* argument, which must be a docutils node class. Most useful + are ``docutils.nodes.emphasis`` or ``docutils.nodes.strong`` -- you can also + use ``docutils.nodes.generated`` if you want no further text decoration. If + the text should be treated as literal (e.g. no smart quote replacement), but + not have typewriter styling, use ``sphinx.addnodes.literal_emphasis`` or + ``sphinx.addnodes.literal_strong``. For the role content, you have the same syntactical possibilities as for standard Sphinx roles (see :ref:`xref-syntax`). diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index d8dca2ce4..e3f6d7d6f 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -168,6 +168,11 @@ class literal_emphasis(nodes.emphasis): applied (e.g. smartypants for HTML output). """ +class literal_strong(nodes.strong): + """Node that behaves like `strong`, but further text processors are not + applied (e.g. smartypants for HTML output). + """ + class abbreviation(nodes.Inline, nodes.TextElement): """Node for abbreviations with explanations.""" diff --git a/sphinx/roles.py b/sphinx/roles.py index 6703b6b8b..3b8585889 100644 --- a/sphinx/roles.py +++ b/sphinx/roles.py @@ -22,15 +22,15 @@ from sphinx.util.nodes import split_explicit_title, process_index_entry, \ generic_docroles = { - 'command' : nodes.strong, + 'command' : addnodes.literal_strong, 'dfn' : nodes.emphasis, 'kbd' : nodes.literal, 'mailheader' : addnodes.literal_emphasis, - 'makevar' : nodes.strong, + 'makevar' : addnodes.literal_strong, 'manpage' : addnodes.literal_emphasis, 'mimetype' : addnodes.literal_emphasis, 'newsgroup' : addnodes.literal_emphasis, - 'program' : nodes.strong, # XXX should be an x-ref + 'program' : addnodes.literal_strong, # XXX should be an x-ref 'regexp' : nodes.literal, } diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py index 6fd8ba956..150bf3a1a 100644 --- a/sphinx/util/docfields.py +++ b/sphinx/util/docfields.py @@ -99,7 +99,8 @@ class GroupedField(Field): return Field.make_field(self, types, domain, items[0]) for fieldarg, content in items: par = nodes.paragraph() - par += self.make_xref(self.rolename, domain, fieldarg, nodes.strong) + par += self.make_xref(self.rolename, domain, fieldarg, + addnodes.literal_strong) par += nodes.Text(' -- ') par += content listnode += nodes.list_item('', par) @@ -137,7 +138,8 @@ class TypedField(GroupedField): def make_field(self, types, domain, items): def handle_item(fieldarg, content): par = nodes.paragraph() - par += self.make_xref(self.rolename, domain, fieldarg, nodes.strong) + par += self.make_xref(self.rolename, domain, fieldarg, + addnodes.literal_strong) if fieldarg in types: par += nodes.Text(' (') # NOTE: using .pop() here to prevent a single type node to be diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py index c54f3369a..612496e55 100644 --- a/sphinx/writers/html.py +++ b/sphinx/writers/html.py @@ -492,6 +492,11 @@ class HTMLTranslator(BaseTranslator): def depart_literal_emphasis(self, node): return self.depart_emphasis(node) + def visit_literal_strong(self, node): + return self.visit_strong(node) + def depart_literal_strong(self, node): + return self.depart_strong(node) + def visit_abbreviation(self, node): attrs = {} if node.hasattr('explanation'): @@ -602,6 +607,14 @@ class SmartyPantsHTMLTranslator(HTMLTranslator): self.depart_emphasis(node) self.no_smarty -= 1 + def visit_literal_strong(self, node): + self.no_smarty += 1 + self.visit_strong(node) + + def depart_literal_strong(self, node): + self.depart_strong(node) + self.no_smarty -= 1 + def visit_desc_signature(self, node): self.no_smarty += 1 HTMLTranslator.visit_desc_signature(self, node) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 3c1a50f84..b55adda04 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -1247,6 +1247,13 @@ class LaTeXTranslator(nodes.NodeVisitor): def depart_strong(self, node): self.body.append('}') + def visit_literal_strong(self, node): + self.body.append(r'\textbf{\texttt{') + self.no_contractions += 1 + def depart_literal_strong(self, node): + self.body.append('}}') + self.no_contractions -= 1 + def visit_abbreviation(self, node): abbr = node.astext() self.body.append(r'\textsc{') diff --git a/sphinx/writers/manpage.py b/sphinx/writers/manpage.py index bc4da17ab..0aa0058c8 100644 --- a/sphinx/writers/manpage.py +++ b/sphinx/writers/manpage.py @@ -304,6 +304,11 @@ class ManualPageTranslator(BaseTranslator): def depart_literal_emphasis(self, node): return self.depart_emphasis(node) + def visit_literal_strong(self, node): + return self.visit_strong(node) + def depart_literal_strong(self, node): + return self.depart_strong(node) + def visit_abbreviation(self, node): pass def depart_abbreviation(self, node): diff --git a/sphinx/writers/texinfo.py b/sphinx/writers/texinfo.py index 7b70485aa..a930a5252 100644 --- a/sphinx/writers/texinfo.py +++ b/sphinx/writers/texinfo.py @@ -1207,6 +1207,11 @@ class TexinfoTranslator(nodes.NodeVisitor): def depart_literal_emphasis(self, node): self.body.append('}') + def visit_literal_strong(self, node): + self.body.append('@code{') + def depart_literal_strong(self, node): + self.body.append('}') + def visit_index(self, node): # terminate the line but don't prevent paragraph breaks if isinstance(node.parent, nodes.paragraph): diff --git a/sphinx/writers/text.py b/sphinx/writers/text.py index 57a40b296..a174bc269 100644 --- a/sphinx/writers/text.py +++ b/sphinx/writers/text.py @@ -762,6 +762,11 @@ class TextTranslator(nodes.NodeVisitor): def depart_strong(self, node): self.add_text('**') + def visit_literal_strong(self, node): + self.add_text('**') + def depart_literal_strong(self, node): + self.add_text('**') + def visit_abbreviation(self, node): self.add_text('') def depart_abbreviation(self, node):