diff --git a/patacrep/build.py b/patacrep/build.py index 679fc82b..5682da1d 100644 --- a/patacrep/build.py +++ b/patacrep/build.py @@ -33,6 +33,7 @@ DEFAULT_CONFIG = { 'content': [], 'titleprefixwords': [], 'encoding': None, + 'datadir': [], } diff --git a/patacrep/data/examples/example-subdir.sb b/patacrep/data/examples/example-subdir.sb new file mode 100644 index 00000000..c7d23631 --- /dev/null +++ b/patacrep/data/examples/example-subdir.sb @@ -0,0 +1,17 @@ +{ +"bookoptions" : [ + "diagram", + "repeatchords", + "lilypond", + "pictures" + ], +"booktype" : "chorded", +"template" : "patacrep.tex", +"lang" : "french", +"encoding": "utf8", +"authwords" : { + "sep" : ["and", "et"] + }, + "content": [["sorted", "subdir/*.sg", "subdir/*.sgc"]] + +} diff --git a/patacrep/data/examples/img/datadir.ly b/patacrep/data/examples/img/datadir.ly new file mode 100644 index 00000000..1fd2bccb --- /dev/null +++ b/patacrep/data/examples/img/datadir.ly @@ -0,0 +1,19 @@ +\include "_lilypond/header" +\paper{paper-height = 6.5\cm} + +{ + \key a \minor + \time 6/8 + \partial 8 a'8 + \relative c''{ + c4 d8 e8. (f16) e8 d4 b8 g8. (a16) b8 + c4 a8 a8. (gis16) a8 b4 gis8 e4 a8 + c4 d8 e8. (f16 e8) d4 b8 g8. (a16) b8 + c8. (b16) a8 gis8. (fis16) gis8 a4 a8 a4. + + g'4. g8. (fis16) e8 d4 b8 g8. (a16) b8 + c4 (a8) a8. (gis16) a8 b4 gis8 e4. + g'4. g8. (fis16) e8 d4 b8 g8. (a16) b8 + c8. (b16) a8 gis8. (fis16) gis8 a4. a4. + } +} diff --git a/patacrep/data/examples/img/datadir.png b/patacrep/data/examples/img/datadir.png new file mode 100644 index 00000000..e2efe409 Binary files /dev/null and b/patacrep/data/examples/img/datadir.png differ diff --git a/patacrep/data/examples/root.ly b/patacrep/data/examples/root.ly new file mode 100644 index 00000000..1fd2bccb --- /dev/null +++ b/patacrep/data/examples/root.ly @@ -0,0 +1,19 @@ +\include "_lilypond/header" +\paper{paper-height = 6.5\cm} + +{ + \key a \minor + \time 6/8 + \partial 8 a'8 + \relative c''{ + c4 d8 e8. (f16) e8 d4 b8 g8. (a16) b8 + c4 a8 a8. (gis16) a8 b4 gis8 e4 a8 + c4 d8 e8. (f16 e8) d4 b8 g8. (a16) b8 + c8. (b16) a8 gis8. (fis16) gis8 a4 a8 a4. + + g'4. g8. (fis16) e8 d4 b8 g8. (a16) b8 + c4 (a8) a8. (gis16) a8 b4 gis8 e4. + g'4. g8. (fis16) e8 d4 b8 g8. (a16) b8 + c8. (b16) a8 gis8. (fis16) gis8 a4. a4. + } +} diff --git a/patacrep/data/examples/root.png b/patacrep/data/examples/root.png new file mode 100644 index 00000000..70ea3b7c Binary files /dev/null and b/patacrep/data/examples/root.png differ diff --git a/patacrep/data/examples/songs/subdir/datadir.sg b/patacrep/data/examples/songs/subdir/datadir.sg new file mode 100644 index 00000000..18e92c3d --- /dev/null +++ b/patacrep/data/examples/songs/subdir/datadir.sg @@ -0,0 +1,10 @@ +\beginsong{Image included from datadir\\\LaTeX} + [cov={datadir}] + + \cover + + \lilypond{datadir.ly} + + \image{datadir} + +\endsong diff --git a/patacrep/data/examples/songs/subdir/datadir.sgc b/patacrep/data/examples/songs/subdir/datadir.sgc new file mode 100644 index 00000000..a209c229 --- /dev/null +++ b/patacrep/data/examples/songs/subdir/datadir.sgc @@ -0,0 +1,6 @@ +{title : Image included from datadir} +{subtitle: Chordpro} +{cover: datadir.png} + +{partition: datadir.ly} +{image: datadir.png} diff --git a/patacrep/data/examples/songs/subdir/relative.ly b/patacrep/data/examples/songs/subdir/relative.ly new file mode 100644 index 00000000..1fd2bccb --- /dev/null +++ b/patacrep/data/examples/songs/subdir/relative.ly @@ -0,0 +1,19 @@ +\include "_lilypond/header" +\paper{paper-height = 6.5\cm} + +{ + \key a \minor + \time 6/8 + \partial 8 a'8 + \relative c''{ + c4 d8 e8. (f16) e8 d4 b8 g8. (a16) b8 + c4 a8 a8. (gis16) a8 b4 gis8 e4 a8 + c4 d8 e8. (f16 e8) d4 b8 g8. (a16) b8 + c8. (b16) a8 gis8. (fis16) gis8 a4 a8 a4. + + g'4. g8. (fis16) e8 d4 b8 g8. (a16) b8 + c4 (a8) a8. (gis16) a8 b4 gis8 e4. + g'4. g8. (fis16) e8 d4 b8 g8. (a16) b8 + c8. (b16) a8 gis8. (fis16) gis8 a4. a4. + } +} diff --git a/patacrep/data/examples/songs/subdir/relative.png b/patacrep/data/examples/songs/subdir/relative.png new file mode 100644 index 00000000..ff1b083e Binary files /dev/null and b/patacrep/data/examples/songs/subdir/relative.png differ diff --git a/patacrep/data/examples/songs/subdir/relative.sg b/patacrep/data/examples/songs/subdir/relative.sg new file mode 100644 index 00000000..681b4086 --- /dev/null +++ b/patacrep/data/examples/songs/subdir/relative.sg @@ -0,0 +1,10 @@ +\beginsong{Image included from song directory\\\LaTeX} + [cov={relative}] + + \cover + + \lilypond{relative.ly} + + \image{relative} + +\endsong diff --git a/patacrep/data/examples/songs/subdir/relative.sgc b/patacrep/data/examples/songs/subdir/relative.sgc new file mode 100644 index 00000000..73241352 --- /dev/null +++ b/patacrep/data/examples/songs/subdir/relative.sgc @@ -0,0 +1,6 @@ +{title : Image included from song directory} +{subtitle: Chordpro} +{cover: relative.png} + +{partition: relative.ly} +{image: relative.png} diff --git a/patacrep/data/examples/songs/subdir/root.sg b/patacrep/data/examples/songs/subdir/root.sg new file mode 100644 index 00000000..2e4a11b0 --- /dev/null +++ b/patacrep/data/examples/songs/subdir/root.sg @@ -0,0 +1,10 @@ +\beginsong{Image included from root directory\\\LaTeX} + [cov={root}] + + \cover + + \lilypond{root.ly} + + \image{root} + +\endsong diff --git a/patacrep/data/examples/songs/subdir/root.sgc b/patacrep/data/examples/songs/subdir/root.sgc new file mode 100644 index 00000000..0aa21297 --- /dev/null +++ b/patacrep/data/examples/songs/subdir/root.sgc @@ -0,0 +1,6 @@ +{title : Image included from root directory} +{subtitle: Chordpro} +{cover: root.png} + +{partition: root.ly} +{image: root.png} diff --git a/patacrep/data/latex/patacrep.sty b/patacrep/data/latex/patacrep.sty index 019de15f..f3218005 100644 --- a/patacrep/data/latex/patacrep.sty +++ b/patacrep/data/latex/patacrep.sty @@ -11,9 +11,9 @@ \RequirePackage{fancybox} \RequirePackage{xstring} \RequirePackage{framed} -\RequirePackage{currfile} \RequirePackage{ifthen} \RequirePackage{tikz} +\RequirePackage{import} % tabs: display the guitar tabs \newif{\iftabs} @@ -134,8 +134,7 @@ \setlength{\coverspace}{0.1cm} \newcommand{\songcover}{} \newcommand{\songalbum}{} -\newsongkey{cov}{\let\songcover\@empty}{\def\songcover{\currfiledir#1}} -\newsongkey{vcov}{\let\songcover\@empty}{\def\songcover{#1}} +\newsongkey{cov}{\let\songcover\@empty}{\def\songcover{#1}} \newsongkey{album}{\let\songalbum\@empty}{\def\songalbum{#1}} \newsongkey{url}{\let\songurl\@empty}{\def\songurl{#1}} \newsongkey{original}{\let\songoriginal\@empty}{\def\songoriginal{#1}} @@ -247,11 +246,6 @@ \newcommand{\lilypond}[1]{% \iflilypond% \epstopdfsetup{suffix=-\the\hsize-converted} - \includegraphics{\currfiledir#1}% - \fi% -} -\newcommand{\vlilypond}[1]{% - \iflilypond% \includegraphics{#1}% \fi% } diff --git a/patacrep/songs/__init__.py b/patacrep/songs/__init__.py index cbc5d9aa..fbf02e36 100644 --- a/patacrep/songs/__init__.py +++ b/patacrep/songs/__init__.py @@ -202,3 +202,39 @@ def unprefixed_title(title, prefixes): if match: return match.group(2) return title + +def search_image(image, chordprofile, config): + """Return the file name of an image, so that LaTeX will find it. + + :param str image: The name, as provided in the chordpro file. + :param str chordprofile: The name of the file including this image. + :param dict config: Songbook configuration dictionary. + + The image can be: + + - in the same directory as the including song file; + - in the same directory as the main LaTeX file; + - in some of the `DATADIR/img` directories. + + If image is not found, the `image` argument is returned. + """ + # Image is in the same folder as its song + texdir = os.path.dirname(chordprofile) + if os.path.exists(os.path.join(texdir, image)): + return os.path.join(texdir, image) + + # Image is in the same directory as the main tex file + rootdir = os.path.dirname(os.path.join( + os.getcwd(), + config['filename'], + )) + if os.path.exists(os.path.join(rootdir, image)): + return image + + # Image is in a datadir + for directory in config['datadir']: + if os.path.exists(os.path.join(directory, 'img', image)): + return os.path.join(directory, 'img', image) + + # Could not find image + return image diff --git a/patacrep/songs/chordpro/__init__.py b/patacrep/songs/chordpro/__init__.py index 97b83670..ae37b79b 100644 --- a/patacrep/songs/chordpro/__init__.py +++ b/patacrep/songs/chordpro/__init__.py @@ -5,7 +5,7 @@ import pkg_resources import os from patacrep import encoding, files -from patacrep.songs import Song +from patacrep.songs import Song, search_image from patacrep.songs.chordpro.syntax import parse_song from patacrep.templates import Renderer @@ -36,11 +36,13 @@ class ChordproSong(Song): "authors": self.authors, "metadata": self.data, "render": self._render_ast, + "config": self.config, } self.jinjaenv = Environment(loader=FileSystemLoader(os.path.join( os.path.abspath(pkg_resources.resource_filename(__name__, 'data')), output_format, ))) + self.jinjaenv.filters['search_image'] = search_image return self._render_ast( context, self.cached['song'].content, diff --git a/patacrep/songs/chordpro/ast.py b/patacrep/songs/chordpro/ast.py index 8dcea1a7..1aaae349 100644 --- a/patacrep/songs/chordpro/ast.py +++ b/patacrep/songs/chordpro/ast.py @@ -3,7 +3,6 @@ # pylint: disable=too-few-public-methods import logging -import os LOGGER = logging.getLogger() @@ -63,7 +62,6 @@ DIRECTIVE_SHORTCUTS = { "c": "comment", "gc": "guitar_comment", "cover": "cov", - "vcover": "vcov", } def directive_name(text): @@ -209,13 +207,6 @@ class Song(AST): "language": "add_cumulative", } - #: Some directives have to be processed before being considered. - PROCESS_DIRECTIVE = { - "cov": "_process_relative", - "partition": "_process_relative", - "image": "_process_relative", - } - def __init__(self, filename): super().__init__() self.content = [] @@ -228,11 +219,6 @@ class Song(AST): def add(self, data): """Add an element to the song""" - if isinstance(data, Directive): - # Some directives are preprocessed - if data.keyword in self.PROCESS_DIRECTIVE: - data = getattr(self, self.PROCESS_DIRECTIVE[data.keyword])(data) - if isinstance(data, Error): return self elif data is None: @@ -311,19 +297,6 @@ class Song(AST): ":".join(argument).strip(), )) - def _process_relative(self, directive): - """Return the directive, in which the argument is given relative to file - - This argument is expected to be a path (as a string). - """ - return Directive( - directive.keyword, - os.path.join( - os.path.dirname(self.filename), - directive.argument, - ), - ) - class Newline(AST): """New line""" _template = "newline" diff --git a/patacrep/songs/chordpro/data/chordpro/song b/patacrep/songs/chordpro/data/chordpro/song index 30bf9a3e..92f474ee 100644 --- a/patacrep/songs/chordpro/data/chordpro/song +++ b/patacrep/songs/chordpro/data/chordpro/song @@ -16,7 +16,7 @@ {artist: (( author[1] )) (( author[0] ))} (* endfor *) -(*- for key in ['album', 'copyright', 'cov', 'vcov', 'tag'] *) +(*- for key in ['album', 'copyright', 'cov', 'tag'] *) (* if key in metadata -*) {(( key )): (( metadata[key] ))} (* endif *) diff --git a/patacrep/songs/chordpro/data/latex/content_image b/patacrep/songs/chordpro/data/latex/content_image index 336233d5..bd132ce6 100644 --- a/patacrep/songs/chordpro/data/latex/content_image +++ b/patacrep/songs/chordpro/data/latex/content_image @@ -1 +1 @@ -\image{(( content.argument ))} +\image{(( content.argument|search_image(path, config) ))} diff --git a/patacrep/songs/chordpro/data/latex/content_partition b/patacrep/songs/chordpro/data/latex/content_partition index 98bfed57..bcb92a0b 100644 --- a/patacrep/songs/chordpro/data/latex/content_partition +++ b/patacrep/songs/chordpro/data/latex/content_partition @@ -1 +1 @@ -\lilypond{((content.argument))} +\lilypond{ ((- content.argument|search_image(path, config) -)) } diff --git a/patacrep/songs/chordpro/data/latex/song b/patacrep/songs/chordpro/data/latex/song index eaa2a86d..4cb04412 100644 --- a/patacrep/songs/chordpro/data/latex/song +++ b/patacrep/songs/chordpro/data/latex/song @@ -22,17 +22,20 @@ (* endif *) (* endfor *) }, - (* for key in ['album', 'copyright', 'cov', 'vcov', 'tag'] *) + (* for key in ['album', 'copyright', 'tag'] *) (* if key in metadata *) (( key ))={(( metadata[key] ))}, (* endif *) (* endfor *) + (* if 'cov' in metadata *) + cov={(( metadata["cov"].argument|search_image(path, config) ))}, + (* endif *) (* for key in metadata.keys *) (( key.keyword ))={(( key.argument ))}, (* endfor *) ] -(* if (metadata.cov is defined) or (metadata.vcov is defined) *) +(* if (metadata.cov is defined) *) \cover (* endif *) diff --git a/patacrep/songs/chordpro/test/greensleeves.sgc b/patacrep/songs/chordpro/test/greensleeves.sgc index 98248e83..bd0ddd71 100644 --- a/patacrep/songs/chordpro/test/greensleeves.sgc +++ b/patacrep/songs/chordpro/test/greensleeves.sgc @@ -5,11 +5,11 @@ {title: Un sous titre} {artist: Traditionnel} {album: Angleterre} -{cov: DIRNAME/traditionnel} +{cov: traditionnel} -{partition: DIRNAME/greensleeves.ly} +{partition: greensleeves.ly} {start_of_verse} diff --git a/patacrep/songs/chordpro/test/greensleeves.tex b/patacrep/songs/chordpro/test/greensleeves.tex index 4c2aac43..6a745a81 100644 --- a/patacrep/songs/chordpro/test/greensleeves.tex +++ b/patacrep/songs/chordpro/test/greensleeves.tex @@ -7,14 +7,14 @@ Un sous titre}[ by={ Traditionnel }, album={Angleterre}, - cov={DIRNAME/traditionnel}, + cov={traditionnel}, ] \cover -\lilypond{DIRNAME/greensleeves.ly} +\lilypond{greensleeves.ly} \begin{verse} diff --git a/patacrep/songs/chordpro/test/metadata.sgc b/patacrep/songs/chordpro/test/metadata.sgc index 45509d2d..e4bb1b21 100644 --- a/patacrep/songs/chordpro/test/metadata.sgc +++ b/patacrep/songs/chordpro/test/metadata.sgc @@ -10,11 +10,10 @@ {artist: Author2} {album: Album} {copyright: Copyright} -{cov: DIRNAME/Cover} -{vcov: VCover} +{cov: Cover} {key: foo: Foo} {comment: Comment} {guitar_comment: GuitarComment} -{image: DIRNAME/Image} -{partition: DIRNAME/Lilypond} +{image: Image} +{partition: Lilypond} diff --git a/patacrep/songs/chordpro/test/metadata.source b/patacrep/songs/chordpro/test/metadata.source index 6e221446..2e106444 100644 --- a/patacrep/songs/chordpro/test/metadata.source +++ b/patacrep/songs/chordpro/test/metadata.source @@ -11,7 +11,6 @@ {album: Album} {copyright: Copyright} {cover: Cover} -{vcover: VCover} {capo: Capo} {key: foo: Foo} {comment: Comment} diff --git a/patacrep/songs/chordpro/test/metadata.tex b/patacrep/songs/chordpro/test/metadata.tex index fbe53fae..11004ef6 100644 --- a/patacrep/songs/chordpro/test/metadata.tex +++ b/patacrep/songs/chordpro/test/metadata.tex @@ -11,8 +11,7 @@ Subtitle5}[ Author2 }, album={Album}, copyright={Copyright}, - cov={DIRNAME/Cover}, - vcov={VCover}, + cov={Cover}, foo={Foo}, ] @@ -20,7 +19,7 @@ Subtitle5}[ \textnote{Comment} \musicnote{GuitarComment} -\image{DIRNAME/Image} -\lilypond{DIRNAME/Lilypond} +\image{Image} +\lilypond{Lilypond} \endsong diff --git a/patacrep/songs/chordpro/test/test_parser.py b/patacrep/songs/chordpro/test/test_parser.py index 26e5181a..3a1e9b7c 100644 --- a/patacrep/songs/chordpro/test/test_parser.py +++ b/patacrep/songs/chordpro/test/test_parser.py @@ -42,6 +42,7 @@ class TestParsingRendering(unittest.TestCase): continue with open(destname, 'r', encoding='utf8') as expectfile: chordproname = "{}.source".format(base) + config['filename'] = chordproname with disable_logging(): with self.subTest(base=os.path.basename(base), format=dest): self.assertMultiLineEqual( @@ -49,8 +50,5 @@ class TestParsingRendering(unittest.TestCase): output=chordproname, output_format=LANGUAGES[dest], ).strip(), - expectfile.read().replace( - "DIRNAME", - os.path.dirname(base), - ).strip(), + expectfile.read().strip(), ) diff --git a/patacrep/songs/latex/__init__.py b/patacrep/songs/latex/__init__.py index 1c84e3f1..a0d9c945 100644 --- a/patacrep/songs/latex/__init__.py +++ b/patacrep/songs/latex/__init__.py @@ -22,16 +22,19 @@ class LatexSong(Song): del self.data['@titles'] self.languages = self.data['@languages'] del self.data['@languages'] - self.authors = [self.data['by']] - del self.data['by'] + if "by" in self.data: + self.authors = [self.data['by']] + del self.data['by'] + else: + self.authors = [] def render_latex(self, output): """Return the code rendering the song.""" - return r'\input{{{}}}'.format(files.path2posix( - files.relpath( - self.fullpath, - os.path.dirname(output) - ))) + path = files.path2posix(files.relpath( + self.fullpath, + os.path.dirname(output) + )) + return r'\import{{{}/}}{{{}}}'.format(os.path.dirname(path), os.path.basename(path)) SONG_PARSERS = { 'is': LatexSong,