mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
latex: Use templates to render tables
This commit is contained in:
parent
7edcec66c9
commit
976fc326b9
21
sphinx/templates/latex/longtable.tex_t
Normal file
21
sphinx/templates/latex/longtable.tex_t
Normal file
@ -0,0 +1,21 @@
|
||||
\begin{longtable}<%= table.get_colspec() %>
|
||||
<%- if table.caption -%>
|
||||
\caption{<%= ''.join(table.caption) %>}<%= labels %>\\
|
||||
<% endif -%>
|
||||
\hline
|
||||
<%= ''.join(table.header) -%>
|
||||
\endfirsthead
|
||||
|
||||
\multicolumn{<%= table.colcount %>}{c}%
|
||||
{{\tablecontinued{\tablename\ \thetable{} -- <%= _('continued from previous page') %>}}} \\
|
||||
\hline
|
||||
<%= ''.join(table.header) -%>
|
||||
\endhead
|
||||
|
||||
\hline \multicolumn{<%= table.colcount %>}{|r|}{{\tablecontinued{<%= _('Continued on next page') %>}}} \\ \hline
|
||||
\endfoot
|
||||
|
||||
\endlastfoot
|
||||
|
||||
<%= ''.join(table.body) -%>
|
||||
\end{longtable}
|
12
sphinx/templates/latex/tabular.tex_t
Normal file
12
sphinx/templates/latex/tabular.tex_t
Normal file
@ -0,0 +1,12 @@
|
||||
<%- if table.caption -%>
|
||||
\begin{threeparttable}
|
||||
\capstart\caption{<%= ''.join(table.caption) %>}<%= labels %>
|
||||
<%- endif %>
|
||||
\noindent\begin{tabular}<%= table.get_colspec() -%>
|
||||
\hline
|
||||
<%= ''.join(table.header) -%>
|
||||
<%= ''.join(table.body) -%>
|
||||
\end{tabular}
|
||||
<%- if table.caption -%>
|
||||
\end{threeparttable}
|
||||
<%- endif -%>
|
12
sphinx/templates/latex/tabulary.tex_t
Normal file
12
sphinx/templates/latex/tabulary.tex_t
Normal file
@ -0,0 +1,12 @@
|
||||
<%- if table.caption -%>
|
||||
\begin{threeparttable}
|
||||
\capstart\caption{<%= ''.join(table.caption) %>}<%= labels %>
|
||||
<%- endif %>
|
||||
\noindent\begin{tabulary}{\linewidth}<%= table.get_colspec() -%>
|
||||
\hline
|
||||
<%= ''.join(table.header) -%>
|
||||
<%= ''.join(table.body) -%>
|
||||
\end{tabulary}
|
||||
<%- if table.caption -%>
|
||||
\end{threeparttable}
|
||||
<%- endif -%>
|
@ -43,8 +43,10 @@ class FileRenderer(BaseRenderer):
|
||||
|
||||
|
||||
class SphinxRenderer(FileRenderer):
|
||||
def __init__(self):
|
||||
super(SphinxRenderer, self).__init__(os.path.join(package_dir, 'templates'))
|
||||
def __init__(self, template_path=None):
|
||||
if template_path is None:
|
||||
template_path = os.path.join(package_dir, 'templates')
|
||||
super(SphinxRenderer, self).__init__(template_path)
|
||||
|
||||
@classmethod
|
||||
def render_from_file(cls, filename, context):
|
||||
@ -53,7 +55,8 @@ class SphinxRenderer(FileRenderer):
|
||||
|
||||
class LaTeXRenderer(SphinxRenderer):
|
||||
def __init__(self):
|
||||
super(LaTeXRenderer, self).__init__()
|
||||
template_path = os.path.join(package_dir, 'templates', 'latex')
|
||||
super(LaTeXRenderer, self).__init__(template_path)
|
||||
|
||||
# use JSP/eRuby like tagging instead because curly bracket; the default
|
||||
# tagging of jinja2 is not good for LaTeX sources.
|
||||
|
@ -46,7 +46,6 @@ BEGIN_DOC = r'''
|
||||
'''
|
||||
|
||||
|
||||
DEFAULT_TEMPLATE = 'latex/content.tex_t'
|
||||
URI_SCHEMES = ('mailto:', 'http:', 'https:', 'ftp:')
|
||||
SECNUMDEPTH = 3
|
||||
|
||||
@ -316,19 +315,49 @@ class ShowUrlsTransform(object):
|
||||
|
||||
|
||||
class Table(object):
|
||||
def __init__(self):
|
||||
# type: () -> None
|
||||
self.classes = []
|
||||
def __init__(self, node):
|
||||
# type: (nodes.table) -> None
|
||||
self.header = [] # type: List[unicode]
|
||||
self.body = [] # type: List[unicode]
|
||||
self.classes = node.get('classes', []) # type: List[unicode]
|
||||
self.col = 0
|
||||
self.colcount = 0
|
||||
self.colspec = None # type: unicode
|
||||
self.colwidths = [] # type: List[int]
|
||||
self.colspec = None # type: unicode
|
||||
self.colwidths = [] # type: List[int]
|
||||
self.rowcount = 0
|
||||
self.had_head = False
|
||||
self.has_problematic = False
|
||||
self.has_verbatim = False
|
||||
self.caption = None # type: List[unicode]
|
||||
self.longtable = False
|
||||
self.caption = None # type: List[unicode]
|
||||
|
||||
def is_longtable(self):
|
||||
# type: () -> bool
|
||||
return self.rowcount > 30 or 'longtable' in self.classes
|
||||
|
||||
def get_table_type(self):
|
||||
# type: () -> unicode
|
||||
if self.is_longtable():
|
||||
return 'longtable'
|
||||
elif self.has_verbatim:
|
||||
return 'tabular'
|
||||
elif self.has_problematic and not self.colspec:
|
||||
return 'tabular'
|
||||
else:
|
||||
return 'tabulary'
|
||||
|
||||
def get_colspec(self):
|
||||
# type: () -> unicode
|
||||
if self.colspec:
|
||||
return self.colspec
|
||||
elif self.colwidths and 'colwidths-given' in self.classes:
|
||||
total = sum(self.colwidths)
|
||||
colspecs = ['\\X{%d}{%d}' % (width, total) for width in self.colwidths]
|
||||
return '{|%s|}\n' % '|'.join(colspecs)
|
||||
elif self.has_problematic:
|
||||
return '{|*{%d}{\\X{1}{%d}|}}\n' % (self.colcount, self.colcount)
|
||||
elif self.is_longtable():
|
||||
return '{|' + ('l|' * self.colcount) + '}\n'
|
||||
else:
|
||||
return '{|' + ('L|' * self.colcount) + '}\n'
|
||||
|
||||
|
||||
def escape_abbr(text):
|
||||
@ -606,7 +635,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
if path.exists(template_path):
|
||||
return LaTeXRenderer().render(template_path, self.elements)
|
||||
else:
|
||||
return LaTeXRenderer().render(DEFAULT_TEMPLATE, self.elements)
|
||||
return LaTeXRenderer().render('content.tex_t', self.elements)
|
||||
|
||||
def hypertarget(self, id, withdoc=True, anchor=True):
|
||||
# type: (unicode, bool, bool) -> unicode
|
||||
@ -1166,95 +1195,29 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
raise UnsupportedError(
|
||||
'%s:%s: nested tables are not yet implemented.' %
|
||||
(self.curfilestack[-1], node.line or ''))
|
||||
self.table = Table()
|
||||
self.table.classes = node['classes']
|
||||
self.table.longtable = 'longtable' in node['classes']
|
||||
self.tablebody = [] # type: List[unicode]
|
||||
self.tableheaders = [] # type: List[unicode]
|
||||
# Redirect body output until table is finished.
|
||||
self.pushbody(self.tablebody)
|
||||
self.table = Table(node)
|
||||
if self.next_table_colspec:
|
||||
self.table.colspec = '{%s}\n' % self.next_table_colspec
|
||||
self.next_table_colspec = None
|
||||
self.restrict_footnote(node)
|
||||
|
||||
def depart_table(self, node):
|
||||
# type: (nodes.Node) -> None
|
||||
if self.table.rowcount > 30:
|
||||
self.table.longtable = True
|
||||
self.popbody()
|
||||
if not self.table.longtable and self.table.caption is not None:
|
||||
self.body.append('\n\n\\begin{threeparttable}\n'
|
||||
'\\capstart\\caption{')
|
||||
for caption in self.table.caption:
|
||||
self.body.append(caption)
|
||||
self.body.append('}')
|
||||
for id in self.pop_hyperlink_ids('table'):
|
||||
self.body.append(self.hypertarget(id, anchor=False))
|
||||
if node['ids']:
|
||||
self.body.append(self.hypertarget(node['ids'][0], anchor=False))
|
||||
if self.table.longtable:
|
||||
self.body.append('\n\\begin{longtable}')
|
||||
endmacro = '\\end{longtable}\n\n'
|
||||
elif self.table.has_verbatim:
|
||||
self.body.append('\n\\noindent\\begin{tabular}')
|
||||
endmacro = '\\end{tabular}\n\n'
|
||||
elif self.table.colspec:
|
||||
self.body.append('\n\\noindent\\begin{tabulary}{\\linewidth}')
|
||||
endmacro = '\\end{tabulary}\n\n'
|
||||
elif self.table.has_problematic or self.table.colwidths:
|
||||
self.body.append('\n\\noindent\\begin{tabular}')
|
||||
endmacro = '\\end{tabular}\n\n'
|
||||
else:
|
||||
self.body.append('\n\\noindent\\begin{tabulary}{\\linewidth}')
|
||||
endmacro = '\\end{tabulary}\n\n'
|
||||
if self.table.colspec:
|
||||
self.body.append(self.table.colspec)
|
||||
elif self.table.colwidths and 'colwidths-given' in self.table.classes:
|
||||
total = sum(self.table.colwidths)
|
||||
colspec = ['\\X{%d}{%d}' % (width, total)
|
||||
for width in self.table.colwidths]
|
||||
self.body.append('{|%s|}\n' % '|'.join(colspec))
|
||||
elif self.table.has_problematic:
|
||||
colspec = ('*{%d}{\\X{1}{%d}|}' %
|
||||
(self.table.colcount, self.table.colcount))
|
||||
self.body.append('{|' + colspec + '}\n')
|
||||
elif self.table.longtable:
|
||||
self.body.append('{|' + ('l|' * self.table.colcount) + '}\n')
|
||||
else:
|
||||
self.body.append('{|' + ('L|' * self.table.colcount) + '}\n')
|
||||
if self.table.longtable and self.table.caption is not None:
|
||||
self.body.append(u'\\caption{')
|
||||
for caption in self.table.caption:
|
||||
self.body.append(caption)
|
||||
self.body.append('}')
|
||||
for id in self.pop_hyperlink_ids('table'):
|
||||
self.body.append(self.hypertarget(id, anchor=False))
|
||||
if node['ids']:
|
||||
self.body.append(self.hypertarget(node['ids'][0], anchor=False))
|
||||
self.body.append(u'\\\\\n')
|
||||
if self.table.longtable:
|
||||
self.body.append('\\hline\n')
|
||||
self.body.extend(self.tableheaders)
|
||||
self.body.append('\\endfirsthead\n\n')
|
||||
self.body.append('\\multicolumn{%s}{c}%%\n' % self.table.colcount)
|
||||
self.body.append(r'{{\tablecontinued{\tablename\ \thetable{} -- %s}}} \\'
|
||||
% _('continued from previous page'))
|
||||
self.body.append('\n\\hline\n')
|
||||
self.body.extend(self.tableheaders)
|
||||
self.body.append('\\endhead\n\n')
|
||||
self.body.append(r'\hline \multicolumn{%s}{|r|}{{\tablecontinued{%s}}} \\ \hline'
|
||||
% (self.table.colcount,
|
||||
_('Continued on next page')))
|
||||
self.body.append('\n\\endfoot\n\n')
|
||||
self.body.append('\\endlastfoot\n\n')
|
||||
else:
|
||||
self.body.append('\\hline\n')
|
||||
self.body.extend(self.tableheaders)
|
||||
self.body.extend(self.tablebody)
|
||||
self.body.append(endmacro)
|
||||
if not self.table.longtable and self.table.caption is not None:
|
||||
self.body.append('\\end{threeparttable}\n\n')
|
||||
labels = '' # type: unicode
|
||||
for labelid in self.pop_hyperlink_ids('table'):
|
||||
labels += self.hypertarget(labelid, anchor=False)
|
||||
if node['ids']:
|
||||
labels += self.hypertarget(node['ids'][0], anchor=False)
|
||||
|
||||
table_type = self.table.get_table_type()
|
||||
table = LaTeXRenderer().render(table_type + '.tex_t',
|
||||
dict(table=self.table, labels=labels))
|
||||
self.body.append("\n\n")
|
||||
self.body.append(table)
|
||||
self.body.append("\n\n")
|
||||
|
||||
self.unrestrict_footnote(node)
|
||||
self.table = None
|
||||
self.tablebody = None
|
||||
|
||||
def visit_colspec(self, node):
|
||||
# type: (nodes.Node) -> None
|
||||
@ -1276,25 +1239,19 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
|
||||
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
|
||||
self.next_table_colspec = None
|
||||
# Redirect head output until header is finished. see visit_tbody.
|
||||
self.body = self.tableheaders
|
||||
self.pushbody(self.table.header) # Redirect head output until header is finished.
|
||||
|
||||
def depart_thead(self, node):
|
||||
# type: (nodes.Node) -> None
|
||||
pass
|
||||
self.popbody()
|
||||
|
||||
def visit_tbody(self, node):
|
||||
# type: (nodes.Node) -> None
|
||||
if not self.table.had_head:
|
||||
self.visit_thead(node)
|
||||
self.body = self.tablebody
|
||||
self.pushbody(self.table.body) # Redirect body output until table is finished.
|
||||
|
||||
def depart_tbody(self, node):
|
||||
# type: (nodes.Node) -> None
|
||||
self.popbody()
|
||||
self.remember_multirow = {}
|
||||
self.remember_multirowcol = {}
|
||||
|
||||
|
@ -841,10 +841,8 @@ def test_latex_table(app, status, warning):
|
||||
|
||||
# table having :widths: option
|
||||
table = tables['table having :widths: option']
|
||||
assert ('\\noindent\\begin{tabulary}{\\linewidth}{'
|
||||
'|p{\\dimexpr(\\linewidth-\\arrayrulewidth)*30/100-2\\tabcolsep-\\arrayrulewidth\\relax}'
|
||||
'|p{\\dimexpr(\\linewidth-\\arrayrulewidth)*70/100-2\\tabcolsep-\\arrayrulewidth\\relax}|}'
|
||||
in table)
|
||||
assert ('\\noindent\\begin{tabulary}{\\linewidth}'
|
||||
'{|\\X{30}{100}|\\X{70}{100}|}' in table)
|
||||
assert ('\\hline\n'
|
||||
'\\sphinxstylethead{\\relax \nheader1\n\\unskip}\\relax &'
|
||||
'\\sphinxstylethead{\\relax \nheader2\n\\unskip}\\relax' in table)
|
||||
@ -869,22 +867,15 @@ def test_latex_table(app, status, warning):
|
||||
|
||||
# table having verbatim
|
||||
table = tables['table having verbatim']
|
||||
assert ('\\noindent\\begin{tabular}{|*{2}{'
|
||||
'p{\\dimexpr(\\linewidth-\\arrayrulewidth)/2-2\\tabcolsep-\\arrayrulewidth\\relax}|}}\n'
|
||||
'\\hline' in table)
|
||||
assert ('\\noindent\\begin{tabular}{|*{2}{\\X{1}{2}|}}\n\\hline' in table)
|
||||
|
||||
# table having problematic cell
|
||||
table = tables['table having problematic cell']
|
||||
assert ('\\noindent\\begin{tabular}{|*{2}{'
|
||||
'p{\\dimexpr(\\linewidth-\\arrayrulewidth)/2-2\\tabcolsep-\\arrayrulewidth\\relax}|}}\n'
|
||||
'\\hline' in table)
|
||||
assert ('\\noindent\\begin{tabular}{|*{2}{\\X{1}{2}|}}\n\\hline' in table)
|
||||
|
||||
# table having both :widths: and problematic cell
|
||||
table = tables['table having both :widths: and problematic cell']
|
||||
assert ('\\noindent\\begin{tabular}{'
|
||||
'|p{\\dimexpr(\\linewidth-\\arrayrulewidth)*30/100-2\\tabcolsep-\\arrayrulewidth\\relax}'
|
||||
'|p{\\dimexpr(\\linewidth-\\arrayrulewidth)*70/100-2\\tabcolsep-\\arrayrulewidth\\relax}|}'
|
||||
in table)
|
||||
assert ('\\noindent\\begin{tabular}{|\\X{30}{100}|\\X{70}{100}|}' in table)
|
||||
|
||||
# longtable
|
||||
table = tables['longtable']
|
||||
@ -909,10 +900,7 @@ def test_latex_table(app, status, warning):
|
||||
|
||||
# longtable having :widths: option
|
||||
table = tables['longtable having :widths: option']
|
||||
assert ('\\begin{longtable}{'
|
||||
'|p{\\dimexpr(\\linewidth-\\arrayrulewidth)*30/100-2\\tabcolsep-\\arrayrulewidth\\relax}'
|
||||
'|p{\\dimexpr(\\linewidth-\\arrayrulewidth)*70/100-2\\tabcolsep-\\arrayrulewidth\\relax}|}'
|
||||
in table)
|
||||
assert ('\\begin{longtable}{|\\X{30}{100}|\\X{70}{100}|}' in table)
|
||||
|
||||
# longtable having caption
|
||||
table = tables['longtable having caption']
|
||||
@ -921,19 +909,12 @@ def test_latex_table(app, status, warning):
|
||||
|
||||
# longtable having verbatim
|
||||
table = tables['longtable having verbatim']
|
||||
assert ('\\begin{longtable}{|*{2}{'
|
||||
'p{\\dimexpr(\\linewidth-\\arrayrulewidth)/2-2\\tabcolsep-\\arrayrulewidth\\relax}|}}\n'
|
||||
'\\hline' in table)
|
||||
assert ('\\begin{longtable}{|*{2}{\\X{1}{2}|}}\n\\hline' in table)
|
||||
|
||||
# longtable having problematic cell
|
||||
table = tables['longtable having problematic cell']
|
||||
assert ('\\begin{longtable}{|*{2}{'
|
||||
'p{\\dimexpr(\\linewidth-\\arrayrulewidth)/2-2\\tabcolsep-\\arrayrulewidth\\relax}|}}\n'
|
||||
'\\hline' in table)
|
||||
assert ('\\begin{longtable}{|*{2}{\\X{1}{2}|}}\n\\hline' in table)
|
||||
|
||||
# longtable having both :widths: and problematic cell
|
||||
table = tables['longtable having both :widths: and problematic cell']
|
||||
assert ('\\begin{longtable}{'
|
||||
'|p{\\dimexpr(\\linewidth-\\arrayrulewidth)*30/100-2\\tabcolsep-\\arrayrulewidth\\relax}'
|
||||
'|p{\\dimexpr(\\linewidth-\\arrayrulewidth)*70/100-2\\tabcolsep-\\arrayrulewidth\\relax}|}'
|
||||
in table)
|
||||
assert ('\\begin{longtable}{|\\X{30}{100}|\\X{70}{100}|}' in table)
|
||||
|
Loading…
Reference in New Issue
Block a user