mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-05-18 20:23:27 +02:00
Switched to docutils/sphinx for parsing docstrings into LaTeX.
This commit is contained in:
@@ -11,11 +11,38 @@
|
||||
[% endif %]
|
||||
\definecolor{mygrey}{gray}{0.7}
|
||||
|
||||
[% include 'preamble.tex' %]
|
||||
|
||||
\title{Wild Shapes}
|
||||
\date{}
|
||||
|
||||
\author{[[ character.name ]]}
|
||||
|
||||
%%% Fallback definitions for Docutils-specific commands
|
||||
[% raw %]
|
||||
% admonition (specially marked topic)
|
||||
\providecommand{\DUadmonition}[2][class-arg]{%
|
||||
% try \DUadmonition#1{#2}:
|
||||
\ifcsname DUadmonition#1\endcsname%
|
||||
\csname DUadmonition#1\endcsname{#2}%
|
||||
\else
|
||||
\begin{center}
|
||||
\fbox{\parbox{0.9\linewidth}{#2}}
|
||||
\end{center}
|
||||
\fi
|
||||
}
|
||||
|
||||
% title for topics, admonitions, unsupported section levels, and sidebar
|
||||
\providecommand*{\DUtitle}[2][class-arg]{%
|
||||
% call \DUtitle#1{#2} if it exists:
|
||||
\ifcsname DUtitle#1\endcsname%
|
||||
\csname DUtitle#1\endcsname{#2}%
|
||||
\else
|
||||
\smallskip\noindent\textbf{#2}\smallskip%
|
||||
\fi
|
||||
}
|
||||
[% endraw %]
|
||||
|
||||
\begin{document}
|
||||
|
||||
|
||||
|
||||
@@ -11,10 +11,40 @@
|
||||
\setlength{\zerosep}{-1em}
|
||||
[% endif %]
|
||||
|
||||
[% include 'preamble.tex' %]
|
||||
|
||||
\title{Features and Magic Items}
|
||||
\author{[[ character.name ]]}
|
||||
\date{}
|
||||
|
||||
%%% Fallback definitions for Docutils-specific commands
|
||||
[% raw %]
|
||||
\usepackage{longtable,ltcaption,array}
|
||||
\setlength{\extrarowheight}{2pt}
|
||||
\newlength{\DUtablewidth} % internal use in tables
|
||||
% admonition (specially marked topic)
|
||||
\providecommand{\DUadmonition}[2][class-arg]{%
|
||||
% try \DUadmonition#1{#2}:
|
||||
\ifcsname DUadmonition#1\endcsname%
|
||||
\csname DUadmonition#1\endcsname{#2}%
|
||||
\else
|
||||
\begin{center}
|
||||
\fbox{\parbox{0.9\linewidth}{#2}}
|
||||
\end{center}
|
||||
\fi
|
||||
}
|
||||
|
||||
% title for topics, admonitions, unsupported section levels, and sidebar
|
||||
\providecommand*{\DUtitle}[2][class-arg]{%
|
||||
% call \DUtitle#1{#2} if it exists:
|
||||
\ifcsname DUtitle#1\endcsname%
|
||||
\csname DUtitle#1\endcsname{#2}%
|
||||
\else
|
||||
\smallskip\noindent\textbf{#2}\smallskip%
|
||||
\fi
|
||||
}
|
||||
[% endraw %]
|
||||
|
||||
\begin{document}
|
||||
|
||||
\maketitle
|
||||
|
||||
@@ -9,10 +9,37 @@
|
||||
\setlength{\zerosep}{-1em}
|
||||
[% endif %]
|
||||
|
||||
[% include 'preamble.tex' %]
|
||||
|
||||
\title{Infusion Descriptions}
|
||||
\author{[[ character.name ]] (Artificer [[ character.Artificer.level ]] level)}
|
||||
\date{}
|
||||
|
||||
%%% Fallback definitions for Docutils-specific commands
|
||||
[% raw %]
|
||||
% admonition (specially marked topic)
|
||||
\providecommand{\DUadmonition}[2][class-arg]{%
|
||||
% try \DUadmonition#1{#2}:
|
||||
\ifcsname DUadmonition#1\endcsname%
|
||||
\csname DUadmonition#1\endcsname{#2}%
|
||||
\else
|
||||
\begin{center}
|
||||
\fbox{\parbox{0.9\linewidth}{#2}}
|
||||
\end{center}
|
||||
\fi
|
||||
}
|
||||
|
||||
% title for topics, admonitions, unsupported section levels, and sidebar
|
||||
\providecommand*{\DUtitle}[2][class-arg]{%
|
||||
% call \DUtitle#1{#2} if it exists:
|
||||
\ifcsname DUtitle#1\endcsname%
|
||||
\csname DUtitle#1\endcsname{#2}%
|
||||
\else
|
||||
\smallskip\noindent\textbf{#2}\smallskip%
|
||||
\fi
|
||||
}
|
||||
[% endraw %]
|
||||
|
||||
\begin{document}
|
||||
|
||||
\maketitle
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
% For parsed docstrings
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage{alltt}
|
||||
@@ -11,10 +11,38 @@
|
||||
\setlength{\zerosep}{-1em}
|
||||
[% endif %]
|
||||
|
||||
[% include 'preamble.tex' %]
|
||||
|
||||
\title{Spell Descriptions}
|
||||
\author{[[ character.name ]]}
|
||||
\date{}
|
||||
|
||||
%%% Fallback definitions for Docutils-specific commands
|
||||
[% raw %]
|
||||
% admonition (specially marked topic)
|
||||
\providecommand{\DUadmonition}[2][class-arg]{%
|
||||
% try \DUadmonition#1{#2}:
|
||||
\ifcsname DUadmonition#1\endcsname%
|
||||
\csname DUadmonition#1\endcsname{#2}%
|
||||
\else
|
||||
\begin{center}
|
||||
\fbox{\parbox{0.9\linewidth}{#2}}
|
||||
\end{center}
|
||||
\fi
|
||||
}
|
||||
|
||||
% title for topics, admonitions, unsupported section levels, and sidebar
|
||||
\providecommand*{\DUtitle}[2][class-arg]{%
|
||||
% call \DUtitle#1{#2} if it exists:
|
||||
\ifcsname DUtitle#1\endcsname%
|
||||
\csname DUtitle#1\endcsname{#2}%
|
||||
\else
|
||||
\smallskip\noindent\textbf{#2}\smallskip%
|
||||
\fi
|
||||
}
|
||||
[% endraw %]
|
||||
|
||||
|
||||
\begin{document}
|
||||
|
||||
\maketitle
|
||||
|
||||
@@ -14,6 +14,8 @@ from itertools import product
|
||||
from fdfgen import forge_fdf
|
||||
import pdfrw
|
||||
from jinja2 import Environment, PackageLoader
|
||||
from docutils import core, io
|
||||
from sphinx.util.docstrings import prepare_docstring
|
||||
|
||||
from dungeonsheets import character as _char
|
||||
from dungeonsheets import exceptions, classes, readers
|
||||
@@ -102,6 +104,45 @@ def _parse_rst_headings(rst):
|
||||
yield heading_rst, heading, level
|
||||
|
||||
|
||||
def latex_parts(input_string, source_path=None, destination_path=None,
|
||||
input_encoding='unicode', doctitle=True,
|
||||
initial_header_level=1):
|
||||
"""
|
||||
Given an input string, returns a dictionary of HTML document parts.
|
||||
|
||||
Dictionary keys are the names of parts, and values are Unicode strings;
|
||||
encoding is up to the client.
|
||||
|
||||
Parameters:
|
||||
|
||||
- `input_string`: A multi-line text string; required.
|
||||
- `source_path`: Path to the source file or object. Optional, but useful
|
||||
for diagnostic output (system messages).
|
||||
- `destination_path`: Path to the file or object which will receive the
|
||||
output; optional. Used for determining relative paths (stylesheets,
|
||||
source links, etc.).
|
||||
- `input_encoding`: The encoding of `input_string`. If it is an encoded
|
||||
8-bit string, provide the correct encoding. If it is a Unicode string,
|
||||
use "unicode", the default.
|
||||
- `doctitle`: Disable the promotion of a lone top-level section title to
|
||||
document title (and subsequent section title to document subtitle
|
||||
promotion); enabled by default.
|
||||
- `initial_header_level`: The initial level for header elements (e.g. 1
|
||||
for "<h1>").
|
||||
"""
|
||||
# Remove indentation, etc
|
||||
input_string = "\n".join(prepare_docstring(input_string))
|
||||
# Parse from rst to TeX
|
||||
overrides = {'input_encoding': input_encoding,
|
||||
'doctitle_xform': doctitle,
|
||||
'initial_header_level': initial_header_level}
|
||||
parts = core.publish_parts(
|
||||
source=input_string, source_path=source_path,
|
||||
destination_path=destination_path,
|
||||
writer_name='latex', settings_overrides=overrides)
|
||||
return parts
|
||||
|
||||
|
||||
def rst_to_latex(rst, top_heading_level=0):
|
||||
"""Basic markup of reST to LaTeX code.
|
||||
|
||||
@@ -124,41 +165,14 @@ def rst_to_latex(rst, top_heading_level=0):
|
||||
The reST text parsed into LaTeX markup.
|
||||
|
||||
"""
|
||||
heading_latex = {
|
||||
0: 'section*',
|
||||
1: 'subsection*',
|
||||
2: 'subsubsection*',
|
||||
3: 'paragraph*',
|
||||
4: 'subparagraph*',
|
||||
}
|
||||
if rst is None:
|
||||
# No reST, so return an empty string
|
||||
tex = ""
|
||||
else:
|
||||
tex = rst
|
||||
# Allow literal backslashes
|
||||
for c in ['\\']:
|
||||
tex = tex.replace(c, '\\' + c)
|
||||
# Lists
|
||||
for list_rst, list_items in _parse_rst_lists(tex):
|
||||
list_tex = "\n\\begin{itemize}\n"
|
||||
for item in list_items:
|
||||
list_tex += f"\\item{{{item}}}\n"
|
||||
list_tex += "\\end{itemize}\n"
|
||||
tex = tex.replace(list_rst, list_tex)
|
||||
# Inline text formatting
|
||||
tex = bold_re.sub(r'\\textbf{\1}', tex)
|
||||
tex = it_re.sub(r'\\textit{\1}', tex)
|
||||
tex = verb_re.sub(r'\\begin{verbatim}{\1}\\end{verbatim}', tex)
|
||||
tex = dice_re.sub(r'\\texttt{\1}', tex)
|
||||
# Headings
|
||||
for heading_rst, heading, heading_level in _parse_rst_headings(tex):
|
||||
heading_level = min(heading_level + top_heading_level, max(heading_latex.keys()))
|
||||
tex = tex.replace(heading_rst, f"\\{heading_latex[heading_level]}{{{heading}}}")
|
||||
# Escape any remaining characters that have meaning in LaTeX
|
||||
for c in ['#', '$', '%', '&', '~', '_', '^']:
|
||||
tex = tex.replace(c, '\\' + c)
|
||||
|
||||
tex_parts = latex_parts(rst)
|
||||
tex = tex_parts['body']
|
||||
# Check for currently un-supported LaTeX commands
|
||||
assert "longtable" not in tex
|
||||
return tex
|
||||
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ setup(name='dungeonsheets',
|
||||
'../VERSION']
|
||||
},
|
||||
install_requires=[
|
||||
'fdfgen', 'npyscreen', 'jinja2', 'pdfrw',
|
||||
'fdfgen', 'npyscreen', 'jinja2', 'pdfrw', 'sphinx',
|
||||
],
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
|
||||
@@ -44,7 +44,7 @@ class MarkdownTestCase(unittest.TestCase):
|
||||
|
||||
def test_rst_bold(self):
|
||||
text = make_sheets.rst_to_latex('**hello**')
|
||||
self.assertEqual(text, '\\textbf{hello}')
|
||||
self.assertEqual(text, '\n\\textbf{hello}\n')
|
||||
|
||||
def test_hit_dice(self):
|
||||
text = make_sheets.rst_to_latex('1d6+3')
|
||||
@@ -56,7 +56,7 @@ class MarkdownTestCase(unittest.TestCase):
|
||||
|
||||
def test_verbatim(self):
|
||||
text = make_sheets.rst_to_latex('``hello, world``')
|
||||
self.assertIn(r'\begin{verbatim}', text)
|
||||
self.assertIn(r'\texttt{hello, world}', text)
|
||||
|
||||
def test_literal_backslash(self):
|
||||
text = make_sheets.rst_to_latex('\\')
|
||||
@@ -114,7 +114,6 @@ class MarkdownTestCase(unittest.TestCase):
|
||||
|
||||
"""
|
||||
tex = make_sheets.rst_to_latex(md_list)
|
||||
print(tex)
|
||||
self.assertIn("\\begin{itemize}", tex)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user