Merge with 'stable'

This commit is contained in:
shimizukawa 2015-11-29 23:10:21 +09:00
commit 9ceea10a62
8 changed files with 103 additions and 16 deletions

View File

@ -85,6 +85,12 @@ Bugs fixed
the page content.
* #1884, #1885: plug-in html themes cannot inherit another plug-in theme. Thanks to
Suzumizaki.
* #1818: `sphinx.ext.todo` directive generates broken html class attribute as
'admonition-' when :confval:`language` is specified with non-ASCII linguistic area like
'ru' or 'ja'. To fix this, now ``todo`` directive can use ```:class:`` option.
* #2140: Fix footnotes in table has broken in LaTeX
* #2127: MecabBinder for html searching feature doesn't work with Python 3.
Thanks to Tomoko Uchida.
Documentation
-------------

View File

@ -16,6 +16,10 @@ There are two additional directives when using this extension:
It will only show up in the output if :confval:`todo_include_todos` is
``True``.
.. versionadded:: 1.3.2
This directive supports an ``class`` option that determines the class attribute
for HTML output. If not given, the class defaults to ``admonition-todo``.
.. rst:directive:: todolist

View File

@ -13,6 +13,7 @@
"""
from docutils import nodes
from docutils.parsers.rst import directives
import sphinx
from sphinx.locale import _
@ -38,13 +39,18 @@ class Todo(Directive):
required_arguments = 0
optional_arguments = 0
final_argument_whitespace = False
option_spec = {}
option_spec = {
'class': directives.class_option,
}
def run(self):
env = self.state.document.settings.env
targetid = 'index-%s' % env.new_serialno('index')
targetnode = nodes.target('', '', ids=[targetid])
if not self.options.get('class'):
self.options['class'] = ['admonition-todo']
ad = make_admonition(todo_node, self.name, [_('Todo')], self.options,
self.content, self.lineno, self.content_offset,
self.block_text, self.state, self.state_machine)
@ -165,6 +171,7 @@ def merge_info(app, env, docnames, other):
def visit_todo_node(self, node):
self.visit_admonition(node)
# self.visit_admonition(node, 'todo')
def depart_todo_node(self, node):

View File

@ -137,6 +137,7 @@ class Table(object):
self.has_verbatim = False
self.caption = None
self.longtable = False
self.footnotes = []
class LaTeXTranslator(nodes.NodeVisitor):
@ -275,6 +276,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
# by .. highlight:: directive in the master file
self.hlsettingstack = 2 * [[builder.config.highlight_language,
sys.maxsize]]
self.bodystack = []
self.footnotestack = []
self.curfilestack = []
self.handled_abbrs = set()
@ -303,6 +305,15 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.remember_multirow = {}
self.remember_multirowcol = {}
def pushbody(self, newbody):
self.bodystack.append(self.body)
self.body = newbody
def popbody(self):
body = self.body
self.body = self.bodystack.pop()
return body
def format_docclass(self, docclass):
""" prepends prefix to sphinx document classes
"""
@ -495,7 +506,8 @@ class LaTeXTranslator(nodes.NodeVisitor):
fnotes = {}
for fn in footnotes_under(node):
num = fn.children[0].astext().strip()
fnotes[num] = [collected_footnote(*fn.children), False]
newnode = collected_footnote(*fn.children, number=num)
fnotes[num] = [newnode, False]
return fnotes
def depart_start_of_file(self, node):
@ -602,8 +614,8 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append('{')
self.context.append('}\n')
elif isinstance(parent, nodes.table):
self.table.caption = self.encode(node.astext())
raise nodes.SkipNode
# Redirect body output until title is finished.
self.pushbody([])
else:
self.builder.warn(
'encountered title node not in section, topic, table, '
@ -615,7 +627,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
def depart_title(self, node):
self.in_title = 0
self.body.append(self.context.pop())
if isinstance(node.parent, nodes.table):
self.table.caption = self.popbody()
else:
self.body.append(self.context.pop())
def visit_subtitle(self, node):
if isinstance(node.parent, nodes.sidebar):
@ -743,7 +758,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
def visit_collected_footnote(self, node):
self.in_footnote += 1
self.body.append('\\footnote{')
if 'in_table' in node:
self.body.append('\\footnotetext[%s]{' % node['number'])
else:
self.body.append('\\footnote[%s]{' % node['number'])
def depart_collected_footnote(self, node):
self.body.append('}')
@ -770,16 +788,18 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.tablebody = []
self.tableheaders = []
# Redirect body output until table is finished.
self._body = self.body
self.body = self.tablebody
self.pushbody(self.tablebody)
def depart_table(self, node):
if self.table.rowcount > 30:
self.table.longtable = True
self.body = self._body
self.popbody()
if not self.table.longtable and self.table.caption is not None:
self.body.append(u'\n\n\\begin{threeparttable}\n'
u'\\capstart\\caption{%s}\n' % self.table.caption)
self.body.append('\n\n\\begin{threeparttable}\n'
'\\capstart\\caption{')
for caption in self.table.caption:
self.body.append(caption)
self.body.append('}')
for id in self.next_table_ids:
self.body.append(self.hypertarget(id, anchor=False))
if node['ids']:
@ -839,6 +859,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append(endmacro)
if not self.table.longtable and self.table.caption is not None:
self.body.append('\\end{threeparttable}\n\n')
if self.table.footnotes:
for footnode in self.table.footnotes:
footnode['in_table'] = True
footnode.walkabout(self)
self.table = None
self.tablebody = None
@ -1531,7 +1555,14 @@ class LaTeXTranslator(nodes.NodeVisitor):
# if a footnote has been inserted once, it shouldn't be repeated
# by the next reference
if used:
self.body.append('\\footnotemark[%s]' % num)
if self.table:
self.body.append('\\protect\\footnotemark[%s]' % num)
else:
self.body.append('\\footnotemark[%s]' % num)
elif self.table:
self.footnotestack[-1][num][1] = True
self.body.append('\\protect\\footnotemark[%s]' % num)
self.table.footnotes.append(footnode)
else:
if self.in_caption:
raise UnsupportedError('%s:%s: footnotes in float captions '

View File

@ -24,6 +24,17 @@ citation
[bar]_
footnotes in table
--------------------
.. list-table:: Table caption [#]_
:header-rows: 1
* - name [#]_
- desription
* - VIDIOC_CROPCAP
- Information about VIDIOC_CROPCAP
footenotes
--------------------
@ -39,6 +50,10 @@ footenotes
.. [bar] cite
.. [#] footnotes in table caption
.. [#] footnotes in table
missing target
--------------------

View File

@ -280,14 +280,18 @@ HTML_XPATH = {
(".//dt/a", "double"),
],
'footnote.html': [
(".//a[@class='footnote-reference'][@href='#id5'][@id='id1']", r"\[1\]"),
(".//a[@class='footnote-reference'][@href='#id6'][@id='id2']", r"\[2\]"),
(".//a[@class='footnote-reference'][@href='#id7'][@id='id1']", r"\[1\]"),
(".//a[@class='footnote-reference'][@href='#id8'][@id='id2']", r"\[2\]"),
(".//a[@class='footnote-reference'][@href='#foo'][@id='id3']", r"\[3\]"),
(".//a[@class='reference internal'][@href='#bar'][@id='id4']", r"\[bar\]"),
(".//a[@class='footnote-reference'][@href='#id9'][@id='id5']", r"\[4\]"),
(".//a[@class='footnote-reference'][@href='#id10'][@id='id6']", r"\[5\]"),
(".//a[@class='fn-backref'][@href='#id1']", r"\[1\]"),
(".//a[@class='fn-backref'][@href='#id2']", r"\[2\]"),
(".//a[@class='fn-backref'][@href='#id3']", r"\[3\]"),
(".//a[@class='fn-backref'][@href='#id4']", r"\[bar\]"),
(".//a[@class='fn-backref'][@href='#id5']", r"\[4\]"),
(".//a[@class='fn-backref'][@href='#id6']", r"\[5\]"),
],
'otherext.html': [
(".//h1", "Generated section"),

View File

@ -297,3 +297,24 @@ def test_contentsname_with_language_ja(app, status, warning):
print(status.getvalue())
print(warning.getvalue())
assert '\\renewcommand{\\contentsname}{Table of content}' in result
@with_app(buildername='latex')
def test_footnote(app, status, warning):
app.builder.build_all()
result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
assert '\\footnote[1]{\nnumbered\n}' in result
assert '\\footnote[2]{\nauto numbered\n}' in result
assert '\\footnote[3]{\nnamed\n}' in result
assert '{\\hyperref[footnote:bar]{\\emph{{[}bar{]}}}}' in result
assert '\\bibitem[bar]{bar}{\\phantomsection\\label{footnote:bar} ' in result
assert '\\bibitem[bar]{bar}{\\phantomsection\\label{footnote:bar} \ncite' in result
assert '\\bibitem[bar]{bar}{\\phantomsection\\label{footnote:bar} \ncite\n}' in result
assert '\\capstart\\caption{Table caption \\protect\\footnotemark[4]}' in result
assert 'name \\protect\\footnotemark[5]' in result
assert ('\\end{threeparttable}\n\n'
'\\footnotetext[4]{\nfootnotes in table caption\n}'
'\\footnotetext[5]{\nfootnotes in table\n}' in result)

View File

@ -137,8 +137,7 @@ def test_extract_messages_without_rawsource():
Check node.rawsource is fall-backed by using node.astext() value.
`extract_message` which is used from Sphinx i18n feature drop ``not node.rawsource``
nodes.
So, all nodes which want to translate must have ``rawsource`` value.
nodes. So, all nodes which want to translate must have ``rawsource`` value.
However, sometimes node.rawsource is not set.
For example: recommonmark-0.2.0 doesn't set rawsource to `paragraph` node.