summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sphinx/writers/latex.py312
-rw-r--r--sphinx/writers/texinfo.py306
-rw-r--r--sphinx/writers/text.py248
-rw-r--r--sphinx/writers/xml.py12
4 files changed, 795 insertions, 83 deletions
diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py
index 60483ded5..e084c0b49 100644
--- a/sphinx/writers/latex.py
+++ b/sphinx/writers/latex.py
@@ -32,6 +32,11 @@ from sphinx.util.template import LaTeXRenderer
from sphinx.util.texescape import tex_escape_map, tex_replace_map
from sphinx.util.smartypants import educate_quotes_latex
+if False:
+ # For type annotation
+ from typing import Any, Callable, Iterator, Pattern, Tuple, Union # NOQA
+ from sphinx.builder import Builder # NOQA
+
BEGIN_DOC = r'''
\begin{document}
@@ -96,7 +101,7 @@ DEFAULT_SETTINGS = {
'tocdepth': '',
'secnumdepth': '',
'pageautorefname': '',
-}
+} # type: Dict[unicode, unicode]
ADDITIONAL_SETTINGS = {
'pdflatex': {
@@ -121,7 +126,7 @@ ADDITIONAL_SETTINGS = {
'platex': {
'latex_engine': 'platex',
},
-}
+} # type: Dict[unicode, Dict[unicode, unicode]]
class collected_footnote(nodes.footnote):
@@ -141,17 +146,19 @@ class LaTeXWriter(writers.Writer):
('Document class', ['--docclass'], {'default': 'manual'}),
('Author', ['--author'], {'default': ''}),
))
- settings_defaults = {}
+ settings_defaults = {} # type: Dict
output = None
def __init__(self, builder):
+ # type: (Builder) -> None
writers.Writer.__init__(self)
self.builder = builder
self.translator_class = (
self.builder.translator_class or LaTeXTranslator)
def translate(self):
+ # type: () -> None
transform = ShowUrlsTransform(self.document)
transform.apply()
visitor = self.translator_class(self.document, self.builder)
@@ -163,10 +170,12 @@ class LaTeXWriter(writers.Writer):
class ExtBabel(Babel):
def __init__(self, language_code):
+ # type: (unicode) -> None
super(ExtBabel, self).__init__(language_code or '')
self.language_code = language_code
def get_shorthandoff(self):
+ # type: () -> unicode
shortlang = self.language.split('_')[0]
if shortlang in ('de', 'ngerman', 'sl', 'slovene', 'pt', 'portuges',
'es', 'spanish', 'nl', 'dutch', 'pl', 'polish', 'it',
@@ -177,15 +186,18 @@ class ExtBabel(Babel):
return ''
def uses_cyrillic(self):
+ # type: () -> bool
shortlang = self.language.split('_')[0]
return shortlang in ('bg', 'bulgarian', 'kk', 'kazakh',
'mn', 'mongolian', 'ru', 'russian',
'uk', 'ukrainian')
def is_supported_language(self):
+ # type: () -> bool
return bool(super(ExtBabel, self).get_language())
def get_language(self):
+ # type: () -> unicode
language = super(ExtBabel, self).get_language()
if not language:
return 'english' # fallback to english
@@ -197,9 +209,11 @@ class ShowUrlsTransform(object):
expanded = False
def __init__(self, document):
+ # type: (nodes.Node) -> None
self.document = document
def apply(self):
+ # type: () -> None
# replace id_prefix temporarily
id_prefix = self.document.settings.id_prefix
self.document.settings.id_prefix = 'show_urls'
@@ -212,6 +226,7 @@ class ShowUrlsTransform(object):
self.document.settings.id_prefix = id_prefix
def expand_show_urls(self):
+ # type: () -> None
show_urls = self.document.settings.env.config.latex_show_urls
if show_urls is False or show_urls == 'no':
return
@@ -234,6 +249,7 @@ class ShowUrlsTransform(object):
node.parent.insert(index + 1, textnode)
def create_footnote(self, uri):
+ # type: (unicode) -> List[Union[nodes.footnote, nodes.footnote_ref]]
label = nodes.label('', '#')
para = nodes.paragraph()
para.append(nodes.reference('', nodes.Text(uri), refuri=uri, nolinkurl=True))
@@ -250,7 +266,9 @@ class ShowUrlsTransform(object):
return [footnote, footnote_ref]
def renumber_footnotes(self):
+ # type: () -> None
def is_used_number(number):
+ # type: (unicode) -> bool
for node in self.document.traverse(nodes.footnote):
if not node.get('auto') and number in node['names']:
return True
@@ -258,13 +276,16 @@ class ShowUrlsTransform(object):
return False
def is_auto_footnote(node):
+ # type: (nodes.Node) -> bool
return isinstance(node, nodes.footnote) and node.get('auto')
def footnote_ref_by(node):
+ # type: (nodes.Node) -> Callable[[nodes.Node], bool]
ids = node['ids']
parent = list(traverse_parent(node, (nodes.document, addnodes.start_of_file)))[0]
def is_footnote_ref(node):
+ # type: (nodes.Node) -> bool
return (isinstance(node, nodes.footnote_reference) and
ids[0] == node['refid'] and
parent in list(traverse_parent(node)))
@@ -293,23 +314,26 @@ class ShowUrlsTransform(object):
class Table(object):
def __init__(self):
+ # type: () -> None
self.col = 0
self.colcount = 0
- self.colspec = None
+ self.colspec = None # type: unicode
self.rowcount = 0
self.had_head = False
self.has_problematic = False
self.has_verbatim = False
- self.caption = None
+ self.caption = None # type: List[unicode]
self.longtable = False
def escape_abbr(text):
+ # type: (unicode) -> unicode
"""Adjust spacing after abbreviations."""
return re.sub('\.(?=\s|$)', '.\\@', text)
def rstdim_to_latexdim(width_str):
+ # type: (unicode) -> unicode
"""Convert `width_str` with rst length to LaTeX length."""
match = re.match('^(\d*\.?\d*)\s*(\S*)$', width_str)
if not match:
@@ -336,9 +360,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
docclasses = ('howto', 'manual')
def __init__(self, document, builder):
+ # type: (nodes.Node, Builder) -> None
nodes.NodeVisitor.__init__(self, document)
self.builder = builder
- self.body = []
+ self.body = [] # type: List[unicode]
# flags
self.in_title = 0
@@ -355,8 +380,8 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.no_contractions = 0
self.compact_list = 0
self.first_param = 0
- self.remember_multirow = {}
- self.remember_multirowcol = {}
+ self.remember_multirow = {} # type: Dict[int, int]
+ self.remember_multirowcol = {} # type: Dict[int, int]
# determine top section level
if builder.config.latex_toplevel_sectioning:
@@ -438,6 +463,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
if getattr(builder, 'usepackages', None):
def declare_package(packagename, options=None):
+ # type:(unicode, unicode) -> unicode
if options:
return '\\usepackage[%s]{%s}' % (options, packagename)
else:
@@ -486,54 +512,61 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.highlighter = highlighting.PygmentsBridge(
'latex',
builder.config.pygments_style, builder.config.trim_doctest_flags)
- self.context = []
- self.descstack = []
- self.bibitems = []
- self.table = None
- self.next_table_colspec = None
+ 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
# the first item here is the default and must not be changed
# the second item is the default for the master file and can be changed
# by .. highlight:: directive in the master file
self.hlsettingstack = 2 * [[builder.config.highlight_language,
sys.maxsize]]
- self.bodystack = []
- self.footnotestack = []
+ self.bodystack = [] # type: List[List[unicode]]
+ self.footnotestack = [] # type: List[Dict[unicode, List[Union[collected_footnote, bool]]]] # NOQA
self.footnote_restricted = False
- self.pending_footnotes = []
- self.curfilestack = []
- self.handled_abbrs = set()
- self.next_hyperlink_ids = {}
- self.next_section_ids = set()
+ self.pending_footnotes = [] # type: List[nodes.footnote_reference]
+ self.curfilestack = [] # type: List[unicode]
+ self.handled_abbrs = set() # type: Set[unicode]
+ self.next_hyperlink_ids = {} # type: Dict[unicode, Set[unicode]]
+ self.next_section_ids = set() # type: Set[unicode]
def pushbody(self, newbody):
+ # type: (List[unicode]) -> None
self.bodystack.append(self.body)
self.body = newbody
def popbody(self):
+ # type: () -> List[unicode]
body = self.body
self.body = self.bodystack.pop()
return body
def push_hyperlink_ids(self, figtype, ids):
+ # type: (unicode, Set[unicode]) -> None
hyperlink_ids = self.next_hyperlink_ids.setdefault(figtype, set())
hyperlink_ids.update(ids)
def pop_hyperlink_ids(self, figtype):
+ # type: (unicode) -> Set[unicode]
return self.next_hyperlink_ids.pop(figtype, set())
def check_latex_elements(self):
+ # type: () -> None
for key in self.builder.config.latex_elements:
if key not in self.elements:
msg = _("Unknown configure key: latex_elements[%r] is ignored.")
self.builder.warn(msg % key)
def restrict_footnote(self, node):
+ # type: (nodes.Node) -> None
if self.footnote_restricted is False:
self.footnote_restricted = node
self.pending_footnotes = []
def unrestrict_footnote(self, node):
+ # type: (nodes.Node) -> None
if self.footnote_restricted == node:
self.footnote_restricted = False
for footnode in self.pending_footnotes:
@@ -542,6 +575,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.pending_footnotes = []
def format_docclass(self, docclass):
+ # type: (unicode) -> unicode
""" prepends prefix to sphinx document classes
"""
if docclass in self.docclasses:
@@ -549,6 +583,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
return docclass
def astext(self):
+ # type: () -> unicode
self.elements.update({
'body': u''.join(self.body),
'indices': self.generate_indices()
@@ -561,26 +596,32 @@ class LaTeXTranslator(nodes.NodeVisitor):
return LaTeXRenderer().render(DEFAULT_TEMPLATE, self.elements)
def hypertarget(self, id, withdoc=True, anchor=True):
+ # type: (unicode, bool, bool) -> unicode
if withdoc:
id = self.curfilestack[-1] + ':' + id
return (anchor and '\\phantomsection' or '') + \
'\\label{%s}' % self.idescape(id)
def hyperlink(self, id):
+ # type: (unicode) -> unicode
return '{\\hyperref[%s]{' % self.hyperrefescape(id)
def hyperpageref(self, id):
+ # type: (unicode) -> unicode
return '\\autopageref*{%s}' % self.idescape(id)
def idescape(self, id):
+ # type: (unicode) -> unicode
return text_type(id).translate(tex_replace_map).\
encode('ascii', 'backslashreplace').decode('ascii').\
replace('\\', '_')
def hyperrefescape(self, ref):
+ # type: (unicode) -> unicode
return self.idescape(ref).replace('-', '\\string-')
def babel_renewcommand(self, command, definition):
+ # type: (unicode, unicode) -> unicode
if self.elements['babel']:
prefix = '\\addto\\captions%s{' % self.babel.get_language()
suffix = '}'
@@ -591,6 +632,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
return ('%s\\renewcommand{%s}{%s}%s\n' % (prefix, command, definition, suffix))
def babel_defmacro(self, name, definition):
+ # type: (unicode, unicode) -> unicode
if self.elements['babel']:
prefix = '\\addto\\extras%s{' % self.babel.get_language()
suffix = '}'
@@ -601,7 +643,8 @@ class LaTeXTranslator(nodes.NodeVisitor):
return ('%s\\def%s{%s}%s\n' % (prefix, name, definition, suffix))
def generate_numfig_format(self, builder):
- ret = []
+ # type: (Builder) -> unicode
+ ret = [] # type: List[unicode]
figure = self.builder.config.numfig_format['figure'].split('%s', 1)
if len(figure) == 1:
ret.append('\\def\\fnum@figure{%s}\n' %
@@ -640,7 +683,9 @@ class LaTeXTranslator(nodes.NodeVisitor):
return ''.join(ret)
def generate_indices(self):
+ # type: (Builder) -> unicode
def generate(content, collapsed):
+ # type: (List[Tuple[unicode, List[Tuple[unicode, unicode, unicode, unicode, unicode]]]], bool) -> unicode # NOQA
ret.append('\\begin{sphinxtheindex}\n')
ret.append('\\def\\bigletter#1{{\\Large\\sffamily#1}'
'\\nopagebreak\\vspace{1mm}}\n')
@@ -685,6 +730,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
return ''.join(ret)
def visit_document(self, node):
+ # type: (nodes.Node) -> None
self.footnotestack.append(self.collect_footnotes(node))
self.curfilestack.append(node.get('docname', ''))
if self.first_document == 1:
@@ -701,8 +747,9 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.sectionlevel = self.top_sectionlevel - 1
def depart_document(self, node):
+ # type: (nodes.Node) -> None
if self.bibitems:
- widest_label = ""
+ widest_label = "" # type: unicode
for bi in self.bibitems:
if len(widest_label) < len(bi[0]):
widest_label = bi[0]
@@ -717,6 +764,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.bibitems = []
def visit_start_of_file(self, node):
+ # type: (nodes.Node) -> None
# collect new footnotes
self.footnotestack.append(self.collect_footnotes(node))
# also add a document target
@@ -726,7 +774,9 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.hlsettingstack.append(self.hlsettingstack[0])
def collect_footnotes(self, node):
+ # type: (nodes.Node) -> Dict[unicode, List[Union[collected_footnote, bool]]]
def footnotes_under(n):
+ # type: (nodes.Node) -> Iterator[nodes.Node]
if isinstance(n, nodes.footnote):
yield n
else:
@@ -735,7 +785,8 @@ class LaTeXTranslator(nodes.NodeVisitor):
continue
for k in footnotes_under(c):
yield k
- fnotes = {}
+
+ fnotes = {} # type: Dict[unicode, List[Union[collected_footnote, bool]]]
for fn in footnotes_under(node):
num = fn.children[0].astext().strip()
newnode = collected_footnote(*fn.children, number=num)
@@ -743,15 +794,18 @@ class LaTeXTranslator(nodes.NodeVisitor):
return fnotes
def depart_start_of_file(self, node):
+ # type: (nodes.Node) -> None
self.footnotestack.pop()
self.curfilestack.pop()
self.hlsettingstack.pop()
def visit_highlightlang(self, node):
+ # type: (nodes.Node) -> None
self.hlsettingstack[-1] = [node['lang'], node['linenothreshold']]
raise nodes.SkipNode
def visit_section(self, node):
+ # type: (nodes.Node) -> None
if not self.this_is_the_title:
self.sectionlevel += 1
self.body.append('\n\n')
@@ -759,40 +813,50 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.next_section_ids.update(node['ids'])
def depart_section(self, node):
+ # type: (nodes.Node) -> None
self.sectionlevel = max(self.sectionlevel - 1,
self.top_sectionlevel - 1)
def visit_problematic(self, node):
+ # type: (nodes.Node) -> None
self.body.append(r'{\color{red}\bfseries{}')
def depart_problematic(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
def visit_topic(self, node):
+ # type: (nodes.Node) -> None
self.in_minipage = 1
self.body.append('\n\\begin{sphinxShadowBox}\n')
def depart_topic(self, node):
+ # type: (nodes.Node) -> None
self.in_minipage = 0
self.body.append('\\end{sphinxShadowBox}\n')
visit_sidebar = visit_topic
depart_sidebar = depart_topic
def visit_glossary(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_glossary(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_productionlist(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\n\\begin{productionlist}\n')
self.in_production_list = 1
def depart_productionlist(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\\end{productionlist}\n\n')
self.in_production_list = 0
def visit_production(self, node):
+ # type: (nodes.Node) -> None
if node['tokenname']:
tn = node['tokenname']
self.body.append(self.hypertarget('grammar-token-' + tn))
@@ -801,15 +865,19 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append('\\productioncont{')
def depart_production(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}\n')
def visit_transition(self, node):
+ # type: (nodes.Node) -> None
self.body.append(self.elements['transition'])
def depart_transition(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_title(self, node):
+ # type: (nodes.Node) -> None
parent = node.parent
if isinstance(parent, addnodes.seealso):
# the environment already handles this
@@ -866,6 +934,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.in_title = 1
def depart_title(self, node):
+ # type: (nodes.Node) -> None
self.in_title = 0
if isinstance(node.parent, nodes.table):
self.table.caption = self.popbody()
@@ -874,6 +943,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.unrestrict_footnote(node)
def visit_subtitle(self, node):
+ # type: (nodes.Node) -> None
if isinstance(node.parent, nodes.sidebar):
self.body.append('\\sphinxstylesidebarsubtitle{')
self.context.append('}\n')
@@ -881,17 +951,21 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.context.append('')
def depart_subtitle(self, node):
+ # type: (nodes.Node) -> None
self.body.append(self.context.pop())
def visit_desc(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\n\\begin{fulllineitems}\n')
if self.table:
self.table.has_problematic = True
def depart_desc(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\\end{fulllineitems}\n\n')
def _visit_signature_line(self, node):
+ # type: (nodes.Node) -> None
for child in node:
if isinstance(child, addnodes.desc_parameterlist):
self.body.append(r'\pysiglinewithargsret{')
@@ -900,9 +974,11 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append(r'\pysigline{')
def _depart_signature_line(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
def visit_desc_signature(self, node):
+ # type: (nodes.Node) -> None
if node.parent['objtype'] != 'describe' and node['ids']:
hyper = self.hypertarget(node['ids'][0])
else:
@@ -912,55 +988,69 @@ class LaTeXTranslator(nodes.NodeVisitor):
self._visit_signature_line(node)
def depart_desc_signature(self, node):
+ # type: (nodes.Node) -> None
if not node.get('is_multiline'):
self._depart_signature_line(node)
def visit_desc_signature_line(self, node):
+ # type: (nodes.Node) -> None
self._visit_signature_line(node)
def depart_desc_signature_line(self, node):
+ # type: (nodes.Node) -> None
self._depart_signature_line(node)
def visit_desc_addname(self, node):
+ # type: (nodes.Node) -> None
self.body.append(r'\sphinxcode{')
self.literal_whitespace += 1
def depart_desc_addname(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
self.literal_whitespace -= 1
def visit_desc_type(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_desc_type(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_desc_returns(self, node):
+ # type: (nodes.Node) -> None
self.body.append(r'{ $\rightarrow$ ')
def depart_desc_returns(self, node):
+ # type: (nodes.Node) -> None
self.body.append(r'}')
def visit_desc_name(self, node):
+ # type: (nodes.Node) -> None
self.body.append(r'\sphinxbfcode{')
self.no_contractions += 1
self.literal_whitespace += 1
def depart_desc_name(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
self.literal_whitespace -= 1
self.no_contractions -= 1
def visit_desc_parameterlist(self, node):
+ # type: (nodes.Node) -> None
# close name, open parameterlist
self.body.append('}{')
self.first_param = 1
def depart_desc_parameterlist(self, node):
+ # type: (nodes.Node) -> None
# close parameterlist, open return annotation
self.body.append('}{')
def visit_desc_parameter(self, node):
+ # type: (nodes.Node) -> None
if not self.first_param:
self.body.append(', ')
else:
@@ -969,36 +1059,46 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append(r'\emph{')
def depart_desc_parameter(self, node):
+ # type: (nodes.Node) -> None
if not node.hasattr('noemph'):
self.body.append('}')
def visit_desc_optional(self, node):
+ # type: (nodes.Node) -> None
self.body.append(r'\sphinxoptional{')
def depart_desc_optional(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
def visit_desc_annotation(self, node):
+ # type: (nodes.Node) -> None
self.body.append(r'\sphinxstrong{')
def depart_desc_annotation(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
def visit_desc_content(self, node):
+ # type: (nodes.Node) -> None
if node.children and not isinstance(node.children[0], nodes.paragraph):
# avoid empty desc environment which causes a formatting bug
self.body.append('~')
def depart_desc_content(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_seealso(self, node):
+ # type: (nodes.Node) -> None
self.body.append(u'\n\n\\sphinxstrong{%s:}\n\n' % admonitionlabels['seealso'])
def depart_seealso(self, node):
+ # type: (nodes.Node) -> None
self.body.append("\n\n")
def visit_rubric(self, node):
+ # type: (nodes.Node) -> None
if len(node.children) == 1 and node.children[0].astext() in \
('Footnotes', _('Footnotes')):
raise nodes.SkipNode
@@ -1007,13 +1107,16 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.in_title = 1
def depart_rubric(self, node):
+ # type: (nodes.Node) -> None
self.in_title = 0
self.body.append(self.context.pop())
def visit_footnote(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_collected_footnote(self, node):
+ # type: (nodes.Node) -> None
self.in_footnote += 1
if 'footnotetext' in node:
self.body.append('%%\n\\begin{footnotetext}[%s]'
@@ -1023,6 +1126,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
'\\sphinxAtStartFootnote\n' % node['number'])
def depart_collected_footnote(self, node):
+ # type: (nodes.Node) -> None
if 'footnotetext' in node:
self.body.append('%\n\\end{footnotetext}')
else:
@@ -1030,6 +1134,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.in_footnote -= 1
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]
@@ -1037,23 +1142,26 @@ class LaTeXTranslator(nodes.NodeVisitor):
raise nodes.SkipNode
def visit_tabular_col_spec(self, node):
+ # type: (nodes.Node) -> None
self.next_table_colspec = node['spec']
raise nodes.SkipNode
def visit_table(self, node):
+ # type: (nodes.Node) -> None
if self.table:
raise UnsupportedError(
'%s:%s: nested tables are not yet implemented.' %
(self.curfilestack[-1], node.line or ''))
self.table = Table()
self.table.longtable = 'longtable' in node['classes']
- self.tablebody = []
- self.tableheaders = []
+ self.tablebody = [] # type: List[unicode]
+ self.tableheaders = [] # type: List[unicode]
# Redirect body output until table is finished.
self.pushbody(self.tablebody)
self.restrict_footnote(node)
def depart_table(self, node):
+ # type: (nodes.Node) -> None
if self.table.rowcount > 30:
self.table.longtable = True
self.popbody()
@@ -1130,18 +1238,23 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.tablebody = None
def visit_colspec(self, node):
+ # type: (nodes.Node) -> None
self.table.colcount += 1
def depart_colspec(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_tgroup(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_tgroup(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_thead(self, node):
+ # type: (nodes.Node) -> None
self.table.had_head = True
if self.next_table_colspec:
self.table.colspec = '{%s}\n' % self.next_table_colspec
@@ -1150,24 +1263,29 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body = self.tableheaders
def depart_thead(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_tbody(self, node):
+ # type: (nodes.Node) -> None
if not self.table.had_head:
self.visit_thead(node)
self.body = self.tablebody
def depart_tbody(self, node):
+ # type: (nodes.Node) -> None
self.remember_multirow = {}
self.remember_multirowcol = {}
def visit_row(self, node):
+ # type: (nodes.Node) -> None
self.table.col = 0
for key, value in self.remember_multirow.items():
if not value and key in self.remember_multirowcol:
del self.remember_multirowcol[key]
def depart_row(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\\\\\n')
if any(self.remember_multirow.values()):
linestart = 1
@@ -1188,6 +1306,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.table.rowcount += 1
def visit_entry(self, node):
+ # type: (nodes.Node) -> None
if self.table.col == 0:
while self.remember_multirow.get(self.table.col + 1, 0):
self.table.col += 1
@@ -1249,6 +1368,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.context.append(context)
def depart_entry(self, node):
+ # type: (nodes.Node) -> None
if self.in_merged_cell:
self.in_merged_cell = 0
self.literal_whitespace -= 1
@@ -1262,6 +1382,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append(self.context.pop()) # header
def visit_acks(self, node):
+ # type: (nodes.Node) -> None
# this is a list in the source, but should be rendered as a
# comma-separated list here
self.body.append('\n\n')
@@ -1271,16 +1392,19 @@ class LaTeXTranslator(nodes.NodeVisitor):
raise nodes.SkipNode
def visit_bullet_list(self, node):
+ # type: (nodes.Node) -> None
if not self.compact_list:
self.body.append('\\begin{itemize}\n')
if self.table:
self.table.has_problematic = True
def depart_bullet_list(self, node):
+ # type: (nodes.Node) -> None
if not self.compact_list:
self.body.append('\\end{itemize}\n')
def visit_enumerated_list(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\\begin{enumerate}\n')
if 'start' in node:
self.body.append('\\setcounter{enumi}{%d}\n' % (node['start'] - 1))
@@ -1288,33 +1412,41 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.table.has_problematic = True
def depart_enumerated_list(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\\end{enumerate}\n')
def visit_list_item(self, node):
+ # type: (nodes.Node) -> None
# Append "{}" in case the next character is "[", which would break
# LaTeX's list environment (no numbering and the "[" is not printed).
self.body.append(r'\item {} ')
def depart_list_item(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n')
def visit_definition_list(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\\begin{description}\n')
if self.table:
self.table.has_problematic = True
def depart_definition_list(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\\end{description}\n')
def visit_definition_list_item(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_definition_list_item(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_term(self, node):
+ # type: (nodes.Node) -> None
self.in_term += 1
- ctx = '}] \\leavevmode'
+ ctx = '}] \\leavevmode' # type: unicode
if node.get('ids'):
ctx += self.hypertarget(node['ids'][0])
self.body.append('\\item[{')
@@ -1322,40 +1454,50 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.context.append(ctx)
def depart_term(self, node):
+ # type: (nodes.Node) -> None
self.body.append(self.context.pop())
self.unrestrict_footnote(node)
self.in_term -= 1
def visit_termsep(self, node):
+ # type: (nodes.Node) -> None
warnings.warn('sphinx.addnodes.termsep will be removed at Sphinx-1.5',
DeprecationWarning)
self.body.append(', ')
raise nodes.SkipNode
def visit_classifier(self, node):
+ # type: (nodes.Node) -> None
self.body.append('{[}')
def depart_classifier(self, node):
+ # type: (nodes.Node) -> None
self.body.append('{]}')
def visit_definition(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_definition(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n')
def visit_field_list(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\\begin{quote}\\begin{description}\n')
if self.table:
self.table.has_problematic = True
def depart_field_list(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\\end{description}\\end{quote}\n')
def visit_field(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_field(self, node):
+ # type: (nodes.Node) -> None
pass
visit_field_name = visit_term
@@ -1365,6 +1507,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
depart_field_body = depart_definition
def visit_paragraph(self, node):
+ # type: (nodes.Node) -> None
index = node.parent.index(node)
if (index > 0 and isinstance(node.parent, nodes.compound) and
not isinstance(node.parent[index - 1], nodes.paragraph) and
@@ -1378,17 +1521,21 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append('\n')
def depart_paragraph(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n')
def visit_centered(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\\begin{center}')
if self.table:
self.table.has_problematic = True
def depart_centered(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\\end{center}')
def visit_hlist(self, node):
+ # type: (nodes.Node) -> None
# for now, we don't support a more compact list format
# don't add individual itemize environments, but one for all columns
self.compact_list += 1
@@ -1398,26 +1545,32 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.table.has_problematic = True
def depart_hlist(self, node):
+ # type: (nodes.Node) -> None
self.compact_list -= 1
self.body.append('\\end{itemize}\n')
def visit_hlistcol(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_hlistcol(self, node):
+ # type: (nodes.Node) -> None
pass
def latex_image_length(self, width_str):
+ # type: (nodes.Node) -> unicode
try:
return rstdim_to_latexdim(width_str)
except ValueError:
self.builder.warn('dimension unit %s is invalid. Ignored.' % width_str)
def is_inline(self, node):
+ # type: (nodes.Node) -> bool
"""Check whether a node represents an inline element."""
return isinstance(node.parent, nodes.TextElement)
def visit_image(self, node):
+ # type: (nodes.Node) -> None
attrs = node.attributes
pre = [] # in reverse order
post = []
@@ -1490,10 +1643,12 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.extend(post)
def depart_image(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_figure(self, node):
- ids = ''
+ # type: (nodes.Node) -> None
+ ids = '' # type: unicode
for id in self.pop_hyperlink_ids('figure'):
ids += self.hypertarget(id, anchor=False)
if node['ids']:
@@ -1549,10 +1704,12 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.context.append(ids + align_end + '\\end{figure}\n')
def depart_figure(self, node):
+ # type: (nodes.Node) -> None
self.body.append(self.context.pop())
self.unrestrict_footnote(node)
def visit_caption(self, node):
+ # type: (nodes.Node) -> None
self.in_caption += 1
self.restrict_footnote(node)
if self.in_container_literal_block:
@@ -1565,29 +1722,36 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append('\\caption{')
def depart_caption(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
self.in_caption -= 1
self.unrestrict_footnote(node)
def visit_legend(self, node):
+ # type: (nodes.Node) -> None
self.body.append('{\\small ')
def depart_legend(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
def visit_admonition(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\\begin{sphinxadmonition}{note}')
def depart_admonition(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\\end{sphinxadmonition}\n')
def _make_visit_admonition(name):
def visit_admonition(self, node):
+ # type: (nodes.Node) -> None
self.body.append(u'\n\\begin{sphinxadmonition}{%s}{%s:}' %
(name, admonitionlabels[name]))
return visit_admonition
def _depart_named_admonition(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\\end{sphinxadmonition}\n')
visit_attention = _make_visit_admonition('attention')
@@ -1610,13 +1774,17 @@ class LaTeXTranslator(nodes.NodeVisitor):
depart_warning = _depart_named_admonition
def visit_versionmodified(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_versionmodified(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_target(self, node):
+ # type: (nodes.Node) -> None
def add_target(id):
+ # type: (unicode) -> None
# indexing uses standard LaTeX index markup, so the targets
# will be generated differently
if id.startswith('index-'):
@@ -1664,16 +1832,20 @@ class LaTeXTranslator(nodes.NodeVisitor):
add_target(id)
def depart_target(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_attribution(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\\begin{flushright}\n')
self.body.append('---')
def depart_attribution(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\\end{flushright}\n')
def visit_index(self, node, scre=re.compile(r';\s*')):
+ # type: (nodes.Node, Pattern) -> None
if not node.get('inline', True):
self.body.append('\n')
entries = node['entries']
@@ -1710,11 +1882,13 @@ class LaTeXTranslator(nodes.NodeVisitor):
raise nodes.SkipNode
def visit_raw(self, node):
+ # type: (nodes.Node) -> None
if 'latex' in node.get('format', '').split():
self.body.append(node.astext())
raise nodes.SkipNode
def visit_reference(self, node):
+ # type: (nodes.Node) -> None
if not self.in_title:
for id in node.get('ids'):
anchor = not self.in_caption
@@ -1773,9 +1947,11 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.context.append('')
def depart_reference(self, node):
+ # type: (nodes.Node) -> None
self.body.append(self.context.pop())
def visit_number_reference(self, node):
+ # type: (nodes.Node) -> None
if node.get('refid'):
id = self.curfilestack[-1] + ':' + node['refid']
else:
@@ -1797,46 +1973,59 @@ class LaTeXTranslator(nodes.NodeVisitor):
raise nodes.SkipNode
def visit_download_reference(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_download_reference(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_pending_xref(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_pending_xref(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_emphasis(self, node):
+ # type: (nodes.Node) -> None
self.body.append(r'\sphinxstyleemphasis{')
def depart_emphasis(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
def visit_literal_emphasis(self, node):
+ # type: (nodes.Node) -> None
self.body.append(r'\sphinxstyleliteralemphasis{')
self.no_contractions += 1
def depart_literal_emphasis(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
self.no_contractions -= 1
def visit_strong(self, node):
+ # type: (nodes.Node) -> None
self.body.append(r'\sphinxstylestrong{')
def depart_strong(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
def visit_literal_strong(self, node):
+ # type: (nodes.Node) -> None
self.body.append(r'\sphinxstyleliteralstrong{')
self.no_contractions += 1
def depart_literal_strong(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
self.no_contractions -= 1
def visit_abbreviation(self, node):
+ # type: (nodes.Node) -> None
abbr = node.astext()
self.body.append(r'\sphinxstyleabbreviation{')
# spell out the explanation once
@@ -1847,39 +2036,48 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.context.append('}')
def depart_abbreviation(self, node):
+ # type: (nodes.Node) -> None
self.body.append(self.context.pop())
def visit_manpage(self, node):
+ # type: (nodes.Node) -> Any
return self.visit_literal_emphasis(node)
def depart_manpage(self, node):
+ # type: (nodes.Node) -> Any
return self.depart_literal_emphasis(node)
def visit_title_reference(self, node):
+ # type: (nodes.Node) -> None
self.body.append(r'\sphinxtitleref{')
def depart_title_reference(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
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))
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
def visit_citation_reference(self, node):
+ # type: (nodes.Node) -> None
# This is currently never encountered, since citation_reference nodes
# are already replaced by pending_xref nodes in the environment.
self.body.append('\\cite{%s}' % self.idescape(node.astext()))
raise nodes.SkipNode
def visit_literal(self, node):
+ # type: (nodes.Node) -> None
self.no_contractions += 1
if self.in_title:
self.body.append(r'\sphinxstyleliteralintitle{')
@@ -1887,10 +2085,12 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append(r'\sphinxcode{')
def depart_literal(self, node):
+ # type: (nodes.Node) -> None
self.no_contractions -= 1
self.body.append('}')
def visit_footnote_reference(self, node):
+ # type: (nodes.Node) -> None
num = node.astext().strip()
try:
footnode, used = self.footnotestack[-1][num]
@@ -1906,18 +2106,20 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.pending_footnotes.append(footnode)
else:
self.footnotestack[-1][num][1] = True
- footnode.walkabout(self)
+ footnode.walkabout(self) # type: ignore
raise nodes.SkipChildren
def depart_footnote_reference(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_literal_block(self, node):
+ # type: (nodes.Node) -> None
if node.rawsource != node.astext():
# most probably a parsed-literal block -- don't highlight
self.body.append('\\begin{alltt}\n')
else:
- ids = ''
+ ids = '' # type: unicode
for id in self.pop_hyperlink_ids('code-block'):
ids += self.hypertarget(id, anchor=False)
if node['ids']:
@@ -1943,6 +2145,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
opts = {}
def warner(msg):
+ # type: (unicode) -> None
self.builder.warn(msg, (self.curfilestack[-1], node.line))
hlcode = self.highlighter.highlight_block(code, lang, opts=opts,
warn=warner, linenos=linenos,
@@ -1974,17 +2177,21 @@ class LaTeXTranslator(nodes.NodeVisitor):
raise nodes.SkipNode
def depart_literal_block(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\\end{alltt}\n')
visit_doctest_block = visit_literal_block
depart_doctest_block = depart_literal_block
def visit_line(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\item[] ')
def depart_line(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n')
def visit_line_block(self, node):
+ # type: (nodes.Node) -> None
if isinstance(node.parent, nodes.line_block):
self.body.append('\\item[]\n'
'\\begin{DUlineblock}{\\DUlineblockindent}\n')
@@ -1994,9 +2201,11 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.table.has_problematic = True
def depart_line_block(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\\end{DUlineblock}\n')
def visit_block_quote(self, node):
+ # type: (nodes.Node) -> None
# If the block quote contains a single object and that object
# is a list, then generate a list not a block quote.
# This lets us indent lists.
@@ -2012,6 +2221,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.table.has_problematic = True
def depart_block_quote(self, node):
+ # type: (nodes.Node) -> None
done = 0
if len(node.children) == 1:
child = node.children[0]
@@ -2024,45 +2234,56 @@ class LaTeXTranslator(nodes.NodeVisitor):
# option node handling copied from docutils' latex writer
def visit_option(self, node):
+ # type: (nodes.Node) -> None
if self.context[-1]:
# this is not the first option
self.body.append(', ')
def depart_option(self, node):
+ # type: (nodes.Node) -> None
# flag that the first option is done.
self.context[-1] += 1
def visit_option_argument(self, node):
+ # type: (nodes.Node) -> None
"""The delimiter betweeen an option and its argument."""
self.body.append(node.get('delimiter', ' '))
def depart_option_argument(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_option_group(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\\item [')
# flag for first option
self.context.append(0)
def depart_option_group(self, node):
+ # type: (nodes.Node) -> None
self.context.pop() # the flag
self.body.append('] ')
def visit_option_list(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\\begin{optionlist}{3cm}\n')
if self.table:
self.table.has_problematic = True
def depart_option_list(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\\end{optionlist}\n')
def visit_option_list_item(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_option_list_item(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_option_string(self, node):
+ # type: (nodes.Node) -> None
ostring = node.astext()
self.no_contractions += 1
self.body.append(self.encode(ostring))
@@ -2070,30 +2291,39 @@ class LaTeXTranslator(nodes.NodeVisitor):
raise nodes.SkipNode
def visit_description(self, node):
+ # type: (nodes.Node) -> None
self.body.append(' ')
def depart_description(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_superscript(self, node):
+ # type: (nodes.Node) -> None
self.body.append('$^{\\text{')
def depart_superscript(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}}$')
def visit_subscript(self, node):
+ # type: (nodes.Node) -> None
self.body.append('$_{\\text{')
def depart_subscript(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}}$')
def visit_substitution_definition(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_substitution_reference(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_inline(self, node):
+ # type: (nodes.Node) -> None
classes = node.get('classes', [])
if classes in [['menuselection'], ['guilabel']]:
self.body.append(r'\sphinxmenuselection{')
@@ -2108,24 +2338,30 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.context.append('')
def depart_inline(self, node):
+ # type: (nodes.Node) -> None
self.body.append(self.context.pop())
def visit_generated(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_generated(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_compound(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_compound(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_container(self, node):
+ # type: (nodes.Node) -> None
if node.get('literal_block'):
self.in_container_literal_block += 1
- ids = ''
+ ids = '' # type: unicode
for id in self.pop_hyperlink_ids('code-block'):
ids += self.hypertarget(id, anchor=False)
if node['ids']:
@@ -2136,31 +2372,38 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append('\n\\def\\sphinxLiteralBlockLabel{' + ids + '}\n')
def depart_container(self, node):
+ # type: (nodes.Node) -> None
if node.get('literal_block'):
self.in_container_literal_block -= 1
self.body.append('\\let\\sphinxVerbatimTitle\\empty\n')
self.body.append('\\let\\sphinxLiteralBlockLabel\\empty\n')
def visit_decoration(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_decoration(self, node):
+ # type: (nodes.Node) -> None
pass
# docutils-generated elements that we don't support
def visit_header(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_footer(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_docinfo(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
# text handling
def encode(self, text):
+ # type: (unicode) -> unicode
text = text_type(text).translate(tex_escape_map)
if self.literal_whitespace:
# Insert a blank before the newline, to avoid
@@ -2172,32 +2415,40 @@ class LaTeXTranslator(nodes.NodeVisitor):
return text
def encode_uri(self, text):
+ # type: (unicode) -> unicode
# in \href, the tilde is allowed and must be represented literally
return self.encode(text).replace('\\textasciitilde{}', '~')
def visit_Text(self, node):
+ # type: (nodes.Node) -> None
text = self.encode(node.astext())
if not self.no_contractions:
text = educate_quotes_latex(text)
self.body.append(text)
def depart_Text(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_comment(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_meta(self, node):
+ # type: (nodes.Node) -> None
# only valid for HTML
raise nodes.SkipNode
def visit_system_message(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_system_message(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n')
def visit_math(self, node):
+ # type: (nodes.Node) -> None
self.builder.warn('using "math" markup without a Sphinx math extension '
'active, please use one of the math extensions '
'described at http://sphinx-doc.org/ext/math.html',
@@ -2207,4 +2458,5 @@ class LaTeXTranslator(nodes.NodeVisitor):
visit_math_block = visit_math
def unknown_visit(self, node):
+ # type: (nodes.Node) -> None
raise NotImplementedError('Unknown node: ' + node.__class__.__name__)
diff --git a/sphinx/writers/texinfo.py b/sphinx/writers/texinfo.py
index 6ec077fd7..0a9a42aca 100644
--- a/sphinx/writers/texinfo.py
+++ b/sphinx/writers/texinfo.py
@@ -16,6 +16,7 @@ import warnings
from six import itervalues
from six.moves import range
+
from docutils import nodes, writers
from sphinx import addnodes, __display_version__
@@ -23,6 +24,11 @@ from sphinx.locale import admonitionlabels, _
from sphinx.util.i18n import format_date
from sphinx.writers.latex import collected_footnote
+if False:
+ # For type annotation
+ from typing import Any, Callable, Iterator, Pattern, Tuple, Union # NOQA
+ from sphinx.builders.texinfo import TexinfoBuilder # NOQA
+
COPYING = """\
@quotation
@@ -80,6 +86,7 @@ TEMPLATE = """\
def find_subsections(section):
+ # type: (nodes.Node) -> List[nodes.Node]
"""Return a list of subsections for the given ``section``."""
result = []
for child in section.children:
@@ -91,6 +98,7 @@ def find_subsections(section):
def smart_capwords(s, sep=None):
+ # type: (unicode, unicode) -> unicode
"""Like string.capwords() but does not capitalize words that already
contain a capital letter."""
words = s.split(sep)
@@ -110,21 +118,23 @@ class TexinfoWriter(writers.Writer):
('Dir entry', ['--texinfo-dir-entry'], {'default': ''}),
('Description', ['--texinfo-dir-description'], {'default': ''}),
('Category', ['--texinfo-dir-category'], {'default':
- 'Miscellaneous'})))
+ 'Miscellaneous'}))) # type: Tuple[unicode, Any, Tuple[Tuple[unicode, List[unicode], Dict[unicode, unicode]], ...]] # NOQA
- settings_defaults = {}
+ settings_defaults = {} # type: Dict
- output = None
+ output = None # type: unicode
visitor_attributes = ('output', 'fragment')
def __init__(self, builder):
+ # type: (TexinfoBuilder) -> None
writers.Writer.__init__(self)
self.builder = builder
self.translator_class = (
self.builder.translator_class or TexinfoTranslator)
def translate(self):
+ # type: () -> None
self.visitor = visitor = self.translator_class(
self.document, self.builder)
self.document.walkabout(visitor)
@@ -153,44 +163,53 @@ class TexinfoTranslator(nodes.NodeVisitor):
}
def __init__(self, document, builder):
+ # type: (nodes.Node, TexinfoBuilder) -> None
nodes.NodeVisitor.__init__(self, document)
self.builder = builder
self.init_settings()
- self.written_ids = set() # node names and anchors in output
+ self.written_ids = set() # type: Set[unicode]
+ # node names and anchors in output
# node names and anchors that should be in output
- self.referenced_ids = set()
- self.indices = [] # (node name, content)
- self.short_ids = {} # anchors --> short ids
- self.node_names = {} # node name --> node's name to display
- self.node_menus = {} # node name --> node's menu entries
- self.rellinks = {} # node name --> (next, previous, up)
+ self.referenced_ids = set() # type: Set[unicode]
+ self.indices = [] # type: List[Tuple[unicode, unicode]]
+ # (node name, content)
+ self.short_ids = {} # type: Dict[unicode, unicode]
+ # anchors --> short ids
+ self.node_names = {} # type: Dict[unicode, unicode]
+ # node name --> node's name to display
+ self.node_menus = {} # type: Dict[unicode, List[unicode]]
+ # node name --> node's menu entries
+ self.rellinks = {} # type: Dict[unicode, List[unicode]]
+ # node name --> (next, previous, up)
self.collect_indices()
self.collect_node_names()
self.collect_node_menus()
self.collect_rellinks()
- self.body = []
- self.context = []
- self.previous_section = None
+ self.body = [] # type: List[unicode]
+ self.context = [] # type: List[unicode]
+ self.previous_section = None # type: nodes.section
self.section_level = 0
self.seen_title = False
- self.next_section_ids = set()
+ self.next_section_ids = set() # type: Set[unicode]
self.escape_newlines = 0
self.escape_hyphens = 0
- self.curfilestack = []
- self.footnotestack = []
+ self.curfilestack = [] # type: List[unicode]
+ self.footnotestack = [] # type: List[Dict[unicode, List[Union[collected_footnote, bool]]]] # NOQA
self.in_footnote = 0
- self.handled_abbrs = set()
+ self.handled_abbrs = set() # type: Set[unicode]
+ self.colwidths = None # type: List[int]
def finish(self):
+ # type: () -> None
if self.previous_section is None:
self.add_menu('Top')
for index in self.indices:
name, content = index
pointers = tuple([name] + self.rellinks[name])
- self.body.append('\n@node %s,%s,%s,%s\n' % pointers)
+ self.body.append('\n@node %s,%s,%s,%s\n' % pointers) # type: ignore
self.body.append('@unnumbered %s\n\n%s\n' % (name, content))
while self.referenced_ids:
@@ -206,6 +225,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
# -- Helper routines
def init_settings(self):
+ # type: () -> None
settings = self.settings = self.document.settings
elements = self.elements = self.default_elements.copy()
elements.update({
@@ -222,17 +242,18 @@ class TexinfoTranslator(nodes.NodeVisitor):
language=self.builder.config.language))
})
# title
- title = elements['title']
+ title = None # type: unicode
+ title = elements['title'] # type: ignore
if not title:
- title = self.document.next_node(nodes.title)
- title = (title and title.astext()) or '<untitled>'
+ title = self.document.next_node(nodes.title) # type: ignore
+ title = (title and title.astext()) or '<untitled>' # type: ignore
elements['title'] = self.escape_id(title) or '<untitled>'
# filename
if not elements['filename']:
elements['filename'] = self.document.get('source') or 'untitled'
- if elements['filename'][-4:] in ('.txt', '.rst'):
- elements['filename'] = elements['filename'][:-4]
- elements['filename'] += '.info'
+ if elements['filename'][-4:] in ('.txt', '.rst'): # type: ignore
+ elements['filename'] = elements['filename'][:-4] # type: ignore
+ elements['filename'] += '.info' # type: ignore
# direntry
if settings.texinfo_dir_entry:
entry = self.format_menu_entry(
@@ -249,11 +270,13 @@ class TexinfoTranslator(nodes.NodeVisitor):
elements.update(settings.texinfo_elements)
def collect_node_names(self):
+ # type: () -> None
"""Generates a unique id for each section.
Assigns the attribute ``node_name`` to each section."""
def add_node_name(name):
+ # type: (unicode) -> unicode
node_id = self.escape_id(name)
nth, suffix = 1, ''
while node_id + suffix in self.written_ids or \
@@ -279,6 +302,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
section['node_name'] = add_node_name(name)
def collect_node_menus(self):
+ # type: () -> None
"""Collect the menu entries for each "node" section."""
node_menus = self.node_menus
for node in ([self.document] +
@@ -303,6 +327,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
node_menus['Top'].append(name)
def collect_rellinks(self):
+ # type: () -> None
"""Collect the relative links (next, previous, up) for each "node"."""
rellinks = self.rellinks
node_menus = self.node_menus
@@ -336,6 +361,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
# characters.
def escape(self, s):
+ # type: (unicode) -> unicode
"""Return a string with Texinfo command characters escaped."""
s = s.replace('@', '@@')
s = s.replace('{', '@{')
@@ -346,6 +372,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
return s
def escape_arg(self, s):
+ # type: (unicode) -> unicode
"""Return an escaped string suitable for use as an argument
to a Texinfo command."""
s = self.escape(s)
@@ -356,6 +383,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
return s
def escape_id(self, s):
+ # type: (unicode) -> unicode
"""Return an escaped string suitable for node names and anchors."""
bad_chars = ',:.()'
for bc in bad_chars:
@@ -364,6 +392,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
return self.escape(s)
def escape_menu(self, s):
+ # type: (unicode) -> unicode
"""Return an escaped string suitable for menu entries."""
s = self.escape_arg(s)
s = s.replace(':', ';')
@@ -371,11 +400,13 @@ class TexinfoTranslator(nodes.NodeVisitor):
return s
def ensure_eol(self):
+ # type: () -> None
"""Ensure the last line in body is terminated by new line."""
if self.body and self.body[-1][-1:] != '\n':
self.body.append('\n')
def format_menu_entry(self, name, node_name, desc):
+ # type: (unicode, unicode, unicode) -> unicode
if name == node_name:
s = '* %s:: ' % (name,)
else:
@@ -386,6 +417,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
return s + wdesc.strip() + '\n'
def add_menu_entries(self, entries, reg=re.compile(r'\s+---?\s+')):
+ # type: (List[unicode], Pattern) -> None
for entry in entries:
name = self.node_names[entry]
# special formatting for entries that are divided by an em-dash
@@ -403,6 +435,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
self.body.append(self.format_menu_entry(name, entry, desc))
def add_menu(self, node_name):
+ # type: (unicode) -> None
entries = self.node_menus[node_name]
if not entries:
return
@@ -415,6 +448,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
return
def _add_detailed_menu(name):
+ # type: (unicode) -> None
entries = self.node_menus[name]
if not entries:
return
@@ -431,6 +465,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
'@end menu\n')
def tex_image_length(self, width_str):
+ # type: (unicode) -> unicode
match = re.match('(\d*\.?\d*)\s*(\S*)', width_str)
if not match:
# fallback
@@ -446,15 +481,17 @@ class TexinfoTranslator(nodes.NodeVisitor):
return res
def collect_indices(self):
+ # type: () -> None
def generate(content, collapsed):
- ret = ['\n@menu\n']
+ # type: (List[Tuple[unicode, List[List[Union[unicode, int]]]]], bool) -> unicode
+ ret = ['\n@menu\n'] # type: List[unicode]
for letter, entries in content:
for entry in entries:
if not entry[3]:
continue
- name = self.escape_menu(entry[0])
+ name = self.escape_menu(entry[0]) # type: ignore
sid = self.get_short_id('%s:%s' % (entry[2], entry[3]))
- desc = self.escape_arg(entry[6])
+ desc = self.escape_arg(entry[6]) # type: ignore
me = self.format_menu_entry(name, sid, desc)
ret.append(me)
ret.append('@end menu\n')
@@ -484,7 +521,9 @@ class TexinfoTranslator(nodes.NodeVisitor):
# TODO: move this to sphinx.util
def collect_footnotes(self, node):
+ # type: (nodes.Node) -> Dict[unicode, List[Union[collected_footnote, bool]]]
def footnotes_under(n):
+ # type: (nodes.Node) -> Iterator[nodes.footnote]
if isinstance(n, nodes.footnote):
yield n
else:
@@ -493,7 +532,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
continue
for k in footnotes_under(c):
yield k
- fnotes = {}
+ fnotes = {} # type: Dict[unicode, List[Union[collected_footnote, bool]]]
for fn in footnotes_under(node):
num = fn.children[0].astext().strip()
fnotes[num] = [collected_footnote(*fn.children), False]
@@ -502,6 +541,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
# -- xref handling
def get_short_id(self, id):
+ # type: (unicode) -> unicode
"""Return a shorter 'id' associated with ``id``."""
# Shorter ids improve paragraph filling in places
# that the id is hidden by Emacs.
@@ -513,6 +553,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
return sid
def add_anchor(self, id, node):
+ # type: (unicode, nodes.Node) -> None
if id.startswith('index-'):
return
id = self.curfilestack[-1] + ':' + id
@@ -524,6 +565,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
self.written_ids.add(id)
def add_xref(self, id, name, node):
+ # type: (unicode, unicode, nodes.Node) -> None
name = self.escape_menu(name)
sid = self.get_short_id(id)
self.body.append('@ref{%s,,%s}' % (sid, name))
@@ -533,16 +575,19 @@ class TexinfoTranslator(nodes.NodeVisitor):
# -- Visiting
def visit_document(self, node):
+ # type: (nodes.Node) -> None
self.footnotestack.append(self.collect_footnotes(node))
self.curfilestack.append(node.get('docname', ''))
if 'docname' in node:
self.add_anchor(':doc', node)
def depart_document(self, node):
+ # type: (nodes.Node) -> None
self.footnotestack.pop()
self.curfilestack.pop()
def visit_Text(self, node):
+ # type: (nodes.Node) -> None
s = self.escape(node.astext())
if self.escape_newlines:
s = s.replace('\n', ' ')
@@ -552,9 +597,11 @@ class TexinfoTranslator(nodes.NodeVisitor):
self.body.append(s)
def depart_Text(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_section(self, node):
+ # type: (nodes.section) -> None
self.next_section_ids.update(node.get('ids', []))
if not self.seen_title:
return
@@ -565,7 +612,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
node_name = node['node_name']
pointers = tuple([node_name] + self.rellinks[node_name])
- self.body.append('\n@node %s,%s,%s,%s\n' % pointers)
+ self.body.append('\n@node %s,%s,%s,%s\n' % pointers) # type: ignore
for id in self.next_section_ids:
self.add_anchor(id, node)
@@ -574,6 +621,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
self.section_level += 1
def depart_section(self, node):
+ # type: (nodes.Node) -> None
self.section_level -= 1
headings = (
@@ -582,15 +630,16 @@ class TexinfoTranslator(nodes.NodeVisitor):
'@section',
'@subsection',
'@subsubsection',
- )
+ ) # type: Tuple[unicode, ...]
rubrics = (
'@heading',
'@subheading',
'@subsubheading',
- )
+ ) # type: Tuple[unicode, ...]
def visit_title(self, node):
+ # type: (nodes.Node) -> None
if not self.seen_title:
self.seen_title = 1
raise nodes.SkipNode
@@ -612,9 +661,11 @@ class TexinfoTranslator(nodes.NodeVisitor):
self.body.append('\n%s ' % heading)
def depart_title(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\n')
def visit_rubric(self, node):
+ # type: (nodes.Node) -> None
if len(node.children) == 1 and node.children[0].astext() in \
('Footnotes', _('Footnotes')):
raise nodes.SkipNode
@@ -625,17 +676,21 @@ class TexinfoTranslator(nodes.NodeVisitor):
self.body.append('\n%s ' % rubric)
def depart_rubric(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\n')
def visit_subtitle(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\n@noindent\n')
def depart_subtitle(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\n')
# -- References
def visit_target(self, node):
+ # type: (nodes.Node) -> None
# postpone the labels until after the sectioning command
parindex = node.parent.index(node)
try:
@@ -660,9 +715,11 @@ class TexinfoTranslator(nodes.NodeVisitor):
self.add_anchor(id, node)
def depart_target(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_reference(self, node):
+ # type: (nodes.Node) -> None
# an xref's target is displayed in Info so we ignore a few
# cases for the sake of appearance
if isinstance(node.parent, (nodes.title, addnodes.desc_type)):
@@ -726,14 +783,17 @@ class TexinfoTranslator(nodes.NodeVisitor):
raise nodes.SkipNode
def depart_reference(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_number_reference(self, node):
+ # type: (nodes.Node) -> None
text = nodes.Text(node.get('title', '#'))
self.visit_Text(text)
raise nodes.SkipNode
def visit_title_reference(self, node):
+ # type: (nodes.Node) -> None
text = node.astext()
self.body.append('@cite{%s}' % self.escape_arg(text))
raise nodes.SkipNode
@@ -741,22 +801,28 @@ class TexinfoTranslator(nodes.NodeVisitor):
# -- Blocks
def visit_paragraph(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n')
def depart_paragraph(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n')
def visit_block_quote(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n@quotation\n')
def depart_block_quote(self, node):
+ # type: (nodes.Node) -> None
self.ensure_eol()
self.body.append('@end quotation\n')
def visit_literal_block(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n@example\n')
def depart_literal_block(self, node):
+ # type: (nodes.Node) -> None
self.ensure_eol()
self.body.append('@end example\n')
@@ -764,101 +830,126 @@ class TexinfoTranslator(nodes.NodeVisitor):
depart_doctest_block = depart_literal_block
def visit_line_block(self, node):
+ # type: (nodes.Node) -> None
if not isinstance(node.parent, nodes.line_block):
self.body.append('\n\n')
self.body.append('@display\n')
def depart_line_block(self, node):
+ # type: (nodes.Node) -> None
self.body.append('@end display\n')
if not isinstance(node.parent, nodes.line_block):
self.body.append('\n\n')
def visit_line(self, node):
+ # type: (nodes.Node) -> None
self.escape_newlines += 1
def depart_line(self, node):
+ # type: (nodes.Node) -> None
self.body.append('@w{ }\n')
self.escape_newlines -= 1
# -- Inline
def visit_strong(self, node):
+ # type: (nodes.Node) -> None
self.body.append('@strong{')
def depart_strong(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
def visit_emphasis(self, node):
+ # type: (nodes.Node) -> None
self.body.append('@emph{')
def depart_emphasis(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
def visit_literal(self, node):
+ # type: (nodes.Node) -> None
self.body.append('@code{')
def depart_literal(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
def visit_superscript(self, node):
+ # type: (nodes.Node) -> None
self.body.append('@w{^')
def depart_superscript(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
def visit_subscript(self, node):
+ # type: (nodes.Node) -> None
self.body.append('@w{[')
def depart_subscript(self, node):
+ # type: (nodes.Node) -> None
self.body.append(']}')
# -- Footnotes
def visit_footnote(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_collected_footnote(self, node):
+ # type: (nodes.Node) -> None
self.in_footnote += 1
self.body.append('@footnote{')
def depart_collected_footnote(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
self.in_footnote -= 1
def visit_footnote_reference(self, node):
+ # type: (nodes.Node) -> None
num = node.astext().strip()
try:
footnode, used = self.footnotestack[-1][num]
except (KeyError, IndexError):
raise nodes.SkipNode
# footnotes are repeated for each reference
- footnode.walkabout(self)
+ footnode.walkabout(self) # type: ignore
raise nodes.SkipChildren
def visit_citation(self, node):
+ # type: (nodes.Node) -> None
for id in node.get('ids'):
self.add_anchor(id, node)
def depart_citation(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_citation_reference(self, node):
+ # type: (nodes.Node) -> None
self.body.append('@w{[')
def depart_citation_reference(self, node):
+ # type: (nodes.Node) -> None
self.body.append(']}')
# -- Lists
def visit_bullet_list(self, node):
+ # type: (nodes.Node) -> None
bullet = node.get('bullet', '*')
self.body.append('\n\n@itemize %s\n' % bullet)
def depart_bullet_list(self, node):
+ # type: (nodes.Node) -> None
self.ensure_eol()
self.body.append('@end itemize\n')
def visit_enumerated_list(self, node):
+ # type: (nodes.Node) -> None
# doesn't support Roman numerals
enum = node.get('enumtype', 'arabic')
starters = {'arabic': '',
@@ -868,75 +959,96 @@ class TexinfoTranslator(nodes.NodeVisitor):
self.body.append('\n\n@enumerate %s\n' % start)
def depart_enumerated_list(self, node):
+ # type: (nodes.Node) -> None
self.ensure_eol()
self.body.append('@end enumerate\n')
def visit_list_item(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n@item ')
def depart_list_item(self, node):
+ # type: (nodes.Node) -> None
pass
# -- Option List
def visit_option_list(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\n@table @option\n')
def depart_option_list(self, node):
+ # type: (nodes.Node) -> None
self.ensure_eol()
self.body.append('@end table\n')
def visit_option_list_item(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_option_list_item(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_option_group(self, node):
+ # type: (nodes.Node) -> None
self.at_item_x = '@item'
def depart_option_group(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_option(self, node):
+ # type: (nodes.Node) -> None
self.escape_hyphens += 1
self.body.append('\n%s ' % self.at_item_x)
self.at_item_x = '@itemx'
def depart_option(self, node):
+ # type: (nodes.Node) -> None
self.escape_hyphens -= 1
def visit_option_string(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_option_string(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_option_argument(self, node):
+ # type: (nodes.Node) -> None
self.body.append(node.get('delimiter', ' '))
def depart_option_argument(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_description(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n')
def depart_description(self, node):
+ # type: (nodes.Node) -> None
pass
# -- Definitions
def visit_definition_list(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\n@table @asis\n')
def depart_definition_list(self, node):
+ # type: (nodes.Node) -> None
self.ensure_eol()
self.body.append('@end table\n')
def visit_definition_list_item(self, node):
+ # type: (nodes.Node) -> None
self.at_item_x = '@item'
def depart_definition_list_item(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_term(self, node):
@@ -951,43 +1063,55 @@ class TexinfoTranslator(nodes.NodeVisitor):
self.at_item_x = '@itemx'
def depart_term(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_termsep(self, node):
+ # type: (nodes.Node) -> None
warnings.warn('sphinx.addnodes.termsep will be removed at Sphinx-1.5',
DeprecationWarning)
self.body.append('\n%s ' % self.at_item_x)
def depart_termsep(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_classifier(self, node):
+ # type: (nodes.Node) -> None
self.body.append(' : ')
def depart_classifier(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_definition(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n')
def depart_definition(self, node):
+ # type: (nodes.Node) -> None
pass
# -- Tables
def visit_table(self, node):
+ # type: (nodes.Node) -> None
self.entry_sep = '@item'
def depart_table(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n@end multitable\n\n')
def visit_tabular_col_spec(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_tabular_col_spec(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_colspec(self, node):
+ # type: (nodes.Node) -> None
self.colwidths.append(node['colwidth'])
if len(self.colwidths) != self.n_cols:
return
@@ -996,82 +1120,104 @@ class TexinfoTranslator(nodes.NodeVisitor):
self.body.append('{%s} ' % ('x' * (n+2)))
def depart_colspec(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_tgroup(self, node):
+ # type: (nodes.Node) -> None
self.colwidths = []
self.n_cols = node['cols']
def depart_tgroup(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_thead(self, node):
+ # type: (nodes.Node) -> None
self.entry_sep = '@headitem'
def depart_thead(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_tbody(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_tbody(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_row(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_row(self, node):
+ # type: (nodes.Node) -> None
self.entry_sep = '@item'
def visit_entry(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n%s\n' % self.entry_sep)
self.entry_sep = '@tab'
def depart_entry(self, node):
+ # type: (nodes.Node) -> None
for i in range(node.get('morecols', 0)):
self.body.append('\n@tab\n')
# -- Field Lists
def visit_field_list(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_field_list(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_field(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n')
def depart_field(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n')
def visit_field_name(self, node):
+ # type: (nodes.Node) -> None
self.ensure_eol()
self.body.append('@*')
def depart_field_name(self, node):
+ # type: (nodes.Node) -> None
self.body.append(': ')
def visit_field_body(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_field_body(self, node):
+ # type: (nodes.Node) -> None
pass
# -- Admonitions
def visit_admonition(self, node, name=''):
+ # type: (nodes.Node, unicode) -> None
if not name:
name = self.escape(node[0].astext())
self.body.append(u'\n@cartouche\n@quotation %s ' % name)
def depart_admonition(self, node):
+ # type: (nodes.Node) -> None
self.ensure_eol()
self.body.append('@end quotation\n'
'@end cartouche\n')
def _make_visit_admonition(name):
def visit(self, node):
+ # type: (nodes.Node) -> None
self.visit_admonition(node, admonitionlabels[name])
return visit
@@ -1097,32 +1243,41 @@ class TexinfoTranslator(nodes.NodeVisitor):
# -- Misc
def visit_docinfo(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_generated(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_header(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_footer(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_container(self, node):
+ # type: (nodes.Node) -> None
if node.get('literal_block'):
self.body.append('\n\n@float LiteralBlock\n')
def depart_container(self, node):
+ # type: (nodes.Node) -> None
if node.get('literal_block'):
self.body.append('\n@end float\n\n')
def visit_decoration(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_decoration(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_topic(self, node):
+ # type: (nodes.Node) -> None
# ignore TOC's since we have to have a "menu" anyway
if 'contents' in node.get('classes', []):
raise nodes.SkipNode
@@ -1131,33 +1286,42 @@ class TexinfoTranslator(nodes.NodeVisitor):
self.body.append('%s\n' % self.escape(title.astext()))
def depart_topic(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_transition(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\n%s\n\n' % ('_' * 66))
def depart_transition(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_attribution(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\n@center --- ')
def depart_attribution(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\n')
def visit_raw(self, node):
+ # type: (nodes.Node) -> None
format = node.get('format', '').split()
if 'texinfo' in format or 'texi' in format:
self.body.append(node.astext())
raise nodes.SkipNode
def visit_figure(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\n@float Figure\n')
def depart_figure(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n@end float\n\n')
def visit_caption(self, node):
+ # type: (nodes.Node) -> None
if (isinstance(node.parent, nodes.figure) or
(isinstance(node.parent, nodes.container) and
node.parent.get('literal_block'))):
@@ -1167,12 +1331,14 @@ class TexinfoTranslator(nodes.NodeVisitor):
(self.curfilestack[-1], node.line))
def depart_caption(self, node):
+ # type: (nodes.Node) -> None
if (isinstance(node.parent, nodes.figure) or
(isinstance(node.parent, nodes.container) and
node.parent.get('literal_block'))):
self.body.append('}\n')
def visit_image(self, node):
+ # type: (nodes.Node) -> None
if node['uri'] in self.builder.images:
uri = self.builder.images[node['uri']]
else:
@@ -1193,73 +1359,93 @@ class TexinfoTranslator(nodes.NodeVisitor):
(name, width, height, alt, ext[1:]))
def depart_image(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_compound(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_compound(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_sidebar(self, node):
+ # type: (nodes.Node) -> None
self.visit_topic(node)
def depart_sidebar(self, node):
+ # type: (nodes.Node) -> None
self.depart_topic(node)
def visit_label(self, node):
+ # type: (nodes.Node) -> None
self.body.append('@w{(')
def depart_label(self, node):
+ # type: (nodes.Node) -> None
self.body.append(')} ')
def visit_legend(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_legend(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_substitution_reference(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_substitution_reference(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_substitution_definition(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_system_message(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n@verbatim\n'
'<SYSTEM MESSAGE: %s>\n'
'@end verbatim\n' % node.astext())
raise nodes.SkipNode
def visit_comment(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n')
for line in node.astext().splitlines():
self.body.append('@c %s\n' % line)
raise nodes.SkipNode
def visit_problematic(self, node):
+ # type: (nodes.Node) -> None
self.body.append('>>')
def depart_problematic(self, node):
+ # type: (nodes.Node) -> None
self.body.append('<<')
def unimplemented_visit(self, node):
+ # type: (nodes.Node) -> None
self.builder.warn("unimplemented node type: %r" % node,
(self.curfilestack[-1], node.line))
def unknown_visit(self, node):
+ # type: (nodes.Node) -> None
self.builder.warn("unknown node type: %r" % node,
(self.curfilestack[-1], node.line))
def unknown_departure(self, node):
+ # type: (nodes.Node) -> None
pass
# -- Sphinx specific
def visit_productionlist(self, node):
+ # type: (nodes.Node) -> None
self.visit_literal_block(None)
names = []
for production in node:
@@ -1278,24 +1464,31 @@ class TexinfoTranslator(nodes.NodeVisitor):
raise nodes.SkipNode
def visit_production(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_production(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_literal_emphasis(self, node):
+ # type: (nodes.Node) -> None
self.body.append('@code{')
def depart_literal_emphasis(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
def visit_literal_strong(self, node):
+ # type: (nodes.Node) -> None
self.body.append('@code{')
def depart_literal_strong(self, node):
+ # type: (nodes.Node) -> None
self.body.append('}')
def visit_index(self, node):
+ # type: (nodes.Node) -> None
# terminate the line but don't prevent paragraph breaks
if isinstance(node.parent, nodes.paragraph):
self.ensure_eol()
@@ -1307,43 +1500,54 @@ class TexinfoTranslator(nodes.NodeVisitor):
self.body.append('@geindex %s\n' % text)
def visit_versionmodified(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n')
def depart_versionmodified(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n')
def visit_start_of_file(self, node):
+ # type: (nodes.Node) -> None
# add a document target
self.next_section_ids.add(':doc')
self.curfilestack.append(node['docname'])
self.footnotestack.append(self.collect_footnotes(node))
def depart_start_of_file(self, node):
+ # type: (nodes.Node) -> None
self.curfilestack.pop()
self.footnotestack.pop()
def visit_centered(self, node):
+ # type: (nodes.Node) -> None
txt = self.escape_arg(node.astext())
self.body.append('\n\n@center %s\n\n' % txt)
raise nodes.SkipNode
def visit_seealso(self, node):
+ # type: (nodes.Node) -> None
self.body.append(u'\n\n@subsubheading %s\n\n' %
admonitionlabels['seealso'])
def depart_seealso(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n')
def visit_meta(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_glossary(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_glossary(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_acks(self, node):
+ # type: (nodes.Node) -> None
self.body.append('\n\n')
self.body.append(', '.join(n.astext()
for n in node.children[0].children) + '.')
@@ -1351,23 +1555,28 @@ class TexinfoTranslator(nodes.NodeVisitor):
raise nodes.SkipNode
def visit_highlightlang(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_highlightlang(self, node):
+ # type: (nodes.Node) -> None
pass
# -- Desc
def visit_desc(self, node):
+ # type: (nodes.Node) -> None
self.desc = node
self.at_deffnx = '@deffn'
def depart_desc(self, node):
+ # type: (nodes.Node) -> None
self.desc = None
self.ensure_eol()
self.body.append('@end deffn\n')
def visit_desc_signature(self, node):
+ # type: (nodes.Node) -> None
self.escape_hyphens += 1
objtype = node.parent['objtype']
if objtype != 'describe':
@@ -1388,42 +1597,54 @@ class TexinfoTranslator(nodes.NodeVisitor):
self.desc_type_name = name
def depart_desc_signature(self, node):
+ # type: (nodes.Node) -> None
self.body.append("\n")
self.escape_hyphens -= 1
self.desc_type_name = None
def visit_desc_name(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_desc_name(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_desc_addname(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_desc_addname(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_desc_type(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_desc_type(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_desc_returns(self, node):
+ # type: (nodes.Node) -> None
self.body.append(' -> ')
def depart_desc_returns(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_desc_parameterlist(self, node):
+ # type: (nodes.Node) -> None
self.body.append(' (')
self.first_param = 1
def depart_desc_parameterlist(self, node):
+ # type: (nodes.Node) -> None
self.body.append(')')
def visit_desc_parameter(self, node):
+ # type: (nodes.Node) -> None
if not self.first_param:
self.body.append(', ')
else:
@@ -1435,12 +1656,15 @@ class TexinfoTranslator(nodes.NodeVisitor):
raise nodes.SkipNode
def visit_desc_optional(self, node):
+ # type: (nodes.Node) -> None
self.body.append('[')
def depart_desc_optional(self, node):
+ # type: (nodes.Node) -> None
self.body.append(']')
def visit_desc_annotation(self, node):
+ # type: (nodes.Node) -> None
# Try to avoid duplicating info already displayed by the deffn category.
# e.g.
# @deffn {Class} Foo
@@ -1453,21 +1677,27 @@ class TexinfoTranslator(nodes.NodeVisitor):
raise nodes.SkipNode
def depart_desc_annotation(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_desc_content(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_desc_content(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_inline(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_inline(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_abbreviation(self, node):
+ # type: (nodes.Node) -> None
abbr = node.astext()
self.body.append('@abbr{')
if node.hasattr('explanation') and abbr not in self.handled_abbrs:
@@ -1477,39 +1707,51 @@ class TexinfoTranslator(nodes.NodeVisitor):
self.context.append('}')
def depart_abbreviation(self, node):
+ # type: (nodes.Node) -> None
self.body.append(self.context.pop())
def visit_manpage(self, node):
+ # type: (nodes.Node) -> Any
return self.visit_literal_emphasis(node)
def depart_manpage(self, node):
+ # type: (nodes.Node) -> Any
return self.depart_literal_emphasis(node)
def visit_download_reference(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_download_reference(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_hlist(self, node):
+ # type: (nodes.Node) -> None
self.visit_bullet_list(node)
def depart_hlist(self, node):
+ # type: (nodes.Node) -> None
self.depart_bullet_list(node)
def visit_hlistcol(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_hlistcol(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_pending_xref(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_pending_xref(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_math(self, node):
+ # type: (nodes.Node) -> None
self.builder.warn('using "math" markup without a Sphinx math extension '
'active, please use one of the math extensions '
'described at http://sphinx-doc.org/ext/math.html')
diff --git a/sphinx/writers/text.py b/sphinx/writers/text.py
index 7032208ea..da58906e7 100644
--- a/sphinx/writers/text.py
+++ b/sphinx/writers/text.py
@@ -22,6 +22,11 @@ from docutils.utils import column_width
from sphinx import addnodes
from sphinx.locale import admonitionlabels, _
+if False:
+ # For type annotation
+ from typing import Any, Callable, Tuple, Union # NOQA
+ from sphinx.builders.text import TextBuilder # NOQA
+
class TextWrapper(textwrap.TextWrapper):
"""Custom subclass that uses a different word separator regex."""
@@ -33,13 +38,14 @@ class TextWrapper(textwrap.TextWrapper):
r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') # em-dash
def _wrap_chunks(self, chunks):
+ # type: (List[unicode]) -> List[unicode]
"""_wrap_chunks(chunks : [string]) -> [string]
The original _wrap_chunks uses len() to calculate width.
This method respects wide/fullwidth characters for width adjustment.
"""
drop_whitespace = getattr(self, 'drop_whitespace', True) # py25 compat
- lines = []
+ lines = [] # type: List[unicode]
if self.width <= 0:
raise ValueError("invalid width %r (must be > 0)" % self.width)
@@ -81,6 +87,7 @@ class TextWrapper(textwrap.TextWrapper):
return lines
def _break_word(self, word, space_left):
+ # type: (unicode, int) -> Tuple[unicode, unicode]
"""_break_word(word : string, space_left : int) -> (string, string)
Break line by unicode width instead of len(word).
@@ -93,14 +100,16 @@ class TextWrapper(textwrap.TextWrapper):
return word, ''
def _split(self, text):
+ # type: (unicode) -> List[unicode]
"""_split(text : string) -> [string]
Override original method that only split by 'wordsep_re'.
This '_split' split wide-characters into chunk by one character.
"""
def split(t):
- return textwrap.TextWrapper._split(self, t)
- chunks = []
+ # type: (unicode) -> List[unicode]
+ return textwrap.TextWrapper._split(self, t) # type: ignore
+ chunks = [] # type: List[unicode]
for chunk in split(text):
for w, g in groupby(chunk, column_width):
if w == 1:
@@ -110,6 +119,7 @@ class TextWrapper(textwrap.TextWrapper):
return chunks
def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
+ # type: (List[unicode], List[unicode], int, int) -> None
"""_handle_long_word(chunks : [string],
cur_line : [string],
cur_len : int, width : int)
@@ -131,6 +141,7 @@ STDINDENT = 3
def my_wrap(text, width=MAXWIDTH, **kwargs):
+ # type: (unicode, int, Any) -> List[unicode]
w = TextWrapper(width=width, **kwargs)
return w.wrap(text)
@@ -138,16 +149,18 @@ def my_wrap(text, width=MAXWIDTH, **kwargs):
class TextWriter(writers.Writer):
supported = ('text',)
settings_spec = ('No options here.', '', ())
- settings_defaults = {}
+ settings_defaults = {} # type: Dict
output = None
def __init__(self, builder):
+ # type: (TextBuilder) -> None
writers.Writer.__init__(self)
self.builder = builder
self.translator_class = self.builder.translator_class or TextTranslator
def translate(self):
+ # type: () -> None
visitor = self.translator_class(self.document, self.builder)
self.document.walkabout(visitor)
self.output = visitor.body
@@ -157,6 +170,7 @@ class TextTranslator(nodes.NodeVisitor):
sectionchars = '*=-~"+`'
def __init__(self, document, builder):
+ # type: (nodes.Node, TextBuilder) -> None
nodes.NodeVisitor.__init__(self, document)
self.builder = builder
@@ -168,28 +182,32 @@ class TextTranslator(nodes.NodeVisitor):
else:
self.nl = '\n'
self.sectionchars = builder.config.text_sectionchars
- self.states = [[]]
+ self.states = [[]] # type: List[List[Tuple[int, Union[unicode, List[unicode]]]]]
self.stateindent = [0]
- self.list_counter = []
+ self.list_counter = [] # type: List[int]
self.sectionlevel = 0
self.lineblocklevel = 0
- self.table = None
+ self.table = None # type: List[Union[unicode, List[int]]]
def add_text(self, text):
+ # type: (unicode) -> None
self.states[-1].append((-1, text))
def new_state(self, indent=STDINDENT):
+ # type: (int) -> None
self.states.append([])
self.stateindent.append(indent)
def end_state(self, wrap=True, end=[''], first=None):
+ # type: (bool, List[unicode], unicode) -> None
content = self.states.pop()
maxindent = sum(self.stateindent)
indent = self.stateindent.pop()
- result = []
- toformat = []
+ result = [] # type: List[Tuple[int, List[unicode]]]
+ toformat = [] # type: List[unicode]
def do_format():
+ # type: () -> None
if not toformat:
return
if wrap:
@@ -201,10 +219,10 @@ class TextTranslator(nodes.NodeVisitor):
result.append((indent, res))
for itemindent, item in content:
if itemindent == -1:
- toformat.append(item)
+ toformat.append(item) # type: ignore
else:
do_format()
- result.append((indent + itemindent, item))
+ result.append((indent + itemindent, item)) # type: ignore
toformat = []
do_format()
if first is not None and result:
@@ -220,9 +238,11 @@ class TextTranslator(nodes.NodeVisitor):
self.states[-1].extend(result)
def visit_document(self, node):
+ # type: (nodes.Node) -> None
self.new_state(0)
def depart_document(self, node):
+ # type: (nodes.Node) -> None
self.end_state()
self.body = self.nl.join(line and (' '*indent + line)
for indent, lines in self.states[0]
@@ -230,126 +250,161 @@ class TextTranslator(nodes.NodeVisitor):
# XXX header/footer?
def visit_highlightlang(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_section(self, node):
+ # type: (nodes.Node) -> None
self._title_char = self.sectionchars[self.sectionlevel]
self.sectionlevel += 1
def depart_section(self, node):
+ # type: (nodes.Node) -> None
self.sectionlevel -= 1
def visit_topic(self, node):
+ # type: (nodes.Node) -> None
self.new_state(0)
def depart_topic(self, node):
+ # type: (nodes.Node) -> None
self.end_state()
visit_sidebar = visit_topic
depart_sidebar = depart_topic
def visit_rubric(self, node):
+ # type: (nodes.Node) -> None
self.new_state(0)
self.add_text('-[ ')
def depart_rubric(self, node):
+ # type: (nodes.Node) -> None
self.add_text(' ]-')
self.end_state()
def visit_compound(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_compound(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_glossary(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_glossary(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_title(self, node):
+ # type: (nodes.Node) -> None
if isinstance(node.parent, nodes.Admonition):
self.add_text(node.astext()+': ')
raise nodes.SkipNode
self.new_state(0)
def depart_title(self, node):
+ # type: (nodes.Node) -> None
if isinstance(node.parent, nodes.section):
char = self._title_char
else:
char = '^'
- text = ''.join(x[1] for x in self.states.pop() if x[0] == -1)
+ text = None # type: unicode
+ text = ''.join(x[1] for x in self.states.pop() if x[0] == -1) # type: ignore
self.stateindent.pop()
- title = ['', text, '%s' % (char * column_width(text)), '']
+ title = ['', text, '%s' % (char * column_width(text)), ''] # type: List[unicode]
if len(self.states) == 2 and len(self.states[-1]) == 0:
# remove an empty line before title if it is first section title in the document
title.pop(0)
self.states[-1].append((0, title))
def visit_subtitle(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_subtitle(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_attribution(self, node):
+ # type: (nodes.Node) -> None
self.add_text('-- ')
def depart_attribution(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_desc(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_desc(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_desc_signature(self, node):
+ # type: (nodes.Node) -> None
self.new_state(0)
def depart_desc_signature(self, node):
+ # type: (nodes.Node) -> None
# XXX: wrap signatures in a way that makes sense
self.end_state(wrap=False, end=None)
def visit_desc_signature_line(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_desc_signature_line(self, node):
+ # type: (nodes.Node) -> None
self.add_text('\n')
def visit_desc_name(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_desc_name(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_desc_addname(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_desc_addname(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_desc_type(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_desc_type(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_desc_returns(self, node):
+ # type: (nodes.Node) -> None
self.add_text(' -> ')
def depart_desc_returns(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_desc_parameterlist(self, node):
+ # type: (nodes.Node) -> None
self.add_text('(')
self.first_param = 1
def depart_desc_parameterlist(self, node):
+ # type: (nodes.Node) -> None
self.add_text(')')
def visit_desc_parameter(self, node):
+ # type: (nodes.Node) -> None
if not self.first_param:
self.add_text(', ')
else:
@@ -358,37 +413,48 @@ class TextTranslator(nodes.NodeVisitor):
raise nodes.SkipNode
def visit_desc_optional(self, node):
+ # type: (nodes.Node) -> None
self.add_text('[')
def depart_desc_optional(self, node):
+ # type: (nodes.Node) -> None
self.add_text(']')
def visit_desc_annotation(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_desc_annotation(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_desc_content(self, node):
+ # type: (nodes.Node) -> None
self.new_state()
self.add_text(self.nl)
def depart_desc_content(self, node):
+ # type: (nodes.Node) -> None
self.end_state()
def visit_figure(self, node):
+ # type: (nodes.Node) -> None
self.new_state()
def depart_figure(self, node):
+ # type: (nodes.Node) -> None
self.end_state()
def visit_caption(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_caption(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_productionlist(self, node):
+ # type: (nodes.Node) -> None
self.new_state()
names = []
for production in node:
@@ -406,13 +472,16 @@ class TextTranslator(nodes.NodeVisitor):
raise nodes.SkipNode
def visit_footnote(self, node):
+ # type: (nodes.Node) -> None
self._footnote = node.children[0].astext().strip()
self.new_state(len(self._footnote) + 3)
def depart_footnote(self, node):
+ # type: (nodes.Node) -> None
self.end_state(first='[%s] ' % self._footnote)
def visit_citation(self, node):
+ # type: (nodes.Node) -> None
if len(node) and isinstance(node[0], nodes.label):
self._citlabel = node[0].astext()
else:
@@ -420,116 +489,150 @@ class TextTranslator(nodes.NodeVisitor):
self.new_state(len(self._citlabel) + 3)
def depart_citation(self, node):
+ # type: (nodes.Node) -> None
self.end_state(first='[%s] ' % self._citlabel)
def visit_label(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_legend(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_legend(self, node):
+ # type: (nodes.Node) -> None
pass
# XXX: option list could use some better styling
def visit_option_list(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_option_list(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_option_list_item(self, node):
+ # type: (nodes.Node) -> None
self.new_state(0)
def depart_option_list_item(self, node):
+ # type: (nodes.Node) -> None
self.end_state()
def visit_option_group(self, node):
+ # type: (nodes.Node) -> None
self._firstoption = True
def depart_option_group(self, node):
+ # type: (nodes.Node) -> None
self.add_text(' ')
def visit_option(self, node):
+ # type: (nodes.Node) -> None
if self._firstoption:
self._firstoption = False
else:
self.add_text(', ')
def depart_option(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_option_string(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_option_string(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_option_argument(self, node):
+ # type: (nodes.Node) -> None
self.add_text(node['delimiter'])
def depart_option_argument(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_description(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_description(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_tabular_col_spec(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_colspec(self, node):
- self.table[0].append(node['colwidth'])
+ # type: (nodes.Node) -> None
+ self.table[0].append(node['colwidth']) # type: ignore
raise nodes.SkipNode
def visit_tgroup(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_tgroup(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_thead(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_thead(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_tbody(self, node):
+ # type: (nodes.Node) -> None
self.table.append('sep')
def depart_tbody(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_row(self, node):
+ # type: (nodes.Node) -> None
self.table.append([])
def depart_row(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_entry(self, node):
+ # type: (nodes.Node) -> None
if 'morerows' in node or 'morecols' in node:
raise NotImplementedError('Column or row spanning cells are '
'not implemented.')
self.new_state(0)
def depart_entry(self, node):
+ # type: (nodes.Node) -> None
text = self.nl.join(self.nl.join(x[1]) for x in self.states.pop())
self.stateindent.pop()
- self.table[-1].append(text)
+ self.table[-1].append(text) # type: ignore
def visit_table(self, node):
+ # type: (nodes.Node) -> None
if self.table:
raise NotImplementedError('Nested tables are not supported.')
self.new_state(0)
self.table = [[]]
def depart_table(self, node):
- lines = self.table[1:]
- fmted_rows = []
- colwidths = self.table[0]
+ # type: (nodes.Node) -> None
+ lines = None # type: List[unicode]
+ lines = self.table[1:] # type: ignore
+ fmted_rows = [] # type: List[List[List[unicode]]]
+ colwidths = None # type: List[int]
+ colwidths = self.table[0] # type: ignore
realwidths = colwidths[:]
separator = 0
# don't allow paragraphs in table cells for now
@@ -537,7 +640,7 @@ class TextTranslator(nodes.NodeVisitor):
if line == 'sep':
separator = len(fmted_rows)
else:
- cells = []
+ cells = [] # type: List[List[unicode]]
for i, cell in enumerate(line):
par = my_wrap(cell, width=colwidths[i])
if par:
@@ -549,13 +652,15 @@ class TextTranslator(nodes.NodeVisitor):
fmted_rows.append(cells)
def writesep(char='-'):
- out = ['+']
+ # type: (unicode) -> None
+ out = ['+'] # type: List[unicode]
for width in realwidths:
out.append(char * (width+2))
out.append('+')
self.add_text(''.join(out) + self.nl)
def writerow(row):
+ # type: (list[List[unicode]]) -> None
lines = zip_longest(*row)
for line in lines:
out = ['|']
@@ -580,6 +685,7 @@ class TextTranslator(nodes.NodeVisitor):
self.end_state(wrap=False)
def visit_acks(self, node):
+ # type: (nodes.Node) -> None
self.new_state(0)
self.add_text(', '.join(n.astext() for n in node.children[0].children) +
'.')
@@ -587,12 +693,14 @@ class TextTranslator(nodes.NodeVisitor):
raise nodes.SkipNode
def visit_image(self, node):
+ # type: (nodes.Node) -> None
if 'alt' in node.attributes:
self.add_text(_('[image: %s]') % node['alt'])
self.add_text(_('[image]'))
raise nodes.SkipNode
def visit_transition(self, node):
+ # type: (nodes.Node) -> None
indent = sum(self.stateindent)
self.new_state(0)
self.add_text('=' * (MAXWIDTH - indent))
@@ -600,24 +708,31 @@ class TextTranslator(nodes.NodeVisitor):
raise nodes.SkipNode
def visit_bullet_list(self, node):
+ # type: (nodes.Node) -> None
self.list_counter.append(-1)
def depart_bullet_list(self, node):
+ # type: (nodes.Node) -> None
self.list_counter.pop()
def visit_enumerated_list(self, node):
+ # type: (nodes.Node) -> None
self.list_counter.append(node.get('start', 1) - 1)
def depart_enumerated_list(self, node):
+ # type: (nodes.Node) -> None
self.list_counter.pop()
def visit_definition_list(self, node):
+ # type: (nodes.Node) -> None
self.list_counter.append(-2)
def depart_definition_list(self, node):
+ # type: (nodes.Node) -> None
self.list_counter.pop()
def visit_list_item(self, node):
+ # type: (nodes.Node) -> None
if self.list_counter[-1] == -1:
# bullet list
self.new_state(2)
@@ -630,6 +745,7 @@ class TextTranslator(nodes.NodeVisitor):
self.new_state(len(str(self.list_counter[-1])) + 2)
def depart_list_item(self, node):
+ # type: (nodes.Node) -> None
if self.list_counter[-1] == -1:
self.end_state(first='* ')
elif self.list_counter[-1] == -2:
@@ -638,88 +754,114 @@ class TextTranslator(nodes.NodeVisitor):
self.end_state(first='%s. ' % self.list_counter[-1])
def visit_definition_list_item(self, node):
+ # type: (nodes.Node) -> None
self._classifier_count_in_li = len(node.traverse(nodes.classifier))
def depart_definition_list_item(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_term(self, node):
+ # type: (nodes.Node) -> None
self.new_state(0)
def depart_term(self, node):
+ # type: (nodes.Node) -> None
if not self._classifier_count_in_li:
self.end_state(end=None)
def visit_termsep(self, node):
+ # type: (nodes.Node) -> None
warnings.warn('sphinx.addnodes.termsep will be removed at Sphinx-1.5',
DeprecationWarning)
self.add_text(', ')
raise nodes.SkipNode
def visit_classifier(self, node):
+ # type: (nodes.Node) -> None
self.add_text(' : ')
def depart_classifier(self, node):
+ # type: (nodes.Node) -> None
self._classifier_count_in_li -= 1
if not self._classifier_count_in_li:
self.end_state(end=None)
def visit_definition(self, node):
+ # type: (nodes.Node) -> None
self.new_state()
def depart_definition(self, node):
+ # type: (nodes.Node) -> None
self.end_state()
def visit_field_list(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_field_list(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_field(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_field(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_field_name(self, node):
+ # type: (nodes.Node) -> None
self.new_state(0)
def depart_field_name(self, node):
+ # type: (nodes.Node) -> None
self.add_text(':')
self.end_state(end=None)
def visit_field_body(self, node):
+ # type: (nodes.Node) -> None
self.new_state()
def depart_field_body(self, node):
+ # type: (nodes.Node) -> None
self.end_state()
def visit_centered(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_centered(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_hlist(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_hlist(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_hlistcol(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_hlistcol(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_admonition(self, node):
+ # type: (nodes.Node) -> None
self.new_state(0)
def depart_admonition(self, node):
+ # type: (nodes.Node) -> None
self.end_state()
def _visit_admonition(self, node):
+ # type: (nodes.Node) -> None
self.new_state(2)
if isinstance(node.children[0], nodes.Sequential):
@@ -727,6 +869,7 @@ class TextTranslator(nodes.NodeVisitor):
def _make_depart_admonition(name):
def depart_admonition(self, node):
+ # type: (nodes.NodeVisitor, nodes.Node) -> None
self.end_state(first=admonitionlabels[name] + ': ')
return depart_admonition
@@ -752,211 +895,274 @@ class TextTranslator(nodes.NodeVisitor):
depart_seealso = _make_depart_admonition('seealso')
def visit_versionmodified(self, node):
+ # type: (nodes.Node) -> None
self.new_state(0)
def depart_versionmodified(self, node):
+ # type: (nodes.Node) -> None
self.end_state()
def visit_literal_block(self, node):
+ # type: (nodes.Node) -> None
self.new_state()
def depart_literal_block(self, node):
+ # type: (nodes.Node) -> None
self.end_state(wrap=False)
def visit_doctest_block(self, node):
+ # type: (nodes.Node) -> None
self.new_state(0)
def depart_doctest_block(self, node):
+ # type: (nodes.Node) -> None
self.end_state(wrap=False)
def visit_line_block(self, node):
+ # type: (nodes.Node) -> None
self.new_state()
self.lineblocklevel += 1
def depart_line_block(self, node):
+ # type: (nodes.Node) -> None
self.lineblocklevel -= 1
self.end_state(wrap=False, end=None)
if not self.lineblocklevel:
self.add_text('\n')
def visit_line(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_line(self, node):
+ # type: (nodes.Node) -> None
self.add_text('\n')
def visit_block_quote(self, node):
+ # type: (nodes.Node) -> None
self.new_state()
def depart_block_quote(self, node):
+ # type: (nodes.Node) -> None
self.end_state()
def visit_compact_paragraph(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_compact_paragraph(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_paragraph(self, node):
+ # type: (nodes.Node) -> None
if not isinstance(node.parent, nodes.Admonition) or \
isinstance(node.parent, addnodes.seealso):
self.new_state(0)
def depart_paragraph(self, node):
+ # type: (nodes.Node) -> None
if not isinstance(node.parent, nodes.Admonition) or \
isinstance(node.parent, addnodes.seealso):
self.end_state()
def visit_target(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_index(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_toctree(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_substitution_definition(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_pending_xref(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_pending_xref(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_reference(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_reference(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_number_reference(self, node):
+ # type: (nodes.Node) -> None
text = nodes.Text(node.get('title', '#'))
self.visit_Text(text)
raise nodes.SkipNode
def visit_download_reference(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_download_reference(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_emphasis(self, node):
+ # type: (nodes.Node) -> None
self.add_text('*')
def depart_emphasis(self, node):
+ # type: (nodes.Node) -> None
self.add_text('*')
def visit_literal_emphasis(self, node):
+ # type: (nodes.Node) -> None
self.add_text('*')
def depart_literal_emphasis(self, node):
+ # type: (nodes.Node) -> None
self.add_text('*')
def visit_strong(self, node):
+ # type: (nodes.Node) -> None
self.add_text('**')
def depart_strong(self, node):
+ # type: (nodes.Node) -> None
self.add_text('**')
def visit_literal_strong(self, node):
+ # type: (nodes.Node) -> None
self.add_text('**')
def depart_literal_strong(self, node):
+ # type: (nodes.Node) -> None
self.add_text('**')
def visit_abbreviation(self, node):
+ # type: (nodes.Node) -> None
self.add_text('')
def depart_abbreviation(self, node):
+ # type: (nodes.Node) -> None
if node.hasattr('explanation'):
self.add_text(' (%s)' % node['explanation'])
def visit_manpage(self, node):
+ # type: (nodes.Node) -> Any
return self.visit_literal_emphasis(node)
def depart_manpage(self, node):
+ # type: (nodes.Node) -> Any
return self.depart_literal_emphasis(node)
def visit_title_reference(self, node):
+ # type: (nodes.Node) -> None
self.add_text('*')
def depart_title_reference(self, node):
+ # type: (nodes.Node) -> None
self.add_text('*')
def visit_literal(self, node):
+ # type: (nodes.Node) -> None
self.add_text('"')
def depart_literal(self, node):
+ # type: (nodes.Node) -> None
self.add_text('"')
def visit_subscript(self, node):
+ # type: (nodes.Node) -> None
self.add_text('_')
def depart_subscript(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_superscript(self, node):
+ # type: (nodes.Node) -> None
self.add_text('^')
def depart_superscript(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_footnote_reference(self, node):
+ # type: (nodes.Node) -> None
self.add_text('[%s]' % node.astext())
raise nodes.SkipNode
def visit_citation_reference(self, node):
+ # type: (nodes.Node) -> None
self.add_text('[%s]' % node.astext())
raise nodes.SkipNode
def visit_Text(self, node):
+ # type: (nodes.Node) -> None
self.add_text(node.astext())
def depart_Text(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_generated(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_generated(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_inline(self, node):
+ # type: (nodes.Node) -> None
if 'xref' in node['classes'] or 'term' in node['classes']:
self.add_text('*')
def depart_inline(self, node):
+ # type: (nodes.Node) -> None
if 'xref' in node['classes'] or 'term' in node['classes']:
self.add_text('*')
def visit_container(self, node):
+ # type: (nodes.Node) -> None
pass
def depart_container(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_problematic(self, node):
+ # type: (nodes.Node) -> None
self.add_text('>>')
def depart_problematic(self, node):
+ # type: (nodes.Node) -> None
self.add_text('<<')
def visit_system_message(self, node):
+ # type: (nodes.Node) -> None
self.new_state(0)
self.add_text('<SYSTEM MESSAGE: %s>' % node.astext())
self.end_state()
raise nodes.SkipNode
def visit_comment(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_meta(self, node):
+ # type: (nodes.Node) -> None
# only valid for HTML
raise nodes.SkipNode
def visit_raw(self, node):
+ # type: (nodes.Node) -> None
if 'text' in node.get('format', '').split():
self.new_state(0)
self.add_text(node.astext())
@@ -964,6 +1170,7 @@ class TextTranslator(nodes.NodeVisitor):
raise nodes.SkipNode
def visit_math(self, node):
+ # type: (nodes.Node) -> None
self.builder.warn('using "math" markup without a Sphinx math extension '
'active, please use one of the math extensions '
'described at http://sphinx-doc.org/ext/math.html',
@@ -973,4 +1180,5 @@ class TextTranslator(nodes.NodeVisitor):
visit_math_block = visit_math
def unknown_visit(self, node):
+ # type: (nodes.Node) -> None
raise NotImplementedError('Unknown node: ' + node.__class__.__name__)
diff --git a/sphinx/writers/xml.py b/sphinx/writers/xml.py
index 5aa0ad96a..879f65dd3 100644
--- a/sphinx/writers/xml.py
+++ b/sphinx/writers/xml.py
@@ -12,16 +12,23 @@
from docutils import writers
from docutils.writers.docutils_xml import Writer as BaseXMLWriter
+if False:
+ # For type annotation
+ from typing import Any, Tuple # NOQA
+ from sphinx.builders import Builder # NOQA
+
class XMLWriter(BaseXMLWriter):
def __init__(self, builder):
+ # type: (Builder) -> None
BaseXMLWriter.__init__(self)
self.builder = builder
if self.builder.translator_class:
self.translator_class = self.builder.translator_class
def translate(self, *args, **kwargs):
+ # type: (Any, Any) -> None
self.document.settings.newlines = \
self.document.settings.indents = \
self.builder.env.config.xml_pretty
@@ -36,18 +43,21 @@ class PseudoXMLWriter(writers.Writer):
"""Formats this writer supports."""
config_section = 'pseudoxml writer'
- config_section_dependencies = ('writers',)
+ config_section_dependencies = ('writers',) # type: Tuple[unicode]
output = None
"""Final translated form of `document`."""
def __init__(self, builder):
+ # type: (Builder) -> None
writers.Writer.__init__(self)
self.builder = builder
def translate(self):
+ # type: () -> None
self.output = self.document.pformat()
def supports(self, format):
+ # type: (unicode) -> bool
"""This writer supports all format-specific elements."""
return True