From 173c0cafc3d07bc3bf156f82d893c3eb419a3e7d Mon Sep 17 00:00:00 2001 From: Louis Date: Tue, 19 Apr 2016 15:25:28 +0200 Subject: [PATCH] [WIP] TeX generation works; TeX compilation does not --- patacrep/data/templates/songbook/default.tex | 4 +- patacrep/data/templates/songbook/patacrep.tex | 6 +-- .../songs/chordpro/chordpro/song_header | 2 +- .../data/templates/songs/chordpro/latex/song | 2 +- patacrep/songs/chordpro/__init__.py | 31 ++++++++++- patacrep/templates.py | 52 +++++++++++++------ test/test_book/special.tex.control | 9 ++-- test/test_book/special.yaml | 4 +- 8 files changed, 79 insertions(+), 31 deletions(-) diff --git a/patacrep/data/templates/songbook/default.tex b/patacrep/data/templates/songbook/default.tex index 5eef827a..d3b6fd34 100644 --- a/patacrep/data/templates/songbook/default.tex +++ b/patacrep/data/templates/songbook/default.tex @@ -66,8 +66,8 @@ description: \usepackage{chords} -\title{(( template_var.title ))} -\author{(( template_var.author ))} +\title{(( template_var.title|escape_specials() ))} +\author{(( template_var.author|escape_specials() ))} \newindex{titleidx}{((filename))_title} \newauthorindex{authidx}{((filename))_auth} diff --git a/patacrep/data/templates/songbook/patacrep.tex b/patacrep/data/templates/songbook/patacrep.tex index 627ee080..d57f44e4 100644 --- a/patacrep/data/templates/songbook/patacrep.tex +++ b/patacrep/data/templates/songbook/patacrep.tex @@ -138,12 +138,12 @@ description: ]{hyperref} -\subtitle{(( template_var.subtitle ))} +\subtitle{(( template_var.subtitle|escape_specials ))} (* if template_var.version -*) \version{(( template_var.version ))} (* endif *) -\mail{(( template_var.email ))} -\web{(( template_var.url ))} +\mail{(( template_var.email|escape_url ))} +\web{(( template_var.url|escape_url ))} \picture{(( template_var.picture ))} \picturecopyright{(( template_var.picturecopyright ))} \footer{(( template_var.footer ))} diff --git a/patacrep/data/templates/songs/chordpro/chordpro/song_header b/patacrep/data/templates/songs/chordpro/chordpro/song_header index e73da259..bca4357e 100644 --- a/patacrep/data/templates/songs/chordpro/chordpro/song_header +++ b/patacrep/data/templates/songs/chordpro/chordpro/song_header @@ -34,7 +34,7 @@ (* endfor *) (*- if 'url' in metadata -*) - {url: (( metadata.url ))} + {url: (( metadata.url|escape_url ))} (* endif -*) (*- for chord in metadata['define'] *) diff --git a/patacrep/data/templates/songs/chordpro/latex/song b/patacrep/data/templates/songs/chordpro/latex/song index 2830fc34..08591d3a 100644 --- a/patacrep/data/templates/songs/chordpro/latex/song +++ b/patacrep/data/templates/songs/chordpro/latex/song @@ -28,7 +28,7 @@ (* endif *) (* endfor *) (* if 'url' in metadata *) - url={(( metadata.url|escape_specials('%#') ))}, + url={(( metadata.url|escape_url ))}, (* endif *) (* if 'cover' in metadata *) (* block cover *) diff --git a/patacrep/songs/chordpro/__init__.py b/patacrep/songs/chordpro/__init__.py index 4318cd6a..6f1ca655 100644 --- a/patacrep/songs/chordpro/__init__.py +++ b/patacrep/songs/chordpro/__init__.py @@ -3,6 +3,7 @@ import logging import operator import os +import urllib from jinja2 import Environment, FileSystemLoader, ChoiceLoader from jinja2 import contextfunction @@ -31,6 +32,12 @@ class ChordproSong(Song): output_language = None _translation_map = {} + _translation_map_url = None + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + if self._translation_map_url is None: + self._translation_map_url = self._translation_map def _parse(self): """Parse content, and return the dictionary of song data.""" @@ -52,6 +59,7 @@ class ChordproSong(Song): 'search_image': self.search_image, 'search_partition': self.search_partition, 'escape_specials': self._escape_specials, + 'escape_url': self._escape_url, }) return filters @@ -86,13 +94,20 @@ class ChordproSong(Song): context.vars['content'] = content return context.environment.get_template(content.template()).render(context) - def _escape_specials(self, content, chars): + def _escape_specials(self, content, chars=None, *, translation_map=None): + if translation_map is None: + translation_map = self._translation_map + if chars is None: + chars = translation_map.keys() return str(content).translate(str.maketrans({ key: value - for key, value in self._translation_map.items() + for key, value in translation_map.items() if key in chars })) + def _escape_url(self, content): + return self._escape_specials(content, translation_map=self._translation_map_url) + class Chordpro2HtmlSong(ChordproSong): """Render chordpro song to html code""" @@ -125,6 +140,13 @@ class Chordpro2LatexSong(ChordproSong): '%': r'\%', '_': r'\_', } + _translation_map_url = { + " ": urllib.parse.quote(" "), + "{": urllib.parse.quote("{"), + "}": urllib.parse.quote("}"), + '%': r'\%', + '#': r'\#', + } def search_file(self, filename, extensions=None, *, datadirs=None): _datadir, filename, _extension = self.search_datadir_file( @@ -191,6 +213,11 @@ class Chordpro2ChordproSong(ChordproSong): '\\': '\\\\', '#': r'\#', } + _translation_map_url = { + '{': r'\{', + '}': r'\}', + '\\': '\\\\', + } def search_file(self, filename, extensions=None, *, datadirs=None): # pylint: disable=unused-variable diff --git a/patacrep/templates.py b/patacrep/templates.py index c18ef454..c68f78cc 100644 --- a/patacrep/templates.py +++ b/patacrep/templates.py @@ -2,6 +2,7 @@ import logging import re +import urllib import yaml @@ -16,15 +17,6 @@ import patacrep.encoding LOGGER = logging.getLogger(__name__) -_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'), -) - _VARIABLE_REGEXP = re.compile( r""" \(\*-?\ *variables\ *\*\) # Match (* variables *) or (*- variables *) @@ -46,15 +38,45 @@ _VARIABLE_REGEXP = re.compile( """, re.VERBOSE|re.DOTALL) -def _escape_tex(value): +TRANSLATION_MAP = { + '{': r'\{', + '}': r'\}', + '\\': r'\textbackslash{}', + '^': r'\textasciicircum{}', + '~': r'\textasciitilde{}', + '#': r'\#', + '&': r'\&', + '$': r'\$', + '%': r'\%', + '_': r'\_', +} +TRANSLATION_MAP_URL = { + ' ': '\\' + urllib.parse.quote(" "), + '{': '\\' + urllib.parse.quote("{"), + '}': '\\' + urllib.parse.quote("}"), + '%': '\\%', + '\\': '\\\\', + } + +def _escape_specials(text, *, chars=None, translation_map=None): '''Escape TeX special characters''' - newval = value - for pattern, replacement in _LATEX_SUBS: - newval = pattern.sub(replacement, newval) - return newval + if translation_map is None: + translation_map = TRANSLATION_MAP + if chars is None: + chars = translation_map.keys() + return str(text).translate(str.maketrans({ + key: value + for key, value in translation_map.items() + if key in chars + })) + +def _escape_url(text): + """Escape TeX special characters, in url.""" + return _escape_specials(text, translation_map=TRANSLATION_MAP_URL) DEFAULT_FILTERS = { - "escape_tex": _escape_tex, + "escape_specials": _escape_specials, + "escape_url": _escape_url, "iter_datadirs": files.iter_datadirs, "path2posix": files.path2posix, } diff --git a/test/test_book/special.tex.control b/test/test_book/special.tex.control index f303e5d5..7c8e24ca 100644 --- a/test/test_book/special.tex.control +++ b/test/test_book/special.tex.control @@ -67,8 +67,8 @@ guitar, \usepackage{chords} -\title{\& \% \$ \# \_ \} \{ \textasciitilde{} \textasciicircum{} \textbackslash{} } -\author{\& \% \$ \# \_ \} \{ \textasciitilde{} \textasciicircum{} \textbackslash{} } +\title{\& \% \$ \# \_ \} \{ \textasciitilde{} \textasciicircum{} \textbackslash{}} +\author{\& \% \$ \# \_ \} \{ \textasciitilde{} \textasciicircum{} \textbackslash{}} \newindex{titleidx}{special_title} \newauthorindex{authidx}{special_auth} @@ -101,9 +101,8 @@ guitar, \subtitle{\& \% \$ \# \_ \} \{ \textasciitilde{} \textasciicircum{} \textbackslash{}} -\mail{http://\%25\%20\%26\%24\%5C\%23_\%7E\%5E\%7B\%7D} TODO Do not use encoded chars (%24, and so on). It is eventually a bad idea. Or as least as possible. -\web{http://\%25\%20\%26\%24\%5C\%23_\%7E\%5E\%7B\%7D} TODO Idem - +\mail{foo@\\\%&$#_~^\%20\%7B\%7D} +\web{http://\\\%&$#_~^\%20\%7B\%7D} \picture{img/treble_a} \picturecopyright{Dbolton \url{http://commons.wikimedia.org/wiki/User:Dbolton}} \footer{Generated using Songbook (\url{http://www.patacrep.com})} diff --git a/test/test_book/special.yaml b/test/test_book/special.yaml index 005bc2c7..24731c57 100644 --- a/test/test_book/special.yaml +++ b/test/test_book/special.yaml @@ -8,7 +8,7 @@ template: author: "& % $ # _ } { ~ ^ \\" patacrep.tex: subtitle: "& % $ # _ } { ~ ^ \\" - url: "http://% &$\\#_~^{}" - email: "% &$\\#_~^{}" + url: "http://\\%&$#_~^ {}" + email: "foo@\\%&$#_~^ {}" picture: "img/treble_a"