mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge with 'stable'
This commit is contained in:
commit
9ceea10a62
6
CHANGES
6
CHANGES
@ -85,6 +85,12 @@ Bugs fixed
|
|||||||
the page content.
|
the page content.
|
||||||
* #1884, #1885: plug-in html themes cannot inherit another plug-in theme. Thanks to
|
* #1884, #1885: plug-in html themes cannot inherit another plug-in theme. Thanks to
|
||||||
Suzumizaki.
|
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
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
@ -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
|
It will only show up in the output if :confval:`todo_include_todos` is
|
||||||
``True``.
|
``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
|
.. rst:directive:: todolist
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
|
from docutils.parsers.rst import directives
|
||||||
|
|
||||||
import sphinx
|
import sphinx
|
||||||
from sphinx.locale import _
|
from sphinx.locale import _
|
||||||
@ -38,13 +39,18 @@ class Todo(Directive):
|
|||||||
required_arguments = 0
|
required_arguments = 0
|
||||||
optional_arguments = 0
|
optional_arguments = 0
|
||||||
final_argument_whitespace = False
|
final_argument_whitespace = False
|
||||||
option_spec = {}
|
option_spec = {
|
||||||
|
'class': directives.class_option,
|
||||||
|
}
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
env = self.state.document.settings.env
|
env = self.state.document.settings.env
|
||||||
targetid = 'index-%s' % env.new_serialno('index')
|
targetid = 'index-%s' % env.new_serialno('index')
|
||||||
targetnode = nodes.target('', '', ids=[targetid])
|
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,
|
ad = make_admonition(todo_node, self.name, [_('Todo')], self.options,
|
||||||
self.content, self.lineno, self.content_offset,
|
self.content, self.lineno, self.content_offset,
|
||||||
self.block_text, self.state, self.state_machine)
|
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):
|
def visit_todo_node(self, node):
|
||||||
self.visit_admonition(node)
|
self.visit_admonition(node)
|
||||||
|
# self.visit_admonition(node, 'todo')
|
||||||
|
|
||||||
|
|
||||||
def depart_todo_node(self, node):
|
def depart_todo_node(self, node):
|
||||||
|
@ -137,6 +137,7 @@ class Table(object):
|
|||||||
self.has_verbatim = False
|
self.has_verbatim = False
|
||||||
self.caption = None
|
self.caption = None
|
||||||
self.longtable = False
|
self.longtable = False
|
||||||
|
self.footnotes = []
|
||||||
|
|
||||||
|
|
||||||
class LaTeXTranslator(nodes.NodeVisitor):
|
class LaTeXTranslator(nodes.NodeVisitor):
|
||||||
@ -275,6 +276,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
# by .. highlight:: directive in the master file
|
# by .. highlight:: directive in the master file
|
||||||
self.hlsettingstack = 2 * [[builder.config.highlight_language,
|
self.hlsettingstack = 2 * [[builder.config.highlight_language,
|
||||||
sys.maxsize]]
|
sys.maxsize]]
|
||||||
|
self.bodystack = []
|
||||||
self.footnotestack = []
|
self.footnotestack = []
|
||||||
self.curfilestack = []
|
self.curfilestack = []
|
||||||
self.handled_abbrs = set()
|
self.handled_abbrs = set()
|
||||||
@ -303,6 +305,15 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
self.remember_multirow = {}
|
self.remember_multirow = {}
|
||||||
self.remember_multirowcol = {}
|
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):
|
def format_docclass(self, docclass):
|
||||||
""" prepends prefix to sphinx document classes
|
""" prepends prefix to sphinx document classes
|
||||||
"""
|
"""
|
||||||
@ -495,7 +506,8 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
fnotes = {}
|
fnotes = {}
|
||||||
for fn in footnotes_under(node):
|
for fn in footnotes_under(node):
|
||||||
num = fn.children[0].astext().strip()
|
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
|
return fnotes
|
||||||
|
|
||||||
def depart_start_of_file(self, node):
|
def depart_start_of_file(self, node):
|
||||||
@ -602,8 +614,8 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
self.body.append('{')
|
self.body.append('{')
|
||||||
self.context.append('}\n')
|
self.context.append('}\n')
|
||||||
elif isinstance(parent, nodes.table):
|
elif isinstance(parent, nodes.table):
|
||||||
self.table.caption = self.encode(node.astext())
|
# Redirect body output until title is finished.
|
||||||
raise nodes.SkipNode
|
self.pushbody([])
|
||||||
else:
|
else:
|
||||||
self.builder.warn(
|
self.builder.warn(
|
||||||
'encountered title node not in section, topic, table, '
|
'encountered title node not in section, topic, table, '
|
||||||
@ -615,7 +627,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
|
|
||||||
def depart_title(self, node):
|
def depart_title(self, node):
|
||||||
self.in_title = 0
|
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):
|
def visit_subtitle(self, node):
|
||||||
if isinstance(node.parent, nodes.sidebar):
|
if isinstance(node.parent, nodes.sidebar):
|
||||||
@ -743,7 +758,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
|
|
||||||
def visit_collected_footnote(self, node):
|
def visit_collected_footnote(self, node):
|
||||||
self.in_footnote += 1
|
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):
|
def depart_collected_footnote(self, node):
|
||||||
self.body.append('}')
|
self.body.append('}')
|
||||||
@ -770,16 +788,18 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
self.tablebody = []
|
self.tablebody = []
|
||||||
self.tableheaders = []
|
self.tableheaders = []
|
||||||
# Redirect body output until table is finished.
|
# Redirect body output until table is finished.
|
||||||
self._body = self.body
|
self.pushbody(self.tablebody)
|
||||||
self.body = self.tablebody
|
|
||||||
|
|
||||||
def depart_table(self, node):
|
def depart_table(self, node):
|
||||||
if self.table.rowcount > 30:
|
if self.table.rowcount > 30:
|
||||||
self.table.longtable = True
|
self.table.longtable = True
|
||||||
self.body = self._body
|
self.popbody()
|
||||||
if not self.table.longtable and self.table.caption is not None:
|
if not self.table.longtable and self.table.caption is not None:
|
||||||
self.body.append(u'\n\n\\begin{threeparttable}\n'
|
self.body.append('\n\n\\begin{threeparttable}\n'
|
||||||
u'\\capstart\\caption{%s}\n' % self.table.caption)
|
'\\capstart\\caption{')
|
||||||
|
for caption in self.table.caption:
|
||||||
|
self.body.append(caption)
|
||||||
|
self.body.append('}')
|
||||||
for id in self.next_table_ids:
|
for id in self.next_table_ids:
|
||||||
self.body.append(self.hypertarget(id, anchor=False))
|
self.body.append(self.hypertarget(id, anchor=False))
|
||||||
if node['ids']:
|
if node['ids']:
|
||||||
@ -839,6 +859,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
self.body.append(endmacro)
|
self.body.append(endmacro)
|
||||||
if not self.table.longtable and self.table.caption is not None:
|
if not self.table.longtable and self.table.caption is not None:
|
||||||
self.body.append('\\end{threeparttable}\n\n')
|
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.table = None
|
||||||
self.tablebody = None
|
self.tablebody = None
|
||||||
|
|
||||||
@ -1531,7 +1555,14 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
# if a footnote has been inserted once, it shouldn't be repeated
|
# if a footnote has been inserted once, it shouldn't be repeated
|
||||||
# by the next reference
|
# by the next reference
|
||||||
if used:
|
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:
|
else:
|
||||||
if self.in_caption:
|
if self.in_caption:
|
||||||
raise UnsupportedError('%s:%s: footnotes in float captions '
|
raise UnsupportedError('%s:%s: footnotes in float captions '
|
||||||
|
@ -24,6 +24,17 @@ citation
|
|||||||
|
|
||||||
[bar]_
|
[bar]_
|
||||||
|
|
||||||
|
footnotes in table
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
.. list-table:: Table caption [#]_
|
||||||
|
:header-rows: 1
|
||||||
|
|
||||||
|
* - name [#]_
|
||||||
|
- desription
|
||||||
|
* - VIDIOC_CROPCAP
|
||||||
|
- Information about VIDIOC_CROPCAP
|
||||||
|
|
||||||
footenotes
|
footenotes
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
@ -39,6 +50,10 @@ footenotes
|
|||||||
|
|
||||||
.. [bar] cite
|
.. [bar] cite
|
||||||
|
|
||||||
|
.. [#] footnotes in table caption
|
||||||
|
|
||||||
|
.. [#] footnotes in table
|
||||||
|
|
||||||
|
|
||||||
missing target
|
missing target
|
||||||
--------------------
|
--------------------
|
||||||
|
@ -280,14 +280,18 @@ HTML_XPATH = {
|
|||||||
(".//dt/a", "double"),
|
(".//dt/a", "double"),
|
||||||
],
|
],
|
||||||
'footnote.html': [
|
'footnote.html': [
|
||||||
(".//a[@class='footnote-reference'][@href='#id5'][@id='id1']", r"\[1\]"),
|
(".//a[@class='footnote-reference'][@href='#id7'][@id='id1']", r"\[1\]"),
|
||||||
(".//a[@class='footnote-reference'][@href='#id6'][@id='id2']", r"\[2\]"),
|
(".//a[@class='footnote-reference'][@href='#id8'][@id='id2']", r"\[2\]"),
|
||||||
(".//a[@class='footnote-reference'][@href='#foo'][@id='id3']", r"\[3\]"),
|
(".//a[@class='footnote-reference'][@href='#foo'][@id='id3']", r"\[3\]"),
|
||||||
(".//a[@class='reference internal'][@href='#bar'][@id='id4']", r"\[bar\]"),
|
(".//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='#id1']", r"\[1\]"),
|
||||||
(".//a[@class='fn-backref'][@href='#id2']", r"\[2\]"),
|
(".//a[@class='fn-backref'][@href='#id2']", r"\[2\]"),
|
||||||
(".//a[@class='fn-backref'][@href='#id3']", r"\[3\]"),
|
(".//a[@class='fn-backref'][@href='#id3']", r"\[3\]"),
|
||||||
(".//a[@class='fn-backref'][@href='#id4']", r"\[bar\]"),
|
(".//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': [
|
'otherext.html': [
|
||||||
(".//h1", "Generated section"),
|
(".//h1", "Generated section"),
|
||||||
|
@ -297,3 +297,24 @@ def test_contentsname_with_language_ja(app, status, warning):
|
|||||||
print(status.getvalue())
|
print(status.getvalue())
|
||||||
print(warning.getvalue())
|
print(warning.getvalue())
|
||||||
assert '\\renewcommand{\\contentsname}{Table of content}' in result
|
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)
|
||||||
|
@ -137,8 +137,7 @@ def test_extract_messages_without_rawsource():
|
|||||||
Check node.rawsource is fall-backed by using node.astext() value.
|
Check node.rawsource is fall-backed by using node.astext() value.
|
||||||
|
|
||||||
`extract_message` which is used from Sphinx i18n feature drop ``not node.rawsource``
|
`extract_message` which is used from Sphinx i18n feature drop ``not node.rawsource``
|
||||||
nodes.
|
nodes. So, all nodes which want to translate must have ``rawsource`` value.
|
||||||
So, all nodes which want to translate must have ``rawsource`` value.
|
|
||||||
However, sometimes node.rawsource is not set.
|
However, sometimes node.rawsource is not set.
|
||||||
|
|
||||||
For example: recommonmark-0.2.0 doesn't set rawsource to `paragraph` node.
|
For example: recommonmark-0.2.0 doesn't set rawsource to `paragraph` node.
|
||||||
|
Loading…
Reference in New Issue
Block a user