Browse Source

Merge branch 'master' into version5

pull/210/head
Louis 8 years ago
parent
commit
2e815f8d5a
  1. 8
      patacrep/authors.py
  2. 15
      patacrep/build.py
  3. 2
      patacrep/content/sort.py
  4. BIN
      patacrep/data/img/internet.png
  5. 21
      patacrep/data/templates/songbook/default.tex
  6. 6
      patacrep/data/templates/songbook/patacrep.tex
  7. 33
      patacrep/data/templates/songbook_model.yml
  8. 2
      patacrep/data/templates/songs/chordpro/chordpro/content_image
  9. 2
      patacrep/data/templates/songs/chordpro/chordpro/content_word
  10. 12
      patacrep/data/templates/songs/chordpro/chordpro/song_header
  11. 4
      patacrep/data/templates/songs/chordpro/latex/content_image
  12. 2
      patacrep/data/templates/songs/chordpro/latex/content_word
  13. 11
      patacrep/data/templates/songs/chordpro/latex/song
  14. 13
      patacrep/data/templates/styles/chords.sty
  15. 4
      patacrep/data/templates/styles/crepbook.sty
  16. 17
      patacrep/data/templates/styles/patacrep.sty
  17. 7
      patacrep/index.py
  18. 4
      patacrep/latex/__init__.py
  19. 2
      patacrep/songs/__init__.py
  20. 77
      patacrep/songs/chordpro/__init__.py
  21. 16
      patacrep/songs/chordpro/ast.py
  22. 18
      patacrep/songs/chordpro/lexer.py
  23. 89
      patacrep/songs/chordpro/syntax.py
  24. 59
      patacrep/templates.py
  25. 77
      patacrep/tools/__main__.py
  26. 5
      patacrep/tools/cache/__main__.py
  27. 3
      patacrep/tools/convert/__main__.py
  28. 2
      setup.py
  29. 0
      test/test_book/.gitignore
  30. 0
      test/test_book/__init__.py
  31. 12
      test/test_book/content.tex.control
  32. 0
      test/test_book/content.yaml
  33. 0
      test/test_book/content_datadir/content/foo.tex
  34. 0
      test/test_book/content_datadir/content/inter.isg
  35. 0
      test/test_book/content_datadir/content/song.csg
  36. 0
      test/test_book/content_datadir/content/song.tsg
  37. 0
      test/test_book/content_datadir/songs/include.sbc
  38. 0
      test/test_book/content_datadir/songs/inter.isg
  39. 0
      test/test_book/content_datadir/songs/song.csg
  40. 0
      test/test_book/content_datadir/songs/song.tsg
  41. 20
      test/test_book/datadir.tex.control
  42. 0
      test/test_book/datadir.yaml
  43. 0
      test/test_book/datadir_datadir/img/datadir.png
  44. 0
      test/test_book/datadir_datadir/scores/datadir.ly
  45. 0
      test/test_book/datadir_datadir/songs/datadir.csg
  46. 0
      test/test_book/datadir_datadir/songs/datadir.tsg
  47. 0
      test/test_book/datadir_datadir/songs/datadir2.csg
  48. 0
      test/test_book/datadir_datadir/songs/datadir2.sg
  49. 0
      test/test_book/datadir_datadir/songs/relative.csg
  50. 0
      test/test_book/datadir_datadir/songs/relative.ly
  51. 0
      test/test_book/datadir_datadir/songs/relative.png
  52. 0
      test/test_book/datadir_datadir/songs/relative.tsg
  53. 0
      test/test_book/datadir_datadir/songs/subdir/subdir.csg
  54. 0
      test/test_book/datadir_datadir/songs/subdir/subdir.ly
  55. 0
      test/test_book/datadir_datadir/songs/subdir/subdir.png
  56. 0
      test/test_book/datadir_datadir/songs/subdir/subdir.tsg
  57. 0
      test/test_book/datadir_datadir2/img/datadir2.png
  58. 0
      test/test_book/datadir_datadir2/scores/datadir2.ly
  59. 131
      test/test_book/lang_de.tex.control
  60. 5
      test/test_book/lang_de.yaml
  61. 12
      test/test_book/lang_default.tex.control
  62. 0
      test/test_book/lang_default.yaml
  63. 12
      test/test_book/lang_en.tex.control
  64. 0
      test/test_book/lang_en.yaml
  65. 12
      test/test_book/lang_fr.tex.control
  66. 0
      test/test_book/lang_fr.yaml
  67. 12
      test/test_book/languages.tex.control
  68. 0
      test/test_book/languages.yaml
  69. 0
      test/test_book/languages_datadir/songs/language.csg
  70. 0
      test/test_book/languages_datadir/songs/language_location.csg
  71. 0
      test/test_book/languages_datadir/songs/no_language.csg
  72. 0
      test/test_book/languages_datadir/songs/wrong_language.csg
  73. 0
      test/test_book/languages_datadir/songs/wrong_location.csg
  74. 12
      test/test_book/onthefly/content.onthefly.tex.control
  75. 0
      test/test_book/onthefly/content.onthefly.yaml
  76. 162
      test/test_book/special.tex.control
  77. 14
      test/test_book/special.yaml
  78. 10
      test/test_book/special_datadir/songs/special.csg
  79. 79
      test/test_book/syntax.tex.control
  80. 0
      test/test_book/syntax.yaml
  81. BIN
      test/test_book/syntax_datadir/img/image with spaces.png
  82. BIN
      test/test_book/syntax_datadir/img/image.png
  83. 35
      test/test_book/syntax_datadir/songs/images.csg
  84. 0
      test/test_book/syntax_datadir/songs/musicnote.csg
  85. 0
      test/test_book/test_compilation.py
  86. 12
      test/test_book/unicode.tex.control
  87. 0
      test/test_book/unicode.yaml
  88. 0
      test/test_book/unicode_datadir/songs/nonbreak.csg
  89. 0
      test/test_song/image with spaces.png
  90. 44
      test/test_song/image.csg
  91. 35
      test/test_song/image.csg.source
  92. 0
      test/test_song/image.png
  93. 59
      test/test_song/image.tsg
  94. 2
      test/test_song/metadata.csg
  95. 2
      test/test_song/metadata.tsg
  96. 13
      test/test_song/special.csg
  97. 10
      test/test_song/special.csg.source
  98. 22
      test/test_song/special.tsg

8
patacrep/authors.py

@ -16,12 +16,12 @@ def compile_authwords(authwords):
return { return {
'ignore': authwords.get('ignore', []), 'ignore': authwords.get('ignore', []),
'after': [ 'after': [
re.compile(RE_AFTER.format(word), re.LOCALE) re.compile(RE_AFTER.format(word))
for word in authwords.get('after') for word in authwords.get('after', [])
], ],
'separators': [ 'separators': [
re.compile(RE_SEPARATOR.format(word), re.LOCALE) re.compile(RE_SEPARATOR.format(word))
for word in ([" %s" % word for word in authwords['separators']] + [',', ';']) for word in ([" %s" % word for word in authwords.get('separators', [])] + [',', ';'])
], ],
} }

15
patacrep/build.py

@ -29,8 +29,6 @@ GENERATED_EXTENSIONS = [
"_title.sxd", "_title.sxd",
] ]
# pylint: disable=too-few-public-methods # pylint: disable=too-few-public-methods
class Songbook: class Songbook:
"""Represent a songbook (.yaml) file. """Represent a songbook (.yaml) file.
@ -101,7 +99,11 @@ class Songbook:
) )
self._config['filename'] = output.name[:-4] self._config['filename'] = output.name[:-4]
# Processing special options
self._config['_bookoptions'] = iter_bookoptions(self._config) self._config['_bookoptions'] = iter_bookoptions(self._config)
self._config['chords']['_notenames'] = self._get_chord_names(
self._config['chords']['notation']
)
renderer.render_tex(output, self._config) renderer.render_tex(output, self._config)
@ -111,6 +113,15 @@ class Songbook:
if self.has_errors(): if self.has_errors():
raise errors.SongbookError("Some songs contain errors. Stopping as requested.") raise errors.SongbookError("Some songs contain errors. Stopping as requested.")
@staticmethod
def _get_chord_names(notation):
"""Return a list of chord names, given the user option."""
if notation == "alphascale":
return ["A", "B", "C", "D", "E", "F", "G"]
if notation == "solfedge":
return ["La", "Si", "Do", r"R\'e", "Mi", "Fa", "Sol"]
return notation
def has_errors(self): def has_errors(self):
"""Return `True` iff errors have been encountered in the book. """Return `True` iff errors have been encountered in the book.

2
patacrep/content/sort.py

@ -56,7 +56,7 @@ def key_generator(sort):
field = song.data[key] field = song.data[key]
except KeyError: except KeyError:
LOGGER.debug( LOGGER.debug(
"Ignoring unknown key '{}' for song {}.".format( "Ignoring missing key '{}' for song {}.".format(
key, key,
files.relpath(song.fullpath), files.relpath(song.fullpath),
) )

BIN
patacrep/data/img/internet.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

21
patacrep/data/templates/songbook/default.tex

@ -66,8 +66,8 @@ description:
\usepackage{chords} \usepackage{chords}
\title{(( template_var.title ))} \title{(( template_var.title|escape_specials() ))}
\author{(( template_var.author ))} \author{(( template_var.author|escape_specials() ))}
\newindex{titleidx}{((filename))_title} \newindex{titleidx}{((filename))_title}
\newauthorindex{authidx}{((filename))_auth} \newauthorindex{authidx}{((filename))_auth}
@ -85,11 +85,7 @@ description:
\authsepword{((word))} \authsepword{((word))}
(* endfor *) (* endfor *)
(* if chords.notation=="alphascale" -*) \notenamesout{(( chords._notenames[0] ))}{(( chords._notenames[1] ))}{(( chords._notenames[2] ))}{(( chords._notenames[3] ))}{(( chords._notenames[4] ))}{(( chords._notenames[5] ))}{(( chords._notenames[6] ))}
\notenamesout{A}{B}{C}{D}{E}{F}{G}
(* else -*)
\notenamesout{La}{Si}{Do}{R\'e}{Mi}{Fa}{Sol}
(* endif *)
(* endblock *) (* endblock *)
(* block title *) (* block title *)
@ -103,12 +99,11 @@ description:
(* block chords *) (* block chords *)
% list of chords % list of chords
\ifchorded \ifdiagrampage
\ifdiagram \phantomsection
\phantomsection \addcontentsline{toc}{section}{\chordlistname}
\addcontentsline{toc}{section}{\chordlistname} \chords
\chords
\fi
\fi \fi
\setcounter{songnum}{1}%
(* endblock *) (* endblock *)

6
patacrep/data/templates/songbook/patacrep.tex

@ -138,12 +138,12 @@ description:
]{hyperref} ]{hyperref}
\subtitle{(( template_var.subtitle ))} \subtitle{(( template_var.subtitle|escape_specials ))}
(* if template_var.version -*) (* if template_var.version -*)
\version{(( template_var.version ))} \version{(( template_var.version ))}
(* endif *) (* endif *)
\mail{(( template_var.email ))} \mail{(( template_var.email|escape_url ))}
\web{(( template_var.url ))} \web{(( template_var.url|escape_url ))}
\picture{(( template_var.picture ))} \picture{(( template_var.picture ))}
\picturecopyright{(( template_var.picturecopyright ))} \picturecopyright{(( template_var.picturecopyright ))}
\footer{(( template_var.footer ))} \footer{(( template_var.footer ))}

33
patacrep/data/templates/songbook_model.yml

@ -27,7 +27,15 @@ schema:
type: //rec type: //rec
required: required:
show: //bool show: //bool
diagrampage: //bool diagrampage:
type: //any
of:
- type: //str
value: "none"
- type: //str
value: "important"
- type: //str
value: "all"
repeatchords: //bool repeatchords: //bool
lilypond: //bool lilypond: //bool
tablatures: //bool tablatures: //bool
@ -48,12 +56,17 @@ schema:
- type: //str - type: //str
value: "ukulele" value: "ukulele"
notation: notation:
type: //any type: //any
of: of:
- type: //str - type: //str
value: "alphascale" value: "alphascale"
- type: //str - type: //str
value: "solfedge" value: "solfedge"
- type: //arr
contents: //str
length:
min: 7
max: 7
authors: authors:
type: //rec type: //rec
required: required:
@ -97,7 +110,7 @@ default:
chords: chords:
show: yes show: yes
diagramreminder: important diagramreminder: important
diagrampage: yes diagrampage: all
repeatchords: yes repeatchords: yes
lilypond: no lilypond: no
tablatures: no tablatures: no
@ -149,7 +162,7 @@ description:
lilypond: "Display lilypond scores" lilypond: "Display lilypond scores"
tablatures: "Display tablatures" tablatures: "Display tablatures"
instrument: "Instrument for the diagrams" instrument: "Instrument for the diagrams"
notation: "Chord notation" notation: "List of chord names, with special values `solfedge` being an alias for `['La', 'Si', 'Do', 'Ré', 'Mi', 'Fa', 'Sol']`, and `alphascale` for `['A', 'B', 'C', 'D', 'E', 'F', 'G']`."
authors: authors:
separators: "Separator words between artists" separators: "Separator words between artists"
@ -175,7 +188,7 @@ description:
lilypond: "Inclure les partitions lilypond" lilypond: "Inclure les partitions lilypond"
tablatures: "Inclure les tablatures" tablatures: "Inclure les tablatures"
instrument: "Instrument pour les diagrammes d'accords" instrument: "Instrument pour les diagrammes d'accords"
notation: "Notation des accords" notation: "Liste des noms de notes, en commençant par LA, sachant que `solfedge` est un alias pour `['La', 'Si', 'Do', 'Ré', 'Mi', 'Fa', 'Sol']`, et `alphascale` pour `['A', 'B', 'C', 'D', 'E', 'F', 'G']`."
authors: authors:
separators: "Mots de séparation entre les artistes" separators: "Mots de séparation entre les artistes"

2
patacrep/data/templates/songs/chordpro/chordpro/content_image

@ -1 +1 @@
{image: (( content.argument|search_image ))} {image: "(( content.filename|search_image ))" ((content.size|render_size))}

2
patacrep/data/templates/songs/chordpro/chordpro/content_word

@ -1 +1 @@
(( content.value )) (( content.value|escape_specials('{}\\#') ))

12
patacrep/data/templates/songs/chordpro/chordpro/song_header

@ -9,16 +9,16 @@
(* endif *) (* endif *)
(*- for title in titles -*) (*- for title in titles -*)
{title: (( title ))} {title: (( title|escape_specials('{}\\') ))}
(* endfor -*) (* endfor -*)
(*- for author in authors -*) (*- for author in authors -*)
{artist: (( author[1] )) (( author[0] ))} {artist: (( author[1]|escape_specials('{}\\') )) (( author[0]|escape_specials('{}\\') ))}
(* endfor -*) (* endfor -*)
(*- for key in ['album', 'copyright'] *) (*- for key in ['album', 'copyright'] *)
(* if key in metadata -*) (* if key in metadata -*)
{(( key )): (( metadata[key] ))} {(( key )): (( metadata[key]|escape_specials('{}\\') ))}
(* endif *) (* endif *)
(* endfor *) (* endfor *)
(* if 'cover' in metadata -*) (* if 'cover' in metadata -*)
@ -30,9 +30,13 @@
(* endfor -*) (* endfor -*)
(*- for key in metadata.morekeys -*) (*- for key in metadata.morekeys -*)
{key: (( key.keyword )): (( key.argument ))} {key: (( key.keyword )): (( key.argument|escape_specials('{}\\') ))}
(* endfor *) (* endfor *)
(*- if 'url' in metadata -*)
{url: (( metadata.url|escape_url ))}
(* endif -*)
(*- for chord in metadata['define'] *) (*- for chord in metadata['define'] *)
((- render(chord) )) ((- render(chord) ))
(* endfor *) (* endfor *)

4
patacrep/data/templates/songs/chordpro/latex/content_image

@ -1,6 +1,6 @@
(* block image *) (* block image *)
(* set image = content.argument|search_image|path2posix *) (* set image = content.filename|search_image|path2posix *)
(* if image *) (* if image *)
\image{(( image ))} \image[(( content.size|render_size ))]{(( image ))}
(*- endif *) (*- endif *)
(*- endblock *) (*- endblock *)

2
patacrep/data/templates/songs/chordpro/latex/content_word

@ -1 +1 @@
(( content.value )) (( content.value|escape_specials('{}&#_^%~$\\') ))

11
patacrep/data/templates/songs/chordpro/latex/song

@ -8,7 +8,7 @@
\beginsong{ \beginsong{
(*- for title in titles -*) (*- for title in titles -*)
(( title )) (( title|escape_specials('{}&#_^%~$\\') ))
(*- if not loop.last -*) (*- if not loop.last -*)
\\ \\
(* endif *) (* endif *)
@ -16,7 +16,7 @@
}[ }[
by={ by={
(* for author in authors *) (* for author in authors *)
(( author[1] )) (( author[0] )) (( author[1]|escape_specials('{}&#_^%~$\\') )) (( author[0]|escape_specials('{}&#_^%~$\\') ))
(*- if not loop.last -*) (*- if not loop.last -*)
, ,
(* endif *) (* endif *)
@ -24,9 +24,12 @@
}, },
(* for key in ['album', 'copyright'] *) (* for key in ['album', 'copyright'] *)
(* if key in metadata *) (* if key in metadata *)
(( key ))={(( metadata[key] ))}, (( key ))={(( metadata[key]|escape_specials('{}&#_^%~$\\') ))},
(* endif *) (* endif *)
(* endfor *) (* endfor *)
(* if 'url' in metadata *)
url={(( metadata.url|escape_url ))},
(* endif *)
(* if 'cover' in metadata *) (* if 'cover' in metadata *)
(* block cover *) (* block cover *)
(* set cover = metadata["cover"].argument|search_image|path2posix *) (* set cover = metadata["cover"].argument|search_image|path2posix *)
@ -36,7 +39,7 @@
(* endblock *) (* endblock *)
(* endif *) (* endif *)
(* for key in metadata.morekeys *) (* for key in metadata.morekeys *)
(( key.keyword ))={(( key.argument ))}, (( key.keyword ))={(( key.argument|escape_specials('{}&#_^%~$\\') ))},
(* endfor *) (* endfor *)
] ]

13
patacrep/data/templates/styles/chords.sty

@ -24,7 +24,7 @@
\raisebox{2em}{\chordname{##1}} % \raisebox{2em}{\chordname{##1}} %
} % } %
% Placing boxes % Placing boxes
\ifimportantdiagramonly% \ifdiagrampagereduced%
\pl@cechord{#1}% \pl@cechord{#1}%
\hspace{\stretch{1}}% \hspace{\stretch{1}}%
\usebox{\@chordgroupbox@ii}% \usebox{\@chordgroupbox@ii}%
@ -75,7 +75,17 @@
\newcommand{\chords}{ \newcommand{\chords}{
\ifdiagrampage
\begin{songs}{} \begin{songs}{}
%important diagrams are hidden by \chordtabs
\renewcommand{\gtab}{\@ifstar
\gtab@Original%
\gtab@Original%
}
\renewcommand{\utab}{\@ifstar
\utab@Original%
\utab@Original%
}
%hide song number %hide song number
\definecolor{SongNumberBgColor}{HTML}{FFFFFF} \definecolor{SongNumberBgColor}{HTML}{FFFFFF}
\renewcommand{\snumbgcolor}{SongNumberBgColor} \renewcommand{\snumbgcolor}{SongNumberBgColor}
@ -391,5 +401,6 @@
\fi \fi
\end{songs} \end{songs}
\fi
} }
\endinput \endinput

4
patacrep/data/templates/styles/crepbook.sty

@ -79,8 +79,8 @@
% Title page % Title page
\long\def\subtitle#1{\long\def\@subtitle{#1}} \long\def\subtitle#1{\long\def\@subtitle{#1}}
\def\version#1{\def\@version{#1}} \def\version#1{\def\@version{#1}}
\def\web#1{\def\@web{#1}} \def\web#1{\def\@web{\url{#1}}}
\def\mail#1{\def\@mail{#1}} \def\mail#1{\def\@mail{\href{mailto:#1}{\nolinkurl{#1}}}}
\def\email#1{\def\@email{#1}} \def\email#1{\def\@email{#1}}
\def\picture#1{\def\@picture{#1}} \def\picture#1{\def\@picture{#1}}
\def\picturecopyright#1{\def\@picturecopyright{#1}} \def\picturecopyright#1{\def\@picturecopyright{#1}}

17
patacrep/data/templates/styles/patacrep.sty

@ -6,6 +6,7 @@
\NeedsTeXFormat{LaTeX2e}[1994/06/01] \NeedsTeXFormat{LaTeX2e}[1994/06/01]
\ProvidesPackage{patacrep}[2014/06/17 Patacrep Package, version 1] \ProvidesPackage{patacrep}[2014/06/17 Patacrep Package, version 1]
\RequirePackage[space]{grffile}
\RequirePackage{graphicx,xcolor} % \RequirePackage{graphicx,xcolor} %
\RequirePackage{epstopdf} % \RequirePackage{epstopdf} %
\RequirePackage{fancybox} \RequirePackage{fancybox}
@ -26,6 +27,14 @@
\newif{\iflilypondauto} \newif{\iflilypondauto}
\DeclareOption{lilypond}{\lilypondautotrue\lilypondtrue} \DeclareOption{lilypond}{\lilypondautotrue\lilypondtrue}
% diagram: insert a page of diagrams before the songs
\newif{\ifdiagrampage}
\DeclareOption{diagrampage}{\diagrampagetrue}
% diagram: insert a page of the "important diagrams" before the songs
\newif{\ifdiagrampagereduced}
\DeclareOption{diagrampagereduced}{\diagrampagereducedtrue\diagrampagetrue}
% diagram: display chord diagrams at the beginning % diagram: display chord diagrams at the beginning
\newif{\ifdiagram} \newif{\ifdiagram}
\DeclareOption{diagram}{\diagramtrue} \DeclareOption{diagram}{\diagramtrue}
@ -392,7 +401,9 @@
\renewcommand{\textnote}[2][]{% \renewcommand{\textnote}[2][]{%
\vspace{.1cm} \vspace{.1cm}
\IfStrEq{}{#1}{\@textnoteold{#2}}{ \IfStrEq{}{#1}{\@textnoteold{#2}}{
\iflanguage{#1}{\@textnoteold{#2}}{} \IfStrEq{\mainlanguage}{#1}{
\@textnoteold{#2}
}{}
} }
} }
@ -400,7 +411,9 @@
\renewcommand{\musicnote}[2][]{% \renewcommand{\musicnote}[2][]{%
\vspace{.1cm} \vspace{.1cm}
\IfStrEq{}{#1}{\@musicnoteold{#2}}{ \IfStrEq{}{#1}{\@musicnoteold{#2}}{
\iflanguage{#1}{\@musicnoteold{#2}}{} \IfStrEq{\mainlanguage}{#1}{
\@musicnoteold{#2}
}{}
} }
} }
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

7
patacrep/index.py

@ -16,8 +16,8 @@ from patacrep.latex import tex2plain
EOL = "\n" EOL = "\n"
# Pattern set to ignore latex command in title prefix # Pattern set to ignore latex command in title prefix
KEYWORD_PATTERN = re.compile(r"^%(\w+)\s?(.*)$", re.LOCALE) KEYWORD_PATTERN = re.compile(r"^%(\w+)\s?(.*)$")
FIRST_LETTER_PATTERN = re.compile(r"^(?:\{?\\\w+\}?)*[^\w]*(\w)", re.LOCALE) FIRST_LETTER_PATTERN = re.compile(r"^(?:\{?\\\w+\}?)*[^\w]*(\w)")
def process_sxd(filename): def process_sxd(filename):
"""Parse sxd file. """Parse sxd file.
@ -90,8 +90,7 @@ class Index:
if 'prefix' in self.keywords: if 'prefix' in self.keywords:
for prefix in self.keywords['prefix']: for prefix in self.keywords['prefix']:
self.prefix_patterns.append(re.compile( self.prefix_patterns.append(re.compile(
r"^({prefix})(\b|\\)(\s*.*)$".format(prefix=prefix), r"^({prefix})(\b|\\)(\s*.*)$".format(prefix=prefix)
re.LOCALE
)) ))
if self.indextype == "AUTHOR": if self.indextype == "AUTHOR":

4
patacrep/latex/__init__.py

@ -16,7 +16,7 @@ LOGGER = logging.getLogger(__name__)
DEFAULT_LANGUAGE = "en_us" DEFAULT_LANGUAGE = "en_us"
BABEL_LANGUAGES = OrderedDict(( BABEL_LANGUAGES = OrderedDict((
('de_de', 'german'), ('de_de', 'ngerman'), # german (old), germanb (like german)
('de_at', 'austrian'), ('de_at', 'austrian'),
('eo_uy', 'esperanto'), ('eo_uy', 'esperanto'),
('en_us', 'english'), # USenglish, american ('en_us', 'english'), # USenglish, american
@ -53,8 +53,6 @@ BABEL_LANGUAGES = OrderedDict((
# ('??_??', 'finnish'), # ('??_??', 'finnish'),
# ('??_??', 'acadian'), # ('??_??', 'acadian'),
# ('??_??', 'galician'), # ('??_??', 'galician'),
# ('??_??', 'germanb'),
# ('??_??', 'ngerman'),
# ('??_??', 'naustrian'), # ('??_??', 'naustrian'),
# ('??_??', 'greek'), # ('??_??', 'greek'),
# ('??_??', 'polutonikogreek'), # ('??_??', 'polutonikogreek'),

2
patacrep/songs/__init__.py

@ -294,7 +294,7 @@ def unprefixed_title(title, prefixes):
"""Remove the first prefix of the list in the beginning of title (if any). """Remove the first prefix of the list in the beginning of title (if any).
""" """
for prefix in prefixes: for prefix in prefixes:
match = re.compile(r"^(%s)\b\s*(.*)$" % prefix, re.LOCALE).match(title) match = re.compile(r"^(%s)\b\s*(.*)$" % prefix).match(title)
if match: if match:
return match.group(2) return match.group(2)
return title return title

77
patacrep/songs/chordpro/__init__.py

@ -3,6 +3,7 @@
import logging import logging
import operator import operator
import os import os
import urllib
from jinja2 import Environment, FileSystemLoader, ChoiceLoader from jinja2 import Environment, FileSystemLoader, ChoiceLoader
from jinja2 import contextfunction from jinja2 import contextfunction
@ -30,6 +31,13 @@ class ChordproSong(Song):
# pylint: disable=abstract-method # pylint: disable=abstract-method
output_language = None 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): def _parse(self):
"""Parse content, and return the dictionary of song data.""" """Parse content, and return the dictionary of song data."""
@ -50,6 +58,8 @@ class ChordproSong(Song):
filters.update({ filters.update({
'search_image': self.search_image, 'search_image': self.search_image,
'search_partition': self.search_partition, 'search_partition': self.search_partition,
'escape_specials': self._escape_specials,
'escape_url': self._escape_url,
}) })
return filters return filters
@ -84,6 +94,20 @@ class ChordproSong(Song):
context.vars['content'] = content context.vars['content'] = content
return context.environment.get_template(content.template()).render(context) return context.environment.get_template(content.template()).render(context)
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 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): class Chordpro2HtmlSong(ChordproSong):
"""Render chordpro song to html code""" """Render chordpro song to html code"""
@ -104,6 +128,25 @@ class Chordpro2LatexSong(ChordproSong):
"""Render chordpro song to latex code""" """Render chordpro song to latex code"""
output_language = "latex" output_language = "latex"
_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("}"),
'%': r'\%',
'#': r'\#',
}
def search_file(self, filename, extensions=None, *, datadirs=None): def search_file(self, filename, extensions=None, *, datadirs=None):
_datadir, filename, _extension = self.search_datadir_file( _datadir, filename, _extension = self.search_datadir_file(
@ -139,6 +182,7 @@ class Chordpro2LatexSong(ChordproSong):
parent = super()._filters() parent = super()._filters()
parent.update({ parent.update({
'lang2babel': self.lang2babel, 'lang2babel': self.lang2babel,
'render_size': self._render_size,
}) })
return parent return parent
@ -160,15 +204,48 @@ class Chordpro2LatexSong(ChordproSong):
self.errors.append(new_error) self.errors.append(new_error)
return error.babel return error.babel
@staticmethod
def _render_size(size):
items = []
for name, value, unit in size:
items.append(name + "=" + value + unit)
return ", ".join(items)
class Chordpro2ChordproSong(ChordproSong): class Chordpro2ChordproSong(ChordproSong):
"""Render chordpro song to chordpro code""" """Render chordpro song to chordpro code"""
output_language = "chordpro" output_language = "chordpro"
_translation_map = {
'{': r'\{',
'}': r'\}',
'\\': '\\\\',
'#': r'\#',
}
_translation_map_url = {
'{': r'\{',
'}': r'\}',
'\\': '\\\\',
}
def _filters(self):
parent = super()._filters()
parent.update({
'render_size': self._render_size,
})
return parent
def search_file(self, filename, extensions=None, *, datadirs=None): def search_file(self, filename, extensions=None, *, datadirs=None):
# pylint: disable=unused-variable # pylint: disable=unused-variable
return filename return filename
@staticmethod
def _render_size(size):
items = []
for name, value, unit in size:
items.append(name + "=" + value + unit)
return " ".join(items)
SONG_RENDERERS = { SONG_RENDERERS = {
"tsg": { "tsg": {
'csg': Chordpro2LatexSong, 'csg': Chordpro2LatexSong,

16
patacrep/songs/chordpro/ast.py

@ -405,6 +405,22 @@ class Define(Directive):
def __str__(self): def __str__(self):
return None return None
class Image(Directive):
"""An image
.. attribute:: filename
The filename of the image.
.. attribute:: size
An iterable of tuples ``(type, float, unit)``.
"""
def __init__(self, filename, size=None):
self.filename = filename
if size is None:
size = []
self.size = size
super().__init__("image", None)
class Tab(AST): class Tab(AST):
"""Tablature""" """Tablature"""

18
patacrep/songs/chordpro/lexer.py

@ -49,7 +49,7 @@ class ChordProLexer:
t_directive_SPACE = r'[ \t]+' t_directive_SPACE = r'[ \t]+'
t_directive_KEYWORD = r'[a-zA-Z_]+' t_directive_KEYWORD = r'[a-zA-Z_]+'
t_directiveargument_TEXT = r'[^}]+' t_directiveargument_TEXT = r'[^\\}]+'
@staticmethod @staticmethod
def t_SOC(token): def t_SOC(token):
@ -118,7 +118,7 @@ class ChordProLexer:
@staticmethod @staticmethod
def t_WORD(token): def t_WORD(token):
r'[^{}\r\n\]\[\t ]+' r'[^{}\\\r\n\]\[\t ]+'
return token return token
def t_LBRACKET(self, __token): def t_LBRACKET(self, __token):
@ -150,6 +150,20 @@ class ChordProLexer:
self.lexer.push_state('directiveargument') self.lexer.push_state('directiveargument')
return token return token
@staticmethod
def t_ESCAPED(token):
r'\\[{} #\\]'
token.value = token.value[1]
token.type = "WORD"
return token
@staticmethod
def t_directiveargument_ESCAPED(token):
r'\\[{} #\\]'
token.value = token.value[1]
token.type = "TEXT"
return token
def error(self, token, more=""): def error(self, token, more=""):
"""Display error message, and skip illegal token.""" """Display error message, and skip illegal token."""
message = "Illegal character '{char}'{more}.".format( message = "Illegal character '{char}'{more}.".format(

89
patacrep/songs/chordpro/syntax.py

@ -2,6 +2,7 @@
import logging import logging
import re import re
import shlex
import ply.yacc as yacc import ply.yacc as yacc
@ -124,10 +125,67 @@ class ChordproParser(Parser):
fingers=fingers, fingers=fingers,
) )
def _iter_raw_image_size_arguments(self, arguments, *, lineno):
for item in arguments:
prefix, _, suffix = item.partition("=")
if prefix in ['width', 'height']:
match = re.compile(
r"^(?P<value>(\d*\.\d+|\d+))(?P<unit>cm|em|pt)$",
re.VERBOSE,
).match(suffix)
if match is not None:
yield (prefix, match.groupdict()['value'], match.groupdict()['unit'])
continue
elif prefix in ['scale']:
match = re.compile(
r"^(?P<value>(\d*\.\d+|\d+))$",
re.VERBOSE,
).match(suffix)
if match is not None:
yield (prefix, match.groupdict()['value'], "")
continue
else:
self.error(
line=lineno,
message="Image: Unknown argument name '{}'.".format(prefix),
)
continue
self.error(
line=lineno,
message="Image: Unsupported {} value: '{}'.".format(prefix, suffix),
)
def _iter_image_size_arguments(self, argument, *, lineno):
arguments = set()
length_names = frozenset(["width", "height"])
for name, value, unit in self._iter_raw_image_size_arguments(argument, lineno=lineno):
if name in arguments:
self.error(
line=lineno,
message="Image: Ignoring repeated argument: {}.".format(name),
)
continue
if (
name == "scale" and not length_names.isdisjoint(arguments)
) or (
name in length_names and "scale" in arguments
):
self.error(
line=lineno,
message=(
"Image: Ignoring '{}' argument: Cannot mix scale and "
"width or height argument."
).format(name),
)
continue
arguments.add(name)
yield name, value, unit
def p_directive(self, symbols): def p_directive(self, symbols):
"""directive : LBRACE KEYWORD directive_next RBRACE """directive : LBRACE KEYWORD directive_next RBRACE
| LBRACE SPACE KEYWORD directive_next RBRACE | LBRACE SPACE KEYWORD directive_next RBRACE
""" """
# pylint: disable=too-many-branches
if len(symbols) == 5: if len(symbols) == 5:
keyword = symbols[2] keyword = symbols[2]
argument = symbols[3] argument = symbols[3]
@ -171,7 +229,21 @@ class ChordproParser(Parser):
symbols[0] = ast.Error() symbols[0] = ast.Error()
return return
self._directives.append(define) self._directives.append(define)
elif keyword == "image":
splitted = shlex.split(argument)
if len(splitted) < 1:
self.error(
line=symbols.lexer.lineno,
message="Missing filename for image directive",
)
symbols[0] = ast.Error()
else:
symbols[0] = ast.Image(
splitted[0],
list(
self._iter_image_size_arguments(splitted[1:], lineno=symbols.lexer.lineno)
),
)
else: else:
directive = ast.Directive(keyword, argument) directive = ast.Directive(keyword, argument)
if directive.inline: if directive.inline:
@ -182,9 +254,8 @@ class ChordproParser(Parser):
@staticmethod @staticmethod
def p_directive_next(symbols): def p_directive_next(symbols):
"""directive_next : SPACE COLON TEXT """directive_next : SPACE COLON directive_argument
| COLON TEXT | COLON directive_argument
| COLON
| empty | empty
""" """
if len(symbols) == 3: if len(symbols) == 3:
@ -196,6 +267,16 @@ class ChordproParser(Parser):
else: else:
symbols[0] = None symbols[0] = None
@staticmethod
def p_directive_argument(symbols):
"""directive_argument : TEXT directive_argument
| empty
"""
if len(symbols) == 3:
symbols[0] = symbols[1] + symbols[2]
else:
symbols[0] = ""
def p_line_error(self, symbols): def p_line_error(self, symbols):
"""line_error : error directive""" """line_error : error directive"""
self.error( self.error(

59
patacrep/templates.py

@ -2,6 +2,7 @@
import logging import logging
import re import re
import urllib
import yaml import yaml
@ -16,15 +17,6 @@ import patacrep.encoding
LOGGER = logging.getLogger(__name__) 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( _VARIABLE_REGEXP = re.compile(
r""" r"""
\(\*-?\ *variables\ *\*\) # Match (* variables *) or (*- variables *) \(\*-?\ *variables\ *\*\) # Match (* variables *) or (*- variables *)
@ -46,15 +38,47 @@ _VARIABLE_REGEXP = re.compile(
""", """,
re.VERBOSE|re.DOTALL) 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''' '''Escape TeX special characters'''
newval = value if translation_map is None:
for pattern, replacement in _LATEX_SUBS: translation_map = TRANSLATION_MAP
newval = pattern.sub(replacement, newval) if chars is None:
return newval 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 = { DEFAULT_FILTERS = {
"escape_tex": _escape_tex, "escape_specials": _escape_specials,
"escape_url": _escape_url,
"iter_datadirs": files.iter_datadirs, "iter_datadirs": files.iter_datadirs,
"path2posix": files.path2posix, "path2posix": files.path2posix,
} }
@ -296,4 +320,9 @@ def iter_bookoptions(config):
elif config['chords']['diagramreminder'] == "all": elif config['chords']['diagramreminder'] == "all":
yield 'diagram' yield 'diagram'
if config['chords']['diagrampage'] == "important":
yield 'diagrampagereduced'
elif config['chords']['diagrampage'] == "all":
yield 'diagrampage'
yield config['chords']['instrument'] yield config['chords']['instrument']

77
patacrep/tools/__main__.py

@ -2,85 +2,26 @@
"""Command line client to :mod:`tools`""" """Command line client to :mod:`tools`"""
import argparse
import logging import logging
import operator
import os
import pkgutil
import re
import sys import sys
import argdispatch
import patacrep import patacrep
# Logging configuration # Logging configuration
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
LOGGER = logging.getLogger("patatools") LOGGER = logging.getLogger("patatools")
def _execlp(program, args):
"""Call :func:`os.execlp`, adding `program` as the first argument to itself."""
return os.execlp(program, program, *args)
def _iter_subcommands():
"""Iterate over subcommands.
The objects returned are tuples of:
- the name of the command;
- its description;
- the function to call to execute the subcommand.
"""
subcommands = []
# Get python subcommands
path = [os.path.join(item, "patacrep", "tools") for item in sys.path]
prefix = "patacrep.tools."
module_re = re.compile(r'{}(?P<subcommand>[^\.]*)\.__main__'.format(prefix))
for module_loader, name, _ in pkgutil.walk_packages(path, prefix):
match = module_re.match(name)
if match:
module = module_loader.find_module(match.string).load_module()
if hasattr(module, "SUBCOMMAND_DESCRIPTION"):
subcommands.append(match.groupdict()['subcommand'])
yield (
match.groupdict()['subcommand'],
getattr(module, "SUBCOMMAND_DESCRIPTION"),
module.main,
)
class ArgumentParser(argparse.ArgumentParser):
"""Proxy class to circumvent an :mod:`argparse` bug.
Contrarily to what documented, the `argparse.REMAINDER
<https://docs.python.org/3/library/argparse.html#nargs>`_ `nargs` setting
does not include the remainder arguments if the first one begins with `-`.
This bug is reperted as `17050 <https://bugs.python.org/issue17050>`_. This
class can be deleted once this bug has been fixed.
"""
def parse_args(self, args=None, namespace=None):
if args is None:
args = sys.argv[1:]
subcommands = [command[0] for command in set(_iter_subcommands())]
if len(args) > 0:
if args[0] in subcommands:
args = [args[0], "--"] + args[1:]
value = super().parse_args(args, namespace)
if hasattr(value, 'remainder'):
value.remainder = value.remainder[1:]
return value
def commandline_parser(): def commandline_parser():
"""Return a command line parser.""" """Return a command line parser."""
parser = ArgumentParser( parser = argdispatch.ArgumentParser(
prog="patatools", prog="patatools",
description=( description=(
"Miscellaneous tools for patacrep." "Miscellaneous tools for patacrep."
), ),
formatter_class=argparse.RawTextHelpFormatter, formatter_class=argdispatch.RawTextHelpFormatter,
) )
parser.add_argument( parser.add_argument(
@ -96,11 +37,7 @@ def commandline_parser():
) )
subparsers.required = True subparsers.required = True
subparsers.dest = "subcommand" subparsers.dest = "subcommand"
subparsers.add_submodules("patacrep.tools")
for command, message, function in sorted(_iter_subcommands(), key=operator.itemgetter(0)):
sub1 = subparsers.add_parser(command, help=message, add_help=False)
sub1.add_argument('remainder', nargs=argparse.REMAINDER)
sub1.set_defaults(function=function)
return parser return parser
@ -108,9 +45,7 @@ def main(args=None):
"""Main function""" """Main function"""
if args is None: if args is None:
args = sys.argv args = sys.argv
parser = commandline_parser() commandline_parser().parse_args(args[1:])
args = parser.parse_args(args[1:])
args.function(["patatools-{}".format(args.subcommand)] + args.remainder)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

5
patacrep/tools/cache/__main__.py

@ -1,4 +1,4 @@
"""`patatools cache` command: cache manipulation.""" """Perform operations on cache."""
import argparse import argparse
import logging import logging
@ -11,7 +11,6 @@ from patacrep import errors
from patacrep.songbook import open_songbook from patacrep.songbook import open_songbook
LOGGER = logging.getLogger("patatools.cache") LOGGER = logging.getLogger("patatools.cache")
SUBCOMMAND_DESCRIPTION = "Perform operations on cache."
def filename(name): def filename(name):
"""Check that argument is an existing, readable file name. """Check that argument is an existing, readable file name.
@ -27,7 +26,7 @@ def commandline_parser():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
prog="patatools cache", prog="patatools cache",
description=SUBCOMMAND_DESCRIPTION, description="Convert between song formats.",
formatter_class=argparse.RawTextHelpFormatter, formatter_class=argparse.RawTextHelpFormatter,
) )

3
patacrep/tools/convert/__main__.py

@ -1,4 +1,4 @@
"""`patatools.convert` command: convert between song formats""" """Convert between song formats."""
import os import os
import logging import logging
@ -10,7 +10,6 @@ from patacrep.utils import yesno
from patacrep.build import config_model from patacrep.build import config_model
LOGGER = logging.getLogger("patatools.convert") LOGGER = logging.getLogger("patatools.convert")
SUBCOMMAND_DESCRIPTION = "Convert between song formats"
def _usage(): def _usage():
return "patatools convert INPUTFORMAT OUTPUTFORMAT FILES" return "patatools convert INPUTFORMAT OUTPUTFORMAT FILES"

2
setup.py

@ -34,7 +34,7 @@ setup(
packages=find_packages(exclude=["test*"]), packages=find_packages(exclude=["test*"]),
license="GPLv2 or any later version", license="GPLv2 or any later version",
install_requires=[ install_requires=[
"unidecode", "jinja2", "ply", "pyyaml", "argdispatch", "unidecode", "jinja2", "ply", "pyyaml",
], ],
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [

0
test/test_songbook/.gitignore → test/test_book/.gitignore

0
test/test_songbook/__init__.py → test/test_book/__init__.py

12
test/test_songbook/content.tex.control → test/test_book/content.tex.control

@ -26,6 +26,7 @@
chorded, chorded,
pictures, pictures,
diagram, diagram,
diagrampage,
guitar, guitar,
]{patacrep} ]{patacrep}
@ -79,13 +80,12 @@ guitar,
\showindex{\authorindexname}{authidx} \showindex{\authorindexname}{authidx}
% list of chords % list of chords
\ifchorded \ifdiagrampage
\ifdiagram \phantomsection
\phantomsection \addcontentsline{toc}{section}{\chordlistname}
\addcontentsline{toc}{section}{\chordlistname} \chords
\chords
\fi
\fi \fi
\setcounter{songnum}{1}%
\phantomsection \phantomsection
\addcontentsline{toc}{section}{\songlistname} \addcontentsline{toc}{section}{\songlistname}

0
test/test_songbook/content.yaml → test/test_book/content.yaml

0
test/test_songbook/content_datadir/content/foo.tex → test/test_book/content_datadir/content/foo.tex

0
test/test_songbook/content_datadir/content/inter.isg → test/test_book/content_datadir/content/inter.isg

0
test/test_songbook/content_datadir/content/song.csg → test/test_book/content_datadir/content/song.csg

0
test/test_songbook/content_datadir/content/song.tsg → test/test_book/content_datadir/content/song.tsg

0
test/test_songbook/content_datadir/songs/include.sbc → test/test_book/content_datadir/songs/include.sbc

0
test/test_songbook/content_datadir/songs/inter.isg → test/test_book/content_datadir/songs/inter.isg

0
test/test_songbook/content_datadir/songs/song.csg → test/test_book/content_datadir/songs/song.csg

0
test/test_songbook/content_datadir/songs/song.tsg → test/test_book/content_datadir/songs/song.tsg

20
test/test_songbook/datadir.tex.control → test/test_book/datadir.tex.control

@ -28,6 +28,7 @@ chorded,
pictures, pictures,
repeatchords, repeatchords,
importantdiagramonly, importantdiagramonly,
diagrampage,
guitar, guitar,
]{patacrep} ]{patacrep}
@ -82,13 +83,12 @@ guitar,
\showindex{\authorindexname}{authidx} \showindex{\authorindexname}{authidx}
% list of chords % list of chords
\ifchorded \ifdiagrampage
\ifdiagram \phantomsection
\phantomsection \addcontentsline{toc}{section}{\chordlistname}
\addcontentsline{toc}{section}{\chordlistname} \chords
\chords
\fi
\fi \fi
\setcounter{songnum}{1}%
\phantomsection \phantomsection
\addcontentsline{toc}{section}{\songlistname} \addcontentsline{toc}{section}{\songlistname}
@ -111,7 +111,7 @@ Chordpro}[
\lilypond{scores/datadir.ly} \lilypond{scores/datadir.ly}
\image{img/datadir.png} \image[]{img/datadir.png}
\endsong \endsong
@ -138,7 +138,7 @@ Chordpro}[
\lilypond{scores/datadir2.ly} \lilypond{scores/datadir2.ly}
\image{img/datadir2.png} \image[]{img/datadir2.png}
\endsong \endsong
@ -165,7 +165,7 @@ Chordpro}[
\lilypond{@TEST_FOLDER@/datadir_datadir/songs/./relative.ly} \lilypond{@TEST_FOLDER@/datadir_datadir/songs/./relative.ly}
\image{@TEST_FOLDER@/datadir_datadir/songs/./relative.png} \image[]{@TEST_FOLDER@/datadir_datadir/songs/./relative.png}
\endsong \endsong
@ -192,7 +192,7 @@ Chordpro}[
\lilypond{@TEST_FOLDER@/datadir_datadir/songs/./subdir/subdir.ly} \lilypond{@TEST_FOLDER@/datadir_datadir/songs/./subdir/subdir.ly}
\image{@TEST_FOLDER@/datadir_datadir/songs/./subdir/subdir.png} \image[]{@TEST_FOLDER@/datadir_datadir/songs/./subdir/subdir.png}
\endsong \endsong

0
test/test_songbook/datadir.yaml → test/test_book/datadir.yaml

0
test/test_songbook/datadir_datadir/img/datadir.png → test/test_book/datadir_datadir/img/datadir.png

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

0
test/test_songbook/datadir_datadir/scores/datadir.ly → test/test_book/datadir_datadir/scores/datadir.ly

0
test/test_songbook/datadir_datadir/songs/datadir.csg → test/test_book/datadir_datadir/songs/datadir.csg

0
test/test_songbook/datadir_datadir/songs/datadir.tsg → test/test_book/datadir_datadir/songs/datadir.tsg

0
test/test_songbook/datadir_datadir/songs/datadir2.csg → test/test_book/datadir_datadir/songs/datadir2.csg

0
test/test_songbook/datadir_datadir/songs/datadir2.sg → test/test_book/datadir_datadir/songs/datadir2.sg

0
test/test_songbook/datadir_datadir/songs/relative.csg → test/test_book/datadir_datadir/songs/relative.csg

0
test/test_songbook/datadir_datadir/songs/relative.ly → test/test_book/datadir_datadir/songs/relative.ly

0
test/test_songbook/datadir_datadir/songs/relative.png → test/test_book/datadir_datadir/songs/relative.png

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

0
test/test_songbook/datadir_datadir/songs/relative.tsg → test/test_book/datadir_datadir/songs/relative.tsg

0
test/test_songbook/datadir_datadir/songs/subdir/subdir.csg → test/test_book/datadir_datadir/songs/subdir/subdir.csg

0
test/test_songbook/datadir_datadir/songs/subdir/subdir.ly → test/test_book/datadir_datadir/songs/subdir/subdir.ly

0
test/test_songbook/datadir_datadir/songs/subdir/subdir.png → test/test_book/datadir_datadir/songs/subdir/subdir.png

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

0
test/test_songbook/datadir_datadir/songs/subdir/subdir.tsg → test/test_book/datadir_datadir/songs/subdir/subdir.tsg

0
test/test_songbook/datadir_datadir2/img/datadir2.png → test/test_book/datadir_datadir2/img/datadir2.png

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

0
test/test_songbook/datadir_datadir2/scores/datadir2.ly → test/test_book/datadir_datadir2/scores/datadir2.ly

131
test/test_book/lang_de.tex.control

@ -0,0 +1,131 @@
%% Automatically 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.
%%
%% Generated using Songbook <http://www.patacrep.com>
\makeatletter
\def\input@path{ %
{@TEST_FOLDER@/templates/styles/} %
{@DATA_FOLDER@/templates/styles/} %
}
\makeatother
\documentclass[
]{article}
\usepackage[
chorded,
pictures,
repeatchords,
importantdiagramonly,
diagrampage,
guitar,
]{crepbook}
\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}
\usepackage{lmodern}
\usepackage[ngerman]{babel}
\lang{ngerman}
\usepackage{graphicx}
\graphicspath{ %
{@TEST_FOLDER@/} %
{@DATA_FOLDER@/} %
}
\makeatletter
\@ifpackageloaded{hyperref}{}{
\usepackage{url}
\newcommand{\phantomsection}{}
\newcommand{\hyperlink}[2]{#2}
\newcommand{\href}[2]{\expandafter\url\expandafter{#1}}
}
\makeatother
\usepackage{chords}
\title{Guitar songbook}
\author{The Patacrep Team}
\newindex{titleidx}{lang_de_title}
\newauthorindex{authidx}{lang_de_auth}
\authignoreword{unknown}
\authbyword{by}
\authsepword{and}
\notenamesout{A}{B}{C}{D}{E}{F}{G}
\pagestyle{empty}\definecolor{SongNumberBgColor}{HTML}{D1E4AE}
\definecolor{NoteBgColor}{HTML}{D1E4AE}
\definecolor{IndexBgColor}{HTML}{D1E4AE}
\renewcommand{\snumbgcolor}{SongNumberBgColor}
\renewcommand{\notebgcolor}{NoteBgColor}
\renewcommand{\idxbgcolor}{IndexBgColor}
\definecolor{tango-green-3}{HTML}{4e9a06}
\definecolor{tango-blue-3}{HTML}{204a87}
\usepackage[
bookmarks,
bookmarksopen,
hyperfigures=true,
colorlinks=true,
linkcolor=tango-green-3,
urlcolor=tango-blue-3
]{hyperref}
\subtitle{}
\mail{crep@team-on-fire.com}
\web{http://www.patacrep.com}
\picture{img/treble_a}
\picturecopyright{Dbolton \url{http://commons.wikimedia.org/wiki/User:Dbolton}}
\footer{Generated using Songbook (\url{http://www.patacrep.com})}
\begin{document}
\maketitle
\showindex{\songindexname}{titleidx}
\showindex{\authorindexname}{authidx}
% list of chords
\ifdiagrampage
\phantomsection
\addcontentsline{toc}{section}{\chordlistname}
\chords
\fi
\setcounter{songnum}{1}%
\phantomsection
\addcontentsline{toc}{section}{\songlistname}
\end{document}

5
test/test_book/lang_de.yaml

@ -0,0 +1,5 @@
book:
lang: de
content:
- sort:

12
test/test_songbook/lang_default.tex.control → test/test_book/lang_default.tex.control

@ -26,6 +26,7 @@ chorded,
pictures, pictures,
repeatchords, repeatchords,
importantdiagramonly, importantdiagramonly,
diagrampage,
guitar, guitar,
]{crepbook} ]{crepbook}
@ -113,13 +114,12 @@ guitar,
\showindex{\authorindexname}{authidx} \showindex{\authorindexname}{authidx}
% list of chords % list of chords
\ifchorded \ifdiagrampage
\ifdiagram \phantomsection
\phantomsection \addcontentsline{toc}{section}{\chordlistname}
\addcontentsline{toc}{section}{\chordlistname} \chords
\chords
\fi
\fi \fi
\setcounter{songnum}{1}%
\phantomsection \phantomsection
\addcontentsline{toc}{section}{\songlistname} \addcontentsline{toc}{section}{\songlistname}

0
test/test_songbook/lang_default.yaml → test/test_book/lang_default.yaml

12
test/test_songbook/lang_en.tex.control → test/test_book/lang_en.tex.control

@ -26,6 +26,7 @@ chorded,
pictures, pictures,
repeatchords, repeatchords,
importantdiagramonly, importantdiagramonly,
diagrampage,
guitar, guitar,
]{crepbook} ]{crepbook}
@ -113,13 +114,12 @@ guitar,
\showindex{\authorindexname}{authidx} \showindex{\authorindexname}{authidx}
% list of chords % list of chords
\ifchorded \ifdiagrampage
\ifdiagram \phantomsection
\phantomsection \addcontentsline{toc}{section}{\chordlistname}
\addcontentsline{toc}{section}{\chordlistname} \chords
\chords
\fi
\fi \fi
\setcounter{songnum}{1}%
\phantomsection \phantomsection
\addcontentsline{toc}{section}{\songlistname} \addcontentsline{toc}{section}{\songlistname}

0
test/test_songbook/lang_en.yaml → test/test_book/lang_en.yaml

12
test/test_songbook/lang_fr.tex.control → test/test_book/lang_fr.tex.control

@ -26,6 +26,7 @@ chorded,
pictures, pictures,
repeatchords, repeatchords,
importantdiagramonly, importantdiagramonly,
diagrampage,
guitar, guitar,
]{crepbook} ]{crepbook}
@ -113,13 +114,12 @@ guitar,
\showindex{\authorindexname}{authidx} \showindex{\authorindexname}{authidx}
% list of chords % list of chords
\ifchorded \ifdiagrampage
\ifdiagram \phantomsection
\phantomsection \addcontentsline{toc}{section}{\chordlistname}
\addcontentsline{toc}{section}{\chordlistname} \chords
\chords
\fi
\fi \fi
\setcounter{songnum}{1}%
\phantomsection \phantomsection
\addcontentsline{toc}{section}{\songlistname} \addcontentsline{toc}{section}{\songlistname}

0
test/test_songbook/lang_fr.yaml → test/test_book/lang_fr.yaml

12
test/test_songbook/languages.tex.control → test/test_book/languages.tex.control

@ -27,6 +27,7 @@ chorded,
pictures, pictures,
repeatchords, repeatchords,
importantdiagramonly, importantdiagramonly,
diagrampage,
guitar, guitar,
]{patacrep} ]{patacrep}
@ -82,13 +83,12 @@ guitar,
\showindex{\authorindexname}{authidx} \showindex{\authorindexname}{authidx}
% list of chords % list of chords
\ifchorded \ifdiagrampage
\ifdiagram \phantomsection
\phantomsection \addcontentsline{toc}{section}{\chordlistname}
\addcontentsline{toc}{section}{\chordlistname} \chords
\chords
\fi
\fi \fi
\setcounter{songnum}{1}%
\phantomsection \phantomsection
\addcontentsline{toc}{section}{\songlistname} \addcontentsline{toc}{section}{\songlistname}

0
test/test_songbook/languages.yaml → test/test_book/languages.yaml

0
test/test_songbook/languages_datadir/songs/language.csg → test/test_book/languages_datadir/songs/language.csg

0
test/test_songbook/languages_datadir/songs/language_location.csg → test/test_book/languages_datadir/songs/language_location.csg

0
test/test_songbook/languages_datadir/songs/no_language.csg → test/test_book/languages_datadir/songs/no_language.csg

0
test/test_songbook/languages_datadir/songs/wrong_language.csg → test/test_book/languages_datadir/songs/wrong_language.csg

0
test/test_songbook/languages_datadir/songs/wrong_location.csg → test/test_book/languages_datadir/songs/wrong_location.csg

12
test/test_songbook/onthefly/content.onthefly.tex.control → test/test_book/onthefly/content.onthefly.tex.control

@ -25,6 +25,7 @@
chorded, chorded,
pictures, pictures,
diagram, diagram,
diagrampage,
guitar, guitar,
]{patacrep} ]{patacrep}
@ -77,13 +78,12 @@ guitar,
\showindex{\authorindexname}{authidx} \showindex{\authorindexname}{authidx}
% list of chords % list of chords
\ifchorded \ifdiagrampage
\ifdiagram \phantomsection
\phantomsection \addcontentsline{toc}{section}{\chordlistname}
\addcontentsline{toc}{section}{\chordlistname} \chords
\chords
\fi
\fi \fi
\setcounter{songnum}{1}%
\phantomsection \phantomsection
\addcontentsline{toc}{section}{\songlistname} \addcontentsline{toc}{section}{\songlistname}

0
test/test_songbook/onthefly/content.onthefly.yaml → test/test_book/onthefly/content.onthefly.yaml

162
test/test_book/special.tex.control

@ -0,0 +1,162 @@
%% Automatically 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.
%%
%% Generated using Songbook <http://www.patacrep.com>
\makeatletter
\def\input@path{ %
{@TEST_FOLDER@/special_datadir/templates/styles/} %
{@TEST_FOLDER@/templates/styles/} %
{@DATA_FOLDER@/templates/styles/} %
}
\makeatother
\documentclass[
]{article}
\usepackage[
chorded,
pictures,
repeatchords,
importantdiagramonly,
diagrampage,
guitar,
]{crepbook}
\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}
\usepackage{lmodern}
\PassOptionsToPackage{english}{babel}
\usepackage[english]{babel}
\lang{english}
\usepackage{graphicx}
\graphicspath{ %
{@TEST_FOLDER@/special_datadir/} %
{@TEST_FOLDER@/} %
{@DATA_FOLDER@/} %
}
\makeatletter
\@ifpackageloaded{hyperref}{}{
\usepackage{url}
\newcommand{\phantomsection}{}
\newcommand{\hyperlink}[2]{#2}
\newcommand{\href}[2]{\expandafter\url\expandafter{#1}}
}
\makeatother
\usepackage{chords}
\title{\& \% \$ \# \_ \} \{ \textasciitilde{} \textasciicircum{} \textbackslash{}}
\author{\& \% \$ \# \_ \} \{ \textasciitilde{} \textasciicircum{} \textbackslash{}}
\newindex{titleidx}{special_title}
\newauthorindex{authidx}{special_auth}
\authignoreword{unknown}
\authbyword{by}
\authsepword{and}
\notenamesout{A}{B}{C}{D}{E}{F}{G}
\pagestyle{empty}\definecolor{SongNumberBgColor}{HTML}{D1E4AE}
\definecolor{NoteBgColor}{HTML}{D1E4AE}
\definecolor{IndexBgColor}{HTML}{D1E4AE}
\renewcommand{\snumbgcolor}{SongNumberBgColor}
\renewcommand{\notebgcolor}{NoteBgColor}
\renewcommand{\idxbgcolor}{IndexBgColor}
\definecolor{tango-green-3}{HTML}{4e9a06}
\definecolor{tango-blue-3}{HTML}{204a87}
\usepackage[
bookmarks,
bookmarksopen,
hyperfigures=true,
colorlinks=true,
linkcolor=tango-green-3,
urlcolor=tango-blue-3
]{hyperref}
\subtitle{\& \% \$ \# \_ \} \{ \textasciitilde{} \textasciicircum{} \textbackslash{}}
\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})}
\begin{document}
\maketitle
\showindex{\songindexname}{titleidx}
\showindex{\authorindexname}{authidx}
% list of chords
\ifdiagrampage
\phantomsection
\addcontentsline{toc}{section}{\chordlistname}
\chords
\fi
\setcounter{songnum}{1}%
\phantomsection
\addcontentsline{toc}{section}{\songlistname}
\begin{songs}{titleidx,authidx}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% songs/./special.csg
\selectlanguage{english}
\beginsong{\& \$ \% \# \_ \} \{ \textasciitilde{} \textasciicircum{} \textbackslash{}}[
by={
\& \$ \% \# \_ \} \{ \textasciitilde{} \textasciicircum{} \textbackslash{} },
album={\& \$ \% \# \_ \} \{ \textasciitilde{} \textasciicircum{} \textbackslash{}},
url={http://&$\%\#_~^},
]
\begin{verse}
\& \$ \% \# \_ \} \{ \textasciitilde{} \textasciicircum{} \textbackslash{}
\end{verse}
\begin{chorus}
\& \$ \% \# \_ \} \{ \textasciitilde{} \textasciicircum{} \textbackslash{}
\end{chorus}
\endsong
\end{songs}
\end{document}

14
test/test_book/special.yaml

@ -0,0 +1,14 @@
book:
datadir:
- special_datadir
template:
default.tex:
title: "& % $ # _ } { ~ ^ \\"
author: "& % $ # _ } { ~ ^ \\"
patacrep.tex:
subtitle: "& % $ # _ } { ~ ^ \\"
url: "http://\\%&$#_~^ {}"
email: "foo@\\%&$#_~^ {}"
picture: "img/treble_a"

10
test/test_book/special_datadir/songs/special.csg

@ -0,0 +1,10 @@
{title: & $ % # _ \} \{ ~ ^ \\}
{artist: & $ % # _ \} \{ ~ ^ \\}
{album: & $ % # _ \} \{ ~ ^ \\}
{url: http://&$%#_~^}
& $ % \# _ \} \{ ~ ^ \\
{start_of_chorus}
& $ % \# _ \} \{ ~ ^ \\
{end_of_chorus}

79
test/test_songbook/syntax.tex.control → test/test_book/syntax.tex.control

@ -2,8 +2,6 @@
%% Automatically generated document. %% Automatically generated document.
%% You may edit this file but all changes will be overwritten. %% You may edit this file but all changes will be overwritten.
%% If you want to change this document, have a look at %% If you want to change this document, have a look at
@ -27,6 +25,7 @@ chorded,
pictures, pictures,
repeatchords, repeatchords,
importantdiagramonly, importantdiagramonly,
diagrampage,
guitar, guitar,
]{patacrep} ]{patacrep}
@ -79,18 +78,80 @@ guitar,
\showindex{\authorindexname}{authidx} \showindex{\authorindexname}{authidx}
% list of chords % list of chords
\ifchorded \ifdiagrampage
\ifdiagram \phantomsection
\phantomsection \addcontentsline{toc}{section}{\chordlistname}
\addcontentsline{toc}{section}{\chordlistname} \chords
\chords
\fi
\fi \fi
\setcounter{songnum}{1}%
\phantomsection \phantomsection
\addcontentsline{toc}{section}{\songlistname} \addcontentsline{toc}{section}{\songlistname}
\begin{songs}{titleidx,authidx} \begin{songs}{titleidx,authidx}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% songs/./images.csg
\selectlanguage{english}
\beginsong{}[
by={
},
]
\image[]{img/image.png}
\image[]{img/image with spaces.png}
\image[scale=2]{img/image.png}
\image[scale=.20]{img/image with spaces.png}
\image[scale=1.2]{img/image.png}
\image[width=2cm]{img/image.png}
\image[height=2cm]{img/image with spaces.png}
\image[width=2cm, height=1cm]{img/image.png}
\image[width=2em]{img/image.png}
\image[height=2em]{img/image with spaces.png}
\image[width=2em, height=1em]{img/image.png}
\image[width=50pt]{img/image.png}
\image[height=50pt]{img/image with spaces.png}
\image[width=50pt, height=100pt]{img/image.png}
\image[width=2.5cm]{img/image.png}
\image[height=2.5cm]{img/image with spaces.png}
\image[width=2.5cm, height=1.5cm]{img/image.png}
\image[width=3cm, height=10pt]{img/image.png}
\image[width=10pt, height=3cm]{img/image with spaces.png}
\image[]{img/image.png}
\image[]{img/image.png}
\image[]{img/image with spaces.png}
\image[]{img/image with spaces.png}
\image[]{img/image.png}
\image[width=2cm]{img/image.png}
\image[width=2cm]{img/image.png}
\image[width=2cm]{img/image.png}
\endsong
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% songs/./musicnote.csg %% songs/./musicnote.csg
@ -117,4 +178,4 @@ guitar,
\end{document} \end{document}

0
test/test_songbook/syntax.yaml → test/test_book/syntax.yaml

BIN
test/test_book/syntax_datadir/img/image with spaces.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

BIN
test/test_book/syntax_datadir/img/image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

35
test/test_book/syntax_datadir/songs/images.csg

@ -0,0 +1,35 @@
{image: image.png}
{image: "image with spaces.png"}
{image: image.png scale=2 }
{image: "image with spaces.png" scale=.20}
{image: image.png scale=1.2}
{image: image.png width=2cm}
{image: "image with spaces.png" height=2cm}
{image: image.png width=2cm height=1cm}
{image: image.png width=2em}
{image: "image with spaces.png" height=2em}
{image: image.png width=2em height=1em}
{image: image.png width=50pt}
{image: "image with spaces.png" height=50pt}
{image: image.png width=50pt height=100pt}
{image: image.png width=2.5cm}
{image: "image with spaces.png" height=2.5cm}
{image: image.png width=2.5cm height=1.5cm}
{image: image.png width=3cm height=10pt}
{image: "image with spaces.png" width=10pt height=3cm}
{image: image.png width= height=}
{image: image.png error=foo}
{image: "image with spaces.png" not_a_size}
{image: "image with spaces.png" too many arguments}
{image: image.png width=2ex height=3km}
{image: image.png width=2cm width=3cm}
{image: image.png width=2cm scale=3cm}
{image: image.png width=2cm scale=3}
{image: }

0
test/test_songbook/syntax_datadir/songs/musicnote.csg → test/test_book/syntax_datadir/songs/musicnote.csg

0
test/test_songbook/test_compilation.py → test/test_book/test_compilation.py

12
test/test_songbook/unicode.tex.control → test/test_book/unicode.tex.control

@ -27,6 +27,7 @@ chorded,
pictures, pictures,
repeatchords, repeatchords,
importantdiagramonly, importantdiagramonly,
diagrampage,
guitar, guitar,
]{patacrep} ]{patacrep}
@ -79,13 +80,12 @@ guitar,
\showindex{\authorindexname}{authidx} \showindex{\authorindexname}{authidx}
% list of chords % list of chords
\ifchorded \ifdiagrampage
\ifdiagram \phantomsection
\phantomsection \addcontentsline{toc}{section}{\chordlistname}
\addcontentsline{toc}{section}{\chordlistname} \chords
\chords
\fi
\fi \fi
\setcounter{songnum}{1}%
\phantomsection \phantomsection
\addcontentsline{toc}{section}{\songlistname} \addcontentsline{toc}{section}{\songlistname}

0
test/test_songbook/unicode.yaml → test/test_book/unicode.yaml

0
test/test_songbook/unicode_datadir/songs/nonbreak.csg → test/test_book/unicode_datadir/songs/nonbreak.csg

0
test/test_song/image with spaces.png

44
test/test_song/image.csg

@ -0,0 +1,44 @@
{lang: en}
{image: "image.png" }
{image: "image with spaces.png" }
{image: "image.png" scale=2}
{image: "image with spaces.png" scale=.20}
{image: "image.png" scale=1.2}
{image: "image.png" width=2cm}
{image: "image with spaces.png" height=2cm}
{image: "image.png" width=2cm height=1cm}
{image: "image.png" width=2em}
{image: "image with spaces.png" height=2em}
{image: "image.png" width=2em height=1em}
{image: "image.png" width=50pt}
{image: "image with spaces.png" height=50pt}
{image: "image.png" width=50pt height=100pt}
{image: "image.png" width=2.5cm}
{image: "image with spaces.png" height=2.5cm}
{image: "image.png" width=2.5cm height=1.5cm}
{image: "image.png" width=3cm height=10pt}
{image: "image with spaces.png" width=10pt height=3cm}
{image: "image.png" }
{image: "image.png" }
{image: "image with spaces.png" }
{image: "image with spaces.png" }
{image: "image.png" }
{image: "image.png" width=2cm}
{image: "image.png" width=2cm}
{image: "image.png" width=2cm}

35
test/test_song/image.csg.source

@ -0,0 +1,35 @@
{image: image.png}
{image: "image with spaces.png"}
{image: image.png scale=2 }
{image: "image with spaces.png" scale=.20}
{image: image.png scale=1.2}
{image: image.png width=2cm}
{image: "image with spaces.png" height=2cm}
{image: image.png width=2cm height=1cm}
{image: image.png width=2em}
{image: "image with spaces.png" height=2em}
{image: image.png width=2em height=1em}
{image: image.png width=50pt}
{image: "image with spaces.png" height=50pt}
{image: image.png width=50pt height=100pt}
{image: image.png width=2.5cm}
{image: "image with spaces.png" height=2.5cm}
{image: image.png width=2.5cm height=1.5cm}
{image: image.png width=3cm height=10pt}
{image: "image with spaces.png" width=10pt height=3cm}
{image: image.png width= height=}
{image: image.png error=foo}
{image: "image with spaces.png" not_a_size}
{image: "image with spaces.png" too many arguments}
{image: image.png width=2ex height=3km}
{image: image.png width=2cm width=3cm}
{image: image.png width=2cm scale=3cm}
{image: image.png width=2cm scale=3}
{image: }

0
test/test_song/image.png

59
test/test_song/image.tsg

@ -0,0 +1,59 @@
\selectlanguage{english}
\beginsong{}[
by={
},
]
\image[]{img/image.png}
\image[]{img/image with spaces.png}
\image[scale=2]{img/image.png}
\image[scale=.20]{img/image with spaces.png}
\image[scale=1.2]{img/image.png}
\image[width=2cm]{img/image.png}
\image[height=2cm]{img/image with spaces.png}
\image[width=2cm, height=1cm]{img/image.png}
\image[width=2em]{img/image.png}
\image[height=2em]{img/image with spaces.png}
\image[width=2em, height=1em]{img/image.png}
\image[width=50pt]{img/image.png}
\image[height=50pt]{img/image with spaces.png}
\image[width=50pt, height=100pt]{img/image.png}
\image[width=2.5cm]{img/image.png}
\image[height=2.5cm]{img/image with spaces.png}
\image[width=2.5cm, height=1.5cm]{img/image.png}
\image[width=3cm, height=10pt]{img/image.png}
\image[width=10pt, height=3cm]{img/image with spaces.png}
\image[]{img/image.png}
\image[]{img/image.png}
\image[]{img/image with spaces.png}
\image[]{img/image with spaces.png}
\image[]{img/image.png}
\image[width=2cm]{img/image.png}
\image[width=2cm]{img/image.png}
\image[width=2cm]{img/image.png}
\endsong

2
test/test_song/metadata.csg

@ -16,7 +16,7 @@
{comment: Comment} {comment: Comment}
{guitar_comment: GuitarComment} {guitar_comment: GuitarComment}
{partition: metadata_lilypond} {partition: metadata_lilypond}
{image: metadata_image} {image: "metadata_image" }
Foo Foo

2
test/test_song/metadata.tsg

@ -20,7 +20,7 @@ Subtitle5}[
\textnote{Comment} \textnote{Comment}
\musicnote{GuitarComment} \musicnote{GuitarComment}
\lilypond{scores/metadata_lilypond} \lilypond{scores/metadata_lilypond}
\image{img/metadata_image} \image[]{img/metadata_image}

13
test/test_song/special.csg

@ -0,0 +1,13 @@
{lang: en}
{title: & $ % # _ \} \{ ~ ^ \\}
{artist: & $ % # _ \} \{ ~ ^ \\}
{album: & $ % # _ \} \{ ~ ^ \\}
{url: http://&$%#_~^}
& $ % \# _ \} \{ ~ ^ \\
{start_of_chorus}
& $ % \# _ \} \{ ~ ^ \\
{end_of_chorus}

10
test/test_song/special.csg.source

@ -0,0 +1,10 @@
{title: & $ % # _ \} \{ ~ ^ \\}
{artist: & $ % # _ \} \{ ~ ^ \\}
{album: & $ % # _ \} \{ ~ ^ \\}
{url: http://&$%#_~^}
& $ % \# _ \} \{ ~ ^ \\
{start_of_chorus}
& $ % \# _ \} \{ ~ ^ \\
{end_of_chorus}

22
test/test_song/special.tsg

@ -0,0 +1,22 @@
\selectlanguage{english}
\beginsong{\& \$ \% \# \_ \} \{ \textasciitilde{} \textasciicircum{} \textbackslash{}}[
by={
\& \$ \% \# \_ \} \{ \textasciitilde{} \textasciicircum{} \textbackslash{} },
album={\& \$ \% \# \_ \} \{ \textasciitilde{} \textasciicircum{} \textbackslash{}},
url={http://&$\%\#_~^},
]
\begin{verse}
\& \$ \% \# \_ \} \{ \textasciitilde{} \textasciicircum{} \textbackslash{}
\end{verse}
\begin{chorus}
\& \$ \% \# \_ \} \{ \textasciitilde{} \textasciicircum{} \textbackslash{}
\end{chorus}
\endsong
Loading…
Cancel
Save