RST now parses tables.

This commit is contained in:
Mark Wolfman
2021-04-14 07:22:54 -05:00
parent 67adc390cb
commit 4aa43d2bec
5 changed files with 79 additions and 6 deletions
+2
View File
@@ -2,3 +2,5 @@
\usepackage[T1]{fontenc} \usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc} \usepackage[utf8]{inputenc}
\usepackage{alltt} \usepackage{alltt}
\usepackage{supertabular}
+18
View File
@@ -0,0 +1,18 @@
from docutils.writers.latex2e import Writer, Table, LaTeXTranslator
class LatexWriter(Writer):
def __init__(self):
super().__init__()
self.translator_class = DNDTranslator
class DNDTable(Table):
pass
class DNDTranslator(LaTeXTranslator):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.settings.table_style = ["borderless"]
self.active_table = DNDTable(self, "supertabular")
+38 -3
View File
@@ -20,6 +20,7 @@ from sphinx.util.docstrings import prepare_docstring
from dungeonsheets import character as _char from dungeonsheets import character as _char
from dungeonsheets import exceptions, classes, readers from dungeonsheets import exceptions, classes, readers
from dungeonsheets.stats import mod_str from dungeonsheets.stats import mod_str
from dungeonsheets.latex import LatexWriter
"""Program to take character definitions and build a PDF of the """Program to take character definitions and build a PDF of the
@@ -29,7 +30,7 @@ bold_re = re.compile(r'\*\*([^*]+)\*\*')
it_re = re.compile(r'\*([^*]+)\*') it_re = re.compile(r'\*([^*]+)\*')
verb_re = re.compile(r'``([^`]+)``') verb_re = re.compile(r'``([^`]+)``')
heading_re = re.compile(r'^[ \t\r\f\v]*(.+)\n\s*([-=\^]+)$', flags=re.MULTILINE) heading_re = re.compile(r'^[ \t\r\f\v]*(.+)\n\s*([-=\^]+)$', flags=re.MULTILINE)
# A dice string, with optinal backticks: ``1d6 + 3`` # A dice string, with optional backticks: ``1d6 + 3``
dice_re = re.compile(r'`*(\d+d\d+(?:\s*\+\s*\d+)?)`*') dice_re = re.compile(r'`*(\d+d\d+(?:\s*\+\s*\d+)?)`*')
# What defines a list in reST: # What defines a list in reST:
# - a blank line # - a blank line
@@ -70,6 +71,7 @@ def _parse_rst_lists(rst):
list_items = [item.replace('\n', ' ').strip() for item in list_items] list_items = [item.replace('\n', ' ').strip() for item in list_items]
yield list_rst, list_items yield list_rst, list_items
def _parse_rst_headings(rst): def _parse_rst_headings(rst):
"""Read headings in reST and iterate. """Read headings in reST and iterate.
@@ -136,13 +138,45 @@ def latex_parts(input_string, source_path=None, destination_path=None,
overrides = {'input_encoding': input_encoding, overrides = {'input_encoding': input_encoding,
'doctitle_xform': doctitle, 'doctitle_xform': doctitle,
'initial_header_level': initial_header_level} 'initial_header_level': initial_header_level}
writer = LatexWriter()
parts = core.publish_parts( parts = core.publish_parts(
source=input_string, source_path=source_path, source=input_string, source_path=source_path,
destination_path=destination_path, destination_path=destination_path,
writer_name='latex', settings_overrides=overrides) writer=writer, settings_overrides=overrides)
return parts return parts
def fixed_latex_table_lines(tex):
"""Replace the longtable package with supertabular package.
longtable doesn't work in two column mode, but supertabular does,
so we need to replace long-table specific formatting with the
supertabular equivalent.
"""
if "longtable" in tex and False:
begin_re = re.compile(r"\\begin{longtable\*?}" # Beginning of the environment
r"(\[.*\])?" # Optional arguments
r"{(.*)}" # Parameters
)
end_re = re.compile(r"\\end{longtable\*?}")
foot_re = re.compile(r"(\\endhead\n)(.*)\\endfoot\n\\endlastfoot", flags=(re.MULTILINE|re.DOTALL))
head_re = re.compile(r"(\\endfirsthead\n)(.*)\\endhead", flags=(re.MULTILINE|re.DOTALL))
firsthead_re = re.compile(r"(\\hline.*)\\endfirsthead", flags=(re.MULTILINE|re.DOTALL))
# Convert opening and closing environment
tex = begin_re.sub(r"\\begin{supertabular}\1{\2}", tex)
tex = end_re.sub(r"\\end{supertabular}", tex)
# Convert table headings
# Order matters for these substitutions
def printlines(t):
for l in t.split("\n"): print(l)
# import pdb; pdb.set_trace()
tex = foot_re.sub(r"\1\\tabletail{%\n\2}", tex)
tex = head_re.sub(r"\1\\tablehead{%\n\2}", tex)
tex = firsthead_re.sub(r"\\tablefirsthead{\1}", tex)
return tex
def rst_to_latex(rst, top_heading_level=0): def rst_to_latex(rst, top_heading_level=0):
"""Basic markup of reST to LaTeX code. """Basic markup of reST to LaTeX code.
@@ -174,7 +208,8 @@ def rst_to_latex(rst, top_heading_level=0):
tex_parts = latex_parts(rst) tex_parts = latex_parts(rst)
tex = tex_parts['body'] tex = tex_parts['body']
# Check for currently un-supported LaTeX commands # Check for currently un-supported LaTeX commands
assert "longtable" not in tex tex = fixed_latex_table_lines(tex)
# assert "longtable" not in tex
return tex return tex
+19 -1
View File
@@ -117,4 +117,22 @@ class MarkdownTestCase(unittest.TestCase):
tex = make_sheets.rst_to_latex(md_list) tex = make_sheets.rst_to_latex(md_list)
self.assertIn("\\begin{itemize}", tex) self.assertIn("\\begin{itemize}", tex)
def test_simple_table(self):
table_rst = """
===== ===== =======
A B A and B
===== ===== =======
False False False
True False False
False True False
True True True
===== ===== =======
"""
tex = make_sheets.rst_to_latex(table_rst)
# Check begin/end environment is fixed
self.assertNotIn("longtable", tex)
self.assertIn("supertabular", tex)
# Check headers and footers are fixed
self.assertNotIn("endfoot", tex)
self.assertNotIn("endhead", tex)
self.assertNotIn("endfirsthead", tex)