diff --git a/CHANGES b/CHANGES index 7469e42f8..c6f345323 100644 --- a/CHANGES +++ b/CHANGES @@ -85,9 +85,24 @@ Documentation Release 1.3.6 (in development) ============================== +Features added +-------------- + +* #1873, #1876, #2278: Add ``page_source_suffix`` html context variable. This should be + introduced with :confval:`source_parsers` feature. Thanks for Eric Holscher. + + Bugs fixed ---------- +* #2265: Fix babel is used in spite of disabling it on ``latex_elements`` +* #2295: Avoid mutating dictionary errors while enumerating members in autodoc + with Python 3 +* #2291: Fix pdflatex "Counter too large" error from footnotes inside tables of contents +* #2292: Fix some footnotes disappear from LaTeX output +* #2287: ``sphinx.transforms.Locale`` always uses rst parser. Sphinx i18n feature should + support parsers that specified source_parsers. + Release 1.3.5 (released Jan 24, 2016) ===================================== @@ -103,7 +118,8 @@ Bugs fixed * #2243: Ignore strange docstring types for classes, do not crash * #2247: Fix #2205 breaks make html for definition list with classifiers that contains regular-expression like string -* #1565: Show warning if Pygments throws an ErrorToken +* #1565: Sphinx will now emit a warning that highlighting was skipped if the syntax + is incorrect for `code-block`, `literalinclude` and so on. * #2211: Fix paragraphs in table cell doesn't work in Latex output * #2253: ``:pyobject:`` option of ``literalinclude`` directive can't detect indented body block when the block starts with blank or comment lines. diff --git a/doc/intl.rst b/doc/intl.rst index bd4f9e889..2290b0fde 100644 --- a/doc/intl.rst +++ b/doc/intl.rst @@ -106,17 +106,23 @@ This section describe a easy way to translate with sphinx-intl. #. Translate your po files under `./locale//LC_MESSAGES/`. -#. Build mo files and make translated document. +#. make translated document. You need a :confval:`language` parameter in ``conf.py`` or you may also specify the parameter on the command line:: - $ sphinx-intl build $ make -e SPHINXOPTS="-D language='de'" html Congratulations! You got the translated documentation in the ``_build/html`` directory. +.. versionadded:: 1.3 + + sphinx-build that is invoked by make command will build po files into mo files. + + If you are using 1.2.x or earlier, please invoke ``sphinx-intl build`` command + before make command. + Translating ^^^^^^^^^^^ @@ -251,9 +257,8 @@ easy to fetch and push translations. ... Done. - Build po files into mo and make html:: + Invoke make html:: - $ sphinx-intl build $ make -e SPHINXOPTS="-D language='de'" html diff --git a/sphinx/application.py b/sphinx/application.py index b88fb311c..7f4aaa1bb 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -35,7 +35,8 @@ from sphinx.errors import SphinxError, SphinxWarning, ExtensionError, \ from sphinx.domains import ObjType, BUILTIN_DOMAINS from sphinx.domains.std import GenericObject, Target, StandardDomain from sphinx.builders import BUILTIN_BUILDERS -from sphinx.environment import BuildEnvironment, SphinxStandaloneReader +from sphinx.environment import BuildEnvironment +from sphinx.io import SphinxStandaloneReader from sphinx.util import pycompat # noqa: imported for side-effects from sphinx.util import import_object from sphinx.util.tags import Tags diff --git a/sphinx/environment.py b/sphinx/environment.py index ad07b642a..13822a755 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -23,24 +23,23 @@ from os import path from glob import glob from itertools import groupby -from six import iteritems, itervalues, text_type, class_types, string_types, next +from six import iteritems, itervalues, text_type, class_types, next from six.moves import cPickle as pickle from docutils import nodes -from docutils.io import FileInput, NullOutput +from docutils.io import NullOutput from docutils.core import Publisher from docutils.utils import Reporter, relative_path, get_source_line -from docutils.readers import standalone from docutils.parsers.rst import roles, directives from docutils.parsers.rst.languages import en as english from docutils.parsers.rst.directives.html import MetaBody -from docutils.writers import UnfilteredWriter from docutils.frontend import OptionParser from sphinx import addnodes +from sphinx.io import SphinxStandaloneReader, SphinxDummyWriter, SphinxFileInput from sphinx.util import url_re, get_matching_docs, docname_join, split_into, \ - FilenameUniqDict, get_figtype, import_object, split_index_msg, split_docinfo + FilenameUniqDict, get_figtype, import_object, split_index_msg from sphinx.util.nodes import clean_astext, make_refnode, WarningStream, is_translatable -from sphinx.util.osutil import SEP, getcwd, fs_encoding +from sphinx.util.osutil import SEP, getcwd, fs_encoding, ensuredir from sphinx.util.i18n import find_catalog_files from sphinx.util.console import bold, purple from sphinx.util.matching import compile_matchers @@ -49,12 +48,7 @@ from sphinx.util.websupport import is_commentable from sphinx.errors import SphinxError, ExtensionError from sphinx.locale import _ from sphinx.versioning import add_uids, merge_doctrees -from sphinx.transforms import ( - DefaultSubstitutions, MoveModuleTargets, ApplySourceWorkaround, - HandleCodeBlocks, AutoNumbering, SortIds, CitationReferences, Locale, - RemoveTranslatableInline, SphinxContentsFilter, ExtraTranslatableNodes, -) - +from sphinx.transforms import SphinxContentsFilter orig_role_function = roles.role orig_directive_function = directives.directive @@ -97,77 +91,6 @@ class NoUri(Exception): pass -class SphinxStandaloneReader(standalone.Reader): - """ - Add our own transforms. - """ - transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, Locale, CitationReferences, - DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, - AutoNumbering, SortIds, RemoveTranslatableInline] - - def __init__(self, app, parsers={}, *args, **kwargs): - standalone.Reader.__init__(self, *args, **kwargs) - self.parser_map = {} - for suffix, parser_class in parsers.items(): - if isinstance(parser_class, string_types): - parser_class = import_object(parser_class, 'source parser') - parser = parser_class() - if hasattr(parser, 'set_application'): - parser.set_application(app) - self.parser_map[suffix] = parser - - def read(self, source, parser, settings): - self.source = source - - for suffix in self.parser_map: - if source.source_path.endswith(suffix): - self.parser = self.parser_map[suffix] - break - - if not self.parser: - self.parser = parser - self.settings = settings - self.input = self.source.read() - self.parse() - return self.document - - def get_transforms(self): - return standalone.Reader.get_transforms(self) + self.transforms - - -class SphinxDummyWriter(UnfilteredWriter): - supported = ('html',) # needed to keep "meta" nodes - - def translate(self): - pass - - -class SphinxFileInput(FileInput): - def __init__(self, app, env, *args, **kwds): - self.app = app - self.env = env - kwds['error_handler'] = 'sphinx' # py3: handle error on open. - FileInput.__init__(self, *args, **kwds) - - def decode(self, data): - if isinstance(data, text_type): # py3: `data` already decoded. - return data - return data.decode(self.encoding, 'sphinx') # py2: decoding - - def read(self): - data = FileInput.read(self) - if self.app: - arg = [data] - self.app.emit('source-read', self.env.docname, arg) - data = arg[0] - docinfo, data = split_docinfo(data) - if self.env.config.rst_epilog: - data = data + '\n' + self.env.config.rst_epilog + '\n' - if self.env.config.rst_prolog: - data = self.env.config.rst_prolog + '\n' + data - return docinfo + data - - class BuildEnvironment: """ The environment in which the ReST files are translated. @@ -859,9 +782,7 @@ class BuildEnvironment: # save the parsed doctree doctree_filename = self.doc2path(docname, self.doctreedir, '.doctree') - dirname = path.dirname(doctree_filename) - if not path.isdir(dirname): - os.makedirs(dirname) + ensuredir(path.dirname(doctree_filename)) f = open(doctree_filename, 'wb') try: pickle.dump(doctree, f, pickle.HIGHEST_PROTOCOL) diff --git a/sphinx/io.py b/sphinx/io.py new file mode 100644 index 000000000..301a0da31 --- /dev/null +++ b/sphinx/io.py @@ -0,0 +1,125 @@ +# -*- coding: utf-8 -*- +""" + sphinx.io + ~~~~~~~~~ + + Input/Output files + + :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" +from docutils.io import FileInput +from docutils.readers import standalone +from docutils.writers import UnfilteredWriter +from six import string_types, text_type + +from sphinx.transforms import ApplySourceWorkaround, ExtraTranslatableNodes, Locale, \ + CitationReferences, DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, \ + AutoNumbering, SortIds, RemoveTranslatableInline +from sphinx.util import import_object, split_docinfo + + +class SphinxBaseReader(standalone.Reader): + """ + Add our source parsers + """ + def __init__(self, app, parsers={}, *args, **kwargs): + standalone.Reader.__init__(self, *args, **kwargs) + self.parser_map = {} + for suffix, parser_class in parsers.items(): + if isinstance(parser_class, string_types): + parser_class = import_object(parser_class, 'source parser') + parser = parser_class() + if hasattr(parser, 'set_application'): + parser.set_application(app) + self.parser_map[suffix] = parser + + def read(self, source, parser, settings): + self.source = source + + for suffix in self.parser_map: + if source.source_path.endswith(suffix): + self.parser = self.parser_map[suffix] + break + + if not self.parser: + self.parser = parser + self.settings = settings + self.input = self.source.read() + self.parse() + return self.document + + def get_transforms(self): + return standalone.Reader.get_transforms(self) + self.transforms + + +class SphinxStandaloneReader(SphinxBaseReader): + """ + Add our own transforms. + """ + transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, Locale, CitationReferences, + DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, + AutoNumbering, SortIds, RemoveTranslatableInline] + + +class SphinxI18nReader(SphinxBaseReader): + """ + Replacer for document.reporter.get_source_and_line method. + + reST text lines for translation do not have the original source line number. + This class provides the correct line numbers when reporting. + """ + + transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences, + DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, + AutoNumbering, SortIds, RemoveTranslatableInline] + + def __init__(self, *args, **kwargs): + SphinxBaseReader.__init__(self, *args, **kwargs) + self.lineno = None + + def set_lineno_for_reporter(self, lineno): + self.lineno = lineno + + def new_document(self): + document = SphinxBaseReader.new_document(self) + reporter = document.reporter + + def get_source_and_line(lineno=None): + return reporter.source, self.lineno + + reporter.get_source_and_line = get_source_and_line + return document + + +class SphinxDummyWriter(UnfilteredWriter): + supported = ('html',) # needed to keep "meta" nodes + + def translate(self): + pass + + +class SphinxFileInput(FileInput): + def __init__(self, app, env, *args, **kwds): + self.app = app + self.env = env + kwds['error_handler'] = 'sphinx' # py3: handle error on open. + FileInput.__init__(self, *args, **kwds) + + def decode(self, data): + if isinstance(data, text_type): # py3: `data` already decoded. + return data + return data.decode(self.encoding, 'sphinx') # py2: decoding + + def read(self): + data = FileInput.read(self) + if self.app: + arg = [data] + self.app.emit('source-read', self.env.docname, arg) + data = arg[0] + docinfo, data = split_docinfo(data) + if self.env.config.rst_epilog: + data = data + '\n' + self.env.config.rst_epilog + '\n' + if self.env.config.rst_prolog: + data = self.env.config.rst_prolog + '\n' + data + return docinfo + data diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index 7d7271824..e3f226e19 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -9,6 +9,7 @@ :license: BSD, see LICENSE for details. """ from __future__ import print_function +from __future__ import absolute_import import re import os diff --git a/sphinx/transforms.py b/sphinx/transforms.py index 4619449e7..f8b0bf984 100644 --- a/sphinx/transforms.py +++ b/sphinx/transforms.py @@ -12,8 +12,8 @@ from os import path from docutils import nodes -from docutils.utils import new_document, relative_path -from docutils.parsers.rst import Parser as RSTParser +from docutils.io import StringInput +from docutils.utils import relative_path from docutils.transforms import Transform from docutils.transforms.parts import ContentsFilter @@ -202,21 +202,35 @@ class ExtraTranslatableNodes(Transform): node['translatable'] = True -class CustomLocaleReporter(object): +def publish_msgstr(app, source, source_path, source_line, config, settings): + """Publish msgstr (single line) into docutils document + + :param sphinx.application.Sphinx app: sphinx application + :param unicode source: source text + :param unicode source_path: source path for warning indication + :param source_line: source line for warning indication + :param sphinx.config.Config config: sphinx config + :param docutils.frontend.Values settings: docutils settings + :return: document + :rtype: docutils.nodes.document """ - Replacer for document.reporter.get_source_and_line method. - - reST text lines for translation do not have the original source line number. - This class provides the correct line numbers when reporting. - """ - def __init__(self, source, line): - self.source, self.line = source, line - - def set_reporter(self, document): - document.reporter.get_source_and_line = self.get_source_and_line - - def get_source_and_line(self, lineno=None): - return self.source, self.line + from sphinx.io import SphinxI18nReader + reader = SphinxI18nReader( + app=app, + parsers=config.source_parsers, + parser_name='restructuredtext', # default parser + ) + reader.set_lineno_for_reporter(source_line) + doc = reader.read( + source=StringInput(source=source, source_path=source_path), + parser=reader.parser, + settings=settings, + ) + try: + doc = doc[0] + except IndexError: # empty node + pass + return doc class Locale(Transform): @@ -244,8 +258,6 @@ class Locale(Transform): if not has_catalog: return - parser = RSTParser() - # phase1: replace reference ids with translated names for node, msg in extract_messages(self.document): msgstr = catalog.gettext(msg) @@ -267,13 +279,8 @@ class Locale(Transform): if isinstance(node, LITERAL_TYPE_NODES): msgstr = '::\n\n' + indent(msgstr, ' '*3) - patch = new_document(source, settings) - CustomLocaleReporter(node.source, node.line).set_reporter(patch) - parser.parse(msgstr, patch) - try: - patch = patch[0] - except IndexError: # empty node - pass + patch = publish_msgstr( + env.app, msgstr, source, node.line, env.config, settings) # XXX doctest and other block markup if not isinstance(patch, nodes.paragraph): continue # skip for now @@ -390,13 +397,8 @@ class Locale(Transform): if isinstance(node, LITERAL_TYPE_NODES): msgstr = '::\n\n' + indent(msgstr, ' '*3) - patch = new_document(source, settings) - CustomLocaleReporter(node.source, node.line).set_reporter(patch) - parser.parse(msgstr, patch) - try: - patch = patch[0] - except IndexError: # empty node - pass + patch = publish_msgstr( + env.app, msgstr, source, node.line, env.config, settings) # XXX doctest and other block markup if not isinstance( patch, diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py index f8d2d0a93..ccea95777 100644 --- a/sphinx/util/nodes.py +++ b/sphinx/util/nodes.py @@ -141,9 +141,10 @@ def find_source_node(node): return pnode.source -def traverse_parent(node): +def traverse_parent(node, cls=None): while node: - yield node + if cls is None or isinstance(node, cls): + yield node node = node.parent diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 6676bfc65..3510c6358 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -25,7 +25,7 @@ from sphinx import highlighting from sphinx.errors import SphinxError from sphinx.locale import admonitionlabels, _ from sphinx.util import split_into -from sphinx.util.nodes import clean_astext +from sphinx.util.nodes import clean_astext, traverse_parent from sphinx.util.osutil import ustrftime from sphinx.util.texescape import tex_escape_map, tex_replace_map from sphinx.util.smartypants import educate_quotes_latex @@ -174,11 +174,15 @@ class ShowUrlsTransform(object): if node.astext() != uri: index = node.parent.index(node) if show_urls == 'footnote': - footnote_nodes = self.create_footnote(uri) - for i, fn in enumerate(footnote_nodes): - node.parent.insert(index + i + 1, fn) + if list(traverse_parent(node, nodes.topic)): + # should not expand references in topics + pass + else: + footnote_nodes = self.create_footnote(uri) + for i, fn in enumerate(footnote_nodes): + node.parent.insert(index + i + 1, fn) - self.expanded = True + self.expanded = True else: # all other true values (b/w compat) textnode = nodes.Text(" (%s)" % uri) node.parent.insert(index + 1, textnode) @@ -210,9 +214,14 @@ class ShowUrlsTransform(object): def is_auto_footnote(node): return isinstance(node, nodes.footnote) and node.get('auto') - def footnote_ref_by(ids): + def footnote_ref_by(node): + ids = node['ids'] + parent = list(traverse_parent(node, (nodes.document, addnodes.start_of_file)))[0] + def is_footnote_ref(node): - return isinstance(node, nodes.footnote_reference) and ids[0] == node['refid'] + return (isinstance(node, nodes.footnote_reference) and + ids[0] == node['refid'] and + parent in list(traverse_parent(node))) return is_footnote_ref @@ -231,7 +240,7 @@ class ShowUrlsTransform(object): footnote['names'].remove(old_label) footnote['names'].append(label) - for footnote_ref in self.document.traverse(footnote_ref_by(footnote['ids'])): + for footnote_ref in self.document.traverse(footnote_ref_by(footnote)): footnote_ref.remove(footnote_ref[0]) footnote_ref += nodes.Text(label) @@ -378,12 +387,6 @@ class LaTeXTranslator(nodes.NodeVisitor): return '\\usepackage{%s}' % (packagename,) usepackages = (declare_package(*p) for p in builder.usepackages) self.elements['usepackages'] += "\n".join(usepackages) - if getattr(document.settings, 'contentsname', None): - self.elements['contentsname'] = \ - self.babel_renewcommand('\\contentsname', document.settings.contentsname) - self.elements['pageautorefname'] = \ - self.babel_defmacro('\\pageautorefname', self.encode(_('page'))) - self.elements['numfig_format'] = self.generate_numfig_format(builder) # allow the user to override them all self.elements.update(builder.config.latex_elements) if self.elements['extraclassoptions']: @@ -396,6 +399,12 @@ class LaTeXTranslator(nodes.NodeVisitor): else: self.elements['tocdepth'] = ('\\setcounter{tocdepth}{%d}' % (document['tocdepth'] - 1)) + if getattr(document.settings, 'contentsname', None): + self.elements['contentsname'] = \ + self.babel_renewcommand('\\contentsname', document.settings.contentsname) + self.elements['pageautorefname'] = \ + self.babel_defmacro('\\pageautorefname', self.encode(_('page'))) + self.elements['numfig_format'] = self.generate_numfig_format(builder) self.highlighter = highlighting.PygmentsBridge( 'latex', diff --git a/tests/roots/test-footnotes/bar.rst b/tests/roots/test-footnotes/bar.rst new file mode 100644 index 000000000..660c66306 --- /dev/null +++ b/tests/roots/test-footnotes/bar.rst @@ -0,0 +1,6 @@ +bar +=== + +Same footnote number [1]_ in bar.rst + +.. [1] footnote in bar diff --git a/tests/roots/test-footnotes/baz.rst b/tests/roots/test-footnotes/baz.rst new file mode 100644 index 000000000..af496c5f6 --- /dev/null +++ b/tests/roots/test-footnotes/baz.rst @@ -0,0 +1,6 @@ +baz +=== + +Auto footnote number [#]_ in baz.rst + +.. [#] footnote in baz diff --git a/tests/roots/test-footnotes/index.rst b/tests/roots/test-footnotes/index.rst index a20052037..3a8bc25c5 100644 --- a/tests/roots/test-footnotes/index.rst +++ b/tests/roots/test-footnotes/index.rst @@ -2,6 +2,14 @@ test-footenotes =============== +.. toctree:: + + bar + baz + +.. contents:: + :local: + The section with a reference to [AuthorYear]_ ============================================= diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index 38dc665c2..d7d208c58 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -264,6 +264,25 @@ def test_numref_with_language_ja(app, status, warning): assert '\\hyperref[baz:code22]{Code-\\ref{baz:code22}}' in result +@with_app(buildername='latex', testroot='numfig', + confoverrides={'numfig': True, 'language': 'ru', 'latex_elements': {'babel': ''}}) +def test_numref_on_bable_disabled(app, status, warning): + app.builder.build_all() + result = (app.outdir / 'Python.tex').text(encoding='utf8') + print(result) + print(status.getvalue()) + print(warning.getvalue()) + assert '\\renewcommand{\\figurename}{Fig. }' in result + assert '\\renewcommand{\\tablename}{Table }' in result + assert '\\SetupFloatingEnvironment{literal-block}{name=Listing }' in result + assert '\\hyperref[index:fig1]{Fig. \\ref{index:fig1}}' in result + assert '\\hyperref[baz:fig22]{Figure\\ref{baz:fig22}}' in result + assert '\\hyperref[index:table-1]{Table \\ref{index:table-1}}' in result + assert '\\hyperref[baz:table22]{Table:\\ref{baz:table22}}' in result + assert '\\hyperref[index:code-1]{Listing \\ref{index:code-1}}' in result + assert '\\hyperref[baz:code22]{Code-\\ref{baz:code22}}' in result + + @with_app(buildername='latex') def test_latex_add_latex_package(app, status, warning): app.add_latex_package('foo') @@ -423,6 +442,15 @@ def test_latex_show_urls_is_inline(app, status, warning): print(result) print(status.getvalue()) print(warning.getvalue()) + assert 'Same footnote number \\footnote[1]{\nfootnote in bar\n} in bar.rst' in result + assert 'Auto footnote number \\footnote[1]{\nfootnote in baz\n} in baz.rst' in result + assert ('\\phantomsection\\label{index:id26}{\\hyperref[index:the\\string-section' + '\\string-with\\string-a\\string-reference\\string-to\\string-authoryear]' + '{\\emph{The section with a reference to \\phantomsection\\label{index:id1}' + '{\\hyperref[index:authoryear]{\\emph{{[}AuthorYear{]}}}}}}}' in result) + assert ('\\phantomsection\\label{index:id27}{\\hyperref[index:the\\string-section' + '\\string-with\\string-a\\string-reference\\string-to]{\\emph{The section ' + 'with a reference to }}}' in result) assert 'First footnote: \\footnote[2]{\nFirst\n}' in result assert 'Second footnote: \\footnote[1]{\nSecond\n}' in result assert '\\href{http://sphinx-doc.org/}{Sphinx} (http://sphinx-doc.org/)' in result @@ -449,20 +477,29 @@ def test_latex_show_urls_is_footnote(app, status, warning): print(result) print(status.getvalue()) print(warning.getvalue()) - assert 'First footnote: \\footnote[2]{\nFirst\n}' in result + assert 'Same footnote number \\footnote[1]{\nfootnote in bar\n} in bar.rst' in result + assert 'Auto footnote number \\footnote[2]{\nfootnote in baz\n} in baz.rst' in result + assert ('\\phantomsection\\label{index:id26}{\\hyperref[index:the\\string-section' + '\\string-with\\string-a\\string-reference\\string-to\\string-authoryear]' + '{\\emph{The section with a reference to \\phantomsection\\label{index:id1}' + '{\\hyperref[index:authoryear]{\\emph{{[}AuthorYear{]}}}}}}}' in result) + assert ('\\phantomsection\\label{index:id27}{\\hyperref[index:the\\string-section' + '\\string-with\\string-a\\string-reference\\string-to]{\\emph{The section ' + 'with a reference to }}}' in result) + assert 'First footnote: \\footnote[3]{\nFirst\n}' in result assert 'Second footnote: \\footnote[1]{\nSecond\n}' in result assert ('\\href{http://sphinx-doc.org/}{Sphinx}' - '\\footnote[3]{\nhttp://sphinx-doc.org/\n}' in result) - assert 'Third footnote: \\footnote[5]{\nThird\n}' in result + '\\footnote[4]{\nhttp://sphinx-doc.org/\n}' in result) + assert 'Third footnote: \\footnote[6]{\nThird\n}' in result assert ('\\href{http://sphinx-doc.org/~test/}{URL including tilde}' - '\\footnote[4]{\nhttp://sphinx-doc.org/\\textasciitilde{}test/\n}' in result) - assert ('\\item[{\\href{http://sphinx-doc.org/}{URL in term}\\protect\\footnotemark[7]}] ' - '\\leavevmode\\footnotetext[7]{\nhttp://sphinx-doc.org/\n}\nDescription' in result) - assert ('\\item[{Footnote in term \\protect\\footnotemark[9]}] ' - '\\leavevmode\\footnotetext[9]{\nFootnote in term\n}\nDescription' in result) - assert ('\\item[{\\href{http://sphinx-doc.org/}{Term in deflist}\\protect' - '\\footnotemark[8]}] ' + '\\footnote[5]{\nhttp://sphinx-doc.org/\\textasciitilde{}test/\n}' in result) + assert ('\\item[{\\href{http://sphinx-doc.org/}{URL in term}\\protect\\footnotemark[8]}] ' '\\leavevmode\\footnotetext[8]{\nhttp://sphinx-doc.org/\n}\nDescription' in result) + assert ('\\item[{Footnote in term \\protect\\footnotemark[10]}] ' + '\\leavevmode\\footnotetext[10]{\nFootnote in term\n}\nDescription' in result) + assert ('\\item[{\\href{http://sphinx-doc.org/}{Term in deflist}\\protect' + '\\footnotemark[9]}] ' + '\\leavevmode\\footnotetext[9]{\nhttp://sphinx-doc.org/\n}\nDescription' in result) assert ('\\href{https://github.com/sphinx-doc/sphinx}' '{https://github.com/sphinx-doc/sphinx}\n' in result) assert ('\\href{mailto:sphinx-dev@googlegroups.com}' @@ -477,6 +514,15 @@ def test_latex_show_urls_is_no(app, status, warning): print(result) print(status.getvalue()) print(warning.getvalue()) + assert 'Same footnote number \\footnote[1]{\nfootnote in bar\n} in bar.rst' in result + assert 'Auto footnote number \\footnote[1]{\nfootnote in baz\n} in baz.rst' in result + assert ('\\phantomsection\\label{index:id26}{\\hyperref[index:the\\string-section' + '\\string-with\\string-a\\string-reference\\string-to\\string-authoryear]' + '{\\emph{The section with a reference to \\phantomsection\\label{index:id1}' + '{\\hyperref[index:authoryear]{\\emph{{[}AuthorYear{]}}}}}}}' in result) + assert ('\\phantomsection\\label{index:id27}{\\hyperref[index:the\\string-section' + '\\string-with\\string-a\\string-reference\\string-to]{\\emph{The section ' + 'with a reference to }}}' in result) assert 'First footnote: \\footnote[2]{\nFirst\n}' in result assert 'Second footnote: \\footnote[1]{\nSecond\n}' in result assert '\\href{http://sphinx-doc.org/}{Sphinx}' in result