From eba5d404d13cebf367b75626e398747bbd497f0f Mon Sep 17 00:00:00 2001 From: Louis Date: Fri, 28 Aug 2015 22:43:19 +0200 Subject: [PATCH] [chordpro] More generic song renderer --- patacrep/build.py | 2 +- patacrep/content/__init__.py | 2 +- patacrep/content/song.py | 2 +- patacrep/data/templates/songs.tex | 2 +- patacrep/songs/__init__.py | 15 +++--- patacrep/songs/chordpro/__init__.py | 28 ++++++----- patacrep/songs/chordpro/ast.py | 4 +- .../{content_chord.tex => content_chord} | 0 ...ontent_chordlist.tex => content_chordlist} | 0 .../{content_comment.tex => content_comment} | 0 .../{content_define.tex => content_define} | 0 .../{content_error.tex => content_error} | 0 ...tar_comment.tex => content_guitar_comment} | 0 .../{content_image.tex => content_image} | 0 .../latex/{content_line.tex => content_line} | 0 .../{content_newline.tex => content_newline} | 0 ...ontent_partition.tex => content_partition} | 0 .../{content_space.tex => content_space} | 0 .../{content_verse.tex => content_verse} | 0 .../latex/{content_word.tex => content_word} | 0 .../chordpro/data/latex/{song.tex => song} | 0 patacrep/songs/latex/__init__.py | 4 +- patacrep/templates.py | 46 +++++++++---------- 23 files changed, 56 insertions(+), 49 deletions(-) rename patacrep/songs/chordpro/data/latex/{content_chord.tex => content_chord} (100%) rename patacrep/songs/chordpro/data/latex/{content_chordlist.tex => content_chordlist} (100%) rename patacrep/songs/chordpro/data/latex/{content_comment.tex => content_comment} (100%) rename patacrep/songs/chordpro/data/latex/{content_define.tex => content_define} (100%) rename patacrep/songs/chordpro/data/latex/{content_error.tex => content_error} (100%) rename patacrep/songs/chordpro/data/latex/{content_guitar_comment.tex => content_guitar_comment} (100%) rename patacrep/songs/chordpro/data/latex/{content_image.tex => content_image} (100%) rename patacrep/songs/chordpro/data/latex/{content_line.tex => content_line} (100%) rename patacrep/songs/chordpro/data/latex/{content_newline.tex => content_newline} (100%) rename patacrep/songs/chordpro/data/latex/{content_partition.tex => content_partition} (100%) rename patacrep/songs/chordpro/data/latex/{content_space.tex => content_space} (100%) rename patacrep/songs/chordpro/data/latex/{content_verse.tex => content_verse} (100%) rename patacrep/songs/chordpro/data/latex/{content_word.tex => content_word} (100%) rename patacrep/songs/chordpro/data/latex/{song.tex => song} (100%) diff --git a/patacrep/build.py b/patacrep/build.py index c9aa87e3..679fc82b 100644 --- a/patacrep/build.py +++ b/patacrep/build.py @@ -113,7 +113,7 @@ class Songbook(object): ) # Configuration set - config['render_content'] = content.render_content + config['render'] = content.render config['content'] = content.process_content( config.get('content', []), config, diff --git a/patacrep/content/__init__.py b/patacrep/content/__init__.py index d92dc99b..040adbad 100755 --- a/patacrep/content/__init__.py +++ b/patacrep/content/__init__.py @@ -131,7 +131,7 @@ class ContentError(SongbookError): return "Content: {}: {}".format(self.keyword, self.message) @jinja2.contextfunction -def render_content(context, content): +def render(context, content): """Render the content of the songbook as a LaTeX code. Arguments: diff --git a/patacrep/content/song.py b/patacrep/content/song.py index f252e314..4f8cd8f4 100755 --- a/patacrep/content/song.py +++ b/patacrep/content/song.py @@ -34,7 +34,7 @@ class SongRenderer(Content): def render(self, context): """Return the string that will render the song.""" - return self.song.tex(output=context['filename']) + return self.song.render(output=context['filename'], output_format="latex") #pylint: disable=unused-argument def parse(keyword, argument, contentlist, config): diff --git a/patacrep/data/templates/songs.tex b/patacrep/data/templates/songs.tex index 1ef8ea7a..bdfcf7bb 100644 --- a/patacrep/data/templates/songs.tex +++ b/patacrep/data/templates/songs.tex @@ -108,6 +108,6 @@ \phantomsection \addcontentsline{toc}{section}{\songlistname} -((render_content(content) )) +(( render(content) )) (* endblock *) diff --git a/patacrep/songs/__init__.py b/patacrep/songs/__init__.py index 59a85f7a..c1af76e7 100644 --- a/patacrep/songs/__init__.py +++ b/patacrep/songs/__init__.py @@ -10,7 +10,6 @@ import re from patacrep.authors import process_listauthors from patacrep import files, encoding -from patacrep.content import Content LOGGER = logging.getLogger(__name__) @@ -63,20 +62,20 @@ class DataSubpath(object): return self # pylint: disable=too-many-instance-attributes -class Song(Content): +class Song: """Song (or song metadata) This class represents a song, bound to a file. - It can parse the file given in arguments. - - It can render the song as some LaTeX code. + - It can render the song as some code (LaTeX, chordpro, depending on subclasses implemetation). - Its content is cached, so that if the file has not been changed, the file is not parsed again. This class is inherited by classes implementing song management for several file formats. Those subclasses must implement: - `parse()` to parse the file; - - `render()` to render the song as LaTeX code. + - `render()` to render the song as code. """ # Version format of cached song. Increment this number if we update @@ -166,12 +165,16 @@ class Song(Content): def __repr__(self): return repr((self.titles, self.data, self.fullpath)) - def tex(self, output): # pylint: disable=no-self-use, unused-argument - """Return the LaTeX code rendering this song. + def render(self, output, output_format): + """Return the code rendering this song. Arguments: - output: Name of the output file. + - output_format: Format of the output file (latex, chordpro...) """ + method = "render_{}".format(output_format) + if hasattr(self, method): + return getattr(self, method)(output) raise NotImplementedError() def parse(self, config): # pylint: disable=no-self-use diff --git a/patacrep/songs/chordpro/__init__.py b/patacrep/songs/chordpro/__init__.py index d5efd135..8be6ad5e 100644 --- a/patacrep/songs/chordpro/__init__.py +++ b/patacrep/songs/chordpro/__init__.py @@ -7,14 +7,14 @@ import os from patacrep import encoding, files from patacrep.songs import Song from patacrep.songs.chordpro.syntax import parse_song -from patacrep.templates import TexRenderer +from patacrep.templates import Renderer class ChordproSong(Song): """Chordpros song parser.""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.texenv = None + self.jinjaenv = None def parse(self, config): """Parse content, and return the dictionary of song data.""" @@ -28,7 +28,7 @@ class ChordproSong(Song): 'song': song, } - def tex(self, output): + def render(self, output, output_format): context = { 'language': self.config.get( 'lang', @@ -38,27 +38,31 @@ class ChordproSong(Song): "titles": self.titles, "authors": self.authors, "metadata": self.data, - "render": self.render_tex, + "render": self._render_ast, } - self.texenv = Environment(loader=FileSystemLoader(os.path.join( + self.jinjaenv = Environment(loader=FileSystemLoader(os.path.join( os.path.abspath(pkg_resources.resource_filename(__name__, 'data')), - 'latex' + output_format, ))) - return self.render_tex(context, self.cached['song'].content, template="song.tex") + return self._render_ast( + context, + self.cached['song'].content, + template="song", + ) @contextfunction - def render_tex(self, context, content, template=None): - """Render ``content`` as tex.""" + def _render_ast(self, context, content, template=None): + """Render ``content``.""" if isinstance(context, dict): context['content'] = content else: context.vars['content'] = content if template is None: - template = content.template('tex') - return TexRenderer( + template = content.template() + return Renderer( template=template, encoding='utf8', - texenv=self.texenv, + jinjaenv=self.jinjaenv, ).template.render(context) SONG_PARSERS = { diff --git a/patacrep/songs/chordpro/ast.py b/patacrep/songs/chordpro/ast.py index 049a3b2f..173f73f4 100644 --- a/patacrep/songs/chordpro/ast.py +++ b/patacrep/songs/chordpro/ast.py @@ -73,14 +73,14 @@ class AST: _template = None inline = False - def template(self, extension): + def template(self): """Return the template to be used to render this object.""" if self._template is None: LOGGER.warning("No template defined for {}.".format(self.__class__)) base = "error" else: base = self._template - return "content_{}.{}".format(base, extension) + return "content_{}".format(base) def chordpro(self): """Return the chordpro string corresponding to this object.""" diff --git a/patacrep/songs/chordpro/data/latex/content_chord.tex b/patacrep/songs/chordpro/data/latex/content_chord similarity index 100% rename from patacrep/songs/chordpro/data/latex/content_chord.tex rename to patacrep/songs/chordpro/data/latex/content_chord diff --git a/patacrep/songs/chordpro/data/latex/content_chordlist.tex b/patacrep/songs/chordpro/data/latex/content_chordlist similarity index 100% rename from patacrep/songs/chordpro/data/latex/content_chordlist.tex rename to patacrep/songs/chordpro/data/latex/content_chordlist diff --git a/patacrep/songs/chordpro/data/latex/content_comment.tex b/patacrep/songs/chordpro/data/latex/content_comment similarity index 100% rename from patacrep/songs/chordpro/data/latex/content_comment.tex rename to patacrep/songs/chordpro/data/latex/content_comment diff --git a/patacrep/songs/chordpro/data/latex/content_define.tex b/patacrep/songs/chordpro/data/latex/content_define similarity index 100% rename from patacrep/songs/chordpro/data/latex/content_define.tex rename to patacrep/songs/chordpro/data/latex/content_define diff --git a/patacrep/songs/chordpro/data/latex/content_error.tex b/patacrep/songs/chordpro/data/latex/content_error similarity index 100% rename from patacrep/songs/chordpro/data/latex/content_error.tex rename to patacrep/songs/chordpro/data/latex/content_error diff --git a/patacrep/songs/chordpro/data/latex/content_guitar_comment.tex b/patacrep/songs/chordpro/data/latex/content_guitar_comment similarity index 100% rename from patacrep/songs/chordpro/data/latex/content_guitar_comment.tex rename to patacrep/songs/chordpro/data/latex/content_guitar_comment diff --git a/patacrep/songs/chordpro/data/latex/content_image.tex b/patacrep/songs/chordpro/data/latex/content_image similarity index 100% rename from patacrep/songs/chordpro/data/latex/content_image.tex rename to patacrep/songs/chordpro/data/latex/content_image diff --git a/patacrep/songs/chordpro/data/latex/content_line.tex b/patacrep/songs/chordpro/data/latex/content_line similarity index 100% rename from patacrep/songs/chordpro/data/latex/content_line.tex rename to patacrep/songs/chordpro/data/latex/content_line diff --git a/patacrep/songs/chordpro/data/latex/content_newline.tex b/patacrep/songs/chordpro/data/latex/content_newline similarity index 100% rename from patacrep/songs/chordpro/data/latex/content_newline.tex rename to patacrep/songs/chordpro/data/latex/content_newline diff --git a/patacrep/songs/chordpro/data/latex/content_partition.tex b/patacrep/songs/chordpro/data/latex/content_partition similarity index 100% rename from patacrep/songs/chordpro/data/latex/content_partition.tex rename to patacrep/songs/chordpro/data/latex/content_partition diff --git a/patacrep/songs/chordpro/data/latex/content_space.tex b/patacrep/songs/chordpro/data/latex/content_space similarity index 100% rename from patacrep/songs/chordpro/data/latex/content_space.tex rename to patacrep/songs/chordpro/data/latex/content_space diff --git a/patacrep/songs/chordpro/data/latex/content_verse.tex b/patacrep/songs/chordpro/data/latex/content_verse similarity index 100% rename from patacrep/songs/chordpro/data/latex/content_verse.tex rename to patacrep/songs/chordpro/data/latex/content_verse diff --git a/patacrep/songs/chordpro/data/latex/content_word.tex b/patacrep/songs/chordpro/data/latex/content_word similarity index 100% rename from patacrep/songs/chordpro/data/latex/content_word.tex rename to patacrep/songs/chordpro/data/latex/content_word diff --git a/patacrep/songs/chordpro/data/latex/song.tex b/patacrep/songs/chordpro/data/latex/song similarity index 100% rename from patacrep/songs/chordpro/data/latex/song.tex rename to patacrep/songs/chordpro/data/latex/song diff --git a/patacrep/songs/latex/__init__.py b/patacrep/songs/latex/__init__.py index 8a0893c1..1c84e3f1 100644 --- a/patacrep/songs/latex/__init__.py +++ b/patacrep/songs/latex/__init__.py @@ -25,8 +25,8 @@ class LatexSong(Song): self.authors = [self.data['by']] del self.data['by'] - def tex(self, output): - """Return the LaTeX code rendering the song.""" + def render_latex(self, output): + """Return the code rendering the song.""" return r'\input{{{}}}'.format(files.path2posix( files.relpath( self.fullpath, diff --git a/patacrep/templates.py b/patacrep/templates.py index 69e5f10c..4b81c08d 100644 --- a/patacrep/templates.py +++ b/patacrep/templates.py @@ -66,28 +66,28 @@ def _escape_tex(value): return newval -class TexRenderer: +class Renderer: """Render a template to a LaTeX file.""" # pylint: disable=too-few-public-methods - def __init__(self, template, texenv, encoding=None): + def __init__(self, template, jinjaenv, encoding=None): self.encoding = encoding - self.texenv = texenv - 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.line_comment_prefix = '%!' - self.texenv.filters['escape_tex'] = _escape_tex - self.texenv.trim_blocks = True - self.texenv.lstrip_blocks = True - self.texenv.globals["path2posix"] = files.path2posix - self.template = self.texenv.get_template(template) - - -class TexBookRenderer(TexRenderer): + self.jinjaenv = jinjaenv + self.jinjaenv.block_start_string = '(*' + self.jinjaenv.block_end_string = '*)' + self.jinjaenv.variable_start_string = '((' + self.jinjaenv.variable_end_string = '))' + self.jinjaenv.comment_start_string = '(% comment %)' + self.jinjaenv.comment_end_string = '(% endcomment %)' + self.jinjaenv.line_comment_prefix = '%!' + self.jinjaenv.filters['escape_tex'] = _escape_tex + self.jinjaenv.trim_blocks = True + self.jinjaenv.lstrip_blocks = True + self.jinjaenv.globals["path2posix"] = files.path2posix + self.template = self.jinjaenv.get_template(template) + + +class TexBookRenderer(Renderer): """Tex renderer for the whole songbook""" def __init__(self, template, datadirs, lang, encoding=None): @@ -106,17 +106,17 @@ class TexBookRenderer(TexRenderer): FileSystemLoader(os.path.join(datadir, 'templates')) for datadir in datadirs ] - texenv = Environment( + jinjaenv = Environment( loader=ChoiceLoader(loaders), extensions=[VariablesExtension], ) try: - super().__init__(template, texenv, encoding) + super().__init__(template, jinjaenv, encoding) except TemplateNotFound as exception: # Only works if all loaders are FileSystemLoader(). paths = [ item - for loader in self.texenv.loader.loaders + for loader in self.jinjaenv.loader.loaders for item in loader.searchpath ] raise errors.TemplateError( @@ -199,13 +199,13 @@ class TexBookRenderer(TexRenderer): """ subvariables = {} - templatename = self.texenv.get_template(template).filename + templatename = self.jinjaenv.get_template(template).filename with patacrep.encoding.open_read( templatename, encoding=self.encoding ) as template_file: content = template_file.read() - subtemplates = list(find_templates(self.texenv.parse(content))) + subtemplates = list(find_templates(self.jinjaenv.parse(content))) match = re.findall(_VARIABLE_REGEXP, content) if match: for var in match: