mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge pull request #2159 from sphinx-doc/1237_footnote_in_deflist
Fix #1237 footnotes not working in definition list in LaTeX
This commit is contained in:
commit
157375baa3
1
CHANGES
1
CHANGES
@ -10,6 +10,7 @@ Bugs fixed
|
||||
* #1833: Fix email addresses is showed again if latex_show_urls is not None
|
||||
* #2176: sphinx.ext.graphviz: use <object> instead of <img> to embed svg
|
||||
* #967: Fix SVG inheritance diagram is not hyperlinked (clickable)
|
||||
* #1237: Fix footnotes not working in definition list in LaTeX
|
||||
|
||||
|
||||
Release 1.3.3 (released Dec 2, 2015)
|
||||
|
@ -69,6 +69,8 @@ FOOTER = r'''
|
||||
\end{document}
|
||||
'''
|
||||
|
||||
URI_SCHEMES = ('mailto:', 'http:', 'https:', 'ftp:')
|
||||
|
||||
|
||||
class collected_footnote(nodes.footnote):
|
||||
"""Footnotes that are collected are assigned this class."""
|
||||
@ -98,6 +100,8 @@ class LaTeXWriter(writers.Writer):
|
||||
self.builder.translator_class or LaTeXTranslator)
|
||||
|
||||
def translate(self):
|
||||
transform = ShowUrlsTransform(self.document)
|
||||
transform.apply()
|
||||
visitor = self.translator_class(self.document, self.builder)
|
||||
self.document.walkabout(visitor)
|
||||
self.output = visitor.astext()
|
||||
@ -126,6 +130,99 @@ if hasattr(Babel, '_ISO639_TO_BABEL'):
|
||||
Babel._ISO639_TO_BABEL['sl'] = 'slovene'
|
||||
|
||||
|
||||
class ShowUrlsTransform(object):
|
||||
expanded = False
|
||||
|
||||
def __init__(self, document):
|
||||
self.document = document
|
||||
|
||||
def apply(self):
|
||||
# replace id_prefix temporarily
|
||||
id_prefix = self.document.settings.id_prefix
|
||||
self.document.settings.id_prefix = 'show_urls'
|
||||
|
||||
self.expand_show_urls()
|
||||
if self.expanded:
|
||||
self.renumber_footnotes()
|
||||
|
||||
# restore id_prefix
|
||||
self.document.settings.id_prefix = id_prefix
|
||||
|
||||
def expand_show_urls(self):
|
||||
show_urls = self.document.settings.env.config.latex_show_urls
|
||||
if show_urls is False or show_urls == 'no':
|
||||
return
|
||||
|
||||
for node in self.document.traverse(nodes.reference):
|
||||
uri = node.get('refuri', '')
|
||||
if uri.startswith(URI_SCHEMES):
|
||||
if uri.startswith('mailto:'):
|
||||
uri = uri[7:]
|
||||
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)
|
||||
|
||||
self.expanded = True
|
||||
else: # all other true values (b/w compat)
|
||||
textnode = nodes.Text(" (%s)" % uri)
|
||||
node.parent.insert(index + 1, textnode)
|
||||
|
||||
def create_footnote(self, uri):
|
||||
label = nodes.label('', '#')
|
||||
para = nodes.paragraph()
|
||||
para.append(nodes.Text(uri))
|
||||
footnote = nodes.footnote(uri, label, para, auto=1)
|
||||
footnote['names'].append('#')
|
||||
self.document.note_autofootnote(footnote)
|
||||
|
||||
label = nodes.Text('#')
|
||||
footnote_ref = nodes.footnote_reference('[#]_', label, auto=1,
|
||||
refid=footnote['ids'][0])
|
||||
self.document.note_autofootnote_ref(footnote_ref)
|
||||
footnote.add_backref(footnote_ref['ids'][0])
|
||||
|
||||
return [footnote, footnote_ref]
|
||||
|
||||
def renumber_footnotes(self):
|
||||
def is_used_number(number):
|
||||
for node in self.document.traverse(nodes.footnote):
|
||||
if not node.get('auto') and number in node['names']:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def is_auto_footnote(node):
|
||||
return isinstance(node, nodes.footnote) and node.get('auto')
|
||||
|
||||
def footnote_ref_by(ids):
|
||||
def is_footnote_ref(node):
|
||||
return isinstance(node, nodes.footnote_reference) and ids[0] == node['refid']
|
||||
|
||||
return is_footnote_ref
|
||||
|
||||
startnum = 1
|
||||
for footnote in self.document.traverse(is_auto_footnote):
|
||||
while True:
|
||||
label = str(startnum)
|
||||
startnum += 1
|
||||
if not is_used_number(label):
|
||||
break
|
||||
|
||||
old_label = footnote[0].astext()
|
||||
footnote.remove(footnote[0])
|
||||
footnote.insert(0, nodes.label('', label))
|
||||
if old_label in footnote['names']:
|
||||
footnote['names'].remove(old_label)
|
||||
footnote['names'].append(label)
|
||||
|
||||
for footnote_ref in self.document.traverse(footnote_ref_by(footnote['ids'])):
|
||||
footnote_ref.remove(footnote_ref[0])
|
||||
footnote_ref += nodes.Text(label)
|
||||
|
||||
|
||||
class Table(object):
|
||||
def __init__(self):
|
||||
self.col = 0
|
||||
@ -278,6 +375,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
sys.maxsize]]
|
||||
self.bodystack = []
|
||||
self.footnotestack = []
|
||||
self.termfootnotestack = []
|
||||
self.curfilestack = []
|
||||
self.handled_abbrs = set()
|
||||
if document.settings.docclass == 'howto':
|
||||
@ -297,6 +395,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
self.in_footnote = 0
|
||||
self.in_caption = 0
|
||||
self.in_container_literal_block = 0
|
||||
self.in_term = 0
|
||||
self.first_document = 1
|
||||
self.this_is_the_title = 1
|
||||
self.literal_whitespace = 0
|
||||
@ -761,7 +860,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
|
||||
def visit_collected_footnote(self, node):
|
||||
self.in_footnote += 1
|
||||
if 'in_table' in node:
|
||||
if 'footnotetext' in node:
|
||||
self.body.append('\\footnotetext[%s]{' % node['number'])
|
||||
else:
|
||||
self.body.append('\\footnote[%s]{' % node['number'])
|
||||
@ -864,7 +963,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
self.body.append('\\end{threeparttable}\n\n')
|
||||
if self.table.footnotes:
|
||||
for footnode in self.table.footnotes:
|
||||
footnode['in_table'] = True
|
||||
footnode['footnotetext'] = True
|
||||
footnode.walkabout(self)
|
||||
self.table = None
|
||||
self.tablebody = None
|
||||
@ -1031,14 +1130,22 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
pass
|
||||
|
||||
def visit_term(self, node):
|
||||
self.in_term += 1
|
||||
ctx = '}] \\leavevmode'
|
||||
if node.get('ids'):
|
||||
ctx += self.hypertarget(node['ids'][0])
|
||||
self.body.append('\\item[{')
|
||||
self.termfootnotestack.append([])
|
||||
self.context.append(ctx)
|
||||
|
||||
def depart_term(self, node):
|
||||
self.body.append(self.context.pop())
|
||||
footnotes = self.termfootnotestack.pop()
|
||||
for footnode in footnotes:
|
||||
footnode['footnotetext'] = True
|
||||
footnode.walkabout(self)
|
||||
|
||||
self.in_term -= 1
|
||||
|
||||
def visit_termsep(self, node):
|
||||
self.body.append(', ')
|
||||
@ -1399,23 +1506,9 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
uri = '%' + self.curfilestack[-1] + '#' + node['refid']
|
||||
if self.in_title or not uri:
|
||||
self.context.append('')
|
||||
elif uri.startswith('mailto:') or uri.startswith('http:') or \
|
||||
uri.startswith('https:') or uri.startswith('ftp:'):
|
||||
elif uri.startswith(URI_SCHEMES):
|
||||
self.body.append('\\href{%s}{' % self.encode_uri(uri))
|
||||
# if configured, put the URL after the link
|
||||
show_urls = self.builder.config.latex_show_urls
|
||||
if uri.startswith('mailto:'):
|
||||
uri = uri[7:]
|
||||
if node.astext() != uri and show_urls and show_urls != 'no':
|
||||
if show_urls == 'footnote' and not \
|
||||
(self.in_footnote or self.in_caption):
|
||||
# obviously, footnotes in footnotes are not going to work
|
||||
self.context.append(
|
||||
r'}\footnote{%s}' % self.encode_uri(uri))
|
||||
else: # all other true values (b/w compat)
|
||||
self.context.append('} (%s)' % self.encode_uri(uri))
|
||||
else:
|
||||
self.context.append('}')
|
||||
self.context.append('}')
|
||||
elif uri.startswith('#'):
|
||||
# references to labels in the same document
|
||||
id = self.curfilestack[-1] + ':' + uri[1:]
|
||||
@ -1566,7 +1659,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
# if a footnote has been inserted once, it shouldn't be repeated
|
||||
# by the next reference
|
||||
if used:
|
||||
if self.table:
|
||||
if self.table or self.in_term:
|
||||
self.body.append('\\protect\\footnotemark[%s]' % num)
|
||||
else:
|
||||
self.body.append('\\footnotemark[%s]' % num)
|
||||
@ -1574,6 +1667,9 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
self.footnotestack[-1][num][1] = True
|
||||
self.body.append('\\protect\\footnotemark[%s]' % num)
|
||||
self.table.footnotes.append(footnode)
|
||||
elif self.in_term:
|
||||
self.body.append('\\footnotemark[%s]' % num)
|
||||
self.termfootnotestack[-1].append(footnode)
|
||||
else:
|
||||
if self.in_caption:
|
||||
raise UnsupportedError('%s:%s: footnotes in float captions '
|
||||
|
@ -51,7 +51,6 @@ latex_documents = [
|
||||
'Georg Brandl \\and someone else', 'manual'),
|
||||
]
|
||||
|
||||
latex_show_urls = 'footnote'
|
||||
latex_additional_files = ['svgimg.svg']
|
||||
|
||||
texinfo_documents = [
|
||||
|
@ -35,18 +35,6 @@ footnotes in table
|
||||
* - VIDIOC_CROPCAP
|
||||
- Information about VIDIOC_CROPCAP
|
||||
|
||||
URLs as footnotes
|
||||
-----------------
|
||||
|
||||
`homepage <http://sphinx.org>`_
|
||||
|
||||
URLs should not be footnotes
|
||||
----------------------------
|
||||
|
||||
GitHub Page: `https://github.com/sphinx-doc/sphinx <https://github.com/sphinx-doc/sphinx>`_
|
||||
|
||||
Mailing list: `sphinx-dev@googlegroups.com <mailto:sphinx-dev@googlegroups.com>`_
|
||||
|
||||
footenotes
|
||||
--------------------
|
||||
|
||||
|
45
tests/roots/test-footnotes/index.rst
Normal file
45
tests/roots/test-footnotes/index.rst
Normal file
@ -0,0 +1,45 @@
|
||||
===============
|
||||
test-footenotes
|
||||
===============
|
||||
|
||||
The section with a reference to [AuthorYear]_
|
||||
=============================================
|
||||
|
||||
.. figure:: rimg.png
|
||||
|
||||
This is the figure caption with a reference to [AuthorYear]_.
|
||||
|
||||
.. list-table:: The table title with a reference to [AuthorYear]_
|
||||
:header-rows: 1
|
||||
|
||||
* - Header1
|
||||
- Header2
|
||||
* - Content
|
||||
- Content
|
||||
|
||||
.. rubric:: The rubric title with a reference to [AuthorYear]_
|
||||
|
||||
.. [#] First
|
||||
|
||||
* First footnote: [#]_
|
||||
* Second footnote: [1]_
|
||||
* `Sphinx <http://sphinx-doc.org/>`_
|
||||
* Third footnote: [#]_
|
||||
* `URL including tilde <http://sphinx-doc.org/~test/>`_
|
||||
* GitHub Page: `https://github.com/sphinx-doc/sphinx <https://github.com/sphinx-doc/sphinx>`_
|
||||
* Mailing list: `sphinx-dev@googlegroups.com <mailto:sphinx-dev@googlegroups.com>`_
|
||||
|
||||
.. [AuthorYear] Author, Title, Year
|
||||
.. [1] Second
|
||||
.. [#] Third
|
||||
|
||||
`URL in term <http://sphinx-doc.org/>`_
|
||||
Description Description Description ...
|
||||
|
||||
Footnote in term [#]_
|
||||
Description Description Description ...
|
||||
|
||||
`Term in deflist <http://sphinx-doc.org/>`_
|
||||
Description2
|
||||
|
||||
.. [#] Footnote in term
|
Before Width: | Height: | Size: 218 B After Width: | Height: | Size: 218 B |
@ -1,22 +0,0 @@
|
||||
==============
|
||||
test-reference
|
||||
==============
|
||||
|
||||
The section with a reference to [AuthorYear]_
|
||||
=============================================
|
||||
|
||||
.. figure:: rimg.png
|
||||
|
||||
This is the figure caption with a reference to [AuthorYear]_.
|
||||
|
||||
.. list-table:: The table title with a reference to [AuthorYear]_
|
||||
:header-rows: 1
|
||||
|
||||
* - Header1
|
||||
- Header2
|
||||
* - Content
|
||||
- Content
|
||||
|
||||
.. rubric:: The rubric title with a reference to [AuthorYear]_
|
||||
|
||||
.. [AuthorYear] Author, Title, Year
|
@ -318,12 +318,9 @@ def test_footnote(app, status, warning):
|
||||
assert ('\\end{threeparttable}\n\n'
|
||||
'\\footnotetext[4]{\nfootnotes in table caption\n}'
|
||||
'\\footnotetext[5]{\nfootnotes in table\n}' in result)
|
||||
assert r'\href{http://sphinx.org}{homepage}\footnote{http://sphinx.org}' in result
|
||||
assert r'\footnote{https://github.com/sphinx-doc/sphinx}' not in result
|
||||
assert r'\footnote{sphinx-dev@googlegroups.com}' not in result
|
||||
|
||||
|
||||
@with_app(buildername='latex', testroot='references-in-caption')
|
||||
@with_app(buildername='latex', testroot='footnotes')
|
||||
def test_reference_in_caption(app, status, warning):
|
||||
app.builder.build_all()
|
||||
result = (app.outdir / 'Python.tex').text(encoding='utf8')
|
||||
@ -335,3 +332,81 @@ def test_reference_in_caption(app, status, warning):
|
||||
assert '\\chapter{The section with a reference to {[}AuthorYear{]}}' in result
|
||||
assert '\\caption{The table title with a reference to {[}AuthorYear{]}}' in result
|
||||
assert '\\paragraph{The rubric title with a reference to {[}AuthorYear{]}}' in result
|
||||
|
||||
|
||||
@with_app(buildername='latex', testroot='footnotes',
|
||||
confoverrides={'latex_show_urls': 'inline'})
|
||||
def test_latex_show_urls_is_inline(app, status, warning):
|
||||
app.builder.build_all()
|
||||
result = (app.outdir / 'Python.tex').text(encoding='utf8')
|
||||
print(result)
|
||||
print(status.getvalue())
|
||||
print(warning.getvalue())
|
||||
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
|
||||
assert 'Third footnote: \\footnote[3]{\nThird\n}' in result
|
||||
assert ('\\href{http://sphinx-doc.org/~test/}{URL including tilde} '
|
||||
'(http://sphinx-doc.org/\\textasciitilde{}test/)' in result)
|
||||
assert ('\\item[{\\href{http://sphinx-doc.org/}{URL in term} (http://sphinx-doc.org/)}] '
|
||||
'\\leavevmode\nDescription' in result)
|
||||
assert ('\\item[{Footnote in term \\footnotemark[4]}] '
|
||||
'\\leavevmode\\footnotetext[4]{\nFootnote in term\n}\nDescription' in result)
|
||||
assert ('\\item[{\\href{http://sphinx-doc.org/}{Term in deflist} '
|
||||
'(http://sphinx-doc.org/)}] \\leavevmode\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}'
|
||||
'{sphinx-dev@googlegroups.com}' in result)
|
||||
|
||||
|
||||
@with_app(buildername='latex', testroot='footnotes',
|
||||
confoverrides={'latex_show_urls': 'footnote'})
|
||||
def test_latex_show_urls_is_footnote(app, status, warning):
|
||||
app.builder.build_all()
|
||||
result = (app.outdir / 'Python.tex').text(encoding='utf8')
|
||||
print(result)
|
||||
print(status.getvalue())
|
||||
print(warning.getvalue())
|
||||
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}'
|
||||
'\\footnote[3]{\nhttp://sphinx-doc.org/\n}' in result)
|
||||
assert 'Third footnote: \\footnote[5]{\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}\\footnotemark[6]}] '
|
||||
'\\leavevmode\\footnotetext[6]{\nhttp://sphinx-doc.org/\n}\nDescription' in result)
|
||||
assert ('\\item[{Footnote in term \\footnotemark[8]}] '
|
||||
'\\leavevmode\\footnotetext[8]{\nFootnote in term\n}\nDescription' in result)
|
||||
assert ('\\item[{\\href{http://sphinx-doc.org/}{Term in deflist}\\footnotemark[7]}] '
|
||||
'\\leavevmode\\footnotetext[7]{\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}'
|
||||
'{sphinx-dev@googlegroups.com}\n' in result)
|
||||
|
||||
|
||||
@with_app(buildername='latex', testroot='footnotes',
|
||||
confoverrides={'latex_show_urls': 'no'})
|
||||
def test_latex_show_urls_is_no(app, status, warning):
|
||||
app.builder.build_all()
|
||||
result = (app.outdir / 'Python.tex').text(encoding='utf8')
|
||||
print(result)
|
||||
print(status.getvalue())
|
||||
print(warning.getvalue())
|
||||
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
|
||||
assert 'Third footnote: \\footnote[3]{\nThird\n}' in result
|
||||
assert '\\href{http://sphinx-doc.org/~test/}{URL including tilde}' in result
|
||||
assert ('\\item[{\\href{http://sphinx-doc.org/}{URL in term}}] '
|
||||
'\\leavevmode\nDescription' in result)
|
||||
assert ('\\item[{Footnote in term \\footnotemark[4]}] '
|
||||
'\\leavevmode\\footnotetext[4]{\nFootnote in term\n}\nDescription' in result)
|
||||
assert ('\\item[{\\href{http://sphinx-doc.org/}{Term in deflist}}] '
|
||||
'\\leavevmode\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}'
|
||||
'{sphinx-dev@googlegroups.com}\n' in result)
|
||||
|
Loading…
Reference in New Issue
Block a user