diff --git a/CHANGES b/CHANGES index 8ab92c40186..ef1b2df9f8d 100644 --- a/CHANGES +++ b/CHANGES @@ -64,9 +64,13 @@ Deprecated * ``sphinx.writers.latex.Table.caption_footnotetexts`` is deprecated * ``sphinx.writers.latex.Table.header_footnotetexts`` is deprecated * ``sphinx.writers.latex.LaTeXWriter.footnotestack`` is deprecated +* ``sphinx.writers.latex.LaTeXWriter.in_container_literal_block`` is deprecated +* ``sphinx.writers.latex.LaTeXWriter.next_hyperlink_ids`` is deprecated * ``sphinx.writers.latex.LaTeXWriter.restrict_footnote()`` is deprecated * ``sphinx.writers.latex.LaTeXWriter.unrestrict_footnote()`` is deprecated -* ``LaTeXWriter.bibitems`` is deprecated +* ``sphinx.writers.latex.LaTeXWriter.push_hyperlink_ids()`` is deprecated +* ``sphinx.writers.latex.LaTeXWriter.pop_hyperlink_ids()`` is deprecated +* ``sphinx.writers.latex.LaTeXWriter.bibitems`` is deprecated * ``BuildEnvironment.load()`` is deprecated * ``BuildEnvironment.loads()`` is deprecated * ``BuildEnvironment.frompickle()`` is deprecated diff --git a/doc/extdev/index.rst b/doc/extdev/index.rst index d10ada464a8..42a999a067d 100644 --- a/doc/extdev/index.rst +++ b/doc/extdev/index.rst @@ -171,6 +171,16 @@ The following is a list of deprecated interface. - 3.0 - N/A + * - ``sphinx.writers.latex.LaTeXWriter.in_container_literal_block`` + - 1.8 + - 3.0 + - N/A + + * - ``sphinx.writers.latex.LaTeXWriter.next_hyperlink_ids`` + - 1.8 + - 3.0 + - N/A + * - ``sphinx.writers.latex.LaTeXWriter.restrict_footnote()`` - 1.8 - 3.0 @@ -181,6 +191,16 @@ The following is a list of deprecated interface. - 3.0 - N/A + * - ``sphinx.writers.latex.LaTeXWriter.push_hyperlink_ids()`` + - 1.8 + - 3.0 + - N/A + + * - ``sphinx.writers.latex.LaTeXWriter.pop_hyperlink_ids()`` + - 1.8 + - 3.0 + - N/A + * - ``sphinx.writers.latex.LaTeXWriter.bibitems`` - 1.8 - 3.0 diff --git a/sphinx/builders/latex/__init__.py b/sphinx/builders/latex/__init__.py index a98b8028969..83b4f15289e 100644 --- a/sphinx/builders/latex/__init__.py +++ b/sphinx/builders/latex/__init__.py @@ -20,7 +20,8 @@ from sphinx.builders import Builder from sphinx.builders.latex.transforms import ( BibliographyTransform, CitationReferenceTransform, MathReferenceTransform, - FootnoteDocnameUpdater, LaTeXFootnoteTransform, ShowUrlsTransform + FootnoteDocnameUpdater, LaTeXFootnoteTransform, LiteralBlockTransform, + ShowUrlsTransform, ) from sphinx.config import string_classes, ENUM from sphinx.environment import NoUri @@ -223,7 +224,8 @@ def apply_transforms(self, doctree): transformer.set_environment(self.env) transformer.add_transforms([BibliographyTransform, ShowUrlsTransform, - LaTeXFootnoteTransform]) + LaTeXFootnoteTransform, + LiteralBlockTransform]) transformer.apply_transforms() def finish(self): diff --git a/sphinx/builders/latex/nodes.py b/sphinx/builders/latex/nodes.py index c79adbae4e9..32ac7c6a0a0 100644 --- a/sphinx/builders/latex/nodes.py +++ b/sphinx/builders/latex/nodes.py @@ -12,6 +12,11 @@ from docutils import nodes +class captioned_literal_block(nodes.container): + """A node for a container of literal_block having a caption.""" + pass + + class footnotemark(nodes.Inline, nodes.Referential, nodes.TextElement): """A node represents ``\footnotemark``.""" pass diff --git a/sphinx/builders/latex/transforms.py b/sphinx/builders/latex/transforms.py index 635f2489c80..9c8a4192f24 100644 --- a/sphinx/builders/latex/transforms.py +++ b/sphinx/builders/latex/transforms.py @@ -13,7 +13,7 @@ from sphinx import addnodes from sphinx.builders.latex.nodes import ( - footnotemark, footnotetext, math_reference, thebibliography + captioned_literal_block, footnotemark, footnotetext, math_reference, thebibliography ) from sphinx.transforms import SphinxTransform @@ -566,3 +566,18 @@ def apply(self): if docname: refnode = math_reference('', docname=docname, target=node['reftarget']) node.replace_self(refnode) + + +class LiteralBlockTransform(SphinxTransform): + """Replace container nodes for literal_block by captioned_literal_block.""" + default_priority = 400 + + def apply(self): + # type: () -> None + if self.app.builder.name != 'latex': + return + + for node in self.document.traverse(nodes.container): + if node['literal_block'] is True: + newnode = captioned_literal_block('', *node.children, **node.attributes) + node.replace_self(newnode) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 9501d69d0f2..4c51097a7b7 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -25,7 +25,7 @@ from sphinx import addnodes from sphinx import highlighting -from sphinx.builders.latex.nodes import footnotetext +from sphinx.builders.latex.nodes import captioned_literal_block, footnotetext from sphinx.deprecation import RemovedInSphinx30Warning from sphinx.errors import SphinxError from sphinx.locale import admonitionlabels, _, __ @@ -58,6 +58,7 @@ nodes.literal_block, nodes.table, nodes.section, + captioned_literal_block, ) DEFAULT_SETTINGS = { @@ -465,7 +466,6 @@ def __init__(self, document, builder): self.in_production_list = 0 self.in_footnote = 0 self.in_caption = 0 - self.in_container_literal_block = 0 self.in_term = 0 self.needs_linetrimming = 0 self.in_minipage = 0 @@ -691,7 +691,6 @@ def declare_package(packagename, options=None): self.pending_footnotes = [] # type: List[nodes.footnote_reference] self.curfilestack = [] # type: List[unicode] self.handled_abbrs = set() # type: Set[unicode] - self.next_hyperlink_ids = {} # type: Dict[unicode, Set[unicode]] self.next_section_ids = set() # type: Set[unicode] def pushbody(self, newbody): @@ -705,15 +704,6 @@ def popbody(self): self.body = self.bodystack.pop() return body - def push_hyperlink_ids(self, figtype, ids): - # type: (unicode, Set[unicode]) -> None - hyperlink_ids = self.next_hyperlink_ids.setdefault(figtype, set()) - hyperlink_ids.update(ids) - - def pop_hyperlink_ids(self, figtype): - # type: (unicode) -> Set[unicode] - return self.next_hyperlink_ids.pop(figtype, set()) - def check_latex_elements(self): # type: () -> None for key in self.builder.config.latex_elements: @@ -1790,7 +1780,7 @@ def depart_figure(self, node): def visit_caption(self, node): # type: (nodes.Node) -> None self.in_caption += 1 - if self.in_container_literal_block: + if isinstance(node.parent, captioned_literal_block): self.body.append('\\sphinxSetupCaptionForVerbatim{') elif self.in_minipage and isinstance(node.parent, nodes.figure): self.body.append('\\captionof{figure}{') @@ -1883,35 +1873,13 @@ def add_target(id): self.body.append(self.hypertarget(id, anchor=anchor)) # skip if visitor for next node supports hyperlink + domain = self.builder.env.get_domain('std') next_node = node.next_node(ascend=True) if isinstance(next_node, HYPERLINK_SUPPORT_NODES): return + elif domain.get_enumerable_node_type(next_node) and domain.get_numfig_title(next_node): + return - # postpone the labels until after the sectioning command - parindex = node.parent.index(node) - try: - try: - next = node.parent[parindex + 1] - except IndexError: - # last node in parent, look at next after parent - # (for section of equal level) if it exists - if node.parent.parent is not None: - next = node.parent.parent[ - node.parent.parent.index(node.parent)] - else: - raise - domain = self.builder.env.get_domain('std') - figtype = domain.get_enumerable_node_type(next) - if figtype and domain.get_numfig_title(next): - ids = set() - # labels for figures go in the figure body, not before - if node.get('refid'): - ids.add(node['refid']) - ids.update(node['ids']) - self.push_hyperlink_ids(figtype, ids) - return - except IndexError: - pass if 'refuri' in node: return if node.get('refid'): @@ -2221,6 +2189,14 @@ def depart_footnotetext(self, node): # the \ignorespaces in particular for after table header use self.body.append('%\n\\end{footnotetext}\\ignorespaces ') + def visit_captioned_literal_block(self, node): + # type: (nodes.Node) -> None + pass + + def depart_captioned_literal_block(self, node): + # type: (nodes.Node) -> None + pass + def visit_literal_block(self, node): # type: (nodes.Node) -> None if node.rawsource != node.astext(): @@ -2229,9 +2205,11 @@ def visit_literal_block(self, node): self.body.append('\\begin{sphinxalltt}\n') else: labels = self.hypertarget_to(node) - # LaTeX code will insert \phantomsection prior to \label + if isinstance(node.parent, captioned_literal_block): + labels += self.hypertarget_to(node.parent) if labels and not self.in_footnote: self.body.append('\n\\def\\sphinxLiteralBlockLabel{' + labels + '}') + code = node.astext() lang = self.hlsettingstack[-1][0] linenos = code.count('\n') >= self.hlsettingstack[-1][1] - 1 @@ -2458,22 +2436,11 @@ def depart_compound(self, node): def visit_container(self, node): # type: (nodes.Node) -> None - if node.get('literal_block'): - self.in_container_literal_block += 1 - ids = '' # type: unicode - for id in self.pop_hyperlink_ids('code-block'): - ids += self.hypertarget(id, anchor=False) - if node['ids']: - # suppress with anchor=False \phantomsection insertion - ids += self.hypertarget(node['ids'][0], anchor=False) - # define label for use in caption. - if ids: - self.body.append('\n\\def\\sphinxLiteralBlockLabel{' + ids + '}\n') + pass def depart_container(self, node): # type: (nodes.Node) -> None - if node.get('literal_block'): - self.in_container_literal_block -= 1 + pass def visit_decoration(self, node): # type: (nodes.Node) -> None @@ -2603,6 +2570,32 @@ def bibitems(self): RemovedInSphinx30Warning) return [] + @property + def in_container_literal_block(self): + # type: () -> int + warnings.warn('LaTeXTranslator.in_container_literal_block is deprecated.', + RemovedInSphinx30Warning) + return 0 + + @property + def next_hyperlink_ids(self): + # type: () -> Dict + warnings.warn('LaTeXTranslator.next_hyperlink_ids is deprecated.', + RemovedInSphinx30Warning) + return {} + + def push_hyperlink_ids(self, figtype, ids): + # type: (unicode, Set[unicode]) -> None + warnings.warn('LaTeXTranslator.push_hyperlink_ids() is deprecated.', + RemovedInSphinx30Warning) + pass + + def pop_hyperlink_ids(self, figtype): + # type: (unicode) -> Set[unicode] + warnings.warn('LaTeXTranslator.pop_hyperlink_ids() is deprecated.', + RemovedInSphinx30Warning) + return set() + # Import old modules here for compatibility # They should be imported after `LaTeXTranslator` to avoid recursive import.