From 304c208d320c82f71d503fcb12854a0e558ffd7a Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 26 Apr 2018 01:13:55 +0900 Subject: [PATCH] Add BibliographyTransform to restruct doctree for LaTeX --- CHANGES | 1 + doc/extdev/index.rst | 5 +++ sphinx/builders/latex/__init__.py | 6 ++-- sphinx/builders/latex/nodes.py | 6 +++- sphinx/builders/latex/transforms.py | 45 ++++++++++++++++++++++++- sphinx/domains/std.py | 1 + sphinx/writers/latex.py | 51 ++++++++++++++--------------- 7 files changed, 84 insertions(+), 31 deletions(-) diff --git a/CHANGES b/CHANGES index 82c423f8b..9f0f3baa0 100644 --- a/CHANGES +++ b/CHANGES @@ -60,6 +60,7 @@ Deprecated * ``sphinx.writers.latex.LaTeXWriter.footnotestack`` is deprecated * ``sphinx.writers.latex.LaTeXWriter.restrict_footnote()`` is deprecated * ``sphinx.writers.latex.LaTeXWriter.unrestrict_footnote()`` is deprecated +* ``LaTeXWriter.bibitems`` is deprecated For more details, see `deprecation APIs list `_ diff --git a/doc/extdev/index.rst b/doc/extdev/index.rst index f179a24c8..dfe8dbaf0 100644 --- a/doc/extdev/index.rst +++ b/doc/extdev/index.rst @@ -151,6 +151,11 @@ The following is a list of deprecated interface. - 3.0 - - + * - ``sphinx.writers.latex.LaTeXWriter.bibitems`` + - 1.8 + - 3.0 + - Nothing + * - ``sphinx.application.CONFIG_FILENAME`` - 1.8 - 3.0 diff --git a/sphinx/builders/latex/__init__.py b/sphinx/builders/latex/__init__.py index dd577668d..3e95d18e6 100644 --- a/sphinx/builders/latex/__init__.py +++ b/sphinx/builders/latex/__init__.py @@ -20,7 +20,8 @@ from six import text_type from sphinx import package_dir, addnodes, highlighting from sphinx.builders import Builder from sphinx.builders.latex.transforms import ( - FootnoteDocnameUpdater, LaTeXFootnoteTransform, ShowUrlsTransform + BibliographyTransform, FootnoteDocnameUpdater, LaTeXFootnoteTransform, + ShowUrlsTransform ) from sphinx.config import string_classes, ENUM from sphinx.environment import NoUri @@ -219,7 +220,8 @@ class LaTeXBuilder(Builder): # type: (nodes.document) -> None transformer = SphinxTransformer(doctree) transformer.set_environment(self.env) - transformer.add_transforms([ShowUrlsTransform, + transformer.add_transforms([BibliographyTransform, + ShowUrlsTransform, LaTeXFootnoteTransform]) transformer.apply_transforms() diff --git a/sphinx/builders/latex/nodes.py b/sphinx/builders/latex/nodes.py index bc05538ae..80734820d 100644 --- a/sphinx/builders/latex/nodes.py +++ b/sphinx/builders/latex/nodes.py @@ -3,7 +3,7 @@ sphinx.builders.latex.nodes ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - docutils nodes for LaTeX builder. + Additional nodes for LaTeX writer. :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. @@ -20,4 +20,8 @@ class footnotemark(nodes.Inline, nodes.Referential, nodes.TextElement): class footnotetext(nodes.General, nodes.BackLinkable, nodes.Element, nodes.Labeled, nodes.Targetable): """A node represents ``\footnotetext``.""" + + +class thebibliography(nodes.container): + """A node for wrapping bibliographies.""" pass diff --git a/sphinx/builders/latex/transforms.py b/sphinx/builders/latex/transforms.py index 7e05e1c5a..7eb6aaadb 100644 --- a/sphinx/builders/latex/transforms.py +++ b/sphinx/builders/latex/transforms.py @@ -12,7 +12,7 @@ from docutils import nodes from sphinx import addnodes -from sphinx.builders.latex.nodes import footnotemark, footnotetext +from sphinx.builders.latex.nodes import footnotemark, footnotetext, thebibliography from sphinx.transforms import SphinxTransform if False: @@ -476,3 +476,46 @@ class LaTeXFootnoteVisitor(nodes.NodeVisitor): return footnote return None + + +class BibliographyTransform(SphinxTransform): + """Gather bibliography entries to tail of document. + + Before:: + + + + blah blah blah + + ... + + blah blah blah + + ... + ... + + After:: + + + + blah blah blah + + blah blah blah + ... + + + ... + + ... + """ + default_priority = 750 + + def apply(self): + # type: () -> None + citations = thebibliography() + for node in self.document.traverse(nodes.citation): + node.parent.remove(node) + citations += node + + if len(citations) > 0: + self.document += citations diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py index 97433b12e..6518091f6 100644 --- a/sphinx/domains/std.py +++ b/sphinx/domains/std.py @@ -590,6 +590,7 @@ class StandardDomain(Domain): def note_citations(self, env, docname, document): # type: (BuildEnvironment, unicode, nodes.Node) -> None for node in document.traverse(nodes.citation): + node['docname'] = docname label = node[0].astext() if label in self.data['citations']: path = env.doc2path(self.data['citations'][label][0]) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 595bbcd88..9898defab 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -660,7 +660,6 @@ class LaTeXTranslator(nodes.NodeVisitor): builder.config.pygments_style, builder.config.trim_doctest_flags) self.context = [] # type: List[Any] self.descstack = [] # type: List[unicode] - self.bibitems = [] # type: List[List[unicode]] self.table = None # type: Table self.next_table_colspec = None # type: unicode # stack of [language, linenothreshold] settings per file @@ -902,20 +901,7 @@ class LaTeXTranslator(nodes.NodeVisitor): def depart_document(self, node): # type: (nodes.Node) -> None - if self.bibitems: - widest_label = "" # type: unicode - for bi in self.bibitems: - if len(widest_label) < len(bi[0]): - widest_label = bi[0] - self.body.append(u'\n\\begin{sphinxthebibliography}{%s}\n' % widest_label) - for bi in self.bibitems: - target = self.hypertarget(bi[2] + ':' + bi[3], - withdoc=False) - self.body.append(u'\\bibitem[%s]{%s}{%s %s}\n' % - (self.encode(bi[0]), self.idescape(bi[0]), - target, bi[1])) - self.body.append(u'\\end{sphinxthebibliography}\n') - self.bibitems = [] + pass def visit_start_of_file(self, node): # type: (nodes.Node) -> None @@ -1282,10 +1268,6 @@ class LaTeXTranslator(nodes.NodeVisitor): def visit_label(self, node): # type: (nodes.Node) -> None - if isinstance(node.parent, nodes.citation): - self.bibitems[-1][0] = node.astext() - self.bibitems[-1][2] = self.curfilestack[-1] - self.bibitems[-1][3] = node.parent['ids'][0] raise nodes.SkipNode def visit_tabular_col_spec(self, node): @@ -2149,19 +2131,25 @@ class LaTeXTranslator(nodes.NodeVisitor): # type: (nodes.Node) -> None self.body.append('}') + def visit_thebibliography(self, node): + # type: (nodes.Node) -> None + longest_label = max((subnode[0].astext() for subnode in node), key=len) + self.body.append(u'\n\\begin{sphinxthebibliography}{%s}\n' % longest_label) + + def depart_thebibliography(self, node): + # type: (nodes.Node) -> None + self.body.append(u'\\end{sphinxthebibliography}\n') + def visit_citation(self, node): # type: (nodes.Node) -> None - # TODO maybe use cite bibitems - # bibitem: [citelabel, citetext, docname, citeid] - self.bibitems.append(['', '', '', '']) - self.context.append(len(self.body)) + label = node[0].astext() + target = self.hypertarget(node['docname'] + ':' + node['ids'][0], withdoc=False) + self.body.append(u'\\bibitem[%s]{%s}{%s ' % + (self.encode(label), self.idescape(label), target)) def depart_citation(self, node): # type: (nodes.Node) -> None - size = self.context.pop() - text = ''.join(self.body[size:]) - del self.body[size:] - self.bibitems[-1][1] = text + self.body.append('}\n') def visit_citation_reference(self, node): # type: (nodes.Node) -> None @@ -2546,6 +2534,15 @@ class LaTeXTranslator(nodes.NodeVisitor): # type: (nodes.Node) -> None raise NotImplementedError('Unknown node: ' + node.__class__.__name__) + # --------- METHODS FOR COMPATIBILITY -------------------------------------- + + @property + def bibitems(self): + # type: () -> List[List[unicode]] + warnings.warn('LaTeXTranslator.bibitems() is deprecated.', + RemovedInSphinx30Warning) + return [] + # Import old modules here for compatibility # They should be imported after `LaTeXTranslator` to avoid recursive import.