diff --git a/songbook_core/build.py b/songbook_core/build.py old mode 100755 new mode 100644 index 68ecb596..f81f00ab --- a/songbook_core/build.py +++ b/songbook_core/build.py @@ -5,7 +5,6 @@ import codecs import glob -import json import logging import os.path import re @@ -26,28 +25,6 @@ DEFAULT_AUTHWORDS = { } -def parse_template(template): - """Return the dict of default parameters defined in the template.""" - embedded_json_pattern = re.compile(r"^%%:") - with open(template) as template_file: - code = [ - line[3:-1] - for line - in template_file - if embedded_json_pattern.match(line) - ] - - parameters = dict() - 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-few-public-methods class Songbook(object): """Represent a songbook (.sb) file. @@ -86,12 +63,9 @@ class Songbook(object): 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"] - ] + [',']) + for sep in ([ + " %s" % sep for sep in self.config['authwords']["sep"] + ] + [',']) ] def _parse(self, raw_songbook): @@ -135,7 +109,7 @@ class Songbook(object): self.config['datadir'], ) - context = parse_template(renderer.file_template()) + context = renderer.get_variables() context.update(self.config) context['titleprefixkeys'] = ["after", "sep", "ignore"] diff --git a/songbook_core/data/templates/default.tex b/songbook_core/data/templates/default.tex index c0a1d265..5d19dda0 100644 --- a/songbook_core/data/templates/default.tex +++ b/songbook_core/data/templates/default.tex @@ -1,6 +1,30 @@ -(* set indexes = "titleidx,authidx" *) +(% variables %) +[ +{"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"} +] +(% endvariables %) (* extends "songs.tex" *) +(* set indexes = "titleidx,authidx" *) (* block songbookpreambule *) (( super() )) diff --git a/songbook_core/data/templates/patacrep.tex b/songbook_core/data/templates/patacrep.tex index 33723475..9a537ec4 100644 --- a/songbook_core/data/templates/patacrep.tex +++ b/songbook_core/data/templates/patacrep.tex @@ -1,31 +1,27 @@ -(% 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 %) +(% variables %) +[ +{"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"} +] +(% endvariables %) (* extends "default.tex" *) diff --git a/songbook_core/plastex.py b/songbook_core/plastex.py old mode 100755 new mode 100644 diff --git a/songbook_core/templates.py b/songbook_core/templates.py index 94107cb1..9cc10280 100644 --- a/songbook_core/templates.py +++ b/songbook_core/templates.py @@ -3,8 +3,10 @@ """Template for .tex generation settings and utilities""" from jinja2 import Environment, FileSystemLoader, ChoiceLoader, PackageLoader +from jinja2.meta import find_referenced_templates as find_templates import os import re +import json _LATEX_SUBS = ( (re.compile(r'\\'), r'\\textbackslash'), @@ -23,6 +25,7 @@ def _escape_tex(value): newval = pattern.sub(replacement, newval) return newval + class TexRenderer(object): """Render a template to a LaTeX file.""" @@ -32,8 +35,6 @@ class TexRenderer(object): Arguments: - datadir: location of the user-defined templates ''' - self.template = template - self.texenv = Environment( loader=ChoiceLoader([ FileSystemLoader( @@ -42,31 +43,69 @@ class TexRenderer(object): 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.comment_start_string = '(% variables %)' + self.texenv.comment_end_string = '(% endvariables %)' + self.texenv.line_comment_prefix = '(%%)' 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 + # TODO: catch the TemplateNotFound + self.template = self.texenv.get_template(template) + + def get_variables(self): + data = self.parse_templates() + variables = dict() + for param in data: + try: + variables[param["name"]] = param["default"] + except KeyError: + variables[param["name"]] = None + return variables + + def parse_templates(self): + templates = self.get_templates(self.template) + templates |= set([self.template.name]) + variables = [] + regex = re.compile(r'\(% variables %\)(?P.*)' + '\(% endvariables %\)', re.DOTALL) + for template_name in templates: + filename = self.texenv.get_template(template_name).filename + with open(filename, 'r') as template_file: + content = template_file.read() + match = re.search(regex, content) + if match: + content = match.group('variables') + variables += json.loads(content) + return variables + + def get_templates(self, template): + '''Recursively get a set of all the templates used + by a particular template. + ''' + with open(template.filename, 'r') as template_file: + content = template_file.readlines() + new_templates = list(find_templates(self.texenv.parse(content))) + all_templates = set(new_templates) + if len(new_templates) > 0: + for new_template_name in new_templates: + new_template = self.texenv.get_template(new_template_name) + # union of the sets + all_templates |= self.get_templates(new_template) + return all_templates 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 + - context: a dict of all the data to populate the template ''' - #pylint: disable=star-args - output.write( - self.texenv.get_template(self.template).render(**context) - ) + output.write(self.template.render(context))