Browse Source

Merge pull request #15 from patacrep/next-template

Amélioration du moteur de templates
pull/20/head
Louis 11 years ago
parent
commit
e79f517aa9
  1. 1
      .gitignore
  2. 2
      setup.py
  3. 297
      songbook_core/build.py
  4. 1
      songbook_core/data/examples/example.sb
  5. 99
      songbook_core/data/latex/chords.sty
  6. 122
      songbook_core/data/latex/crepbook.cls
  7. 60
      songbook_core/data/templates/default.tex
  8. 154
      songbook_core/data/templates/default.tmpl
  9. 65
      songbook_core/data/templates/layout.tex
  10. 53
      songbook_core/data/templates/patacrep.tex
  11. 25
      songbook_core/data/templates/songs.tex
  12. 1
      songbook_core/index.py
  13. 3
      songbook_core/plastex.py
  14. 5
      songbook_core/plastex_patchedbabel.py
  15. 14
      songbook_core/songs.py
  16. 72
      songbook_core/templates.py

1
.gitignore

@ -1,5 +1,6 @@
deb_dist
build
dist
.gitignore
*~
*.aux

2
setup.py

@ -19,7 +19,7 @@ setup(name='songbook-core',
requires=[
"argparse", "codecs", "distutils", "fnmatch", "glob", "json",
"locale", "logging", "os", "plasTeX", "re", "subprocess", "sys",
"textwrap", "unidecode"
"textwrap", "unidecode", "jinja2"
],
packages=['songbook_core'],
package_data={'songbook_core': ['data/latex/*',

297
songbook_core/build.py

@ -16,12 +16,18 @@ from songbook_core import errors
from songbook_core.files import recursive_find
from songbook_core.index import process_sxd
from songbook_core.songs import Song, SongsList
from songbook_core.templates import TexRenderer
EOL = "\n"
DEFAULT_AUTHWORDS = {
"after": ["by"],
"ignore": ["unknown"],
"sep": ["and"],
}
def parse_template(template):
"""Return the list of parameters defined in the template."""
"""Return the dict of default parameters defined in the template."""
embedded_json_pattern = re.compile(r"^%%:")
with open(template) as template_file:
code = [
@ -31,65 +37,119 @@ def parse_template(template):
if embedded_json_pattern.match(line)
]
data = json.loads(''.join(code))
parameters = dict()
for param in data:
parameters[param["name"]] = param
if code:
data = json.loads(''.join(code))
for param in data:
try:
parameters[param["name"]] = param["default"]
except KeyError:
parameters[param["name"]] = None
return parameters
# pylint: disable=too-many-return-statements
def to_value(parameter, data):
"""Convert 'data' to a LaTeX string.
# pylint: disable=too-few-public-methods
class Songbook(object):
"""Represent a songbook (.sb) file.
Conversion is done according to the template parameter it corresponds to.
- Low level: provide a Python representation of the values stored in the
'.sb' file.
- High level: provide some utility functions to manipulate these data.
"""
if "type" not in parameter:
return data
elif parameter["type"] == "stringlist":
if "join" in parameter:
join_text = parameter["join"]
else:
join_text = ''
return join_text.join(data)
elif parameter["type"] == "color":
return data[1:]
elif parameter["type"] == "font":
return data + 'pt'
elif parameter["type"] == "enum":
return data
elif parameter["type"] == "file":
return data
elif parameter["type"] == "flag":
if "join" in parameter:
join_text = parameter["join"]
else:
join_text = ''
return join_text.join(data)
def format_declaration(name, parameter):
"""Write LaTeX code to declare a variable"""
value = ""
if "default" in parameter:
value = parameter["default"]
return (
r'\def\set@{name}#1{{\def\get{name}{{#1}}}}'.format(name=name)
+ EOL
+ format_definition(name, to_value(parameter, value))
)
def __init__(self, raw_songbook, basename):
super(Songbook, self).__init__()
self.basename = basename
# Default values: will be updated while parsing raw_songbook
self.config = {
'template': "default.tex",
'titleprefixwords': [],
'authwords': {},
'lang': 'french',
'sort': [u"by", u"album", u"@title"],
'songs': None,
'datadir': os.path.abspath('.'),
}
self.songslist = None
self._parse(raw_songbook)
self._set_songs_default()
def _set_songs_default(self):
"""Set the default values for the Song() class."""
Song.sort = self.config['sort']
Song.prefixes = self.config['titleprefixwords']
Song.authwords['after'] = [
re.compile(r"^.*%s\b(.*)" % after)
for after
in self.config['authwords']["after"]
]
Song.authwords['ignore'] = self.config['authwords']['ignore']
Song.authwords['sep'] = [
re.compile(r"^(.*)%s (.*)$" % sep)
for sep
in ([
" %s" % sep
for sep
in self.config['authwords']["sep"]
] + [','])
]
def format_definition(name, value):
"""Write LaTeX code to set a value to a variable"""
return r'\set@{name}{{{value}}}'.format(name=name, value=value) + EOL
def _parse(self, raw_songbook):
"""Parse raw_songbook.
The principle is: some special keys have their value processed; others
are stored verbatim in self.config.
"""
self.config.update(raw_songbook)
self.config['datadir'] = os.path.abspath(self.config['datadir'])
### Some post-processing
# Compute song list
if self.config['songs'] is None:
self.config['songs'] = [
os.path.relpath(
filename,
os.path.join(self.config['datadir'], 'songs'),
)
for filename
in recursive_find(
os.path.join(self.config['datadir'], 'songs'),
'*.sg',
)
]
self.songslist = SongsList(self.config['datadir'], self.config["lang"])
self.songslist.append_list(self.config['songs'])
# Ensure self.config['authwords'] contains all entries
for (key, value) in DEFAULT_AUTHWORDS.items():
if key not in self.config['authwords']:
self.config['authwords'][key] = value
def write_tex(self, output):
"""Build the '.tex' file corresponding to self.
Arguments:
- output: a file object, in which the file will be written.
"""
renderer = TexRenderer(
self.config['template'],
self.config['datadir'],
)
context = parse_template(renderer.file_template())
context.update(self.config)
context['titleprefixkeys'] = ["after", "sep", "ignore"]
context['songlist'] = self.songslist
context['filename'] = output.name[:-4]
renderer.render_tex(output, context)
def clean(basename):
"""Clean (some) temporary files used during compilation.
Depending of the LaTeX modules used in the template, there may be others
that are note deleted by this function."""
that are not deleted by this function."""
generated_extensions = [
"_auth.sbx",
"_auth.sxd",
@ -109,133 +169,8 @@ def clean(basename):
raise errors.CleaningError(basename + ext, exception)
def make_tex_file(songbook, output):
"""Create the LaTeX file corresponding to the .sb file given in argument."""
datadir = songbook['datadir']
name = output[:-4]
template_dir = os.path.join(datadir, 'templates')
songs = []
prefixes_tex = ""
prefixes = []
authwords_tex = ""
authwords = {"after": ["by"], "ignore": ["unknown"], "sep": ["and"]}
# parse the songbook data
if "template" in songbook:
template = songbook["template"]
del songbook["template"]
else:
template = os.path.join(__DATADIR__, "templates", "default.tmpl")
if "songs" in songbook:
songs = songbook["songs"]
del songbook["songs"]
if "titleprefixwords" in songbook:
prefixes = songbook["titleprefixwords"]
for prefix in songbook["titleprefixwords"]:
prefixes_tex += r"\titleprefixword{%s}" % prefix + EOL
songbook["titleprefixwords"] = prefixes_tex
if "authwords" in songbook:
# Populating default value
for key in ["after", "sep", "ignore"]:
if key not in songbook["authwords"]:
songbook["authwords"][key] = authwords[key]
# Processing authwords values
authwords = songbook["authwords"]
for key in ["after", "sep", "ignore"]:
for word in authwords[key]:
if key == "after":
authwords_tex += r"\auth%sword{%s}" % ("by", word) + EOL
else:
authwords_tex += r"\auth%sword{%s}" % (key, word) + EOL
songbook["authwords"] = authwords_tex
if "after" in authwords:
authwords["after"] = [re.compile(r"^.*%s\b(.*)" % after)
for after in authwords["after"]]
if "sep" in authwords:
authwords["sep"] = [" %s" % sep for sep in authwords["sep"]] + [","]
authwords["sep"] = [re.compile(r"^(.*)%s (.*)$" % sep)
for sep in authwords["sep"]]
if "lang" not in songbook:
songbook["lang"] = "french"
if "sort" in songbook:
sort = songbook["sort"]
del songbook["sort"]
else:
sort = [u"by", u"album", u"@title"]
Song.sort = sort
Song.prefixes = prefixes
Song.authwords = authwords
parameters = parse_template(os.path.join(template_dir, template))
# compute songslist
if songs == "all":
songs = [
os.path.relpath(filename, os.path.join(datadir, 'songs'))
for filename
in recursive_find(os.path.join(datadir, 'songs'), '*.sg')
]
songslist = SongsList(datadir, songbook["lang"])
songslist.append_list(songs)
songbook["languages"] = ",".join(songslist.languages())
# output relevant fields
out = codecs.open(output, 'w', 'utf-8')
out.write('%% This file has been automatically generated, do not edit!\n')
out.write(r'\makeatletter' + EOL)
# output automatic parameters
out.write(format_declaration("name", {"default": name}))
out.write(format_declaration("songslist", {"type": "stringlist"}))
# output template parameter command
for name, parameter in parameters.iteritems():
out.write(format_declaration(name, parameter))
# output template parameter values
for name, value in songbook.iteritems():
if name in parameters:
out.write(format_definition(
name,
to_value(parameters[name], value),
))
if len(songs) > 0:
out.write(format_definition('songslist', songslist.latex()))
out.write(r'\makeatother' + EOL)
# output template
comment_pattern = re.compile(r"^\s*%")
with codecs.open(
os.path.join(template_dir, template), 'r', 'utf-8'
) as template_file:
content = [
line
for line
in template_file
if not comment_pattern.match(line)
]
for index, line in enumerate(content):
if re.compile("getDataImgDirectory").search(line):
if os.path.abspath(os.path.join(datadir, "img")).startswith(
os.path.abspath(os.path.dirname(output))
):
imgdir = os.path.relpath(
os.path.join(datadir, "img"),
os.path.dirname(output)
)
else:
imgdir = os.path.abspath(os.path.join(datadir, "img"))
line = line.replace(r"\getDataImgDirectory", ' {%s/} ' % imgdir)
content[index] = line
out.write(u''.join(content))
out.close()
def buildsongbook(
songbook,
raw_songbook,
basename,
interactive=False,
logger=logging.getLogger()
@ -243,15 +178,15 @@ def buildsongbook(
"""Build a songbook
Arguments:
- songbook: Python representation of the .sb songbook configuration file.
- raw_songbook: Python representation of the .sb songbook configuration
file.
- basename: basename of the songbook to be built.
- interactive: in False, do not expect anything from stdin.
"""
tex_file = basename + ".tex"
# Make TeX file
make_tex_file(songbook, tex_file)
songbook = Songbook(raw_songbook, basename)
with codecs.open("{}.tex".format(basename), 'w', 'utf-8') as output:
songbook.write_tex(output)
if not 'TEXINPUTS' in os.environ.keys():
os.environ['TEXINPUTS'] = ''
@ -260,18 +195,18 @@ def buildsongbook(
'latex',
)
os.environ['TEXINPUTS'] += os.pathsep + os.path.join(
songbook['datadir'],
songbook.config['datadir'],
'latex',
)
# pdflatex options
pdflatex_options = []
pdflatex_options.append("--shell-escape") # Lilypond compilation
pdflatex_options.append("--shell-escape") # Lilypond compilation
if not interactive:
pdflatex_options.append("-halt-on-error")
# First pdflatex pass
if subprocess.call(["pdflatex"] + pdflatex_options + [tex_file]):
if subprocess.call(["pdflatex"] + pdflatex_options + [basename]):
raise errors.LatexCompilationError(basename)
# Make index
@ -284,7 +219,7 @@ def buildsongbook(
index_file.close()
# Second pdflatex pass
if subprocess.call(["pdflatex"] + pdflatex_options + [tex_file]):
if subprocess.call(["pdflatex"] + pdflatex_options + [basename]):
raise errors.LatexCompilationError(basename)
# Cleaning

1
songbook_core/data/examples/example.sb

@ -7,7 +7,6 @@
],
"booktype" : "chorded",
"lang" : "french",
"songs" : "all",
"authwords" : {
"sep" : ["and", "et"]
},

99
songbook_core/data/latex/chords.sty

@ -4,7 +4,50 @@
\newcommand*{\Sharp}{\nolinebreak\hspace{-.05em}\raisebox{.6ex}{\,\small\bf \#}}
\newcommand*{\Flat}{\nolinebreak\hspace{-.05em}\raisebox{.6ex}{\,\small$\mathbf{\flat}$}}
\newcommand*{\chordrule}{\mbox{\hspace{1cm}\rule[0.5cm]{15cm}{0.02cm}}\vspace{-.4cm}}
\newcommand*{\chordname}[2]{\makebox[3cm]{\raisebox{.5cm}{\large \textbf{\IfStrEq{\getlang}{english}{#1}{#2}}}}}
\newcommand*{\chordname}[1]{\makebox[3cm]{\raisebox{.5cm}{\large \textbf{#1}}}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Multilanguage management
\AtBeginDocument{
% Default names (english)
\newcommand{\guitarchordsname}{Guitar chords}
\newcommand{\ukulelechordsname}{Ukulele chords}
\newcommand{\chordnameAsharp}{A\Sharp = B\Flat}
\newcommand{\chordnameA}{A}
\newcommand{\chordnameB}{B}
\newcommand{\chordnameCsharp}{C\Sharp = D\Flat}
\newcommand{\chordnameC}{C}
\newcommand{\chordnameDsharp}{D\Sharp = E\Flat}
\newcommand{\chordnameD}{D}
\newcommand{\chordnameE}{E}
\newcommand{\chordnameFsharp}{F\Sharp = G\Flat}
\newcommand{\chordnameF}{F}
\newcommand{\chordnameGsharp}{G\Sharp = A\Flat}
\newcommand{\chordnameG}{G}
\IfStrEq{\mainlanguage}{french}{
% French names
\renewcommand{\guitarchordsname}{Accords de guitare}
\renewcommand{\ukulelechordsname}{Accords de ukulélé}
\renewcommand{\chordnameAsharp}{La\Sharp = Si\Flat}
\renewcommand{\chordnameA}{La}
\renewcommand{\chordnameB}{Si}
\renewcommand{\chordnameCsharp}{Do\Sharp = Ré\Flat}
\renewcommand{\chordnameC}{Do}
\renewcommand{\chordnameDsharp}{Ré\Sharp = Mi\Flat}
\renewcommand{\chordnameD}{Ré}
\renewcommand{\chordnameE}{Mi}
\renewcommand{\chordnameFsharp}{Fa\Sharp = Sol\Flat}
\renewcommand{\chordnameF}{Fa}
\renewcommand{\chordnameGsharp}{Sol\Sharp = La\Flat}
\renewcommand{\chordnameG}{Sol}
}{}
}
% End of multilanguage management
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\chords}{
\begin{songs}{}
@ -16,8 +59,8 @@
\songcolumns{1}
\ifguitar
\IfStrEq{\getlang}{english}{\beginsong{Guitar chords}}{\beginsong{Accords de guitare}}
\chordname{C}{Do}
\beginsong{\guitarchordsname}
\chordname{\chordnameC}
\gtab{C}{~:X32010}
\gtab{C7}{~:X32310}
\gtab{Cm}{3:X02210}
@ -29,7 +72,7 @@
\gtab*{C6}{~:XX2213}
\chordrule
\chordname{C\Sharp = D\Flat}{Do\Sharp = Ré\Flat}
\chordname{\chordnameCsharp}
\gtab{C\#}{4:X02220}
\gtab{C\#7}{4:X02020}
\gtab{C\#m}{4:X02210}
@ -41,7 +84,7 @@
\gtab*{C\#6}{1:X02010}
\chordrule
\chordname{D}{Ré}
\chordname{\chordnameD}
\gtab{D}{~:XX0232}
\gtab{D7}{~:XX0212}
\gtab{Dm}{~:XX0231}
@ -53,7 +96,7 @@
\gtab*{D6}{~:X00202}
\chordrule
\chordname{D\Sharp = E\Flat}{Ré\Sharp = Mi\Flat}
\chordname{\chordnameDsharp}
\gtab{D\#}{6:X02220}
\gtab{D\#7}{6:X02020}
\gtab{D\#m}{6:X02210}
@ -65,7 +108,7 @@
\gtab*{D\#6}{1:X00202}
\chordrule
\chordname{E}{Mi}
\chordname{\chordnameE}
\gtab{E}{~:022100}
\gtab{E7}{~:020100}
\gtab{Em}{~:022000}
@ -77,7 +120,7 @@
\gtab*{E6}{~:022120}
\chordrule
\chordname{F}{Fa}
\chordname{\chordnameF}
\gtab{F}{1:022100}
\gtab{F7}{1:020100}
\gtab{Fm}{1:022000}
@ -89,7 +132,7 @@
\gtab*{F6}{~:XX0211}
\chordrule
\chordname{F\Sharp = G\Flat}{Fa\Sharp = Sol\Flat}
\chordname{\chordnameFsharp}
\gtab{F\#}{2:022100}
\gtab{F\#7}{2:020100}
\gtab{F\#m}{2:022000}
@ -101,7 +144,7 @@
\gtab*{F\#6}{~:XX1322}
\chordrule
\chordname{G}{Sol}
\chordname{\chordnameG}
\gtab{G}{~:320003}
\gtab{G7}{~:320001}
\gtab{Gm}{3:022000}
@ -113,7 +156,7 @@
\gtab*{G6}{~:320000}
\chordrule
\chordname{G\Sharp = A\Flat}{Sol\Sharp = La\Flat}
\chordname{\chordnameGsharp}
\gtab{G\#}{4:022100}
\gtab{G\#7}{4:020100}
\gtab{G\#m}{4:022000}
@ -125,7 +168,7 @@
\gtab*{G\#6}{~:XX1111}
\chordrule
\chordname{A}{La}
\chordname{\chordnameA}
\gtab{A}{~:X02220}
\gtab{A7}{~:X02020}
\gtab{Am}{~:X02210}
@ -137,7 +180,7 @@
\gtab*{A6}{~:XX2222}
\chordrule
\chordname{A\Sharp = B\Flat}{La\Sharp = Si\Flat}
\chordname{\chordnameAsharp}
\gtab{A\#}{1:X02220}
\gtab{A\#7}{1:X02020}
\gtab{A\#m}{1:X02210}
@ -149,7 +192,7 @@
\gtab*{A\#6}{~:XX3333}
\chordrule
\chordname{B}{Si}
\chordname{\chordnameB}
\gtab{B}{2:X02220}
\gtab{B7}{X21202}
\gtab{Bm}{2:X02210}
@ -169,9 +212,9 @@
\fi
\ifukulele
\IfStrEq{\getlang}{english}{\beginsong{Ukulele chords}}{\beginsong{Accords de ukulélé}}
\beginsong{\ukulelechordsname}
\chordname{C}{Do}
\chordname{\chordnameC}
\utab{C}{~:0003}
\utab{C7}{~:0001}
\utab{Cm}{~:0333}
@ -183,7 +226,7 @@
\utab*{Cdim}{2:3101}
\chordrule
\chordname{C\Sharp = D\Flat}{Do\Sharp = Ré\Flat}
\chordname{\chordnameCsharp}
\utab{C\#}{1:0003}
\utab{C\#7}{1:0001}
\utab{C\#m}{~:1104}
@ -195,7 +238,7 @@
\utab*{C\#dim}{~:0104}
\chordrule
\chordname{D}{Ré}
\chordname{\chordnameD}
\utab{D}{~:2220}
\utab{D7}{2:0001}
\utab{Dm}{~:2210}
@ -207,7 +250,7 @@
\utab*{Ddim}{1:0104}
\chordrule
\chordname{D\Sharp = E\Flat}{Ré\Sharp = Mi\Flat}
\chordname{\chordnameDsharp}
\utab{D\#}{1:2220}
\utab{D\#7}{3:0001}
\utab{D\#m}{1:2210}
@ -219,7 +262,7 @@
\utab*{D\#dim}{~:2320}
\chordrule
\chordname{E}{Mi}
\chordname{\chordnameE}
\utab{E}{2:2220}
\utab{E7}{~:1202}
\utab{Em}{~:0432}
@ -231,7 +274,7 @@
\utab*{Edim}{1:2320}
\chordrule
\chordname{F}{Fa}
\chordname{\chordnameF}
\utab{F}{~:2010}
\utab{F7}{~:2310}
\utab{Fm}{~:1013}
@ -243,7 +286,7 @@
\utab*{Fdim}{2:2320}
\chordrule
\chordname{F\Sharp = G\Flat}{Fa\Sharp = Sol\Flat}
\chordname{\chordnameFsharp}
\utab{F\#}{1:2010}
\utab{F\#7}{1:2310}
\utab{F\#m}{~:2120}
@ -255,7 +298,7 @@
\utab*{F\#dim}{~:2020}
\chordrule
\chordname{G}{Sol}
\chordname{\chordnameG}
\utab{G}{~:0232}
\utab{G7}{~:0212}
\utab{Gm}{~:0231}
@ -267,7 +310,7 @@
\utab*{Gdim}{~:0131}
\chordrule
\chordname{G\Sharp = A\Flat}{Sol\Sharp = La\Flat}
\chordname{\chordnameGsharp}
\utab{G\#}{3:2010}
\utab{G\#7}{1:0212}
\utab{G\#m}{1:0231}
@ -279,7 +322,7 @@
\utab*{G\#dim}{1:0131}
\chordrule
\chordname{A}{La}
\chordname{\chordnameA}
\utab{A}{~:2100}
\utab{A7}{~:0100}
\utab{Am}{~:2000}
@ -291,7 +334,7 @@
\utab*{Adim}{2:0131}
\chordrule
\chordname{A\Sharp = B\Flat}{La\Sharp = Si\Flat}
\chordname{\chordnameAsharp}
\utab{A\#}{1:2100}
\utab{A\#7}{1:0100}
\utab{A\#m}{1:2000}
@ -303,7 +346,7 @@
\utab*{A\#dim}{~:3101}
\chordrule
\chordname{B}{Si}
\chordname{\chordnameB}
\utab{B}{2:2100}
\utab{B7}{2:0100}
\utab{Bm}{2:2000}
@ -324,4 +367,4 @@
\end{songs}
}
\endinput
\endinput

122
songbook_core/data/latex/crepbook.cls

@ -84,6 +84,60 @@
\fi
% Start
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Multilanguage management
\AtBeginDocument{
% Default names (english)
\newcommand{\songlistname}{Songs list}
\newcommand{\labelversionname}{version:}
\newcommand{\labeldatename}{date:}
\newcommand{\labelauthorname}{authors:}
\newcommand{\labelwebname}{web:}
\newcommand{\labelmailname}{mail:}
\newcommand{\originalsongname}{Original song:}
\newcommand{\introname}{intro}
\newcommand{\outroname}{outro}
\newcommand{\bridgename}{bridge}
\newcommand{\chorusname}{chorus}
\newcommand{\versename}{verse}
\newcommand{\soloname}{solo}
\newcommand{\patternname}{pattern}
\newcommand{\rythmname}{rythm}
\newcommand{\transpositionname}{transposition:}
\newcommand{\songindexname}{Songs Index}
\newcommand{\authorindexname}{Authors Index}
\newcommand{\chordlistname}{Chords list}
\IfStrEq{\mainlanguage}{french}{
% French names
\renewcommand{\songlistname}{Liste des chansons}{}
\renewcommand{\labelversionname}{version :}
\renewcommand{\labeldatename}{date :}
\renewcommand{\labelauthorname}{auteurs :}
\renewcommand{\labelwebname}{web :}
\renewcommand{\labelmailname}{mail :}
\renewcommand{\originalsongname}{Chanson originale :}
\renewcommand{\introname}{intro}
\renewcommand{\outroname}{outro}
\renewcommand{\bridgename}{pont}
\renewcommand{\chorusname}{refrain}
\renewcommand{\versename}{couplet}
\renewcommand{\soloname}{solo}
\renewcommand{\patternname}{motif}
\renewcommand{\rythmname}{rythme}
\renewcommand{\transpositionname}{transposition :}
\renewcommand{\songindexname}{Index des chansons}
\renewcommand{\authorindexname}{Index des auteurs}
\renewcommand{\chordlistname}{Liste des accords}
}{}
}
% End of multilanguage management
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\def\andname{and}
\def\lastandname{\unskip, and}
@ -111,30 +165,9 @@
\def\picture#1{\gdef\@picture{#1}}
\def\picturecopyright#1{\gdef\@picturecopyright{#1}}
\def\footer#1{\gdef\@footer{#1}}
\def\lang#1{\gdef\@lang{#1}}
\def\lang#1{\gdef\mainlanguage{#1}}
\clearheadinfo
\newcommand{\l@belVersion}{
\IfStrEq{\@lang}{english}{\bf version:}{}
\IfStrEq{\@lang}{french}{\bf version :}{}
}
\newcommand{\l@belDate}{
\IfStrEq{\@lang}{english}{\bf date:}{}
\IfStrEq{\@lang}{french}{\bf date :}{}
}
\newcommand{\l@belAuthor}{
\IfStrEq{\@lang}{english}{\bf authors:}{}
\IfStrEq{\@lang}{french}{\bf auteurs :}{}
}
\newcommand{\l@belWeb}{
\IfStrEq{\@lang}{english}{\bf web:}{}
\IfStrEq{\@lang}{french}{\bf web :}{}
}
\newcommand{\l@belMail}{
\IfStrEq{\@lang}{english}{\bf mail:}{}
\IfStrEq{\@lang}{french}{\bf mail :}{}
}
\renewcommand\maketitle{
\@maketitle
@ -172,11 +205,11 @@
\begin{flushleft}
\begin{tabular}{l l}
\if!\@version!\else{\l@belVersion} & \@version \\ \fi
\if!\@date!\else{\l@belDate} & \@date \\ \fi
\if!\@author!\else{\l@belAuthor} & \@author \\ \fi
\if!\@web!\else{\l@belWeb} & \url{\@web} \\ \fi
\if!\@mail!\else{\l@belMail} & \url{\@mail} \\ \fi
\if!\@version!\else{\textbf{\labelversionname}} & \@version \\ \fi
\if!\@date!\else{\textbf{\labeldatename}} & \@date \\ \fi
\if!\@author!\else{\textbf{\labelauthorname}} & \@author \\ \fi
\if!\@web!\else{\textbf{\labelwebname}} & \url{\@web} \\ \fi
\if!\@mail!\else{\textbf{\labelmailname}} & \url{\@mail} \\ \fi
\end{tabular}
\end{flushleft}
@ -194,8 +227,6 @@
\thispagestyle{empty}
}
\makeatletter
\newlength{\coverheight}
\setlength{\coverheight}{2cm}
\newlength{\coverspace}
@ -229,7 +260,7 @@
\renewcommand{\extendpostlude}{
{\footnotesize%
\IfStrEq{\songoriginal}{}{}{
\IfStrEq{\@lang}{english}{Original song:}{Chanson originale :}
\originalsongname
\songoriginal
}
}
@ -446,36 +477,28 @@
%% End of tabs.sty file
\newcommand*{\Intro}{%
\IfStrEq{\@lang}{english}{intro}{}%
\IfStrEq{\@lang}{french}{intro}{}%
\introname%
}%
\newcommand*{\Outro}{%
\IfStrEq{\@lang}{english}{outro}{}%
\IfStrEq{\@lang}{french}{outro}{}%
\outroname%
}%
\newcommand*{\Bridge}{%
\IfStrEq{\@lang}{english}{bridge}{}%
\IfStrEq{\@lang}{french}{pont}{}%
\bridgename%
}%
\newcommand*{\Chorus}{%
\IfStrEq{\@lang}{english}{chorus}{}%
\IfStrEq{\@lang}{french}{refrain}{}%
\chorusname%
}%
\newcommand*{\Verse}{%
\IfStrEq{\@lang}{english}{verse}{}%
\IfStrEq{\@lang}{french}{couplet}{}%
\versename%
}%
\newcommand*{\Solo}{%
\IfStrEq{\@lang}{english}{solo}{}%
\IfStrEq{\@lang}{french}{solo}{}%
\soloname%
}%
\newcommand*{\Pattern}{%
\IfStrEq{\@lang}{english}{pattern}{}%
\IfStrEq{\@lang}{french}{motif}{}%
\patternname%
}%
\newcommand*{\Rythm}{%
\IfStrEq{\@lang}{english}{rythm}{}%
\IfStrEq{\@lang}{french}{rythme}{}%
\rythmname%
}%
\newcommand*{\Adlib}{%
\emph{ad~lib.}%
@ -485,7 +508,7 @@
\renewcommand{\musicnote}[2][]{%
\vspace{.1cm}
\IfStrEq{}{#1}{\musicnoteORIG{#2}}{
\IfStrEq{\@lang}{#1}{\musicnoteORIG{#2}}{}
\iflanguage{#1}{\musicnoteORIG{#2}}{}
}
}
@ -493,7 +516,7 @@
\renewcommand{\textnote}[2][]{%
\vspace{.1cm}
\IfStrEq{}{#1}{\textnoteORIG{#2}}{
\IfStrEq{\@lang}{#1}{\textnoteORIG{#2}}{}
\iflanguage{#1}{\textnoteORIG{#2}}{}
}
}
@ -559,8 +582,7 @@
\newcommand{\transposition}[1]{%
\ifnorepeatchords%
\musicnote{%
\IfStrEq{\@lang}{english}{transposition:~}{}%
\IfStrEq{\@lang}{french}{transposition~:~}{}%
\transpositionname~
\ifthenelse{#1>0}{#1$\Uparrow$}{\removefirstch@r#1$\Downarrow$}%
}%
\else%

60
songbook_core/data/templates/default.tex

@ -0,0 +1,60 @@
(* set indexes = "titleidx,authidx" *)
(* extends "songs.tex" *)
(* block songbookpreambule *)
(( super() ))
\usepackage{chords}
\title{((title))}
\author{((author))}
\subtitle{((subtitle))}
(* if version!="unknown" *)
\version{((version))}
(* endif *)
\mail{((mail))}
\web{((web))}
\picture{((picture))}
\picturecopyright{((picturecopyright))}
\footer{((footer))}
\newindex{titleidx}{((filename))_title}
\newauthorindex{authidx}{((filename))_auth}
(* for prefix in titleprefixwords *)
\titleprefixwords{((prefix))}
(* endfor*)
(* for key in titleprefixkeys *)
(* for word in authwords.key *)
(* if key=="after" *)
\authbyword{((word))}
(* else *)
\auth((key))word{((word))}
(* endif *)
(* endfor *)
(* endfor*)
(* endblock *)
(* block title *)
\maketitle
(* endblock *)
(* block index *)
\showindex{\songindexname}{titleidx}
\showindex{\authorindexname}{authidx}
(* if lang==french *)
\notenamesin{A}{B}{C}{D}{E}{F}{G}
\notenamesout{La}{Si}{Do}{}{Mi}{Fa}{Sol}
(* endif *)
(* endblock *)
(* block chords *)
% list of chords
\ifchorded
\phantomsection
\addcontentsline{toc}{section}{\chordlistname}
\chords
\fi
(* endblock *)

154
songbook_core/data/templates/default.tmpl

@ -1,154 +0,0 @@
% Copyright (C) 2009-2010 Romain Goffe, Alexandre Dupas
% Copyright (C) 2008 Kevin W. Hamlen
%
% This program is free software; you can redistribute it and/or
% modify it under the terms of the GNU General Public License
% as published by the Free Software Foundation; either version 2
% of the License, or (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
% MA 02110-1301, USA.
%
% The latest version of this program can be obtained from
% http://songs.sourceforge.net.
%
% Modified to serve personnal purposes. Newer versions can be
% obtained from http://www.lohrun.net.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Template parameters
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%:[
%%: {"name":"title", "description":"Title", "default":"Recueil de chansons pour guitare", "mandatory":true},
%%: {"name":"author", "description":"Author", "default":"The Songbook Team", "mandatory":true},
%%: {"name":"booktype", "description":"Type", "type":"enum", "values":["chorded","lyric"], "default":"chorded", "mandatory":true},
%%: {"name":"lang", "description":"Language", "default":"english"},
%%: {"name":"instruments", "description":"Instruments", "type":"flag", "values":["guitar","ukulele"], "join":",", "mandatory":true, "default":["guitar"]},
%%: {"name":"bookoptions", "description":"Options", "type":"flag", "values":["diagram","importantdiagramonly","lilypond","pictures","tabs","repeatchords","onesongperpage"], "join":",", "mandatory":true, "default":["diagram","pictures"]},
%%: {"name":"version", "description":"Version", "default":"unknown"},
%%: {"name":"subtitle", "description":"Subtitle"},
%%: {"name":"web", "description":"Web", "default":"http://www.patacrep.com"},
%%: {"name":"mail", "description":"Email", "default":"crep@team-on-fire.com"},
%%: {"name":"picture", "description":"Picture", "type":"file", "default":"treble_a"},
%%: {"name":"picturecopyright", "description":"Copyright", "default":"Dbolton \\url{http://commons.wikimedia.org/wiki/User:Dbolton}"},
%%: {"name":"footer", "description":"Footer", "default":"\\begin{flushright}Generated using Songbook (\\url{http://www.patacrep.com})\\end{flushright}"},
%%: {"name":"mainfontsize", "description":"Font Size", "type":"font", "default":"10"},
%%: {"name":"songnumberbgcolor", "description":"Number Shade", "type":"color", "default":"#D1E4AE"},
%%: {"name":"notebgcolor", "description":"Note Shade", "type":"color", "default":"#D1E4AE"},
%%: {"name":"indexbgcolor", "description":"Index Shade", "type":"color", "default":"#D1E4AE"},
%%: {"name":"titleprefixwords", "description":"Ignore some words in the beginning of song titles"},
%%: {"name":"authwords", "descriptipn":"Set of options to process author string (LaTeX commands authsepword, authignoreword, authbyword)"},
%%: {"name":"languages", "description":"List of languages used by songs", "default":""}
%%:]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% begin document
\makeatletter\def\input@path{{tex/}}
\documentclass[\getbooktype,\getinstruments,\getbookoptions,\getmainfontsize]{crepbook}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\PassOptionsToPackage{\getlanguages}{babel}
\PassOptionsToPackage{\getlang}{babel}
\usepackage{babel}
\title{\gettitle}
\author{\getauthor}
\subtitle{\getsubtitle}
\version{\getversion}
\mail{\getmail}
\web{\getweb}
\picture{\getpicture}
\picturecopyright{\getpicturecopyright}
\footer{\getfooter}
\lang{\getlang}
\newindex{titleidx}{\getname_title}
\newauthorindex{authidx}{\getname_auth}
\graphicspath{\getDataImgDirectory}
\definecolor{SongNumberBgColor}{HTML}{\getsongnumberbgcolor}
\definecolor{NoteBgColor}{HTML}{\getnotebgcolor}
\definecolor{IndexBgColor}{HTML}{\getindexbgcolor}
\renewcommand{\snumbgcolor}{SongNumberBgColor}
\renewcommand{\notebgcolor}{NoteBgColor}
\renewcommand{\idxbgcolor}{IndexBgColor}
\gettitleprefixwords
\getauthwords
\pagestyle{empty}
% Customization of the page appearance
\usepackage[
a4paper % paper size
,includeheadfoot % include header and footer into text size
,hmarginratio=1:1 % ratio between inner and outer margin (default)
,outer=1.8cm % outer margin (right)
,vmarginratio=1:1 % ratio between top and bottom margin
,bmargin=1.3cm % bottom margin
% ,bindingoffset=1.7cm % space reserved to bound pages together
]{geometry}
\usepackage{chords}
\begin{document}
% translate default title
\IfStrEq{\gettitle}{Recueil de chansons pour guitare}{
\IfStrEq{\getlang}{english}{\title{Patacrep songbook}}{}
}{}
\maketitle
% indexes
\IfStrEq{\getlang}{english}{
\showindex{Songs Index}{titleidx}
}{
\showindex{Index des chansons}{titleidx}
}
\IfStrEq{\getlang}{english}{
\showindex{Authors Index}{authidx}
}{
\showindex{Index des auteurs}{authidx}
}
% chords notation
\IfStrEq{\getlang}{french}{
\notenamesin{A}{B}{C}{D}{E}{F}{G}
\notenamesout{La}{Si}{Do}{Ré}{Mi}{Fa}{Sol}
}{}
% list of chords
\ifchorded
\phantomsection
\IfStrEq{\getlang}{english}{
\addcontentsline{toc}{section}{Chords list}
}{
\addcontentsline{toc}{section}{Liste des accords}
}
\chords
\fi
% songs
\phantomsection
\IfStrEq{\getlang}{english}{
\addcontentsline{toc}{section}{Songs list}
}{
\addcontentsline{toc}{section}{Liste des chansons}
}
\begin{songs}{titleidx,authidx}
\getsongslist
\end{songs}
\end{document}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% end document

65
songbook_core/data/templates/layout.tex

@ -0,0 +1,65 @@
%% Automaticly generated document.
%% You may edit this file but all changes will be overwritten.
%% If you want to change this document, have a look at
%% the templating system.
% This program is free software; you can redistribute it and/or
% modify it under the terms of the GNU General Public License
% as published by the Free Software Foundation; either version 2
% of the License, or (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
% MA 02110-1301, USA.
%
% The latest version of this program can be obtained from
% https://github.com/patacrep/
% Copyright (C) 2014 The Songbook team (www.patacrep.com)
(* block documentclass *)
\documentclass[((booktype)),
(* for option in bookoptions *)((option)),
(* endfor *)
(* for instrument in instruments *)((instrument)),
(* endfor *)
((mainfontsize))pt]{crepbook}
(* endblock *)
(* block songbookpreambule *)
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
(* endblock songbookpreambule *)
(* block preambule *)
(* endblock preambule *)
\begin{document}
(* block title *)
(* endblock *)
(* block preface *)
(* endblock *)
(* block index *)
(* endblock *)
(* block chords *)
(* endblock *)
(* block songs *)
(* endblock *)
(* block postface *)
(* endblock *)
\end{document}
% End of file

53
songbook_core/data/templates/patacrep.tex

@ -0,0 +1,53 @@
(% comment %)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Template parameters
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%:[
%%: {"name":"title", "description":"Title", "default":"Recueil de chansons pour guitare", "mandatory":true},
%%: {"name":"author", "description":"Author", "default":"The Songbook Team", "mandatory":true},
%%: {"name":"booktype", "description":"Type", "type":"enum", "values":["chorded","lyric"], "default":"chorded", "mandatory":true},
%%: {"name":"lang", "description":"Language", "default":"english"},
%%: {"name":"instruments", "description":"Instruments", "type":"flag", "values":["guitar","ukulele"], "join":",", "mandatory":true, "default":["guitar"]},
%%: {"name":"bookoptions", "description":"Options", "type":"flag", "values":["diagram","importantdiagramonly","lilypond","pictures","tabs","repeatchords","onesongperpage"], "join":",", "mandatory":true, "default":["diagram","pictures"]},
%%: {"name":"version", "description":"Version", "default":"unknown"},
%%: {"name":"subtitle", "description":"Subtitle"},
%%: {"name":"web", "description":"Web", "default":"http://www.patacrep.com"},
%%: {"name":"mail", "description":"Email", "default":"crep@team-on-fire.com"},
%%: {"name":"picture", "description":"Picture", "type":"file", "default":"treble_a"},
%%: {"name":"picturecopyright", "description":"Copyright", "default":"Dbolton \\url{http://commons.wikimedia.org/wiki/User:Dbolton}"},
%%: {"name":"footer", "description":"Footer", "default":"\\begin{flushright}Generated using Songbook (\\url{http://www.patacrep.com})\\end{flushright}"},
%%: {"name":"mainfontsize", "description":"Font Size", "type":"font", "default":"10"},
%%: {"name":"songnumberbgcolor", "description":"Number Shade", "type":"color", "default":"D1E4AE"},
%%: {"name":"notebgcolor", "description":"Note Shade", "type":"color", "default":"D1E4AE"},
%%: {"name":"indexbgcolor", "description":"Index Shade", "type":"color", "default":"D1E4AE"},
%%: {"name":"titleprefixwords", "description":"Ignore some words in the beginning of song titles"},
%%: {"name":"authwords", "descriptipn":"Set of options to process author string (LaTeX commands authsepword, authignoreword, authbyword)"},
%%: {"name":"languages", "description":"List of languages used by songs", "default":"english"}
%%:]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
(% endcomment %)
(* extends "default.tex" *)
(* block songbookpreambule *)
\usepackage[
a4paper % paper size
,includeheadfoot % include header and footer into text size
,hmarginratio=1:1 % ratio between inner and outer margin (default)
,outer=1.8cm % outer margin (right)
,vmarginratio=1:1 % ratio between top and bottom margin
,bmargin=1.3cm % bottom margin
]{geometry}
(( super() ))
\pagestyle{empty}
\definecolor{SongNumberBgColor}{HTML}{((songnumberbgcolor))}
\definecolor{NoteBgColor}{HTML}{((notebgcolor))}
\definecolor{IndexBgColor}{HTML}{((indexbgcolor))}
\renewcommand{\snumbgcolor}{SongNumberBgColor}
\renewcommand{\notebgcolor}{NoteBgColor}
\renewcommand{\idxbgcolor}{IndexBgColor}
(* endblock *)

25
songbook_core/data/templates/songs.tex

@ -0,0 +1,25 @@
(* extends "layout.tex" *)
(* block songbookpreambule *)
(( super() ))
(* for lang in songlist.languages() *)
\PassOptionsToPackage{((lang))}{babel}
(* endfor *)
\usepackage[((lang))]{babel}
\lang{((lang))}
\graphicspath{{((datadir))/img/}}
(* endblock *)
(* block songs *)
\phantomsection
\addcontentsline{toc}{section}{\songlistname}
\begin{songs}{((indexes|default('')))}
(* for song in songlist.songs *)
\input{((song.path))}
(* endfor *)
\end{songs}
(* endblock *)

1
songbook_core/index.py

@ -11,7 +11,6 @@ from a file generated by the latex compilation of the songbook (.sxd).
from unidecode import unidecode
import locale
import re
import sys
from songbook_core.authors import processauthors
from songbook_core.plastex import simpleparse

3
songbook_core/plastex.py

@ -74,7 +74,8 @@ def parsetex(filename):
"""
# /* BEGIN plasTeX patch
# The following lines, and another line a few lines later, are used to
# circumvent a plasTeX bug. It has been reported, with a patch.
# circumvent a plasTeX bug. It has been reported and corrected :
# https://github.com/tiarno/plastex/commit/8f4e5a385f3cb6a04d5863f731ce24a7e856f2a4
# To see if you can delete those lines, set your LC_TIME locale to French,
# during a month containing diacritics (e.g. Février), and run songbook. If
# no plasTeX bug appears, it is safe to remove those lines.

5
songbook_core/plastex_patchedbabel.py

@ -11,8 +11,9 @@ en production. En attendant, nous utilisons cette version modifiée.
Dés que la correction sera entrée en production, il faudra supprimer ce
fichier, et remplater l'occurence à "patchedbabel" par "babel" dans le fichier
"plastex.py".
La correction à suveiller est la révision 1.3 du fichier babel.py :
http://plastex.cvs.sourceforge.net/viewvc/plastex/plastex/plasTeX/Packages/babel.py?view=log
La correction à suveiller est la révision
41a48c0c229dd46b69fb0e3720595000a71b17d8 du fichier babel.py :
https://github.com/tiarno/plastex/commit/41a48c0c229dd46b69fb0e3720595000a71b17d8
# Comment vérifier si on peut supprimer ce fichier ?

14
songbook_core/songs.py

@ -126,14 +126,10 @@ class SongsList(object):
for filename in glob.iglob(os.path.join(self._songdir, regexp)):
self.append(filename)
def latex(self):
"""Renvoie le code LaTeX nécessaire pour intégrer la liste de chansons.
"""
result = [r'\input{{{0}}}'.format(song.path.replace("\\", "/").strip())
for song in self.songs]
result.append(r'\selectlanguage{%s}' % self._language)
return '\n'.join(result)
def languages(self):
"""Renvoie la liste des langues utilisées par les chansons"""
return set().union(*[set(song.languages) for song in self.songs])
languages = set().union(*[set(song.languages) for song in self.songs])
if languages:
return languages
else:
return set(['english'])

72
songbook_core/templates.py

@ -0,0 +1,72 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Template for .tex generation settings and utilities"""
from jinja2 import Environment, FileSystemLoader, ChoiceLoader, PackageLoader
import os
import re
_LATEX_SUBS = (
(re.compile(r'\\'), r'\\textbackslash'),
(re.compile(r'([{}_#%&$])'), r'\\\1'),
(re.compile(r'~'), r'\~{}'),
(re.compile(r'\^'), r'\^{}'),
(re.compile(r'"'), r"''"),
(re.compile(r'\.\.\.+'), r'\\ldots'),
)
def _escape_tex(value):
'''Escape TeX special characters'''
newval = value
for pattern, replacement in _LATEX_SUBS:
newval = pattern.sub(replacement, newval)
return newval
class TexRenderer(object):
"""Render a template to a LaTeX file."""
def __init__(self, template, datadir=''):
'''Start a new jinja2 environment for .tex creation.
Arguments:
- datadir: location of the user-defined templates
'''
self.template = template
self.texenv = Environment(
loader=ChoiceLoader([
FileSystemLoader(
os.path.join(datadir, 'templates')
),
PackageLoader(
'songbook_core', os.path.join('data', 'templates')
),
])
)
self.texenv.block_start_string = '(*'
self.texenv.block_end_string = '*)'
self.texenv.variable_start_string = '(('
self.texenv.variable_end_string = '))'
self.texenv.comment_start_string = '(% comment %)'
self.texenv.comment_end_string = '(% endcomment %)'
self.texenv.filters['escape_tex'] = _escape_tex
self.texenv.trim_blocks = True
self.texenv.lstrip_blocks = True
def file_template(self):
"""Return the filename of the selected template."""
return self.texenv.get_template(self.template).filename
def render_tex(self, output, context):
'''Render a template into a .tex file
Arguments:
- output: a file object to write the result
- context: all the data to populate the template
'''
#pylint: disable=star-args
output.write(
self.texenv.get_template(self.template).render(**context)
)
Loading…
Cancel
Save