latex: Use templates to render tables

This commit is contained in:
Takeshi KOMIYA 2017-02-04 17:06:53 +09:00
parent 7edcec66c9
commit 976fc326b9
6 changed files with 120 additions and 134 deletions

View 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}

View 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 -%>

View 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 -%>

View File

@ -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.

View File

@ -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.rowcount = 0
self.had_head = False
self.has_problematic = False
self.has_verbatim = False
self.caption = None # type: List[unicode]
self.longtable = False
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))
labels = '' # type: unicode
for labelid in self.pop_hyperlink_ids('table'):
labels += self.hypertarget(labelid, 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 += 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 = {}

View File

@ -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)