From: Jan Nieuwenhuizen Date: Thu, 5 Feb 2004 22:43:34 +0000 (+0000) Subject: * Documentation/topdocs/NEWS.texi: Add item about lilypond-book. X-Git-Tag: release/2.1.23~83 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=e8313629f67d876c0056a50931887e8a47a8a7cd;p=lilypond.git * Documentation/topdocs/NEWS.texi: Add item about lilypond-book. * Documentation/user/lilypond-book.itely: Update. * make/ly-rules.make: Update lilypond-book commands. * Documentation/user/GNUmakefile: Update makeinfo commands, lilypond-book flags. * scripts/lilypond-book.py: Rewrite (was: filter-lilypond-book.ly). * scripts/old-lilypond-book.py: New file (was: lilypond-book.ly). * scripts/filter-lilypond-book.py: Remove. --- diff --git a/ChangeLog b/ChangeLog index a3c4d5debd..395bebdd31 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2004-02-05 Jan Nieuwenhuizen + + * Documentation/topdocs/NEWS.texi: Add item about lilypond-book. + + * Documentation/user/lilypond-book.itely: Update. + + * make/ly-rules.make: Update lilypond-book commands. + + * Documentation/user/GNUmakefile: Update makeinfo commands, + lilypond-book flags. + + * scripts/lilypond-book.py: Rewrite (was: filter-lilypond-book.ly). + + * scripts/old-lilypond-book.py: New file (was: lilypond-book.ly). + + * scripts/filter-lilypond-book.py: Remove. + + * Documentation/user/*tely: Update options for new lilypond-book. + + * tex/texinfo.tex: New file; from texinfo CVS. This fixes build + with @macros in @includes. + 2004-02-05 Han-Wen Nienhuys * lily/drum-note-performer.cc: new file: perform drum notes. diff --git a/Documentation/topdocs/NEWS.texi b/Documentation/topdocs/NEWS.texi index f6bb7151a9..348a896a3b 100644 --- a/Documentation/topdocs/NEWS.texi +++ b/Documentation/topdocs/NEWS.texi @@ -17,6 +17,16 @@ Version 2.1.13 @end ignore @itemize @bullet + +@item The lilypond-book script has been rewritten. It now supports +running convert-ly on the lilypond snippets like so: +@example + lilypond-book --filter='convert-ly --from=2.0.0' my-book.tely +@end example +It is also twice as short and thrice as fast. The special construct +@code{mbinclude} has been removed, plain @code{@@include} or +@code{\\input} can be used now. + @item The @code{Lyrics} context has been removed. Lyrics should only be constructed in @code{LyricsVoice}. diff --git a/Documentation/user/GNUmakefile b/Documentation/user/GNUmakefile index dea8570b27..4e51ac5e82 100644 --- a/Documentation/user/GNUmakefile +++ b/Documentation/user/GNUmakefile @@ -29,15 +29,10 @@ STEPMAKE_TEMPLATES=tex texinfo omf documentation OMF_FILES += $(outdir)/lilypond-internals.html.omf LOCALSTEPMAKE_TEMPLATES=lilypond ly -LILYPOND_BOOK_FLAGS=--extra-options '-e "(ly:set-option (quote internal-type-checking) \#t)"' +LILYPOND_BOOK_FLAGS = --process="lilypond-bin -I $(srcdir)/input/test -e '(ly:set-option (quote internal-type-checking) \#t)'" include $(depth)/make/stepmake.make -# Ugh,ugh. -# emacs cannot fix the menu structure when @mbinclude is used -# lilypond.tely uses mbinclude -TEXINFO_SOURCES := $(filter-out lilypond.tely, $(TEXINFO_SOURCES)) - dvi: $(DVI_FILES) ps: $(PS_FILES) @@ -67,14 +62,14 @@ extra-local-help: # $(outdir)/%/%.html: $(outdir)/%.texi $(outdir)/lilypond/lilypond.html: $(outdir)/lilypond.texi mkdir -p $(dir $@) - $(MAKEINFO) --output=$(outdir)/lilypond --html $< - $(MAKEINFO) -I $(outdir) --output=$@ --html --no-split --no-headers $< + $(MAKEINFO) -I$(outdir) --output=$(outdir)/lilypond --html $< + $(MAKEINFO) -I$(outdir) --output=$@ --html --no-split --no-headers $< -ln -f $(outdir)/*.png $(outdir)/*.ly $(outdir)/lilypond/ $(outdir)/lilypond-internals/lilypond-internals.html: $(outdir)/lilypond-internals.texi mkdir -p $(dir $@) $(MAKEINFO) --output=$(outdir)/lilypond-internals --html $< - $(MAKEINFO) -I $(outdir) --output=$@ --html --no-split --no-headers $< + $(MAKEINFO) -I$(outdir) --output=$@ --html --no-split --no-headers $< ifeq ($(SPLITTING_MAKEINFO),yes) diff --git a/Documentation/user/cheatsheet.itely b/Documentation/user/cheatsheet.itely index e789f92a6d..44507391dd 100644 --- a/Documentation/user/cheatsheet.itely +++ b/Documentation/user/cheatsheet.itely @@ -13,7 +13,7 @@ @item @code{1 2 8 16} @tab durations @tab -@lilypond[relative 1, notime] +@lilypond[relative=1,notime] \property Staff.autoBeaming = ##f \property Staff.Clef = \turnOff c1 c2 c8 c16 @@ -22,7 +22,7 @@ c1 c2 c8 c16 @item @code{c4. c4..} @tab augmentation dots @tab -@lilypond[relative 1, notime] +@lilypond[relative=1,notime] \property Staff.Clef = \turnOff c4. c4.. @end lilypond @@ -30,14 +30,14 @@ c4. c4.. @item @code{c d e f g a b } @tab scale @tab -@lilypond[relative 1, notime] +@lilypond[relative=1,notime] c d e f g a b @end lilypond @item @code{fis bes} @tab alteration @tab -@lilypond[relative 0, notime] +@lilypond[relative,notime] fis bes @end lilypond @@ -66,7 +66,7 @@ s16_" " @item @code{r4 r8} @tab rest @tab -@lilypond[relative 1, notime] +@lilypond[relative=1,notime] \property Staff.Clef = \turnOff r4 r8 @end lilypond @@ -74,7 +74,7 @@ r4 r8 @item @code{d ~ d} @tab tie @tab -@lilypond[relative 1, notime] +@lilypond[relative=1,notime] \property Score.timing = ##f \property Staff.autoBeaming = ##f d ~ d @@ -92,7 +92,7 @@ s4 @item @var{note}@code{'} @tab raise octave @tab -@lilypond[relative 1, notime] +@lilypond[relative=1,notime] \property Score.timing = ##f \property Staff.autoBeaming = ##f a a' @@ -101,7 +101,7 @@ a a' @item @var{note}@code{,} @tab lower octave @tab -@lilypond[relative 1, notime] +@lilypond[relative=1,notime] \property Score.timing = ##f \property Staff.autoBeaming = ##f c c, @@ -111,7 +111,7 @@ c c, @item @code{c( d e)} @tab slur @tab -@lilypond[fragment, relative 1] +@lilypond[fragment,relative=1] \property Score.timing = ##f \property Staff.TimeSignature = \turnOff \property Staff.autoBeaming = ##f @@ -122,7 +122,7 @@ c( d e) @item @code{c\( c( d) e\)} @tab phrasing slur @tab -@lilypond[fragment, relative 1] +@lilypond[fragment,relative=1] \property Score.timing = ##f \property Staff.TimeSignature = \turnOff \property Staff.autoBeaming = ##f @@ -133,7 +133,7 @@ c\( c( d) e\) @item @code{a8[ b]} @tab beam @tab -@lilypond[fragment, relative 1] +@lilypond[fragment,relative=1] \property Score.timing = ##f \property Staff.TimeSignature = \turnOff \property Staff.autoBeaming = ##f @@ -153,7 +153,7 @@ a8-[ b-] @item @code{c-> c-.} @tab articulations @tab -@lilypond[fragment, relative 1] +@lilypond[fragment,relative=1] \property Staff.TimeSignature = \turnOff c-> c-. @end lilypond @@ -162,7 +162,7 @@ c-> c-. @item @code{c\mf c\sfz} @tab dynamics @tab -@lilypond[fragment, relative 1] +@lilypond[fragment,relative=1] \property Staff.TimeSignature = \turnOff c\mf c\sfz @end lilypond @@ -171,7 +171,7 @@ c\mf c\sfz @item @code{a\< b\!} @tab crescendo @tab -@lilypond[fragment, relative 1] +@lilypond[fragment,relative=1] \property Score.timing = ##f \property Staff.TimeSignature = \turnOff \property Staff.autoBeaming = ##f @@ -181,7 +181,7 @@ a\< a \!a @item @code{a\> b\!} @tab decrescendo @tab -@lilypond[fragment, relative 1] +@lilypond[fragment,relative=1] \property Score.timing = ##f \property Staff.TimeSignature = \turnOff \property Staff.autoBeaming = ##f @@ -192,7 +192,7 @@ a\> a a\! @item @code{< >} @tab chord @tab -@lilypond[fragment, relative 1] +@lilypond[fragment,relative=1] @end lilypond @@ -200,7 +200,7 @@ a\> a a\! @item @code{\partial 8} @tab upstep @tab -@lilypond[fragment,relative 1] +@lilypond[fragment,relative=1] \partial 8 f8 c2 d e @end lilypond @@ -209,7 +209,7 @@ a\> a a\! @item @code{\times 2/3 @{f g a@}} @tab triplets @tab -@lilypond[relative 1,fragment] +@lilypond[relative=1,fragment] \times 2/3 { f8 g a } @end lilypond @@ -217,7 +217,7 @@ a\> a a\! @item @code{\grace} @tab grace notes @tab -@lilypond[relative 1,fragment] +@lilypond[relative=1,fragment] \context Voice { \grace b16 c4 } @end lilypond @@ -232,7 +232,7 @@ a\> a a\! @item @code{twin -- kle} @tab lyric hyphen @tab -@lilypond[fragment,relative 1] +@lilypond[fragment,relative=1] \notes { g'4 g } \lyricsto "" \new LyricsVoice \lyrics { twin -- kle } @end lilypond @@ -240,21 +240,21 @@ a\> a a\! @item @code{\chords @{ c:dim f:maj7 @}} @tab chords @tab -@lilypond[fragment,relative 1] +@lilypond[fragment,relative=1] \chords { c:dim f:maj7 } @end lilypond @item @code{\context ChordNames} @tab printing chord names @tab -@lilypond[fragment,relative 1] +@lilypond[fragment,relative=1] \context ChordNames \chords { c:dim f:maj7 } @end lilypond @item @code{<<@{e f@} \\@{c d@}>>} @tab polyphony @tab -@lilypond[fragment,relative 2] +@lilypond[fragment,relative=2] \context Staff <<{e f} \\ {c d}>> @end lilypond diff --git a/Documentation/user/internals.itely b/Documentation/user/internals.itely index ac46967e20..9a0a738c4f 100644 --- a/Documentation/user/internals.itely +++ b/Documentation/user/internals.itely @@ -168,7 +168,7 @@ This means that @var{musicexpr} should be interpreted within a context of type @var{contexttype} (with name @var{contextname} if specified). If no such context exists, it will be created: -@lilypond[verbatim,singleline] +@lilypond[verbatim,raggedright] \score { \notes \relative c'' { c4 <> f @@ -213,7 +213,7 @@ the following example, only the sequential expression has an explicit context. The notes contained therein inherit the @code{goUp} context from the enclosing music expression. -@lilypond[verbatim,singleline] +@lilypond[verbatim,raggedright] \notes \context Voice = goUp { c'4 d' e' } @end lilypond @@ -221,7 +221,7 @@ from the enclosing music expression. Second, contexts are created automatically to be able to interpret the music expressions. Consider the following example: -@lilypond[verbatim, singleline] +@lilypond[verbatim,raggedright] \score { \notes { c'4-( d' e'-) } } @end lilypond @@ -439,7 +439,7 @@ system. In the following example, the @code{Clef_engraver} is removed from the Staff context. The result is a staff without a clef, where the central C is at its default position, the center line: -@lilypond[verbatim,singleline] +@lilypond[verbatim,raggedright] \score { \notes { c'4 f'4 @@ -887,7 +887,7 @@ properties using the functions @code{ly:get-mus-property} and An example is a function that reverses the order of elements in its argument: -@lilypond[verbatim,singleline] +@lilypond[verbatim,raggedright] #(define (rev-music-1 m) (ly:set-mus-property! m 'elements (reverse (ly:get-mus-property m 'elements))) diff --git a/Documentation/user/lilypond-book.itely b/Documentation/user/lilypond-book.itely index c700d59683..220796f7f0 100644 --- a/Documentation/user/lilypond-book.itely +++ b/Documentation/user/lilypond-book.itely @@ -59,18 +59,18 @@ Short Introduction to LaTeX} provides a introction to using La@TeX{}. Music is specified like this: @example -@@lilypond[options, go, here] +@@lilypond[options,go,here] YOUR LILYPOND CODE @@end lilypond -@@lilypond[options, go, here]@{ YOUR LILYPOND CODE @} -@@lilypondfile[options, go, here]@{@var{filename}@} +@@lilypond[options,go,here]@{ YOUR LILYPOND CODE @} +@@lilypondfile[options,go,here]@{@var{filename}@} @end example When lilypond-book is run on it, this results in a texinfo file. We show two simple examples here. First a complete block: @example -@@lilypond[26pt] +@@lilypond[staffsize=26] c' d' e' f' g'2 g' @@end lilypond @end example @@ -85,31 +85,17 @@ produces Then the short version: @example -@@lilypond[11pt]@{@} +@@lilypond[staffsize=11]@{@} @end example @noindent produces -@lilypond[11pt]{ } - -@command{lilypond-book} knows the default margins and a few paper -sizes. One of these commands should be in the beginning of the document: - -@itemize @bullet -@item @code{@@afourpaper} -@item @code{@@afourlatex} -@item @code{@@afourwide} -@item @code{@@smallbook} -@end itemize - -@noindent -@code{@@pagesizes} are not yet supported. +@lilypond[staffsize=11]{ } When producing texinfo, lilypond-book also generates bitmaps of the music, so you can make a HTML document with embedded music. - @c @TeX{} in node name seems to barf @node Integrating LaTeX and music @section Integrating LaTeX and music @@ -118,13 +104,13 @@ music, so you can make a HTML document with embedded music. For La@TeX{}, music is entered using @example -\begin[options, go, here]@{lilypond@} +\begin[options,go,here]@{lilypond@} YOUR LILYPOND CODE \end@{lilypond@} @end example @example -\lilypondfile[options, go,here]@{@var{filename}@} +\lilypondfile[options,go,here]@{@var{filename}@} @end example @noindent @@ -141,7 +127,7 @@ La@TeX{}. We show some examples here: @example -\begin[26pt]@{lilypond@} +\begin[staffsize=26]@{lilypond@} c' d' e' f' g'2 g'2 \end@{lilypond@} @end example @@ -149,20 +135,20 @@ We show some examples here: @noindent produces -@lilypond[26pt] +@lilypond[staffsize=26] c' d' e' f' g'2 g'2 @end lilypond Then the short version: @example -\lilypond[11pt]@{@} +\lilypond[staffsize=11]@{@} @end example @noindent produces -@lilypond[11pt]{} +@lilypond[staffsize=11]{} The linewidth of the music will be adjust by examining the commands in the document preamble, the part of the document before @@ -171,9 +157,12 @@ La@TeX{} to find out how wide the text is. The line width variable for the music fragments are adjusted to the text width. After @code{\begin@{document@}}, the column changing commands -@code{\onecolumn} , @code{\twocolumn} commands and the -@code{multicols} environment from the multicol package are also -interpreted. +@code{\onecolumn}, @code{\twocolumn} commands +@ignore +and the +@code{multicols} environment from the multicol package +@end ignore +are also interpreted. The titling from the @code{\header} section of the fragments can be imported by adding the following to the top of the La@TeX{} file: @@ -219,7 +208,7 @@ PDF can then be produced with @code{ps2pdf}. Music is entered using @example - + \key c \minor r8 c16 b c8 g as c16 b c8 d | g,4 @end example @@ -229,12 +218,12 @@ of which lilypond-book will produce a HTML with appropriate image tags for the music fragments: @example - + \key c \minor r8 c16 b c8 g as c16 b c8 d | g,4 @end example -@lilypond[relative1] +@lilypond[relative=1] \key c \minor r8 c16 b c8 g as c16 b c8 d | g,4 @end lilypond @@ -272,62 +261,23 @@ the short version of the music blocks: @code{ @@lilypond@{ CONTENTS @} } and @code{ \lilypond@{ CONTENTS @} } -@item smallverbatim -works like @code{verbatim}, but in a smaller font. - -@item intertext="@var{text}" -is used in conjunction with @code{verbatim} option: This puts -@var{text} between the code and the music (without indentation). - @item filename=@var{filename} name the file (for @code{printfilename} option). The argument should be unquoted. -@item 11pt -@lilypond[11pt] -\relative c' { - r16 c[ d e] f[ d e c] g'8[ c] b[\prall c] | - d16[ g, a b] c[ a b g] d'8[ g f\prall g] -} -@end lilypond - -@item 13pt -@lilypond[13pt] +@item staffsize=POINTS +@lilypond[staffsize=31.41592658] \relative c' { r16 c[ d e] f[ d e c] g'8[ c] b[\prall c] | d16[ g, a b] c[ a b g] d'8[ g f\prall g] } @end lilypond -@item 16pt -@lilypond[16pt] -\relative c' { - r16 c[ d e] f[ d e c] g'8[ c] b[\prall c] | -} -@end lilypond - -@item 20pt -@lilypond[20pt] -\relative c' { - r16 c[ d e] f[ d e c] g'8[ c] b[\prall c] | -} -@end lilypond - -@item 26pt -@lilypond[26pt] -\relative c' { - r16 c[ d e] f[ d e c] g'8[ c] b[\prall c] | -} -@end lilypond - @item raggedright produces naturally spaced lines (i.e., @code{raggedright = ##t}); this works well for small music fragments. -@item multiline -is the opposite of @code{singleline}: it justifies and breaks lines. - -@item linewidth=@var{size}@var{unit} +@item linewidth=@var{size}\\@var{unit} sets linewidth to @var{size}, where @var{unit} = cm, mm, in, or pt. This option affects LilyPond output, not the text layout. @@ -335,11 +285,11 @@ This option affects LilyPond output, not the text layout. prevents printing time signature. @item fragment -@itemx nofragment +@item nofragment overrides @command{lilypond-book} auto detection of what type of code is in the LilyPond block, voice contents or complete code. -@item indent=@var{size}@var{unit} +@item indent=@var{size}\\@var{unit} sets indentation of the first music system to @var{size}, where @var{unit} = cm, mm, in, or pt. This option affects LilyPond, not the text layout. For single-line fragments the default is to @@ -347,7 +297,7 @@ use no indentation. For example @example - \begin[indent=5cm,raggedright]@{lilypond@} + \begin[indent=\\5cm,raggedright]@{lilypond@} ... \end@{lilypond@} @end example @@ -371,15 +321,7 @@ documents are composed from small @file{.ly} files in this way: \score @{ \notes @{ c'4 @} @} @end example -@item quote -instructs @command{lilypond-book} to put La@TeX{} and Texinfo output -into a quotation block. - -@item printfilename -prints the file name before the music example. Useful in conjunction -with @code{\lilypondfile}. - -@item relative, relative @var{N} +@item relative, relative=@var{N} uses relative octave mode. By default, notes are specified relative central C. The optional integer argument specifies the octave of the starting note, where the default @code{1} is central C. @@ -398,12 +340,12 @@ cd out && lilypond-book ../yourfile.tex @end example @noindent -or to use the @option{--outdir} command line option, and change to +or to use the @option{--output} command line option, and change to that director before running La@TeX{} or @file{makeinfo}: @example -lilypond-book --outdir=out yourfile.tex -cd out && latex yourfile.latex +lilypond-book --output=out yourfile.lytex +cd out && latex yourfile.tex @end example @@ -420,46 +362,34 @@ fragments in the DVI output only. For getting images in the HTML version, the format @code{texi-html} must be used. -@item @option{--default-music-fontsize=@var{sz}pt} -Set the music font size to use if no fontsize is given as option. +@item @option{-F @var{filter}}, @option{--filter=@var{filter}} +Pipe snippets through @var{filter}. -@item @option{--force-music-fontsize=@var{sz}pt} -Force all music to use this fontsize, overriding options given to -@code{\begin@{lilypond@}}. +For example: +@example + lilypond-book --filter='convert-ly --from=2.0.0' my-book.tely +@end example + +@item @option{--help} +Print a short help message. @item @option{-I @var{dir}}, @option{--include=@var{dir}} Add @var{DIR} to the include path. -@item @option{-M}, @option{--dependencies} -Write dependencies to @file{filename.dep}. - -@item @option{--dep-prefix=@var{pref}} -Prepend @var{pref} before each @option{-M} dependency. - -@item @option{-n}, @option{--no-lily} -Generate the @code{.ly} files, but do not process them. - -@item @option{--no-music} -Strip all music from the input file. +@item @option{-o @var{dir}}, @option{--output=@var{dir}} +Place generated files in @var{dir}. -@item @option{--no-pictures} -Do not generate pictures when processing Texinfo. +@item @option{-P @var{process}}, @option{--process=@var{COMMAND}} +Process lilypond snippets using @var{command}. The default command is +@var{lilypon-bin}. -@item @option{--outname=@var{file}} -The name of La@TeX{} file to output. If this option is not given, -the output name is derived from the input name. - -@item @option{--outdir=@var{dir}} -Place generated files in @var{dir}. +@item @option{--verbose} +Be verbose. @item @option{--version} Print version information. - -@item @option{--help} -Print a short help message. @end table - For La@TeX{} input, the file to give to La@TeX{} has extension @file{.latex}. Texinfo input will be written to a file with extension @file{.texi}. @@ -475,11 +405,10 @@ La@TeX{} commands that change margins and line widths are ignored. Only the first @code{\score} of a LilyPond block is processed. +@c CHECKME--FIXME The size of a music block is limited to 1.5 kb, due to technical -problems with the Python regular expression engine. For longer files, -use @code{\lilypondfile}. Using @code{\lilypondfile} also makes -upgrading files (through convert-ly, see @ref{Invoking convert-ly}) -easier. +problems with the Python regular expression engine. For longer files, +use @code{\lilypondfile}. @command{lilypond-book} processes all music fragments in one big run. The state of the GUILE interpreter is not reset between fragments; diff --git a/Documentation/user/lilypond.tely b/Documentation/user/lilypond.tely index c891847585..2ef34d8d10 100644 --- a/Documentation/user/lilypond.tely +++ b/Documentation/user/lilypond.tely @@ -5,8 +5,6 @@ @afourpaper @end iftex - - @ignore Distributions will want to install lilypond.info doing: @@ -93,17 +91,18 @@ Copyright @copyright{} 1999--2003 by the authors @vskip 20pt -@lilypond[singleline] -\score { \context LyricsVoice \notes { - \property Score.RehearsalMark \set #'self-alignment-X = #LEFT - -\mark #(ly:export (string-append "(For LilyPond version " -(lilypond-version) ")")) -s2 - } - \paper { indent = 0.0\pt - raggedright = ##t - } +@lilypond[raggedright] +\score { + \context LyricsVoice \notes { + \property Score.RehearsalMark \set #'self-alignment-X = #LEFT + \mark #(ly:export (string-append + "(For LilyPond version " (lilypond-version) ")")) + s2 + } + \paper { + indent = 0.0\pt + raggedright = ##t + } } @end lilypond @@ -140,7 +139,7 @@ A further source of information is the website, which can be found at @uref{http://www.lilypond.org/}. The website contains on-line copies of this and other documentation. -@mbinclude dedication.itely +@include dedication.itely @menu * Preface:: Preface. @@ -160,19 +159,19 @@ this and other documentation. @end menu @end ifnottex - @contents -@mbinclude macros.itexi -@mbinclude preface.itely -@mbinclude introduction.itely -@mbinclude tutorial.itely -@mbinclude refman.itely -@mbinclude literature.itely -@mbinclude internals.itely -@mbinclude invoking.itexi -@mbinclude lilypond-book.itely -@mbinclude converters.itely + +@include macros.itexi +@include preface.itely +@include introduction.itely +@include tutorial.itely +@include refman.itely +@include literature.itely +@include internals.itely +@include invoking.itexi +@include lilypond-book.itely +@include converters.itely @c FIXME: Index has two alphabetically sorted lists @code vs plain? @@ -181,8 +180,8 @@ this and other documentation. @printindex cp -@mbinclude appendices.itely -@mbinclude cheatsheet.itely -@mbinclude fdl.itexi +@include appendices.itely +@include cheatsheet.itely +@include fdl.itexi @bye diff --git a/Documentation/user/macros.itexi b/Documentation/user/macros.itexi index c0000cc179..36693d24d7 100644 --- a/Documentation/user/macros.itexi +++ b/Documentation/user/macros.itexi @@ -1,6 +1,5 @@ @c -*-texinfo-*- - @c Reference GLOSsary @macro rglos {NAME} @ifhtml @@ -157,3 +156,4 @@ internals document, @internalsref{\NAME\} @heading Syntax @end macro + diff --git a/Documentation/user/music-glossary.tely b/Documentation/user/music-glossary.tely index 1892d96a4e..635be7a5cb 100644 --- a/Documentation/user/music-glossary.tely +++ b/Documentation/user/music-glossary.tely @@ -955,7 +955,7 @@ also the contrapunctal technique used in the @emph{fugue} which, since the music of the baroque era, has been one of the most popular polyphonic composition methods. -@lilypond[11pt,noquote] +@lilypond[staffsize=11,noquote] \property Score.TimeSignature \override #'style = #'() \notes\context PianoStaff << \context Staff = SA \relative c' { @@ -1176,7 +1176,7 @@ of a piano keybord are diatonic. The church modes are used in gregorial chant and pre baroque early music but also to some extent in newer jazz music. -@lilypond[notime,linewidth=110mm] +@lilypond[notime,linewidth=110\mm] \property Score.automaticBars = ##f %\property Score.LyricText \set #'font-style = #'large %\property Score.TextScript \set #'font-style = #'large diff --git a/Documentation/user/refman.itely b/Documentation/user/refman.itely index aa53ce929a..ace7cf0593 100644 --- a/Documentation/user/refman.itely +++ b/Documentation/user/refman.itely @@ -112,7 +112,7 @@ Half-flats and half-sharps are formed by adding @code{-eh} and @cindex quarter tones @cindex semi-flats, semi-sharps -@lilypond[verbatim,relative 2] +@lilypond[verbatim,relative=2] ceses4 ceseh ces @@ -213,7 +213,7 @@ articulations, just like simple notes. Rests are entered like notes, with the note name @code{r}: -@lilypond[singleline,verbatim] +@lilypond[raggedright,verbatim] r1 r2 r4 r8 @end lilypond @@ -227,7 +227,7 @@ note with the @code{\rest} keyword appended. This makes manual formatting in polyphonic music easier. Rest collision testing will leave these rests alone: -@lilypond[singleline,verbatim] +@lilypond[raggedright,verbatim] a'4\rest d'4\rest @end lilypond @@ -246,14 +246,14 @@ Internals: @internalsref{RestEvent}, and @internalsref{Rest}. An invisible rest (also called a `skip') can be entered like a note with note name `@code{s}' or with @code{\skip @var{duration}}: -@lilypond[singleline,verbatim] +@lilypond[raggedright,verbatim] a2 s4 a4 \skip 1 a4 @end lilypond The @code{s} syntax is only available in Note mode and Chord mode. In other situations, you should use the @code{\skip} command: -@lilypond[singleline,verbatim] +@lilypond[raggedright,verbatim] \score { \new Staff << { \time 4/8 \skip 2 \time 4/4 } @@ -332,7 +332,7 @@ appending `@code{*}@var{N/M}' (or `@code{*}@var{N}' if @var{M=1}). This will not affect the appearance of the notes or rests produced. In the following example, the first three notes take up exactly two beats: -@lilypond[fragment,relative 2,verbatim] +@lilypond[fragment,relative=2,verbatim] \time 2/4 a4*2/3 gis4*2/3 a4*2/3 a4 @@ -396,7 +396,7 @@ In its meaning a tie is just a way of extending a note duration, similar to the augmentation dot; in the following example there are two ways of notating exactly the same concept: @c -@lilypond[fragment, singleline,quote] +@lilypond[fragment,raggedright,quote] \time 3/4 c'2. c'2 ~ c'4 @end lilypond If you need to tie a lot of notes over bars, it may be easier to use automatic @@ -471,7 +471,7 @@ typing @code{\times} only once, saving lots of typing. In the next example, there are two triplets shown, while @code{\times} was only used once: -@lilypond[fragment, relative, singleline, verbatim] +@lilypond[fragment,relative,raggedright,verbatim] \property Voice.tupletSpannerDuration = #(ly:make-moment 1 4) \times 2/3 { c'8 c c c c c } @end lilypond @@ -565,7 +565,7 @@ an absolute starting pitch must be specified that will act as the predecessor of the first note of @var{musicexpr}. Here is the relative mode shown in action: -@lilypond[fragment,singleline,verbatim,center] +@lilypond[fragment,raggedright,verbatim,center] \relative c'' { b c d c b c bes a } @@ -699,7 +699,7 @@ typesetting is switched off, the music is processed much more quickly. This can be used to skip over the parts of a score that have already been checked for errors: -@lilypond[fragment,singleline,verbatim] +@lilypond[fragment,raggedright,verbatim] \relative c'' { c8 d \property Score.skipTypesetting = ##t e f g a g c, f e d @@ -1039,7 +1039,7 @@ Automatic beaming does not use measure grouping specified with Partial measures, for example in upsteps, are entered using the @code{\partial} command: -@lilypond[fragment,verbatim,relative 1] +@lilypond[fragment,verbatim,relative=1] \partial 16*5 c16 cis d dis e | a2. c,4 | b2 @end lilypond @@ -1094,7 +1094,7 @@ of barlines can be forced with the @code{\bar} command: @end lilypond The following bar types are available: -@lilypond[fragment, relative, singleline, verbatim] +@lilypond[fragment,relative,raggedright,verbatim] c4 \bar "|" c \bar "" c @@ -1118,7 +1118,7 @@ In scores with many staves, a @code{\bar} command in one staff is automatically applied to all staves. The resulting bar lines are connected between different staves of a @internalsref{StaffGroup}: @c -@lilypond[fragment, verbatim] +@lilypond[fragment,verbatim] << \context StaffGroup << \new Staff { e'4 d' \bar "||" @@ -1198,7 +1198,7 @@ by hand, and using @code{\voiceOne}, up to @code{\voiceFour} to assign a stem directions and horizontal shift for each part: @c -@lilypond[singleline, verbatim] +@lilypond[raggedright,verbatim] \relative c'' \context Staff << \new Voice { \voiceOne cis2 b } \new Voice { \voiceThree b4 ais ~ ais4 gis4 } @@ -1213,7 +1213,7 @@ The command @code{\oneVoice} will revert back to the normal setting. Normally, note heads with a different number of dots are not merged, but when the object property @code{merge-differently-dotted} is set in the @internalsref{NoteCollision} object, they are merged: -@lilypond[verbatim,fragment,singleline] +@lilypond[verbatim,fragment,raggedright] \relative c'' \context Voice << { g8 g8 \property Staff.NoteCollision \override @@ -1225,7 +1225,7 @@ the @internalsref{NoteCollision} object, they are merged: Similarly, you can merge half note heads with eighth notes, by setting @code{merge-differently-headed}: -@lilypond[fragment, relative=2,verbatim] +@lilypond[fragment,relative=2,verbatim] \context Voice << { c8 c4. \property Staff.NoteCollision @@ -1236,7 +1236,7 @@ Similarly, you can merge half note heads with eighth notes, by setting LilyPond also vertically shifts rests that are opposite of a stem: -@lilypond[singleline,fragment,verbatim] +@lilypond[raggedright,fragment,verbatim] \context Voice << c''4 \\ r4 >> @end lilypond @@ -1307,7 +1307,7 @@ notation (see @ref{Clusters}). Beams are used to group short notes into chunks that are aligned with the metrum. They are inserted automatically in most cases: -@lilypond[fragment,verbatim, relative=2] +@lilypond[fragment,verbatim,relative=2] \time 2/4 c8 c c c \time 6/8 c c c c8. c16 c8 @end lilypond @@ -1496,7 +1496,7 @@ In the example below, the autobeamer makes eight beams and sixteenth end at 3 eights; the third beam can only be corrected by specifying manual beaming. -@lilypond[singleline,fragment,relative,noverbatim,quote] +@lilypond[raggedright,fragment,relative,noverbatim,quote] \property Voice.autoBeamSettings \override #'(end * * * *) = #(ly:make-moment 3 8) % rather show case where it goes wrong @@ -1548,7 +1548,7 @@ creation of the piano staff: >> @} @end example -@lilypond[singleline] +@lilypond[raggedright] \score { \notes \relative c'' << \new Staff { cis4 d e2 } @@ -1588,7 +1588,7 @@ rule is similar to @code{\defaultAccidentals}. This leads to some weird and often unwanted results because accidentals from one voice do not get cancelled in other voices: -@lilypond[singleline,relative,fragment,verbatim,quote] +@lilypond[raggedright,relative,fragment,verbatim,quote] \context Staff << \voiceAccidentals << @@ -1610,7 +1610,7 @@ instead. You get all the same accidentals, but temporary accidentals also get cancelled in other octaves. Furthermore, in the same octave, they also get cancelled in the following measure: -@lilypond[singleline,fragment,verbatim] +@lilypond[raggedright,fragment,verbatim] \modernAccidentals cis' c'' cis'2 | c'' c' @end lilypond @@ -1621,7 +1621,7 @@ instead. ``extra'' accidentals (the ones not typeset by @code{\defaultAccidentals}) are typeset as cautionary accidentals. They are printed in reduced size or with parentheses: -@lilypond[singleline,fragment,verbatim] +@lilypond[raggedright,fragment,verbatim] \modernCautionaries cis' c'' cis'2 | c'' c' @end lilypond @@ -1657,7 +1657,7 @@ some of them are typeset as cautionaries. @cindex @code{\noResetKey} Same as @code{\defaultAccidentals} but with accidentals lasting ``forever'' and not only until the next measure: -@lilypond[singleline,fragment,verbatim,relative] +@lilypond[raggedright,fragment,verbatim,relative] \noResetKey c1 cis cis c @end lilypond @@ -1668,7 +1668,7 @@ some of them are typeset as cautionaries. are not remembered at all---and hence all accidentals are typeset relative to the key signature, regardless of what was before in the music: -@lilypond[singleline,fragment,verbatim,relative] +@lilypond[raggedright,fragment,verbatim,relative] \forgetAccidentals \key d\major c4 c cis cis d d dis dis @end lilypond @@ -1745,7 +1745,7 @@ This example shows two examples of the same music giving different accidentals depending on the order in which the notes occur in the input file: -@lilypond[singleline,fragment,verbatim] +@lilypond[raggedright,fragment,verbatim] \property Staff.autoAccidentals = #'( Staff (any-octave . 0) ) cis'4 r2 | cis'4 r2 | r | r | @@ -1786,7 +1786,7 @@ A slur indicates that notes are to be played bound or @emph{legato}. @syntax They are entered using parentheses: -@lilypond[relative 1,fragment,verbatim,center] +@lilypond[relative=1,fragment,verbatim,center] f( g)( a) a8 b( a4 g2 f4) 2( 2) @end lilypond @@ -1987,7 +1987,7 @@ To use this, add the @internalsref{Horizontal_bracket_engraver} to @internalsref{Staff} context. A bracket is started with @code{\startGroup} and closed with @code{\stopGroup}: -@lilypond[singleline,verbatim] +@lilypond[raggedright,verbatim] \score { \notes \relative c'' { c4\startGroup\startGroup c4\stopGroup @@ -2029,7 +2029,7 @@ The meanings of these shorthands can be changed: see The script is automatically placed, but if you need to force directions, you can use @code{_} to force them down, or @code{^} to put them up: -@lilypond[fragment, verbatim] +@lilypond[fragment,verbatim] c''4^^ c''4_^ @end lilypond @@ -2038,7 +2038,7 @@ Other symbols can be added using the syntax can be forced up or down using @code{^} and @code{_}, eg. -@lilypond[verbatim,fragment,relative 2] +@lilypond[verbatim,fragment,relative=2] c\fermata c^\fermata c_\fermata @end lilypond @@ -2106,7 +2106,7 @@ Fingering instructions can be entered using @end example For finger changes, use markup texts: @c -@lilypond[verbatim, singleline, fragment] +@lilypond[verbatim,raggedright,fragment] c'4-1 c'4-2 c'4-3 c'4-4 c'^\markup { \fontsize #-3 \number "2-3" } @end lilypond @@ -2119,14 +2119,14 @@ For finger changes, use markup texts: You can use the thumb-script to indicate that a note should be played with the thumb (e.g. in cello music): -@lilypond[verbatim, singleline, fragment] +@lilypond[verbatim,raggedright,fragment] 8(_\thumb )_\thumb (_\thumb )_\thumb @end lilypond Fingerings for chords can also be added to individual notes of the chord by adding them after the pitches: -@lilypond[verbatim,singleline,fragment,relative=1] +@lilypond[verbatim,raggedright,fragment,relative=1] < c-1 e-2 g-3 b-5 > 4 @end lilypond @@ -2134,7 +2134,7 @@ of the chord by adding them after the pitches: In this case, setting @code{fingeringOrientations} will put fingerings next to note heads: -@lilypond[verbatim,singleline,fragment,relative=1] +@lilypond[verbatim,raggedright,fragment,relative=1] \property Voice.fingeringOrientations = #'(left down) 4 \property Voice.fingeringOrientations = #'(up right down) @@ -2163,7 +2163,7 @@ It is possible to place arbitrary strings of text or markup text (see note spacing, but by using the command @code{\fatText}, the widths will be taken into account: @c -@lilypond[fragment,singleline,verbatim] \relative c' { +@lilypond[fragment,raggedright,verbatim] \relative c' { c4^"longtext" \fatText c4_"longlongtext" c4 } @end lilypond @@ -2229,7 +2229,7 @@ time. Every point in time consists of two rational numbers: one denotes the logical time, one denotes the grace timing. The above example is shown here with timing tuples: -@lilypond[singleline] +@lilypond[raggedright] << \relative c''{ c4 \grace c16 c4 \grace { @@ -2262,7 +2262,7 @@ every eighth grace note: If you want to end a note with a grace, then the standard trick is to put the grace notes after a ``space note'', e.g. -@lilypond[fragment,verbatim, relative=2] +@lilypond[fragment,verbatim,relative=2] \context Voice { << { d1^\trill ( } { s2 \grace { c16[ d] } } >> @@ -2279,7 +2279,7 @@ A @code{\grace} section will introduce special typesetting settings, for example, to produce smaller type, and set directions. Hence, when introducing layout tweaks, they should be inside the grace section, for example, -@lilypond[fragment,verbatim,relative 1] +@lilypond[fragment,verbatim,relative=1] \new Voice { \acciaccatura { \property Voice.Stem \override #'direction = #-1 @@ -2396,7 +2396,7 @@ note: @code{c4\ff}. The available dynamic marks are @code{\ppp}, @code{\fff}, @code{\fff}, @code{\fp}, @code{\sf}, @code{\sff}, @code{\sp}, @code{\spp}, @code{\sfz}, and @code{\rfz}: -@lilypond[verbatim,singleline,fragment,relative] +@lilypond[verbatim,raggedright,fragment,relative] c'\ppp c\pp c \p c\mp c\mf c\f c\ff c\fff c2\sf c\rfz @end lilypond @@ -2547,21 +2547,21 @@ give enough alternatives for all of the repeats, then the first alternative is assumed to be played more than once. Normal notation repeats are used like this: -@lilypond[fragment,verbatim,relative 1] +@lilypond[fragment,verbatim,relative=1] c1 \repeat volta 2 { c4 d e f } \repeat volta 2 { f e d c } @end lilypond With alternative endings: -@lilypond[fragment,verbatim,relative 1] +@lilypond[fragment,verbatim,relative=1] c1 \repeat volta 2 {c4 d e f} \alternative { {d2 d} {f f,} } @end lilypond -@lilypond[fragment,verbatim,relative 1] +@lilypond[fragment,verbatim,relative=1] \context Staff { \partial 4 \repeat volta 4 { e | c2 d2 | e2 f2 | } @@ -2626,7 +2626,7 @@ alphabetic characters. Or, stops a running volta bracket: @end table -@lilypond[verbatim, fragment,relative 2] +@lilypond[verbatim,fragment,relative=2] c4 \property Score.repeatCommands = #'((volta "93") end-repeat) c4 c4 @@ -2648,7 +2648,7 @@ Internals: @internalsref{VoltaBracket}, @internalsref{RepeatedMusic}, To place tremolo marks between notes, use @code{\repeat} with tremolo style: -@lilypond[verbatim,singleline] +@lilypond[verbatim,raggedright] \score { \context Voice \notes\relative c' { \repeat "tremolo" 8 { c16 d16 } @@ -2660,7 +2660,7 @@ style: Tremolo marks can also be put on a single note. In this case, the note should not be surrounded by braces. -@lilypond[verbatim,singleline] +@lilypond[verbatim,raggedright] \repeat "tremolo" 4 c16 @end lilypond @@ -2716,7 +2716,7 @@ printed once, and then the pattern is replaced with a special sign. Patterns of a one and two measures are replaced by percent-like signs, patterns that divide the measure length are replaced by slashes: -@lilypond[verbatim,singleline] +@lilypond[verbatim,raggedright] \context Voice { \repeat "percent" 4 { c'4 } \repeat "percent" 2 { c'2 es'2 f'4 fis'4 g'4 c''4 } } @@ -2735,8 +2735,8 @@ Internals: @internalsref{RepeatSlash}, @internalsref{PercentRepeat}, @menu +* Showing melody rhythms:: * Percussion staves:: -* Percussion MIDI output:: @end menu @@ -2776,7 +2776,7 @@ Percussion notes may be entered in @code{\drums} mode, which is similar to @code{notes}. Each piece of percussion has a full name and an abbreviated name, and both be used in input files: -@lilypond[singleline] +@lilypond[raggedright] \drums { hihat4 hh4 } @end lilypond @@ -2784,7 +2784,7 @@ To typeset the music, the notes must be interpreted in a @internalsref{DrumStaff} and @internalsref{DrumVoice} contexts: @c -@lilypond[singleline,verbatim,quote] +@lilypond[raggedright,verbatim,quote] up = \drums { crashcymbal4 hihat8 halfopenhihat hh hh hh openhihat } down = \drums { bassdrum4 snare8 bd r bd sn4 } \score { @@ -2833,7 +2833,7 @@ the three middle lines you use @code{tommh}, @code{tomml} and @item timbales-style to typeset timbales on a two line staff: -@lilypond[singleline] +@lilypond[raggedright] nam = \lyrics { timh ssh timl ssl cb } mus = \drums { timh ssh timl ssl cb s16 } \score { @@ -2855,7 +2855,7 @@ mus = \drums { timh ssh timl ssl cb s16 } @item congas-style to typeset congas on a two line staff: -@lilypond[singleline] +@lilypond[raggedright] nam = \lyrics { cgh cgho cghm ssh cgl cglo cglm ssl } mus = \drums { cgh cgho cghm ssh cgl cglo cglm ssl s16 } \score { @@ -2878,7 +2878,7 @@ mus = \drums { cgh cgho cghm ssh cgl cglo cglm ssl s16 } @item bongos-style to typeset bongos on a two line staff: -@lilypond[singleline] +@lilypond[raggedright] nam = \lyrics { boh boho bohm ssh bol bolo bolm ssl } mus = \drums { boh boho bohm ssh bol bolo bolm ssl s16 } \score { @@ -2901,7 +2901,7 @@ mus = \drums { boh boho bohm ssh bol bolo bolm ssl s16 } @item percussion-style to typeset all kinds of simple percussion on one line staves: -@lilypond[singleline] +@lilypond[raggedright] nam = \lyrics { tri trio trim gui guis guil cb cl tamb cab mar hc } mus = \drums { tri trio trim gui guis guil cb cl tamb cab mar hc s16 } \score { @@ -2923,7 +2923,7 @@ mus = \drums { tri trio trim gui guis guil cb cl tamb cab mar hc s16 } If you do not like any of the predefined lists you can define your own list at the top of your file: -@lilypond[singleline, verbatim] +@lilypond[raggedright,verbatim] #(define mydrums '( (bassdrum default #f -1) (snare default #f 0) @@ -3014,7 +3014,7 @@ The autochanger switches on basis of pitch (central C is the turning point), and it looks ahead skipping over rests to switch in advance. Here is a practical example: -@lilypond[verbatim,singleline,quote] +@lilypond[verbatim,raggedright,quote] \score { \notes \context PianoStaff << \context Staff = "up" { \autochange \new Voice \relative c' { @@ -3391,7 +3391,7 @@ an unslurred group of notes to be a melisma, then insert @code{\melisma} after the first note of the group, and @code{\melismaEnd} after the last one, e.g. -@lilypond[relative 1, singleline, fragment,verbatim] +@lilypond[relative=1,raggedright,fragment,verbatim] << \context Voice = "lala" { \time 3/4 f4 g8 \melisma @@ -3478,7 +3478,7 @@ that identity followed by a dash. In the preceding example, the @end example The complete example is shown here: -@lilypond[singleline,verbatim] +@lilypond[raggedright,verbatim] \score { << \notes \relative c'' \context Voice = duet { \time 3/4 g2 e4 a2 f4 g2. } @@ -3581,7 +3581,7 @@ To apply, add the @internalsref{Ambitus_engraver} to the @end example This results in the following output: -@lilypond[singleline] +@lilypond[raggedright] upper = \notes \relative c { \clef "treble" \key c \minor @@ -3746,7 +3746,7 @@ also be entered by name. Internally, the chords are represented as a set of pitches, so they can be transposed: -@lilypond[verbatim,singleline] +@lilypond[verbatim,raggedright] twoWays = \notes \transpose c c' { \chords { c1 f:sus4 bes/f @@ -3780,7 +3780,7 @@ Chord mode is a mode where you can input sets of pitches using common names. It is introduced by the keyword @code{\chords}. In chords mode, a chord is entered by the root, which is entered like a common pitch: -@lilypond[fragment,verbatim,quote, relative=1] +@lilypond[fragment,verbatim,quote,relative=1] \chords { es4. d8 c2 } @end lilypond @cindex chord entry @@ -3904,7 +3904,7 @@ For displaying printed chord names, use the @internalsref{ChordNames} context. The chords may be entered either using the notation described above, or directly using @code{<} and @code{>}: -@lilypond[verbatim,singleline] +@lilypond[verbatim,raggedright] scheme = \notes { \chords {a1 b c} } @@ -3921,7 +3921,7 @@ You can make the chord changes stand out by setting display chord names when there is a change in the chords scheme and at the start of a new line: -@lilypond[verbatim, linewidth=9cm] +@lilypond[verbatim,linewidth=9\cm] scheme = \chords { c1:m c:m \break c:m c:m d } @@ -4108,7 +4108,7 @@ as argument. It should return a markup object. In the following example, @code{markFormatter} is set to a canned procedure. After a few measures, it is set to function that produces a boxed number. -@lilypond[verbatim,fragment,relative 1] +@lilypond[verbatim,fragment,relative=1] \property Score.markFormatter = #format-mark-numbers c1 \mark \default c1 \mark \default @@ -4212,7 +4212,7 @@ the start of the staff. For the first start, @code{instrument} is used, for the next ones @code{instr} is used: @quotation -@lilypond[verbatim,singleline] +@lilypond[verbatim,raggedright] \property Staff.instrument = "ploink " { c''4 } @end lilypond @end quotation @@ -4221,7 +4221,7 @@ You can also use markup texts to construct more complicated instrument names: @quotation -@lilypond[fragment,verbatim,singleline] +@lilypond[fragment,verbatim,raggedright] \notes { \property Staff.instrument = \markup { \column < "Clarinetti" @@ -4283,7 +4283,7 @@ between enharmonic pitches: both @code{\transpose c cis} or @code{\transpose c des} will transpose up half a tone. The first version will print sharps and the second version will print flats: -@lilypond[singleline, verbatim] +@lilypond[raggedright,verbatim] mus =\notes { \key d \major cis d fis g } \score { \notes \context Staff { \clef "F" \mus @@ -4430,7 +4430,7 @@ The following example demonstrates the basic functionality of the part combiner: putting parts on one staff, and setting stem directions and polyphony: -@lilypond[verbatim,singleline,fragment,relative 1] +@lilypond[verbatim,raggedright,fragment,relative=1] \new Staff \partcombine { g a( b) r @@ -4450,7 +4450,7 @@ first part (with context called @code{one}) always gets up stems, and If you just want the merging parts, and not the textual markings, you may set the property @var{soloADue} to false: -@lilypond[verbatim,singleline,fragment] +@lilypond[verbatim,raggedright,fragment] \new Staff << \property Staff.soloADue = ##f \partcombine @@ -4680,7 +4680,7 @@ printings of the 16th century. The following example demonstrates the @code{neo_mensural} style: -@lilypond[fragment,singleline,verbatim] +@lilypond[fragment,raggedright,verbatim] \property Voice.NoteHead \set #'style = #'neo_mensural a'\longa a'\breve a'1 a'2 a'4 a'8 a'16 @end lilypond @@ -4714,7 +4714,7 @@ Use the @code{style} property of grob @internalsref{Accidental} to select ancient accidentals. Supported styles are @code{mensural}, @code{vaticana}, @code{hufnagel} and @code{medicaea}. -@lilypond[singleline,26pt] +@lilypond[raggedright,staffsize=26] \score { \notes { \fatText @@ -4797,7 +4797,7 @@ in historic prints of the 16th century. The following example demonstrates the @code{neo_mensural} style: -@lilypond[fragment,singleline,verbatim] +@lilypond[fragment,raggedright,verbatim] \property Voice.Rest \set #'style = #'neo_mensural r\longa r\breve r1 r2 r4 r8 r16 @end lilypond @@ -4846,7 +4846,7 @@ with respect to that clef. modern style mensural C clef @tab @code{neo_mensural_c1}, @code{neo_mensural_c2}, @code{neo_mensural_c3}, @code{neo_mensural_c4} @tab -@lilypond[relative 0, notime] +@lilypond[relative,notime] \property Staff.TimeSignature \set #'transparent = ##t \clef "neo_mensural_c2" c @end lilypond @@ -4870,7 +4870,7 @@ petrucci style mensural C clefs, for use on different stafflines @code{petrucci_c5} @tab -@lilypond[relative 0, notime] +@lilypond[relative,notime] \property Staff.TimeSignature \set #'transparent = ##t \clef "petrucci_c2" c @end lilypond @@ -4879,7 +4879,7 @@ petrucci style mensural C clefs, for use on different stafflines @code{clefs-petrucci_f} @tab petrucci style mensural F clef @tab @code{petrucci_f} @tab -@lilypond[relative 0, notime] +@lilypond[relative,notime] \property Staff.TimeSignature \set #'transparent = ##t \clef "petrucci_f" c @end lilypond @@ -4888,7 +4888,7 @@ petrucci style mensural F clef @tab @code{clefs-petrucci_g} @tab petrucci style mensural G clef @tab @code{petrucci_g} @tab -@lilypond[relative 0, notime] +@lilypond[relative,notime] \property Staff.TimeSignature \set #'transparent = ##t \clef "petrucci_g" c @end lilypond @@ -4898,7 +4898,7 @@ petrucci style mensural G clef @tab historic style mensural C clef @tab @code{mensural_c1}, @code{mensural_c2}, @code{mensural_c3}, @code{mensural_c4} @tab -@lilypond[relative 0, notime] +@lilypond[relative,notime] \property Staff.TimeSignature \set #'transparent = ##t \clef "mensural_c2" c @end lilypond @@ -4907,7 +4907,7 @@ historic style mensural C clef @tab @code{clefs-mensural_f} @tab historic style mensural F clef @tab @code{mensural_f} @tab -@lilypond[relative 0, notime] +@lilypond[relative,notime] \property Staff.TimeSignature \set #'transparent = ##t \clef "mensural_f" c @end lilypond @@ -4916,7 +4916,7 @@ historic style mensural F clef @tab @code{clefs-mensural_g} @tab historic style mensural G clef @tab @code{mensural_g} @tab -@lilypond[relative 0, notime] +@lilypond[relative,notime] \property Staff.TimeSignature \set #'transparent = ##t \clef "mensural_g" c @end lilypond @@ -4925,7 +4925,7 @@ historic style mensural G clef @tab @code{clefs-vaticana_do} @tab Editio Vaticana style do clef @tab @code{vaticana_do1}, @code{vaticana_do2}, @code{vaticana_do3} @tab -@lilypond[relative 0, notime] +@lilypond[relative,notime] \property Staff.StaffSymbol \set #'line-count = #4 \property Staff.TimeSignature \set #'transparent = ##t \clef "vaticana_do2" c @@ -4935,7 +4935,7 @@ Editio Vaticana style do clef @tab @code{clefs-vaticana_fa} @tab Editio Vaticana style fa clef @tab @code{vaticana_fa1}, @code{vaticana_fa2} @tab -@lilypond[relative 0, notime] +@lilypond[relative,notime] \property Staff.StaffSymbol \set #'line-count = #4 \property Staff.TimeSignature \set #'transparent = ##t \clef "vaticana_fa2" c @@ -4945,7 +4945,7 @@ Editio Vaticana style fa clef @tab @code{clefs-medicaea_do} @tab Editio Medicaea style do clef @tab @code{medicaea_do1}, @code{medicaea_do2}, @code{medicaea_do3} @tab -@lilypond[relative 0, notime] +@lilypond[relative,notime] \property Staff.StaffSymbol \set #'line-count = #4 \property Staff.TimeSignature \set #'transparent = ##t \clef "medicaea_do2" c @@ -4955,7 +4955,7 @@ Editio Medicaea style do clef @tab @code{clefs-medicaea_fa} @tab Editio Medicaea style fa clef @tab @code{medicaea_fa1}, @code{medicaea_fa2} @tab -@lilypond[relative 0, notime] +@lilypond[relative,notime] \property Staff.StaffSymbol \set #'line-count = #4 \property Staff.TimeSignature \set #'transparent = ##t \clef "medicaea_fa2" c @@ -4965,7 +4965,7 @@ Editio Medicaea style fa clef @tab @code{clefs-hufnagel_do} @tab historic style hufnagel do clef @tab @code{hufnagel_do1}, @code{hufnagel_do2}, @code{hufnagel_do3} @tab -@lilypond[relative 0, notime] +@lilypond[relative,notime] \property Staff.StaffSymbol \set #'line-count = #4 \property Staff.TimeSignature \set #'transparent = ##t \clef "hufnagel_do2" c @@ -4975,7 +4975,7 @@ historic style hufnagel do clef @tab @code{clefs-hufnagel_fa} @tab historic style hufnagel fa clef @tab @code{hufnagel_fa1}, @code{hufnagel_fa2} @tab -@lilypond[relative 0, notime] +@lilypond[relative,notime] \property Staff.StaffSymbol \set #'line-count = #4 \property Staff.TimeSignature \set #'transparent = ##t \clef "hufnagel_fa2" c @@ -4985,7 +4985,7 @@ historic style hufnagel fa clef @tab @code{clefs-hufnagel_do_fa} @tab historic style hufnagel combined do/fa clef @tab @code{hufnagel_do_fa} @tab -@lilypond[relative 0, notime] +@lilypond[relative,notime] \property Staff.TimeSignature \set #'transparent = ##t \clef "hufnagel_do_fa" c @end lilypond @@ -5046,7 +5046,7 @@ Use the @code{flag-style} property of grob @internalsref{Stem} to select ancient flags. Besides the @code{default} flag style, only @code{mensural} style is supported: -@lilypond[fragment,singleline,verbatim] +@lilypond[fragment,raggedright,verbatim] \property Voice.Stem \set #'flag-style = #'mensural \property Voice.Stem \set #'thickness = #1.0 \property Voice.NoteHead \set #'style = #'mensural @@ -5062,7 +5062,7 @@ grob @internalsref{Stem} to @code{##f}. Then, the vertical position of the end of each flare is different between notes on staff lines and notes between staff lines: -@lilypond[fragment,singleline] +@lilypond[fragment,raggedright] \property Voice.Stem \set #'flag-style = #'mensural \property Voice.Stem \set #'thickness = #1.0 \property Voice.Stem \set #'adjust-if-on-staffline = ##f @@ -5398,7 +5398,7 @@ additional input syntax specific for this particular type of ligature. By default, the @internalsref{LigatureBracket} engraver just puts a square bracket above the ligature: -@lilypond[singleline,verbatim] +@lilypond[raggedright,verbatim] \score { \notes \transpose c c' { \[ g c a f d' \] @@ -5467,7 +5467,7 @@ For example, s4 \[ e1 f1 a\breve g\longa \] @end example -@lilypond[singleline] +@lilypond[raggedright] \score { \notes \transpose c c' { \property Score.timing = ##f @@ -5493,7 +5493,7 @@ Without replacing @internalsref{Ligature_bracket_engraver} with @internalsref{Mensural_ligature_engraver}, the same music transcribes to the following: -@lilypond[singleline] +@lilypond[raggedright] \score { \notes \transpose c c' { \property Score.timing = ##f @@ -5549,7 +5549,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published @item @code{1. Punctum} @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.5cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.5\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -5587,7 +5587,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=2.5cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=2.5\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -5629,7 +5629,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -5666,7 +5666,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published @item @code{2. Virga} @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -5705,7 +5705,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published @item @code{3. Apostropha vel Stropha} @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -5739,7 +5739,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -5777,7 +5777,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published @item @code{4. Oriscus} @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -5816,7 +5816,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published @item @code{5. Clivis vel Flexa} @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -5850,7 +5850,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=2.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=2.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -5888,7 +5888,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -5925,7 +5925,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published @item @code{6. Podatus vel Pes} @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -5959,7 +5959,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=2.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=2.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -5997,7 +5997,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6034,7 +6034,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published @item @code{7. Pes Quassus} @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6068,7 +6068,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6106,7 +6106,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published @item @code{8. Quilisma Pes} @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6140,7 +6140,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6178,7 +6178,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published @item @code{9. Podatus Initio Debilis} @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6212,7 +6212,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6250,7 +6250,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published @item @code{10. Torculus} @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6284,7 +6284,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6318,7 +6318,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6355,7 +6355,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published @item @code{11. Torculus Initio Debilis} @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6389,7 +6389,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6423,7 +6423,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6460,7 +6460,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published @item @code{12. Porrectus} @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6494,7 +6494,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6528,7 +6528,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6565,7 +6565,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published @item @code{13. Climacus} @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6599,7 +6599,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6633,7 +6633,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6670,7 +6670,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published @item @code{14. Scandicus} @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6704,7 +6704,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6738,7 +6738,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6775,7 +6775,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published @item @code{15. Salicus} @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6809,7 +6809,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published } @end lilypond @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -6847,7 +6847,7 @@ volume of the Antiphonale Romanum (@emph{Liber Hymnarius}), published @item @code{16. Trigonus} @tab -@lilypond[noindent, 26pt, nofragment, linewidth=1.0cm] +@lilypond[noindent,staffsize=26,nofragment,linewidth=1.0\cm] \include "gregorian-init.ly" \score { \notes \transpose c c' { @@ -7331,7 +7331,7 @@ A cluster is engraved as the envelope of a set of cluster-notes. Cluster notes are created by applying the function @code{notes-to-clusters} to a sequence of chords, e.g. @c -@lilypond[relative 1,verbatim] +@lilypond[relative=1,verbatim] \apply #notes-to-clusters { } @end lilypond @@ -7377,7 +7377,7 @@ indicate fermatas of differing lengths. The following are supported -@lilypond[singleline] +@lilypond[raggedright] \score { << \addlyrics \notes { b' @@ -7425,7 +7425,7 @@ balloon. The primary purpose of this feature is to explain notation. The following example demonstrates its use. -@lilypond[verbatim,fragment,singleline,relative 1] +@lilypond[verbatim,fragment,raggedright,relative=1] \context Voice \applyoutput #(add-balloon-text 'NoteHead "heads, or tails?" @@ -7457,7 +7457,7 @@ Examples: @inputfileref{input/regression,balloon.ly} The `easy play' note head includes a note name inside the head. It is used in music aimed at beginners: -@lilypond[singleline,verbatim,26pt] +@lilypond[raggedright,verbatim,staffsize=26] \score { \notes { c'2 e'4 f' | g'1 } \paper { \translator { \EasyNotation } } @@ -7565,7 +7565,7 @@ This command applies a setting only during one moment in the score. In the following example, only one @internalsref{Stem} object is changed from its original setting: -@lilypond[verbatim, fragment, relative=1] +@lilypond[verbatim,fragment,relative=1] c4 \once \property Voice.Stem \set #'thickness = #4 c4 @@ -8360,7 +8360,7 @@ duration adds a fixed amount (this amount is controlled by For example, the following piece contains lots of half, quarter and 8th notes, the eighth note is followed by 1 note head width (NHW). The quarter note is followed by 2 NHW, the half by 3 NHW, etc. -@lilypond[fragment, verbatim, relative=1] c2 c4. c8 c4. c8 c4. c8 c8 +@lilypond[fragment,verbatim,relative=1] c2 c4. c8 c4. c8 c4. c8 c8 c8 c4 c4 c4 @end lilypond @@ -8382,7 +8382,7 @@ duration relative to the common shortest note. So if we were to add only a few 16th notes to the example above, they would be followed by half a NHW: -@lilypond[fragment, verbatim, relative=2] +@lilypond[fragment,verbatim,relative=2] c2 c4. c8 c4. c16[ c] c4. c8 c8 c8 c4 c4 c4 @end lilypond @@ -8616,7 +8616,7 @@ score lines will stretch in order to fill the full page @cindex @code{interscorelinefill} If the variable @code{lastpagefill} is defined, -@c fixme: this should only be done if lastpagefill == #t +@c fixme: this should only be done if lastpagefill= #t systems are evenly distributed vertically on the last page. This might produce ugly results in case there are not enough systems on the last page. The @command{lilypond-book} command ignores diff --git a/Documentation/user/tutorial.itely b/Documentation/user/tutorial.itely index 476ca0c725..bd2cb300b1 100644 --- a/Documentation/user/tutorial.itely +++ b/Documentation/user/tutorial.itely @@ -24,8 +24,12 @@ picture in the HTML version of this manual, you will see the exact LilyPond input that was used to generate that image. @ifhtml For example, consider the following input: -@c TODO: intertext fixme -@lilypond[relative 1,singleline,verbatim,intertext="with the following output:"] +@example + c'^\markup @{ \bold \huge @{ Click on this image! @} @} +@end example +@c @lily pond[relative=1,raggedright,with the following output:] +with the following output: +@lilypond[relative=1,raggedright] c'^\markup { \bold \huge { Click on this image! } } @end lilypond @@ -85,7 +89,7 @@ then the result looks like this: @c \transpose c c' { c d e f g a b } @c @lily pond[notime] @c \property Score.timing = ##f -@lilypond[notime, relative=2] +@lilypond[notime,relative=2] c d e f g a b @end lilypond @@ -190,7 +194,7 @@ s4_" " s16_" " @end lilypond -Notes and commands like @code{\clef} and @code{\time} , are enclosed +Notes and commands like @code{\clef} and @code{\time}, are enclosed in @code{\notes @{@dots{}@}}. This indicates that music (as opposed to @rglos{lyrics}) follows: @@ -464,7 +468,7 @@ different rules. A tie is created by adding a tilde ``@code{~}'' to the first note being tied: @quotation -@lilypond[fragment,verbatim,relative 2] +@lilypond[fragment,verbatim,relative=2] g4~ g a2~ a4 @end lilypond @end quotation @@ -518,7 +522,7 @@ Beams are drawn automatically, but if you do not like where they are put, they can be entered by hand. Mark the first note to be beamed with @code{[} and the last one with @code{]}: @quotation -@lilypond[fragment,relative 1, verbatim] +@lilypond[fragment,relative=1,verbatim] a8[ ais] d[ es r d] @end lilypond @end quotation @@ -571,7 +575,7 @@ c'4 c'' c''' \clef bass c c, @separate An example of the use of quotes is in the following Mozart fragment: -@lilypond[singleline,fragment,verbatim] +@lilypond[raggedright,fragment,verbatim] \key a \major \time 6/8 cis''8. d''16 cis''8 e''4 e''8 @@ -584,9 +588,9 @@ solution is to use ``relative octave'' mode. In practice, this is the most convenient way to copy existing music. To use relative mode, add @code{\relative} before the piece of music. You must also give a note from which relative starts, in this case @code{c''}. If you do not -use octavation quotes (i.e. do not add ' or , after a note), relative -mode chooses the note that is closest to the previous one. -For example, @code{c f} goes up while @code{c g} goes down: +use octavation quotes (i.e. do not add @code{'} or @code{,} after a +note), relative mode chooses the note that is closest to the previous +one. For example, @code{c f} goes up while @code{c g} goes down: @quotation @example @@ -610,7 +614,7 @@ Since most music has small intervals, pieces can be written almost without octavation quotes in relative mode. The previous example is entered as @c -@lilypond[singleline,fragment,verbatim] +@lilypond[raggedright,fragment,verbatim] \relative c'' { \key a \major \time 6/8 @@ -742,7 +746,7 @@ the context indicated. We can now typeset a melody with two staves: @quotation -@lilypond[verbatim,singleline] +@lilypond[verbatim,raggedright] \score { \notes << \new Staff { @@ -794,7 +798,7 @@ it to a music expression yields a new expression. Like mathematical expressions, music expressions can be nested arbitrarily deep, e.g. -@lilypond[verbatim,relative 1] +@lilypond[verbatim,relative=1] { c <> << { e f } { c <> } >> @@ -836,7 +840,7 @@ in @ref{Interpretation context}. Common accents can be added to a note using a dash (`@code{-}') and a single character: @quotation -@lilypond[verbatim,relative 1] +@lilypond[verbatim,relative=1] c-. c-- c-> c-^ c-+ c-_ @end lilypond @end quotation @@ -846,14 +850,14 @@ c-. c-- c-> c-^ c-+ c-_ Similarly, fingering indications can be added to a note using a dash (`@code{-}') and the digit to be printed: @c -@lilypond[verbatim,relative 1] +@lilypond[verbatim,relative=1] c-3 e-5 b-2 a-1 @end lilypond Dynamic signs are made by adding the markings to the note: @quotation -@lilypond[verbatim,relative 1] +@lilypond[verbatim,relative=1] c\ff c\mf @end lilypond @end quotation @@ -867,7 +871,7 @@ Crescendi and decrescendi are started with the commands @code{\<} and @code{\>}. The command @code{\!} finishes a crescendo on the note it is attached to: @quotation -@lilypond[verbatim,relative 1] +@lilypond[verbatim,relative=1] c2\< c2\!\ff\> c2 c2\! @end lilypond @end quotation @@ -882,7 +886,7 @@ A slur is drawn across many notes, and indicates bound articulation ``@code{(}'' and a ``@code{)}'' respectively: @quotation -@lilypond[fragment,relative 1, verbatim] +@lilypond[fragment,relative=1,verbatim] d4( c16)( cis d e c cis d e)( d4) @end lilypond @end quotation @@ -894,7 +898,7 @@ notes with the same pitch. Slurs indicate the articulations of notes, and can be used on larger groups of notes. Slurs and ties are also nested in practice: @c -@lilypond[fragment, relative=1] +@lilypond[fragment,relative=1] c2~( c8 fis fis4 ~ fis2 g2) @end lilypond @@ -904,7 +908,7 @@ phrasing), you can also make a phrasing slur with @code{\(} and @code{\)}. @quotation -@lilypond[fragment,relative 1, verbatim] +@lilypond[fragment,relative=1,verbatim] a8(\( ais b c) cis2 b'2 a4 cis, c\) @end lilypond @end quotation @@ -932,7 +936,7 @@ For more information on Chords can be made by surrounding pitches with @code{<} and @code{>}: @quotation -@lilypond[relative 0, fragment,verbatim] +@lilypond[,fragment,verbatim] r4 4 8 @end lilypond @end quotation @@ -942,7 +946,7 @@ r4 4 8 You can combine beams and ties with chords. Beam and tie markings must be placed outside the chord markers: @quotation -@lilypond[relative 0, fragment,verbatim] +@lilypond[,fragment,verbatim] r4 8[ ]~ @end lilypond @end quotation @@ -951,7 +955,7 @@ r4 8[ ]~ @example r4 8\>( 8\!) @end example -@lilypond[relative 0, fragment] +@lilypond[,fragment] \slurUp r4 8\>( 8\!) @end lilypond @@ -975,7 +979,7 @@ r4 8\>( 8\!) A pickup (or upstep) is entered with the keyword @code{\partial}. It is followed by a duration: @code{\partial 4} is a quarter note upstep and @code{\partial 8} an eighth note: -@lilypond[relative 1,verbatim,fragment] +@lilypond[relative=1,verbatim,fragment] \partial 8 f8 c2 d e @end lilypond @@ -987,7 +991,7 @@ arguments: a fraction and a piece of music. The duration of the piece of music is multiplied by the fraction. Triplets make notes occupy 2/3 of their notated duration, so a triplet has 2/3 as its fraction: @c -@lilypond[relative 0,verbatim,fragment] +@lilypond[,verbatim,fragment] \times 2/3 { f8 g a } \times 2/3 { c r c } @end lilypond @@ -1000,7 +1004,7 @@ and @code{\acciaccatura} @cindex appoggiatura @cindex acciaccatura -@lilypond[relative 1, verbatim,fragment] +@lilypond[relative=1,verbatim,fragment] c4 \appoggiatura b16 c4 c4 \acciaccatura b16 c4 @end lilypond @@ -1085,7 +1089,7 @@ aligned. In this case, there is only one melody, so we can leave it empty. The final result is -@lilypond[verbatim,linewidth=6.0cm] +@lilypond[verbatim,linewidth=6.0\cm] \score { \notes << \relative c' \new Voice { @@ -1126,7 +1130,7 @@ resulting in a centered hyphen between two syllables: @example Twin -- kle twin -- kle @end example -@lilypond[singleline] +@lilypond[raggedright] \score { << \notes \relative f' { \time 2/4 f4 f c' c' } @@ -1322,7 +1326,7 @@ voices with @code{\\}: << @{ a4 g2 f4~ f4 @} \\ @{ r4 g4 f2 f4 @} >> @end example -@lilypond[relative 1] +@lilypond[relative=1] \context Staff << { a4 g2 f4~ f4 } \\ { r4 g4 f2 f4 } >> @end lilypond @@ -1334,7 +1338,7 @@ temporarily do not play: << @{ a4 g2 f4~ f4 @} \\ @{ s4 g4 f2 f4 @} >> @end example -@lilypond[relative 1] +@lilypond[relative=1] \context Staff << { a4 g2 f4~ f4 } \\ { s4 g4 f2 f4 } >> @end lilypond @@ -1381,7 +1385,7 @@ but now this entire expression must be interpreted as a Here is a full-fledged example: -@lilypond[relative 0,fragment] +@lilypond[,fragment] \new PianoStaff << \new Staff { \time 2/4 c4 c g' g } @@ -1410,7 +1414,7 @@ It sets the property named @code{autoBeaming} in the current staff at this point in the music to @code{##f}, which means `false'. This property controls whether beams are printed automatically: @c -@lilypond[relative 1,fragment,verbatim] +@lilypond[relative=1,fragment,verbatim] c8 c c c \property Staff.autoBeaming = ##f c8 c c c @@ -1488,7 +1492,7 @@ object. These layout objects also carry variables, which we call @emph{layout properties}. By changing these variables from their values, we can alter the look of a formatted score: -@lilypond[verbatim,relative 0] +@lilypond[verbatim,] c4 \property Voice.Stem \override #'thickness = #3.0 c4 c4 c4 @@ -1508,7 +1512,7 @@ changed. This can be achieved by prefixing @code{\once} to the \once \property Voice.Stem \set #'thickness = #3.0 @end example -@lilypond[relative 0] +@lilypond[relative] c4 \once \property Voice.Stem \set #'thickness = #3.0 c4 c4 c4 @@ -1540,12 +1544,12 @@ offsets are staff-spaces. The @code{extra-offset} property is a low-level feature: the formatting engine is completely oblivious to these offsets. -In the following example example, the second fingering is moved a -little to the left, and 1.8 staff space downwards: +In the following example, the second fingering is moved a little to +the left, and 1.8 staff space downwards: @cindex setting object properties -@lilypond[relative 1,verbatim] +@lilypond[relative=1,verbatim] \stemUp f-5 \once \property Voice.Fingering @@ -1567,7 +1571,7 @@ using ties. Normally ties only happen between notes of the same voice. By introducing a tie in a different voice, and blanking a stem in that voice, the tie appears to cross voices: -@lilypond[fragment,relative 1,verbatim] +@lilypond[fragment,relative=1,verbatim] c4 << { \once \property Voice.Stem \set #'transparent = ##t b8~ b8 @@ -1584,7 +1588,7 @@ symbols that are printed above or below notes. We only give an example; a more elaborate explanation is in @ref{Constructing a tweak}: -@lilypond[relative 1,verbatim] +@lilypond[relative=1,verbatim] c2\fermata \property Voice.Script \set #'padding = #3 b2\fermata @@ -1617,7 +1621,7 @@ later by preceding the name with a backslash, i.e. @code{\namedMusic}. In the next example, a two note motive is repeated two times by using variable substitution: -@lilypond[singleline,verbatim] +@lilypond[raggedright,verbatim] seufzer = \notes { dis'8 e'8 } @@ -1690,7 +1694,7 @@ downwards: sounding @code{f} is denoted by notated @code{c'}, which corresponds with tuning of a normal French Horn in F. The transposition can be seen in the following output: -@lilypond[singleline] +@lilypond[raggedright] \score { \notes \transpose f c' \notes \relative c { \time 2/4 @@ -1718,7 +1722,7 @@ rests: Prepending the rest and the property setting above, leads to the following result: -@lilypond[singleline] +@lilypond[raggedright] \score {\notes { \transpose f c' \relative c { \time 2/4 \property Score.skipBars = ##t R2*3 @@ -1741,7 +1745,7 @@ file @file{bassoon-music.ly}: This would lead to the simple score depicted below: -@lilypond[singleline] +@lilypond[raggedright] \score { \notes \relative c \simultaneous { \new Staff { \time 2/4 @@ -1800,7 +1804,7 @@ In the example you see here, two things happened: a \verb+\score+ block was added, and the line width was set to natural length. You can specify options by putting them in brackets: -\begin[26pt,verbatim]@{lilypond@} +\begin[staffsize=26,verbatim]@{lilypond@} c'4 f16 \end@{lilypond@} @@ -1816,23 +1820,23 @@ Under Unix, you can view the results as follows: @example $ cd input/tutorial $ mkdir -p out/ -$ lilypond-book --outdir=out/ lilbook.tex -lilypond-book (GNU LilyPond) 1.7.23 -Reading `input/tutorial/lilbook.tex' +$ lilypond-book --output=out/ lilybook.tex +lilypond-book (GNU LilyPond) 2.1.19 +Reading `input/tutorial/lilybook.tex' Reading `input/screech-boink6.ly' @var{lots of stuff deleted} -Writing `out/lilbook.latex' +Writing `out/lilybook.latex' $ cd out -$ latex lilbook.latex +$ latex lilybook.latex @var{lots of stuff deleted} -$ xdvi lilbook +$ xdvi lilybook @end example To convert the file into a nice PDF document, run the following commands: @example -$ dvips -Ppdf -u +lilypond lilbook -$ ps2pdf lilbook.ps +$ dvips -Ppdf -u +lilypond lilybook +$ ps2pdf lilybook.ps @end example @@ -1867,9 +1871,9 @@ If you have no @code{\score} block in the fragment, In the example you see here, two things happened: a @code{score} block was added, and the line width was set to natural -length. You can specify options by putting them in brackets: +length. You can specify options by putting them in brackets: -@lilypond[26pt,verbatim] +@lilypond[staffsize=26,verbatim] c'4 f16 @end lilypond diff --git a/make/ly-rules.make b/make/ly-rules.make index 261a5b7355..82ef20d523 100644 --- a/make/ly-rules.make +++ b/make/ly-rules.make @@ -1,9 +1,9 @@ -.SUFFIXES: .doc .dvi .mudtex .tely .texi .ly +.SUFFIXES: .doc .dvi .tely .texi .ly $(outdir)/%.latex: %.doc if [ -f $@ ]; then chmod a+w $@; fi - $(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) $(LILYPOND_BOOK_FLAGS) --verbose --dependencies --outdir=$(outdir) $< + $(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) --process='$(LILYPOND) $(LILYPOND_BOOK_INCLUDES)' --output=$(outdir) --verbose $(LILYPOND_BOOK_FLAGS) $< chmod -w $@ # don't do ``cd $(outdir)'', and assume that $(outdir)/.. is the src dir. @@ -11,14 +11,14 @@ $(outdir)/%.latex: %.doc $(outdir)/%.texi: %.tely if [ -f $@ ]; then chmod a+w $@; fi set|egrep '(TEX|LILY)' # ugh, what's this? - $(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) --dependencies --outdir=$(outdir) --format=$(LILYPOND_BOOK_FORMAT) --verbose $(LILYPOND_BOOK_FLAGS) $< + $(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) --process='$(LILYPOND) $(LILYPOND_BOOK_INCLUDES)' --output=$(outdir) --format=$(LILYPOND_BOOK_FORMAT) --verbose $(LILYPOND_BOOK_FLAGS) $< chmod -w $@ $(outdir)/%.texi: $(outdir)/%.tely if [ -f $@ ]; then chmod a+w $@; fi # debugging: # set|egrep '(TEX|LILY)' - $(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) --dependencies --outdir=$(outdir) --format=$(LILYPOND_BOOK_FORMAT) --verbose $(LILYPOND_BOOK_FLAGS) $< + $(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) --process='$(LILYPOND) $(LILYPOND_BOOK_INCLUDES)' --output=$(outdir) --format=$(LILYPOND_BOOK_FORMAT) --verbose $(LILYPOND_BOOK_FLAGS) $< # # DON'T REMOVE SOURCE FILES, otherwise the .TEXI ALWAYS OUT OF DATE. # rm -f $< @@ -28,12 +28,13 @@ $(outdir)/%.texi: $(outdir)/%.tely # for plain info doco: don't run lily $(outdir)/%.nexi: %.tely if [ -f $@ ]; then chmod a+w $@; fi - $(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) --dependencies --outdir=$(outdir) --format=$(LILYPOND_BOOK_FORMAT) --no-lily $(LILYPOND_BOOK_FLAGS) -o $(notdir $@) $< + $(PYTHON) $(LILYPOND_BOOK) $(LILYPOND_BOOK_INCLUDES) --output=$(outdir) --format=$(LILYPOND_BOOK_FORMAT) --verbose $(LILYPOND_BOOK_FLAGS) --process='true' $< + mv $(outdir)/$*.texinfo $@ 2>/dev/null || mv $(outdir)/$*.texi $@ chmod -w $@ # nfo: info from non-lily texi $(outdir)/%.info: $(outdir)/%.nexi - $(MAKEINFO) --output=$(outdir)/$(*F).info $< + $(MAKEINFO) -I $(outdir) --output=$(outdir)/$(*F).info $< # nfo: info from non-lily texi #$(outdir)/%.nfo: $(outdir)/%.nexi diff --git a/scripts/filter-lilypond-book.py b/scripts/filter-lilypond-book.py deleted file mode 100644 index 18d2ddc9fe..0000000000 --- a/scripts/filter-lilypond-book.py +++ /dev/null @@ -1,815 +0,0 @@ -#!@PYTHON@ - -''' -TODO: - ly-options: intertext, quote ? - --linewidth? - eps in latex? - check latex parameters, twocolumn - multicolumn? - papersizes? - ly2dvi/notexidoc? - -Example usage: - -test: - filter-lilypond-book --filter="tr '[a-z]' '[A-Z]'" BOOK - -convert-ly on book: - filter-lilypond-book --filter="convert-ly --no-version --from=1.6.11 -" BOOK - -classic lilypond-book: - filter-lilypond-book --process="lilypond-bin" BOOK.tely - - must substitute: - @mbinclude foo.itely -> @include foo.itely - \mbinput -> \input - -''' - -import string -import __main__ - -################################################################ -# Users of python modules should include this snippet -# and customize variables below. - -# We'll suffer this path init stuff as long as we don't install our -# python packages in /lib/pythonx.y (and don't kludge around -# it as we do with teTeX on Red Hat Linux: set some environment var -# (PYTHONPATH) in profile) - -# If set, LILYPONDPREFIX must take prevalence -# if datadir is not set, we're doing a build and LILYPONDPREFIX -import getopt, os, sys -datadir = '@local_lilypond_datadir@' -if not os.path.isdir (datadir): - datadir = '@lilypond_datadir@' -if os.environ.has_key ('LILYPONDPREFIX') : - datadir = os.environ['LILYPONDPREFIX'] - while datadir[-1] == os.sep: - datadir= datadir[:-1] - -sys.path.insert (0, os.path.join (datadir, 'python')) - -# Customize these -#if __name__ == '__main__': - -import lilylib as ly -global _;_=ly._ -global re;re = ly.re - -# lilylib globals -program_version = '@TOPLEVEL_VERSION@' -#program_name = 'new-book' -program_name = 'filter-lilypond-book' -verbose_p = 0 -pseudo_filter_p = 0 -original_dir = os.getcwd () - - -# help_summary = _ ("Process LilyPond snippets in hybrid html, LaTeX or texinfo document") -help_summary = _ ("""Process ly snippets from lilypond-book source. Example usage: - - filter-lilypond-book --filter="tr '[a-z]' '[A-Z]'" BOOK - filter-lilypond-book --filter="convert-ly --no-version --from=1.6.11 -" BOOK - -""") -copyright = ('Jan Nieuwenhuizen >', - 'Han-Wen Nienhuys ') - -option_definitions = [ - (_ ("EXT"), 'f', 'format', _ ("use output format EXT (texi [default], texi-html, latex, html)")), - (_ ("FILTER"), 'F', 'filter', _ ("pipe snippets through FILTER [convert-ly -n -]")), - ('', 'h', 'help', _ ("print this help")), - (_ ("DIR"), 'I', 'include', _ ("add DIR to include path")), - (_ ("COMMAND"), 'P', 'process', _ ("process ly_files using COMMAND FILE...")), - (_ ("FILE"), 'o', 'output', _ ("write output to FILE")), - ('', 'V', 'verbose', _ ("be verbose")), - ('', 'v', 'version', _ ("print version information")), - ('', 'w', 'warranty', _ ("show warranty and copyright")), - ('', 'M', 'dependencies', _ ("TODO")), - (_ ("DIR"), '', 'outdir', _ ("DEPRECATED, use --output")), - ] - -include_path = [ly.abspath (os.getcwd ())] - -lilypond_binary = os.path.join ('@bindir@', 'lilypond-bin') - -# only use installed binary when we're installed too. -if '@bindir@' == ('@' + 'bindir@') or not os.path.exists (lilypond_binary): - lilypond_binary = 'lilypond-bin' - - -use_hash_p = 1 -format = 0 -output_name = 0 -latex_filter_cmd = 'latex "\\nonstopmode \input /dev/stdin"' -##filter_cmd = 'convert-ly --no-version --from=2.0.0 -' -filter_cmd = 0 - -#process_cmd = 'convert-ly --no-version --from=2.0.0' -#process_cmd = 0 -# process_cmd = 'lilypond-bin' -process_cmd = 'lilypond-bin -I ../../../input/test' -default_ly_options = { } - -LATEX = 'latex' -HTML = 'html' -TEXINFO = 'texinfo' -BEFORE = 'before' -OUTPUT = 'output' -AFTER = 'after' -VERBATIM = 'verbatim' -LINEWIDTH = 'linewidth' - -## lilypond-book heritage. to be cleaned - -################################################################ -# Recognize special sequences in the input - - -# Warning: This uses extended regular expressions. Tread with care. -# -# legenda -# -# (?Pregex) -- assign result of REGEX to NAME -# *? -- match non-greedily. -# (?m) -- multiline regex: make ^ and $ match at each line -# (?s) -- make the dot match all characters including newline -no_match = 'a\ba' -snippet_res = { - HTML: { - #'header': no_match, - #'input': no_match, - #'landscape': no_match, - #'ly2dvi': r'(?m)(?P[^>]+)?>\s*(?P[^<]+)\s*)', - #'multicols': no_match, - #'numcols': no_match, - 'include': no_match, - 'lilypond' : '(?m)(?P[^:]*):)(?P.*?)/>)', - 'lilypond-block': r'''(?ms)(?P[^>]+)?>(?P.*?))''', - 'lilypond-file': r'(?m)(?P[^>]+)?>\s*(?P[^<]+)\s*)', - 'multiline-comment': r"(?sm)\s*(?!@c\s+)(?P)\s", - 'singleline-comment': no_match, - 'verb': r'''(?P
.*?
)''', - 'verbatim': r'''(?s)(?P
\s.*?
\s)''', - }, - - LATEX: { - #'def-post-re': r"\\def\\postLilyPondExample", - #'def-pre-re': r"\\def\\preLilyPondExample", - #'header': r"\n*\\documentclass\s*(\[.*?\])?", - #'ly2dvi': no_match, - #'multicols': r"(?P\\(?Pbegin|end)\s*{multicols}({(?P\d+)?})?)", - #'numcols': r"(?P\\(?Pone|two)column)", - #'usepackage-graphics': r"\usepackage\s*{graphics}", - 'include': r'(?m)^[^%\n]*?(?P\\input{(?P[^}]+)})', - 'lilypond' : r'(?m)^[^%\n]*?(?P\\lilypond\s*(\[(?P.*?)\])?\s*{(?P.*?)})', - 'lilypond-block': r"(?sm)^[^%\n]*?(?P\\begin\s*(\[(?P.*?)\])?\s*{lilypond}(?P.*?)\\end{lilypond})", - 'lilypond-file': r'(?m)^[^%\n]*?(?P\\lilypondfile\s*(\[(?P.*?)\])?\s*\{(?P.+)})', - 'multiline-comment': no_match, - 'singleline-comment': r"(?m)^.*?(?P(?P^%.*$\n+))", - 'verb': r"(?P\\verb(?P.).*?(?P=del))", - 'verbatim': r"(?s)(?P\\begin\s*{verbatim}.*?\\end{verbatim})", - }, - - TEXINFO: { - #'header': no_match, - #'landscape': no_match, - #'multicols': no_match, - #'numcols': no_match, - 'include': '(?m)^[^%\n]*?(?P@include\s+(?P\S*))', - 'lilypond' : '(?m)^(?P@lilypond(\[(?P[^]]*)\])?{(?P.*?)})', - 'lilypond-block': r'''(?ms)^(?P@lilypond(\[(?P[^]]*)\])?\s(?P.*?)@end lilypond)\s''', - 'lilypond-file': '(?m)^(?P@lilypondfile(\[(?P[^]]*)\])?{(?P[^}]+)})', - 'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P@ignore\s.*?@end ignore)\s", - 'singleline-comment': r"(?m)^.*?(?P(?P@c([ \t][^\n]*|)\n))", - 'verb': r'''(?P@code{.*?})''', - 'verbatim': r'''(?s)(?P@example\s.*?@end example\s)''', - }, - } - -format_res = { - HTML: { - 'option-sep' : '\s*', - 'intertext': r',?\s*intertext=\".*?\"', - }, - LATEX: { - 'intertext': r',?\s*intertext=\".*?\"', - 'option-sep' : ',\s*', - }, - TEXINFO: { - 'intertext': r',?\s*intertext=\".*?\"', - 'option-sep' : ',\s*', - }, - } - -NOTES = 'body' -PREAMBLE = 'preamble' -PAPER = 'paper' - -ly_options = { - NOTES: { - #'xrelative': r'''\relative #(ly:make-pitch %(relative)s 0 0)''', - 'relative': r'''\relative c%(relative_quotes)s''', - }, - PAPER: { - 'indent' : r''' - indent = %(indent)s''', - 'linewidth' : r''' - linewidth = %(linewidth)s''', - 'noindent' : r''' - indent = 0.0\mm''', - 'notime' : r''' - \translator { - \StaffContext - \remove Time_signature_engraver - }''', - 'raggedright' : r''' - indent = 0.0\mm - raggedright = ##t''', - }, - PREAMBLE: { - 'staffsize': r''' -#(set-global-staff-size %(staffsize)s)''', - }, - } - -output = { - HTML : { - AFTER: '', - BEFORE: '', - OUTPUT: r'''[picture of music]''', - VERBATIM: r'''
-%(verb)s
''', - }, - - LATEX : { - AFTER: '', - BEFORE: '', - OUTPUT: r'''{\parindent 0pt -\catcode`\@=12 -\ifx\preLilyPondExample\preLilyPondExample\fi -\def\lilypondbook{} -\input %(base)s.tex -\ifx\preLilyPondExample\postLilyPondExample\fi -\catcode`\@=0}''', - VERBATIM: r'''\begin{verbatim} -%(verb)s\end{verbatim} -''', - }, - - TEXINFO : { - BEFORE: '', - AFTER: '', - VERBATIM: r'''@example -%(verb)s@end example''', - - }, - - } - -PREAMBLE_LY = r'''%% Generated by %(program_name)s -%% Options: [%(option_string)s] -%(preamble_string)s -\paper {%(paper_string)s -} -''' - -FRAGMENT_LY = r'''\score{ - \notes%(notes_string)s{ - %(code)s } -}''' -FULL_LY = '%(code)s' - -def classic_lilypond_book_compatibility (o): - if o == 'singleline': - return 'raggedright' - m = re.search ('relative\s*([-0-9])', o) - if m: - return 'relative=%s' % m.group (1) - m = re.match ('([0-9]+)pt', o) - if m: - return 'staffsize=%s' % m.group (1) - m = re.match ('indent=([-.0-9]+)(cm|in|mm|pt)', o) - if m: - f = float (m.group (1)) - return 'indent=%f\\%s' % (f, m.group (2)) - m = re.match ('linewidth=([-.0-9]+)(cm|in|mm|pt)', o) - if m: - f = float (m.group (1)) - return 'linewidth=%f\\%s' % (f, m.group (2)) - return None - -def compose_ly (code, option_string): - options = [] - # urg - for i in default_ly_options.keys (): - options.append (i) - vars ()[i] = default_ly_options[i] - - if option_string: - options = options + split_options (option_string) - - m = re.search (r'''\\score''', code) - if not m and (not options \ - or not 'nofragment' in options \ - or 'fragment' in options): - options.append ('raggedright') - body = FRAGMENT_LY - else: - body = FULL_LY - - # defaults - relative = 0 - staffsize = '16' - - notes_options = [] - paper_options = [] - preamble_options = [] - for i in options: - c = classic_lilypond_book_compatibility (i) - if c: - ly.warning (_ ("deprecated ly-option used: %s" % i)) - ly.warning (_ ("compatibility mode translation: %s" \ - % c)) - i = c - - if string.find (i, '=') > 0: - key, value = string.split (i, '=') - # hmm - vars ()[key] = value - else: - key = i - - if key in ly_options[NOTES].keys (): - notes_options.append (ly_options[NOTES][key]) - elif key in ly_options[PREAMBLE].keys (): - preamble_options.append (ly_options[PREAMBLE][key]) - elif key in ly_options[PAPER].keys (): - paper_options.append (ly_options[PAPER][key]) - elif key not in ('fragment', 'nofragment', - 'relative', 'verbatim'): - ly.warning (_("ignoring unknown ly option: %s") % i) - - relative_quotes = (",,,", ",,", ",", "", "'", "''", "'''")[relative-3] - program_name = __main__.program_name - notes_string = string.join (notes_options, '\n ') % vars () - paper_string = string.join (paper_options, '\n ') % vars () - preamble_string = string.join (preamble_options, '\n ') % vars () - return (PREAMBLE_LY + body) % vars () - - -# BARF -# use lilypond-bin for latex (.lytex) books, -# and lilypond --preview for html, texinfo books? -def to_eps (file): - cmd = r'latex "\nonstopmode \input %s"' % file - # Ugh. (La)TeX writes progress and error messages on stdout - # Redirect to stderr - cmd = '(( %s >&2 ) >&- )' % cmd - ly.system (cmd) - ly.system ('dvips -Ppdf -u+lilypond.map -E -o %s.eps %s' \ - % (file, file)) - -def find_file (name): - for i in include_path: - full = os.path.join (i, name) - if os.path.exists (full): - return full - ly.error (_ ('file not found: %s\n' % name)) - ly.exit (1) - return '' - -def verbatim_html (s): - return re.sub ('>', '>', - re.sub ('<', '<', - re.sub ('&', '&', s))) - -def verbatim_texinfo (s): - return re.sub ('{', '@{', - re.sub ('}', '@}', - re.sub ('@', '@@', s))) - -def split_options (option_string): - return re.split (format_res[format]['option-sep'], option_string) - - -## make index static of Snippet? -index = 0 - -class Snippet: - def __init__ (self, type, source, index, match): - self.type = type - self.source = source - self.index = index - self.match = match - self.hash = 0 - - def start (self, s): - return self.index + self.match.start (s) - - def end (self, s): - return self.index + self.match.end (s) - - def substring (self, s): - return self.source[self.start (s):self.end (s)] - - def ly (self): - s = '' - if self.type == 'lilypond-block' or self.type == 'lilypond': - s = self.substring ('code') - elif self.type == 'lilypond-file': - name = self.substring ('filename') - s = open (find_file (name)).read () - return s - - def full_ly (self): - s = self.ly () - if s: - return compose_ly (s, self.match.group ('options')) - return '' - - def get_hash (self): - if not self.hash: - self.hash = abs (hash (self.ly ())) - if not self.hash: - print 'TYPE:: ' + self.type - print 'CODE:: ' + self.substring (0) - raise 'URG' - return self.hash - - def basename (self): - if use_hash_p: - return 'lily-%d' % self.get_hash () - raise 'to be done' - - def write_ly (self): - if self.type == 'lilypond-block' or self.type == 'lilypond'\ - or self.type == 'lilypond-file': - h = open (self.basename () + '.ly', 'w') - h.write (self.full_ly ()) - - def output_html (self): - base = self.basename () - option_string = self.match.group ('options') - if option_string and VERBATIM in split_options (option_string)\ - and format == HTML: - verb = verbatim_html (self.substring ('code')) - h.write (output[HTML][VERBATIM] % vars ()) - h.write (output[HTML][BEFORE]) - h.write (output[HTML][OUTPUT] % vars ()) - h.write (output[HTML][AFTER]) - - def output_latex (self): - option_string = self.match.group ('options') - if option_string and VERBATIM in split_options (option_string)\ - and format == LATEX: - verb = self.substring ('code') - h.write (output[LATEX][VERBATIM] % vars ()) - h.write (output[LATEX][BEFORE]) - base = self.basename () - h.write (output[LATEX][OUTPUT] % vars ()) - h.write (output[LATEX][AFTER]) - - def output_texinfo (self): - option_string = self.match.group ('options') - if option_string and VERBATIM in split_options (option_string): - verb = verbatim_texinfo (self.substring ('code')) - h.write (output[TEXINFO][VERBATIM] % vars ()) - h.write ('\n@tex\n') - self.output_latex () - h.write ('\n@end tex\n') - - h.write ('\n@html\n') - self.output_html () - h.write ('\n@end html\n') - - def outdated_p (self): - if self.type != 'lilypond-block' and self.type != 'lilypond'\ - and self.type != 'lilypond-file': - return None - base = self.basename () - if os.path.exists (base + '.ly') \ - and os.path.exists (base + '.tex') \ - and (use_hash_p \ - or self.ly () == open (base + '.ly').read ()): - # TODO: something smart with target formats - # (ps, png) and m/ctimes - return None - return self - - def filter_code (self): - global index - # Hmm, why is verbatim's group called 'code'; rename to 'verb'? - #if snippet.match.group ('code'): - # urg - if self.type == 'lilypond' or self.type == 'lilypond-block': - h.write (self.source[index:self.start ('code')]) - h.write (run_filter (self.substring ('code'))) - h.write (self.source[self.end ('code'):self.end (0)]) - else: - h.write (self.source[index:self.end (0)]) - index = self.end (0) - - def compile_output (self): - global index - # Hmm, why is verbatim's group called 'code'; rename to 'verb'? - # if snippet.match.group ('code'): - # urg - if self.type == 'lilypond' \ - or self.type == 'lilypond-block'\ - or self.type == 'lilypond-file': - h.write (self.source[index:self.start (0)]) - snippet_output = eval ("Snippet.output_" + format) - snippet_output (self) - elif self.type == 'include': - h.write (self.source[index:self.start ('filename')]) - base = os.path.splitext (self.substring ('filename'))[0] - h.write (base + format2ext[format]) - h.write (self.source[self.end ('filename'):self.end (0)]) - else: - h.write (self.source[index:self.end (0)]) - index = self.end (0) - -def find_toplevel_snippets (s, types): - res = {} - for i in types: - res[i] = ly.re.compile (snippet_res[format][i]) - - snippets = [] - index = 0 - found = {}.fromkeys (types) - while 1: - first = 0 - endex = 1 << 30 - for i in types: - if not found[i] or found[i].start (0) < index: - found[i] = 0 - m = res[i].search (s[index:endex]) - if m: - found[i] = Snippet (i, s, index, m) - if found[i] \ - and (not first \ - or found[i].start (0) < found[first].start (0)): - first = i - endex = found[first].start (0) - if not first: - break - snippets.append (found[first]) - index = found[first].end (0) - - return snippets - -def filter_pipe (input, cmd): - if verbose_p: - ly.progress (_ ("Opening filter `%s\'") % cmd) - - stdin, stdout, stderr = os.popen3 (cmd) - stdin.write (input) - status = stdin.close () - - if not status: - status = 0 - output = stdout.read () - status = stdout.close () - error = stderr.read () - - if not status: - status = 0 - signal = 0x0f & status - if status or (not output and error): - exit_status = status >> 8 - ly.error (_ ("`%s\' failed (%d)") % (cmd, exit_status)) - ly.error (_ ("The error log is as follows:")) - sys.stderr.write (error) - sys.stderr.write (stderr.read ()) - ly.exit (status) - - if verbose_p: - ly.progress ('\n') - - return output - -def run_filter (s): - return filter_pipe (s, filter_cmd) - -def process_snippets (cmd, snippets): - names = filter (lambda x:x, map (Snippet.basename, snippets)) - if names: - ly.system (string.join ([cmd] + names)) - - if format == HTML or format == TEXINFO: - for i in names: - to_eps (i) - ly.make_ps_images (i + '.eps', resolution=110) - -LATEX_DOCUMENT = r''' -%(preamble)s -\begin{document} -\typeout{textwidth=\the\textwidth} -\typeout{columnsep=\the\columnsep} -\makeatletter\if@twocolumn\typeout{columns=2}\fi\makeatother -\end{document} -''' -#need anything else besides textwidth? -def get_latex_textwidth (source): - m = re.search (r'''(?P\\begin\s*{document})''', source) - preamble = source[:m.start (0)] - latex_document = LATEX_DOCUMENT % vars () - parameter_string = filter_pipe (latex_document, latex_filter_cmd) - - columns = 0 - m = re.search ('columns=([0-9.]*)', parameter_string) - if m: - columns = string.atoi (m.group (1)) - - columnsep = 0 - m = re.search ('columnsep=([0-9.]*)pt', parameter_string) - if m: - columnsep = string.atof (m.group (1)) - - textwidth = 0 - m = re.search('textwidth=([0-9.]*)pt', parameter_string) - if m: - textwidth = string.atof (m.group (1)) - if columns: - textwidth = (textwidth - columnsep) / columns - - return textwidth - - -ext2format = { - '.html' : HTML, - '.itely' : TEXINFO, - '.lytex' : LATEX, - '.tely' : TEXINFO, - '.tex': LATEX, - '.texi' : TEXINFO, - '.texinfo' : TEXINFO, - '.xml' : HTML, - } - -format2ext = { - HTML: '.html', - #TEXINFO: '.texinfo', - TEXINFO: '.texi', - LATEX: '.tex', - } - -def do_file (input_filename): - #ugh - global format - if not format: - e = os.path.splitext (input_filename)[1] - if e in ext2format.keys (): - #FIXME - format = ext2format[e] - else: - ly.error (_ ("cannot determine format for: %s" \ - % input_filename)) - - ly.progress (_ ("Reading %s...") % input_filename) - if not input_filename or input_filename == '-': - ih = sys.stdin - else: - ih = open (input_filename) - source = ih.read () - ly.progress ('\n') - - ly.progress (_ ("Dissecting...")) - #snippets = find_toplevel_snippets (source, snippet_res[format].keys ()) - snippet_types = ( - 'lilypond-block', - 'verb', - 'verbatim', - 'singleline-comment', - 'multiline-comment', - 'lilypond-file', - 'include', - 'lilypond', ) - - snippets = find_toplevel_snippets (source, snippet_types) - ly.progress ('\n') - - global h - if output_name == '-' or not output_name: - h = sys.stdout - output_filename = '-' - else: - if not os.path.isdir (output_name): - os.mkdir (output_name, 0777) - if input_filename == '-': - input_base = 'stdin' - else: - input_base = os.path.splitext (input_filename)[0] - output_filename = output_name + '/' + input_base \ - + format2ext[format] - h = open (output_filename, 'w') - os.chdir (output_name) - - global default_ly_options - textwidth = 0 - if format == LATEX and LINEWIDTH not in default_ly_options.keys (): - textwidth = get_latex_textwidth (source) - default_ly_options[LINEWIDTH] = '''%.0f\pt''' % textwidth - - global index - if filter_cmd: - index = 0 - map (Snippet.filter_code, snippets) - h.write (source[index:]) - elif process_cmd: - outdated = filter (lambda x:x, - map (Snippet.outdated_p, snippets)) - ly.progress (_ ("Writing snippets...")) - map (Snippet.write_ly, snippets) - ly.progress ('\n') - - if outdated: - ly.progress (_ ("Processing...")) - process_snippets (process_cmd, outdated) - else: - ly.progress (_ ("All snippets are up to date...")) - ly.progress ('\n') - - ly.progress (_ ("Compiling %s...") % output_filename) - index = 0 - map (Snippet.compile_output, snippets) - h.write (source[index:]) - ly.progress ('\n') - - if h != sys.stdout: - h.close () - - def process_include (snippet): - os.chdir (original_dir) - name = snippet.substring ('filename') - ly.progress (_ ('Processing include: %s') % name) - ly.progress ('\n') - do_file (name) - - map (process_include, filter (lambda x: x.type == 'include', snippets)) - -def do_options (): - global format, output_name - global filter_cmd, process_cmd, verbose_p - - (sh, long) = ly.getopt_args (option_definitions) - try: - (options, files) = getopt.getopt (sys.argv[1:], sh, long) - except getopt.error, s: - sys.stderr.write ('\n') - ly.error (_ ("getopt says: `%s\'" % s)) - sys.stderr.write ('\n') - ly.help () - ly.exit (2) - - for opt in options: - o = opt[0] - a = opt[1] - - if 0: - pass - elif o == '--version' or o == '-v': - ly.identify (sys.stdout) - sys.exit (0) - elif o == '--verbose' or o == '-V': - verbose_p = 1 - elif o == '--filter' or o == '-F': - filter_cmd = a - process_cmd = 0 - elif o == '--format' or o == '-f': - format = a - if a == 'texi-html' or a == 'texi': - format = TEXINFO - elif o == '--help' or o == '-h': - ly.help () - sys.exit (0) - elif o == '--include' or o == '-I': - include_path.append (os.path.join (original_dir, - ly.abspath (a))) - elif o == '--output' or o == '-o': - output_name = a - elif o == '--outdir': - output_name = a - elif o == '--process' or o == '-P': - process_cmd = a - filter_cmd = 0 - elif o == '--warranty' or o == '-w': - if 1 or status: - ly.warranty () - sys.exit (0) - return files - -def main (): - files = do_options () - ly.identify (sys.stderr) - ly.setup_environment () - if files: - do_file (files[0]) - -if __name__ == '__main__': - main () diff --git a/scripts/lilypond-book.py b/scripts/lilypond-book.py index ab4bc7b796..dbc6965780 100644 --- a/scripts/lilypond-book.py +++ b/scripts/lilypond-book.py @@ -1,77 +1,34 @@ #!@PYTHON@ -# vim: set noexpandtab: -""" - - TODO: - * junk --outdir for--output - * Figure out clean set of options. - * - * texinfo: add support for @pagesize - - todo: dimension handling (all the x2y) is clumsy. (tca: Thats - because the values are taken directly from texinfo.tex, - geometry.sty and article.cls. Give me a hint, and I'll - fix it.) - - - TODO: magnification support should also work for texinfo -> html: eg. add as option to dvips. - - - - This is a slightly hairy program. The general approach is as follows - The input string is chopped up in chunks, i.e. , a list of tuples - - with the format (TAG_STR, MAIN_STR, OPTIONS, TODO, BASE) - - This list is built step by step: first ignore and verbatim commands - are handled, delivering a list of chunks. - - then all chunks containing lilypond commands are chopped up - - when all chunks have their final form, all bodies from lilypond blocks are - extracted, and if applicable, written do disk and run through lilypond. - - -tags supported - - ignore - lilypond - input - verb - verbatim - multicols - numcols - - - - -""" - -# This is was the idea for handling of comments: -# Multiline comments, @ignore .. @end ignore is scanned for -# in read_doc_file, and the chunks are marked as 'ignore', so -# lilypond-book will not touch them any more. The content of the -# chunks are written to the output file. Also 'include' and 'input' -# regex has to check if they are commented out. -# - -# Then it is scanned for 'lilypond', 'lilypond-file' and 'lilypond-block'. -# These three regex's has to check if they are on a commented line, -# % for latex, @c for texinfo. -# -# Then lines that are commented out with % (latex) and @c (Texinfo) -# are put into chunks marked 'ignore'. This cannot be done before -# searching for the lilypond-blocks because % is also the comment character -# for lilypond. -# -# The the rest of the rexeces are searched for. They don't have to test -# if they are on a commented out line. +''' +TODO: + ly-options: intertext, quote ? + --linewidth? + eps in latex? + check latex parameters, twocolumn + multicolumn? + papersizes? + ly2dvi/notexidoc? + +Example usage: + +test: + filter-lilypond-book --filter="tr '[a-z]' '[A-Z]'" BOOK + +convert-ly on book: + filter-lilypond-book --filter="convert-ly --no-version --from=1.6.11 -" BOOK + +classic lilypond-book: + filter-lilypond-book --process="lilypond-bin" BOOK.tely + + must substitute: + @mbinclude foo.itely -> @include foo.itely + \mbinput -> \input + +''' -import glob -import stat import string - +import __main__ ################################################################ # Users of python modules should include this snippet @@ -102,6 +59,7 @@ import lilylib as ly global _;_=ly._ global re;re = ly.re + # lilylib globals program_version = '@TOPLEVEL_VERSION@' program_name = 'lilypond-book' @@ -110,46 +68,30 @@ pseudo_filter_p = 0 original_dir = os.getcwd () -preview_resolution = 90 +help_summary = _ ("""Process LilyPond snippets in hybrid HTML, LaTeX or texinfo document. Example usage: + + filter-lilypond-book --filter="tr '[a-z]' '[A-Z]'" BOOK + filter-lilypond-book --filter="convert-ly --no-version --from=2.0.0 -" BOOK + filter-lilypond-book --process='lilypond-bin -I include' BOOK -## FIXME -## do -P or -p by default? -##help_summary = _ ("Run LilyPond using LaTeX for titling") -help_summary = _ ("Process LilyPond snippets in hybrid html, LaTeX or texinfo document") -copyright = ('Tom Cato Amundsen ', +""") + +copyright = ('Jan Nieuwenhuizen >', 'Han-Wen Nienhuys ') option_definitions = [ (_ ("EXT"), 'f', 'format', _ ("use output format EXT (texi [default], texi-html, latex, html)")), - (_ ("DIM"), '', 'default-music-fontsize', _ ("default fontsize for music. DIM is assumed to be in points")), - (_ ("DIM"), '', 'default-lilypond-fontsize', _ ("deprecated, use --default-music-fontsize")), - (_ ("OPT"), '', 'extra-options', _ ("pass OPT quoted to the lilypond command line")), - (_ ("DIM"), '', 'force-music-fontsize', _ ("force fontsize for all inline lilypond. DIM is assumed to be in points")), - (_ ("DIM"), '', 'force-lilypond-fontsize', _ ("deprecated, use --force-music-fontsize")), + (_ ("FILTER"), 'F', 'filter', _ ("pipe snippets through FILTER [convert-ly -n -]")), ('', 'h', 'help', _ ("print this help")), - (_ ("DIR"), 'I', 'include', _ ("include path")), - ('', 'M', 'dependencies', _ ("write dependencies")), - (_ ("PREF"), '', 'dep-prefix', _ ("prepend PREF before each -M dependency")), - ('', 'n', 'no-lily', _ ("don't run lilypond")), - ('', '', 'no-pictures', _ ("don't generate pictures")), - ('', '', 'no-music', _ ("strip all lilypond blocks from output")), - (_ ("FILE"), 'o', 'outname', _ ("filename main output file")), - (_ ("FILE"), '', 'outdir', _ ("where to place generated files")), - (_ ('RES'), '', 'preview-resolution', - _ ("set the resolution of the preview to RES")), + (_ ("DIR"), 'I', 'include', _ ("add DIR to include path")), + (_ ("COMMAND"), 'P', 'process', _ ("process ly_files using COMMAND FILE...")), + (_ ("DIR"), 'o', 'output', _ ("write output to DIR")), ('', 'V', 'verbose', _ ("be verbose")), ('', 'v', 'version', _ ("print version information")), ('', 'w', 'warranty', _ ("show warranty and copyright")), ] -# format specific strings, ie. regex-es for input, and % strings for output - -# global variables - -include_path = [os.getcwd ()] - -#lilypond_binary = 'valgrind --suppressions=/home/hanwen/usr/src/guile-1.6.supp --num-callers=10 /home/hanwen/usr/src/lilypond/lily/out/lilypond' - +include_path = [ly.abspath (os.getcwd ())] lilypond_binary = os.path.join ('@bindir@', 'lilypond-bin') # only use installed binary when we're installed too. @@ -157,1500 +99,681 @@ if '@bindir@' == ('@' + 'bindir@') or not os.path.exists (lilypond_binary): lilypond_binary = 'lilypond-bin' +use_hash_p = 1 +format = 0 +output_name = 0 +latex_filter_cmd = 'latex "\\nonstopmode \input /dev/stdin"' +filter_cmd = 0 +process_cmd = lilypond_binary +default_ly_options = { } -ly2dvi_binary = os.path.join ('@bindir@', 'ly2dvi') - -# only use installed binary when we're installed too. -if '@bindir@' == ('@' + 'bindir@') or not os.path.exists (lilypond_binary): - ly2dvi_binary = 'ly2dvi' - - - -g_extra_opts = '' -g_here_dir = os.getcwd () -g_dep_prefix = '' -g_outdir = '' -g_force_music_fontsize = 0 -g_do_pictures = 1 -g_do_music = 1 -g_make_html = 0 - -format = '' -g_run_lilypond = 1 -no_match = 'a\ba' +AFTER = 'after' +BEFORE = 'before' +HTML = 'html' +LATEX = 'latex' +LINEWIDTH = 'linewidth' +NOTES = 'body' +OUTPUT = 'output' +PAPER = 'paper' +PREAMBLE = 'preamble' +TEXINFO = 'texinfo' +VERBATIM = 'verbatim' -default_music_fontsize = 16 -default_text_fontsize = 12 -paperguru = None -################################################################ -# Dimension handling for LaTeX. -# -class LatexPaper: - def __init__ (self): - self.m_document_preamble = [] - self.m_num_cols = 1 - self.m_multicols = 1 - - def find_latex_dims (self): - if g_outdir: - fname = os.path.join (g_outdir, "lily-tmp.tex") - else: - fname = "lily-tmp.tex" - try: - f = open (fname, "w") - except IOError: - error ("Error creating temporary file '%s'" % fname) - - for s in self.m_document_preamble: - f.write (s) - f.write (r""" -\begin{document} -\typeout{---} -\typeout{\columnsep \the\columnsep} -\typeout{\textwidth \the\textwidth} -\typeout{---} -\end{document} - """) - f.close () - re_dim = re.compile (r"\\(\w+)\s+(\d+\.\d+)") - - cmd = "latex '\\nonstopmode \input %s'" % fname - # Ugh. (La)TeX writes progress and error messages on stdout - # Redirect to stderr - cmd = '(( %s >&2 ) >&- )' % cmd - status = ly.system (cmd, ignore_error = 1) - signal = 0xf & status - exit_status = status >> 8 - - if status: - ly.error (_ ("LaTeX failed.")) - ly.error (_ ("The error log is as follows:")) - - #URG see lilypond - try: - lns = open ('lily-tmp.log').readlines () - except: - lns = '' - countdown = -3 - for ln in lns: - sys.stderr.write (ln) - if re.match ('^!', ln): - countdown = 3 - - if countdown == 0: - break - - if countdown > 0: - countdown = countdown -1 - - sys.stderr.write (" ... (further messages elided)...\n") - sys.exit (1) - - lns = open ('lily-tmp.log').readlines () - for ln in lns: - ln = string.strip (ln) - m = re_dim.match (ln) - if m: - if m.groups ()[0] in ('textwidth', 'columnsep'): - self.__dict__['m_%s' % m.groups ()[0]] = float (m.groups ()[1]) - - try: - os.remove (fname) - os.remove (os.path.splitext (fname)[0]+".aux") - os.remove (os.path.splitext (fname)[0]+".log") - except: - pass - - if not self.__dict__.has_key ('m_textwidth'): - raise 'foo!' - - def get_linewidth (self): - if self.m_num_cols == 1: - w = self.m_textwidth - else: - w = (self.m_textwidth - self.m_columnsep)/2 - if self.m_multicols > 1: - return (w - self.m_columnsep* (self.m_multicols-1)) \ - / self.m_multicols - return w - - -class HtmlPaper: - def __init__ (self): - self.m_papersize = 'letterpaper' - self.m_fontsize = 12 - def get_linewidth (self): - return html_linewidths[self.m_papersize][self.m_fontsize] - -class TexiPaper: - def __init__ (self): - self.m_papersize = 'letterpaper' - self.m_fontsize = 12 - def get_linewidth (self): - return texi_linewidths[self.m_papersize][self.m_fontsize] - -def mm2pt (x): - return x * 2.8452756 -def in2pt (x): - return x * 72.26999 -def em2pt (x, fontsize = 10): - return {10: 10.00002, 11: 10.8448, 12: 11.74988}[fontsize] * x -def ex2pt (x, fontsize = 10): - return {10: 4.30554, 11: 4.7146, 12: 5.16667}[fontsize] * x - -def pt2pt (x): - return x - -dimension_conversion_dict ={ - 'mm': mm2pt, - 'cm': lambda x: mm2pt (10*x), - 'in': in2pt, - 'em': em2pt, - 'ex': ex2pt, - 'pt': pt2pt - } - -# Convert numeric values, with or without specific dimension, to floats. -# Keep other strings -def conv_dimen_to_float (value): - if type (value) == type (""): - m = re.match ("([0-9.]+)(cm|in|pt|mm|em|ex)",value) - if m: - unit = m.group (2) - num = string.atof (m.group (1)) - conv = dimension_conversion_dict[m.group (2)] - - value = conv (num) - - elif re.match ("^[0-9.]+$",value): - value = float (value) - - return value - -texi_linewidths = { - 'afourpaper': {12: mm2pt (160)}, - 'afourwide': {12: in2pt (6.5)}, - 'afourlatex': {12: mm2pt (150)}, - 'smallbook': {12: in2pt (5)}, - 'letterpaper': {12: in2pt (6)}} - -html_linewidths = { - 'afourpaper': {12: mm2pt (160)}, - 'afourwide': {12: in2pt (6.5)}, - 'afourlatex': {12: mm2pt (150)}, - 'smallbook': {12: in2pt (5)}, - 'letterpaper': {12: in2pt (6)}} - - -################################################################ -# How to output various structures. -output_dict= { - - - 'html' : { - - 'output-filename' : r''' - -''', - ## maybe
? - 'pagebreak': None, - # Verbatim text is always finished with \n. FIXME: For HTML, - # this newline should be removed. - 'output-verbatim': r'''
-%s
''', - # Verbatim text is always finished with \n. FIXME: For HTML, - # this newline should be removed. - 'output-small-verbatim': r'''
-%s
''', - ## Ugh we need to differentiate on origin: - ## lilypond-block origin wants an extra

, but - ## inline music doesn't. - ## possibly other center options? - 'output-html': r''' -%(htmlimages)s''', - }, - - - 'latex': { - - 'output-lilypond-fragment' : r'''\begin[singleline,%s]{lilypond} - \context Voice{ - %s - } -\end{lilypond}''', - 'output-filename' : r'''\verb+%s+:\\ -%% %s -%% %s -''', - - # verbatim text is always finished with \n - 'output-verbatim': r'''\begin{verbatim} -%s\end{verbatim} -''', - # verbatim text is always finished with \n - 'output-small-verbatim': r'''{\small\begin{verbatim} -%s\end{verbatim}} -''', - 'output-default-post': "\\def\postLilyPondExample{}\n", - 'output-default-pre': "\\def\preLilyPondExample{}\n", - 'usepackage-graphics': '\\usepackage{graphics}\n', - 'output-eps': '\\noindent\includegraphics{%(fn)s}', - 'output-noinline': r''' -%% generated: %(fn)s.eps -''', - 'output-latex-quoted': r'''{\preLilyPondExample -\def\lilypondbook{} -\input %(fn)s.tex -\postLilyPondExample}''', - 'output-latex-noquote': r'''{\parindent 0pt -\preLilyPondExample -\def\lilypondbook{} -\input %(fn)s.tex -\postLilyPondExample}''', - 'pagebreak': r'\pagebreak', - }, - - - 'texi' : { - - - 'output-filename' : r''' -@ifnothtml -@file{%s}:@* -@end ifnothtml -@ifhtml -@uref{%s,@file{%s}} -@end ifhtml -''', - 'output-lilypond-fragment': '''@lilypond[%s] -\context Staff\context Voice{ %s } -@end lilypond ''', - 'output-noinline': r''' -@c generated: %(fn)s.png -''', - 'pagebreak': None, - # verbatim text is always finished with \n - 'output-small-verbatim': r'''@smallexample -%s@end smallexample -''', - # verbatim text is always finished with \n - 'output-verbatim': r'''@example -%s@end example -''', - # do some tweaking: @ is needed in some ps stuff. - # - # ugh, the

below breaks inline images... - 'output-texi-noquote': r'''@tex -\catcode`\@=12 -\parindent 0pt -\def\lilypondbook{} -\input %(fn)s.tex -\catcode`\@=0 -@end tex -@html -

%(htmlimages)s -

-@end html -''', - 'output-texi-quoted': r'''@quotation -@tex -\catcode`\@=12 -\def\lilypondbook{} -\input %(fn)s.tex -\catcode`\@=0 -@end tex -@html -

%(htmlimages)s -

-@end html -@end quotation -''', - } - - } - -def output_verbatim (body, small): - global format - if format == 'html': - body = re.sub ('&', '&', body) - body = re.sub ('>', '>', body) - body = re.sub ('<', '<', body) - elif format == 'texi': - # clumsy workaround for python 2.2 pre bug. - body = re.sub ('@', '@@', body) - body = re.sub ('{', '@{', body) - body = re.sub ('}', '@}', body) - - if small: - key = 'output-small-verbatim' - else: - key = 'output-verbatim' - return get_output (key) % body - - -################################################################ # Recognize special sequences in the input - - -# Warning: This uses extended regular expressions. Tread with care. -# -# legenda # # (?Pregex) -- assign result of REGEX to NAME # *? -- match non-greedily. # (?m) -- multiline regex: make ^ and $ match at each line # (?s) -- make the dot match all characters including newline -re_dict = { - 'html': { - 'include': no_match, - 'input': no_match, - 'header': no_match, - 'preamble-end': no_match, - 'landscape': no_match, - 'verbatim': r'''(?s)(?P

\s.*?
\s)''', - 'verb': r'''(?P
.*?
)''', - 'lilypond-file': r'(?m)(?P[^>]+)?>\s*(?P[^<]+)\s*)', - 'lilypond' : '(?m)(?P[^:]*):)(?P.*?)/>)', - 'lilypond-block': r'''(?ms)(?P[^>]+)?>(?P.*?)
)''', - 'option-sep' : '\s*', - 'intertext': r',?\s*intertext=\".*?\"', - 'multiline-comment': r"(?sm)\s*(?!@c\s+)(?P)\s", - 'singleline-comment': no_match, - 'numcols': no_match, - 'multicols': no_match, - 'ly2dvi': r'(?m)(?P[^>]+)?>\s*(?P[^<]+)\s*)', - }, - - 'latex': { - 'input': r'(?m)^[^%\n]*?(?P\\mbinput{?([^}\t \n}]*))', - 'include': r'(?m)^[^%\n]*?(?P\\mbinclude{(?P[^}]+)})', - 'option-sep' : ',\s*', - 'header': r"\n*\\documentclass\s*(\[.*?\])?", - 'preamble-end': r'(?P\\begin\s*{document})', - 'verbatim': r"(?s)(?P\\begin\s*{verbatim}.*?\\end{verbatim})", - 'verb': r"(?P\\verb(?P.).*?(?P=del))", - 'lilypond-file': r'(?m)^[^%\n]*?(?P\\lilypondfile\s*(\[(?P.*?)\])?\s*\{(?P.+)})', - 'lilypond' : r'(?m)^[^%\n]*?(?P\\lilypond\s*(\[(?P.*?)\])?\s*{(?P.*?)})', - 'lilypond-block': r"(?sm)^[^%\n]*?(?P\\begin\s*(\[(?P.*?)\])?\s*{lilypond}(?P.*?)\\end{lilypond})", - 'def-post-re': r"\\def\\postLilyPondExample", - 'def-pre-re': r"\\def\\preLilyPondExample", - 'usepackage-graphics': r"\usepackage\s*{graphics}", - 'intertext': r',?\s*intertext=\".*?\"', - 'multiline-comment': no_match, - 'singleline-comment': r"(?m)^.*?(?P(?P^%.*$\n+))", - 'numcols': r"(?P\\(?Pone|two)column)", - 'multicols': r"(?P\\(?Pbegin|end)\s*{multicols}({(?P\d+)?})?)", - 'ly2dvi': no_match, - - }, - - # why do we have distinction between @mbinclude and @include? - - 'texi': { - 'include': '(?m)^[^%\n]*?(?P@mbinclude\s+(?P\S*))', - 'input': no_match, - 'header': no_match, - 'preamble-end': no_match, - 'landscape': no_match, - 'verbatim': r'''(?s)(?P@example\s.*?@end example\s)''', - 'verb': r'''(?P@code{.*?})''', - 'lilypond-file': '(?m)^(?P@lilypondfile(\[(?P[^]]*)\])?{(?P[^}]+)})', - 'lilypond' : '(?m)^(?P@lilypond(\[(?P[^]]*)\])?{(?P.*?)})', - 'lilypond-block': r'''(?ms)^(?P@lilypond(\[(?P[^]]*)\])?\s(?P.*?)@end lilypond)\s''', - 'option-sep' : ',\s*', - 'intertext': r',?\s*intertext=\".*?\"', - 'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P@ignore\s.*?@end ignore)\s", - 'singleline-comment': r"(?m)^.*?(?P(?P@c.*$\n+))", - 'numcols': no_match, - 'multicols': no_match, - 'ly2dvi': no_match, - } +no_match = 'a\ba' +snippet_res = { + HTML: { + 'include': no_match, + 'lilypond' : '(?m)(?P[^:]*):)(?P.*?)/>)', + 'lilypond-block': r'''(?ms)(?P[^>]+)?>(?P.*?))''', + 'lilypond-file': r'(?m)(?P[^>]+)?>\s*(?P[^<]+)\s*)', + 'multiline-comment': r"(?sm)\s*(?!@c\s+)(?P)\s", + 'singleline-comment': no_match, + 'verb': r'''(?P
.*?
)''', + 'verbatim': r'''(?s)(?P
\s.*?
\s)''', + }, + + LATEX: { + 'include': r'(?m)^[^%\n]*?(?P\\input{(?P[^}]+)})', + 'lilypond' : r'(?m)^[^%\n]*?(?P\\lilypond\s*(\[(?P.*?)\])?\s*{(?P.*?)})', + 'lilypond-block': r"(?sm)^[^%\n]*?(?P\\begin\s*(\[(?P.*?)\])?\s*{lilypond}(?P.*?)\\end{lilypond})", + 'lilypond-file': r'(?m)^[^%\n]*?(?P\\lilypondfile\s*(\[(?P.*?)\])?\s*\{(?P.+)})', + 'multiline-comment': no_match, + 'singleline-comment': r"(?m)^.*?(?P(?P^%.*$\n+))", + 'verb': r"(?P\\verb(?P.).*?(?P=del))", + 'verbatim': r"(?s)(?P\\begin\s*{verbatim}.*?\\end{verbatim})", + }, + + TEXINFO: { + 'include': '(?m)^[^%\n]*?(?P@include\s+(?P\S*))', + 'lilypond' : '(?m)^(?P@lilypond(\[(?P[^]]*)\])?{(?P.*?)})', + 'lilypond-block': r'''(?ms)^(?P@lilypond(\[(?P[^]]*)\])?\s(?P.*?)@end lilypond)\s''', + 'lilypond-file': '(?m)^(?P@lilypondfile(\[(?P[^]]*)\])?{(?P[^}]+)})', + 'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P@ignore\s.*?@end ignore)\s", + 'singleline-comment': r"(?m)^.*?(?P(?P@c([ \t][^\n]*|)\n))", + 'verb': r'''(?P@code{.*?})''', + 'verbatim': r'''(?s)(?P@example\s.*?@end example\s)''', + }, } +format_res = { + HTML: { + 'option-sep' : '\s*', + 'intertext': r',?\s*intertext=\".*?\"', + }, + LATEX: { + 'intertext': r',?\s*intertext=\".*?\"', + 'option-sep' : ',\s*', + }, + TEXINFO: { + 'intertext': r',?\s*intertext=\".*?\"', + 'option-sep' : ',\s*', + }, + } -for r in re_dict.keys (): - olddict = re_dict[r] - newdict = {} - for k in olddict.keys (): - try: - newdict[k] = re.compile (olddict[k]) - except: - print 'invalid regexp: %s' % olddict[k] - - ## we'd like to catch and reraise a more - ## detailed error, but alas, the exceptions - ## changed across the 1.5/2.1 boundary. - - raise "Invalid re" - re_dict[r] = newdict - - -def uniq (list): - list.sort () - s = list - list = [] - for x in s: - if x not in list: - list.append (x) - return list - - -def get_output (name): - return output_dict[format][name] - -def get_re (name): - return re_dict[format][name] - -def bounding_box_dimensions (fname): - if g_outdir: - fname = os.path.join (g_outdir, fname) - try: - fd = open (fname) - except IOError: - error ("Error opening `%s'" % fname) - str = fd.read () - s = re.search ('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', str) - if s: - - gs = map (lambda x: string.atoi (x), s.groups ()) - return (int (gs[2] - gs[0] + 0.5), - int (gs[3] - gs[1] + 0.5)) - else: - return (0,0) - -def error (str): - sys.stderr.write ("\n\n" + str + "\nExiting ... \n\n") - raise 'Exiting.' - - -def compose_full_body (body, opts): - '''Construct the lilypond code to send to LilyPond. - Add stuff to BODY using OPTS as options.''' - music_size = default_music_fontsize - if g_force_music_fontsize: - music_size = g_force_music_fontsize - indent = '' - linewidth = '' - notime = '' - for o in opts: - if not g_force_music_fontsize: - m = re.match ('([0-9]+)pt', o) - if m: - music_size = string.atoi (m.group (1)) - - m = re.match ('indent=([-.0-9]+)(cm|in|mm|pt)', o) - if m: - f = float (m.group (1)) - indent = 'indent = %f\\%s' % (f, m.group (2)) - - m = re.match ('linewidth=([-.0-9]+)(cm|in|mm|pt)', o) - if m: - f = float (m.group (1)) - linewidth = 'linewidth = %f\\%s' % (f, m.group (2)) - - if re.search ('\\\\score', body): - is_fragment = 0 - else: - is_fragment = 1 - if 'fragment' in opts: - is_fragment = 1 - if 'nofragment' in opts: - is_fragment = 0 - - if is_fragment and not 'multiline' in opts: - opts.append ('singleline') - - if 'raggedright' in opts or 'singleline' in opts: - if not linewidth: - linewidth = 'raggedright = ##t' - if not indent: - indent = 'indent = 0.0\mm' - elif not linewidth: - global paperguru - l = paperguru.get_linewidth () - linewidth = 'linewidth = %f\pt' % l - - if 'noindent' in opts: - indent = 'indent = 0.0\mm' - - if 'notime' in opts: - notime = r''' -\translator { - \StaffContext - \remove Time_signature_engraver -} -''' - - orig_name = '' - for o in opts: - m= re.search ('relative(.*)', o) - v = 0 - if m: - try: - v = string.atoi (m.group (1)) - except ValueError: - pass - - v = v + 1 - pitch = 'c' - if v < 0: - pitch = pitch + '\,' * v - elif v > 0: - pitch = pitch + '\'' * v - - body = '\\relative %s { %s }' % (pitch, body) - m =re.search ("filename=(.*)", o) - if m: - orig_name = m.group (1) - - if is_fragment: - body = r''' -\score { - \notes { -%s - } -} -''' % body - - opts = uniq (opts) - optstring = string.join (opts, ' ') - optstring = re.sub ('\n', ' ', optstring) - body = r''' -%% Generated automatically by: lilypond-book.py -%% options are %s -#(set-global-staff-size %d) - -\paper { - %s - %s - %s -} -''' % (optstring, music_size, linewidth, indent, notime) + body +ly_options = { + NOTES: { + 'relative': r'''\relative c%(relative_quotes)s''', + }, + PAPER: { + 'indent' : r''' + indent = %(indent)s''', + 'linewidth' : r''' + linewidth = %(linewidth)s''', + 'noindent' : r''' + indent = 0.0\mm''', + 'notime' : r''' + \translator { + \StaffContext + \remove Time_signature_engraver + }''', + 'raggedright' : r''' + indent = 0.0\mm + raggedright = ##t''', + }, + PREAMBLE: { + 'staffsize': r''' +#(set-global-staff-size %(staffsize)s)''', + }, + } - if orig_name: - body = '\\renameinput \"%s\"\n%s' % (orig_name, body) +output = { + HTML : { + AFTER: '', + BEFORE: '', + OUTPUT: r'''[picture of music]''', + VERBATIM: r'''
+%(verb)s
''', + }, - - # ughUGH not original options - return body - -def scan_html_preamble (chunks): - return - -def scan_latex_preamble (chunks): - # First we want to scan the \documentclass line - # it should be the first non-comment line. - # The only thing we really need to know about the \documentclass line - # is if there are one or two columns to begin with. - idx = 0 - while 1: - if chunks[idx][0] == 'ignore': - idx = idx + 1 - continue - m = get_re ('header').match (chunks[idx][1]) - if not m: - error ("Latex documents must start with a \documentclass command") - if m.group (1): - options = re.split (r',\s*', m.group (1)[1:-1]) - else: - options = [] - if 'twocolumn' in options: - paperguru.m_num_cols = 2 - break - - - # Then we add everything before \begin{document} to - # paperguru.m_document_preamble so that we can later write this header - # to a temporary file in find_latex_dims() to find textwidth. - while idx < len (chunks) and chunks[idx][0] != 'preamble-end': - if chunks[idx] == 'ignore': - idx = idx + 1 - continue - paperguru.m_document_preamble.append (chunks[idx][1]) - idx = idx + 1 - - if len (chunks) == idx: - error ("Didn't find end of preamble (\\begin{document})") - - paperguru.find_latex_dims () - -def scan_texi_preamble (chunks): - # this is not bulletproof..., it checks the first 10 chunks - for c in chunks[:10]: - if c[0] == 'input': - for s in ('afourpaper', 'afourwide', 'letterpaper', - 'afourlatex', 'smallbook'): - if string.find (c[1], "@%s" % s) != -1: - paperguru.m_papersize = s - - -def scan_preamble (chunks): - global format - if format == 'html': - scan_html_preamble (chunks) - elif format == 'latex': - scan_latex_preamble (chunks) - elif format == 'texi': - scan_texi_preamble (chunks) - - -def completize_preamble (chunks): - global format - if format != 'latex': - return chunks - pre_b = post_b = graphics_b = None - for chunk in chunks: - if chunk[0] == 'preamble-end': - break - if chunk[0] == 'input': - m = get_re ('def-pre-re').search (chunk[1]) - if m: - pre_b = 1 - if chunk[0] == 'input': - m = get_re ('def-post-re').search (chunk[1]) - if m: - post_b = 1 - - if chunk[0] == 'input': - m = get_re ('usepackage-graphics').search (chunk[1]) - if m: - graphics_b = 1 - x = 0 - while x < len (chunks) and chunks[x][0] != 'preamble-end': - x = x + 1 - - if x == len (chunks): - return chunks - - if not pre_b: - chunks.insert (x, ('input', get_output ('output-default-pre'))) - if not post_b: - chunks.insert (x, ('input', get_output ('output-default-post'))) - if not graphics_b: - chunks.insert (x, ('input', get_output ('usepackage-graphics'))) - - return chunks - - -read_files = [] -def find_file (name): - ''' - Search the include path for NAME. If found, return the (CONTENTS, PATH) of the file. - ''' - - if name == '-': - return (sys.stdin.read (), '') - f = None - nm = '' - for a in include_path: - try: - nm = os.path.join (a, name) - f = open (nm) - global read_files - read_files.append (nm) - break - except IOError: - pass - if f: - sys.stderr.write ("Reading `%s'\n" % nm) - return (f.read (), nm) - else: - error ("File not found `%s'\n" % name) - return ('', '') - -def do_ignore (match_object): - return [('ignore', match_object.group ('code'))] -def do_preamble_end (match_object): - return [('preamble-end', match_object.group ('code'))] - -def make_verbatim (match_object): - return [('verbatim', match_object.group ('code'))] - -def make_verb (match_object): - return [('verb', match_object.group ('code'))] - -def do_include_file (m): - "m: MatchObject" - return [('input', get_output ('pagebreak'))] \ - + read_doc_file (m.group ('filename')) \ - + [('input', get_output ('pagebreak'))] - -def do_input_file (m): - return read_doc_file (m.group ('filename')) - -def make_lilypond (m): - if m.group ('options'): - options = m.group ('options') - else: - options = '' - return [('input', get_output ('output-lilypond-fragment') % - (options, m.group ('code')))] - -def make_lilypond_file (m): - ''' - - Find @lilypondfile{bla.ly} occurences and substitute bla.ly - into a @lilypond .. @end lilypond block. - - ''' - - if m.group ('options'): - options = get_re ('option-sep').split (m.group ('options')) - else: - options = [] - (content, nm) = find_file (m.group ('filename')) - options.append ("filename=%s" % nm) - (path, base) = os.path.split (nm) + LATEX : { + AFTER: '', + BEFORE: '', + OUTPUT: r'''{\parindent 0pt +\catcode`\@=12 +\ifx\preLilyPondExample\preLilyPondExample\fi +\def\lilypondbook{} +\input %(base)s.tex +\ifx\preLilyPondExample\postLilyPondExample\fi +\catcode`\@=0}''', + VERBATIM: r'''\begin{verbatim} +%(verb)s\end{verbatim} +''', + }, - if path not in include_path: - include_path.append (path) - - return [('lilypond', content, options)] + TEXINFO : { + BEFORE: '', + AFTER: '', + VERBATIM: r'''@example +%(verb)s@end example''', + }, + + } -def make_ly2dvi_block (m): - ''' - - Find - ''' - - return [('ly2dvi', m.group ('filename'), m.group ('options'))] - - -def make_lilypond_block (m): - if not g_do_music: - return [] - - if m.group ('options'): - options = get_re ('option-sep').split (m.group ('options')) - else: - options = [] - options = filter (lambda s: s != '', options) - return [('lilypond', m.group ('code'), options)] - - -def do_columns (m): - global format - if format != 'latex': - return [] - if m.group ('num') == 'one': - return [('numcols', m.group ('code'), 1)] - if m.group ('num') == 'two': - return [('numcols', m.group ('code'), 2)] - -def do_multicols (m): - global format - if format != 'latex': - return [] - if m.group ('be') == 'begin': - return [('multicols', m.group ('code'), int (m.group ('num')))] +PREAMBLE_LY = r'''%% Generated by %(program_name)s +%% Options: [%(option_string)s] +%(preamble_string)s +\paper {%(paper_string)s +} +''' + +FRAGMENT_LY = r'''\score{ + \notes%(notes_string)s{ + %(code)s } +}''' +FULL_LY = '%(code)s' + +def classic_lilypond_book_compatibility (o): + if o == 'singleline': + return 'raggedright' + m = re.search ('relative\s*([-0-9])', o) + if m: + return 'relative=%s' % m.group (1) + m = re.match ('([0-9]+)pt', o) + if m: + return 'staffsize=%s' % m.group (1) + m = re.match ('indent=([-.0-9]+)(cm|in|mm|pt)', o) + if m: + f = float (m.group (1)) + return 'indent=%f\\%s' % (f, m.group (2)) + m = re.match ('linewidth=([-.0-9]+)(cm|in|mm|pt)', o) + if m: + f = float (m.group (1)) + return 'linewidth=%f\\%s' % (f, m.group (2)) + return None + +def compose_ly (code, option_string): + options = [] + # urg + for i in default_ly_options.keys (): + options.append (i) + vars ()[i] = default_ly_options[i] + + if option_string: + options = options + split_options (option_string) + + m = re.search (r'''\\score''', code) + if not m and (not options \ + or not 'nofragment' in options \ + or 'fragment' in options): + options.append ('raggedright') + body = FRAGMENT_LY else: - return [('multicols', m.group ('code'), 1)] - return [] - -def chop_chunks (chunks, re_name, func, use_match=0): - newchunks = [] - for c in chunks: - if c[0] == 'input': - str = c[1] - while str: - m = get_re (re_name).search (str) - if m == None: - newchunks.append (('input', str)) - str = '' - else: - if use_match: - newchunks.append (('input', str[:m.start ('match')])) - else: - newchunks.append (('input', str[:m.start (0)])) - #newchunks.extend (func (m)) - # python 1.5 compatible: - newchunks = newchunks + func (m) - str = str [m.end (0):] + body = FULL_LY + + # defaults + relative = 0 + staffsize = '16' + + notes_options = [] + paper_options = [] + preamble_options = [] + for i in options: + c = classic_lilypond_book_compatibility (i) + if c: + ly.warning (_ ("deprecated ly-option used: %s" % i)) + ly.warning (_ ("compatibility mode translation: %s" \ + % c)) + i = c + + if string.find (i, '=') > 0: + key, value = string.split (i, '=') + # hmm + vars ()[key] = value else: - newchunks.append (c) - return newchunks + key = i + + if key in ly_options[NOTES].keys (): + notes_options.append (ly_options[NOTES][key]) + elif key in ly_options[PREAMBLE].keys (): + preamble_options.append (ly_options[PREAMBLE][key]) + elif key in ly_options[PAPER].keys (): + paper_options.append (ly_options[PAPER][key]) + elif key not in ('fragment', 'nofragment', + 'relative', 'verbatim'): + ly.warning (_("ignoring unknown ly option: %s") % i) + + relative_quotes = (",,,", ",,", ",", "", "'", "''", "'''")[relative-3] + program_name = __main__.program_name + notes_string = string.join (notes_options, '\n ') % vars () + paper_string = string.join (paper_options, '\n ') % vars () + preamble_string = string.join (preamble_options, '\n ') % vars () + return (PREAMBLE_LY + body) % vars () + + +# BARF +# use lilypond-bin for latex (.lytex) books, +# and lilypond --preview for html, texinfo books? +def to_eps (file): + cmd = r'latex "\nonstopmode \input %s"' % file + # Ugh. (La)TeX writes progress and error messages on stdout + # Redirect to stderr + cmd = '(( %s >&2 ) >&- )' % cmd + ly.system (cmd) + ly.system ('dvips -Ppdf -u+lilypond.map -E -o %s.eps %s' \ + % (file, file)) -def determine_format (str): - """ - - SIDE EFFECT! This sets FORMAT and PAPERGURU - - """ +def find_file (name): + for i in include_path: + full = os.path.join (i, name) + if os.path.exists (full): + return full + ly.error (_ ('file not found: %s\n' % name)) + ly.exit (1) + return '' - global format - if format == '': - html = re.search ('(?i)<[dh]tml', str[:200]) - latex = re.search (r'''\\document''', str[:200]) - texi = re.search ('@node|@setfilename', str[:200]) - - f = '' - g = None - - if html and not latex and not texi: - f = 'html' - elif latex and not html and not texi: - f = 'latex' - elif texi and not html and not latex: - f = 'texi' - else: - error ("can't determine format, please specify") - format = f - - global paperguru - if paperguru == None: - if format == 'html': - g = HtmlPaper () - elif format == 'latex': - g = LatexPaper () - elif format == 'texi': - g = TexiPaper () - - paperguru = g - - -def read_doc_file (filename): - '''Read the input file, find verbatim chunks and do \input and \include - ''' - (str, path) = find_file (filename) - determine_format (str) - - chunks = [('input', str)] - - # we have to check for verbatim before doing include, - # because we don't want to include files that are mentioned - # inside a verbatim environment - chunks = chop_chunks (chunks, 'verbatim', make_verbatim) - - chunks = chop_chunks (chunks, 'verb', make_verb) - chunks = chop_chunks (chunks, 'multiline-comment', do_ignore) - #ugh fix input - chunks = chop_chunks (chunks, 'include', do_include_file, 1) - chunks = chop_chunks (chunks, 'input', do_input_file, 1) - return chunks - - -taken_file_names = {} - -def unique_file_name (body): - return 'lily-' + `abs (hash (body))` - -def schedule_lilypond_block (chunk): - '''Take the body and options from CHUNK, figure out how the - real .ly should look. The .ly is written, and scheduled in - TODO. - - Return: a single chunk. - - The chunk pertaining to the lilypond output - has the format (TYPE_STR, MAIN_STR, OPTIONS, TODO, BASE), - where TODO has format [basename, extension, extension, ... ] - ''' - - (type, body, opts) = chunk - assert type == 'lilypond' - file_body = compose_full_body (body, opts) - ## Hmm, we should hash only lilypond source, and skip the - ## %options are ... - ## comment line - basename = unique_file_name (file_body) - for o in opts: - m = re.search ('filename="(.*?)"', o) - if m: - basename = m.group (1) - if not taken_file_names.has_key (basename): - taken_file_names[basename] = 0 - else: - taken_file_names[basename] = taken_file_names[basename] + 1 - basename = basename + "-t%i" % taken_file_names[basename] - update_file (file_body, os.path.join (g_outdir, basename) + '.ly') - needed_filetypes = ['tex'] - - if format == 'html' or g_make_html: - needed_filetypes.append ('eps') - needed_filetypes.append ('png') - if 'eps' in opts and not ('eps' in needed_filetypes): - needed_filetypes.append ('eps') - - pathbase = os.path.join (g_outdir, basename) - def must_rebuild (base, ext1, ext2): - - f2 = base + ext2 - f1 = base + ext1 - fp2 = base + '-page1' + ext2 - - isfile2 = os.path.isfile (f2) +def verbatim_html (s): + return re.sub ('>', '>', + re.sub ('<', '<', + re.sub ('&', '&', s))) + +def verbatim_texinfo (s): + return re.sub ('{', '@{', + re.sub ('}', '@}', + re.sub ('@', '@@', s))) + +def split_options (option_string): + return re.split (format_res[format]['option-sep'], option_string) + + +## make index static of Snippet? +index = 0 + +class Snippet: + def __init__ (self, type, source, index, match): + self.type = type + self.source = source + self.index = index + self.match = match + self.hash = 0 + + def start (self, s): + return self.index + self.match.start (s) + + def end (self, s): + return self.index + self.match.end (s) + + def substring (self, s): + return self.source[self.start (s):self.end (s)] + + def ly (self): + s = '' + if self.type == 'lilypond-block' or self.type == 'lilypond': + s = self.substring ('code') + elif self.type == 'lilypond-file': + name = self.substring ('filename') + s = open (find_file (name)).read () + return s - if not isfile2 and os.path.isfile (fp2): - f2 = fp2 - isfile2 = os.path.isfile (fp2) + def full_ly (self): + s = self.ly () + if s: + return compose_ly (s, self.match.group ('options')) + return '' + + def get_hash (self): + if not self.hash: + self.hash = abs (hash (self.ly ())) + return self.hash + + def basename (self): + if use_hash_p: + return 'lily-%d' % self.get_hash () + raise 'to be done' + + def write_ly (self): + if self.type == 'lilypond-block' or self.type == 'lilypond'\ + or self.type == 'lilypond-file': + h = open (self.basename () + '.ly', 'w') + h.write (self.full_ly ()) + + def output_html (self): + base = self.basename () + option_string = self.match.group ('options') + if option_string and VERBATIM in split_options (option_string)\ + and format == HTML: + verb = verbatim_html (self.substring ('code')) + h.write (output[HTML][VERBATIM] % vars ()) + h.write (output[HTML][BEFORE]) + h.write (output[HTML][OUTPUT] % vars ()) + h.write (output[HTML][AFTER]) - if (os.path.isfile (f2) and isfile2 and - os.stat (f1)[stat.ST_MTIME] > - os.stat (f2)[stat.ST_MTIME]) or \ - not isfile2: - - return 1 + def output_latex (self): + option_string = self.match.group ('options') + if option_string and VERBATIM in split_options (option_string)\ + and format == LATEX: + verb = self.substring ('code') + h.write (output[LATEX][VERBATIM] % vars ()) + h.write (output[LATEX][BEFORE]) + base = self.basename () + h.write (output[LATEX][OUTPUT] % vars ()) + h.write (output[LATEX][AFTER]) + + def output_texinfo (self): + option_string = self.match.group ('options') + if option_string and VERBATIM in split_options (option_string): + verb = verbatim_texinfo (self.substring ('code')) + h.write (output[TEXINFO][VERBATIM] % vars ()) + h.write ('\n@tex\n') + self.output_latex () + h.write ('\n@end tex\n') - todo = [] - if 'tex' in needed_filetypes and must_rebuild (pathbase, '.ly', '.tex'): - todo.append ('tex') - if 'eps' in needed_filetypes and must_rebuild (pathbase, '.tex', '.eps'): - todo.append ('eps') - if 'png' in needed_filetypes and must_rebuild (pathbase, '.eps', '.png'): - todo.append ('png') - - return ('lilypond', body, opts, todo, basename) - -def format_lilypond_block (chunk): - """ - - Figure out what should be left MAIN_STR (meant - for the main file) from a lilypond chunk: process - verbatim, and other options. Return: multiple chunks. - - - """ - - - return_chunks = [] - - (type, body, opts, todo, basename) = chunk - assert type == 'lilypond' - - - newbody = '' - filename_chunk = None - if 'printfilename' in opts: - for o in opts: - m= re.match ("filename=(.*)", o) - if m: - template = get_output ("output-filename") - b = basename + '.ly' - human_base = os.path.basename (m.group (1)) - - ## todo: include path, but strip - ## first part of the path. - filename_chunk = ('input', template % (human_base, b,human_base)) - break - - - if 'smallverbatim' in opts: - newbody += output_verbatim (body, 1) - elif 'verbatim' in opts: - newbody += output_verbatim (body, 0) - - for o in opts: - m = re.search ('intertext="(.*?)"', o) - if m: - newbody = newbody + "\n" - if format == 'texi': - newbody = newbody + "@noindent\n" - elif format == 'latex': - newbody = newbody + "\\noindent\n" - newbody = newbody + m.group (1) + "\n" - - if 'noinline' in opts: - s = 'output-noinline' - elif format == 'latex': - if 'quote' in opts: - s = 'output-latex-quoted' - elif 'eps' in opts: - s = 'output-eps' + h.write ('\n@html\n') + self.output_html () + h.write ('\n@end html\n') + + def outdated_p (self): + if self.type != 'lilypond-block' and self.type != 'lilypond'\ + and self.type != 'lilypond-file': + return None + base = self.basename () + if os.path.exists (base + '.ly') \ + and os.path.exists (base + '.tex') \ + and (use_hash_p \ + or self.ly () == open (base + '.ly').read ()): + # TODO: something smart with target formats + # (ps, png) and m/ctimes + return None + return self + + def filter_code (self): + global index + # Hmm, why is verbatim's group called 'code'; rename to 'verb'? + #if snippet.match.group ('code'): + # urg + if self.type == 'lilypond' or self.type == 'lilypond-block': + h.write (self.source[index:self.start ('code')]) + h.write (run_filter (self.substring ('code'))) + h.write (self.source[self.end ('code'):self.end (0)]) else: - s = 'output-latex-noquote' - elif format == 'texi': - if 'quote' in opts: - s = 'output-texi-quoted' + h.write (self.source[index:self.end (0)]) + index = self.end (0) + + def compile_output (self): + global index + # Hmm, why is verbatim's group called 'code'; rename to 'verb'? + # if snippet.match.group ('code'): + # urg + if self.type == 'lilypond' \ + or self.type == 'lilypond-block'\ + or self.type == 'lilypond-file': + h.write (self.source[index:self.start (0)]) + snippet_output = eval ("Snippet.output_" + format) + snippet_output (self) + elif self.type == 'include': + h.write (self.source[index:self.start ('filename')]) + base = os.path.splitext (self.substring ('filename'))[0] + h.write (base + format2ext[format]) + h.write (self.source[self.end ('filename'):self.end (0)]) else: - s = 'output-texi-noquote' - else: # format == 'html' - s = 'output-html' + h.write (self.source[index:self.end (0)]) + index = self.end (0) + +def find_toplevel_snippets (s, types): + res = {} + for i in types: + res[i] = ly.re.compile (snippet_res[format][i]) - def html_pages (basename): - pat = os.path.join (g_outdir, "%s-page*.png"% basename) + snippets = [] + index = 0 + found = {}.fromkeys (types) + while 1: + first = 0 + endex = 1 << 30 + for i in types: + if not found[i] or found[i].start (0) < index: + found[i] = 0 + m = res[i].search (s[index:endex]) + if m: + found[i] = Snippet (i, s, index, m) + if found[i] \ + and (not first \ + or found[i].start (0) < found[first].start (0)): + first = i + endex = found[first].start (0) + if not first: + break + snippets.append (found[first]) + index = found[first].end (0) - files = glob.glob (pat) + return snippets + +def filter_pipe (input, cmd): + if verbose_p: + ly.progress (_ ("Opening filter `%s\'") % cmd) + stdin, stdout, stderr = os.popen3 (cmd) + stdin.write (input) + status = stdin.close () + + if not status: + status = 0 + output = stdout.read () + status = stdout.close () + error = stderr.read () - template = '''[picture of music]''' - - str = '' - if files == []: - files = [basename+'.png' ] - else: - files = map (os.path.basename, files) - - for f in files: - str += template % f - - str = '%s' % (basename, str) - - return str - + if not status: + status = 0 + signal = 0x0f & status + if status or (not output and error): + exit_status = status >> 8 + ly.error (_ ("`%s\' failed (%d)") % (cmd, exit_status)) + ly.error (_ ("The error log is as follows:")) + sys.stderr.write (error) + sys.stderr.write (stderr.read ()) + ly.exit (status) - newbody = newbody + get_output (s) % {'fn': basename, - 'htmlimages': html_pages(basename) - } + if verbose_p: + ly.progress ('\n') - if filename_chunk: - return_chunks += [filename_chunk] + return output - return_chunks += [('lilypond', newbody, opts, todo, basename)] - - return return_chunks - -def format_lilypond_output_bodies (chunks): - newchunks = [] - for c in chunks: +def run_filter (s): + return filter_pipe (s, filter_cmd) + +def process_snippets (cmd, snippets): + names = filter (lambda x:x, map (Snippet.basename, snippets)) + if names: + ly.system (string.join ([cmd] + names)) + + if format == HTML or format == TEXINFO: + for i in names: + if os.path.exists (i + '.tex'): + to_eps (i) + ly.make_ps_images (i + '.eps', resolution=110) + +LATEX_DOCUMENT = r''' +%(preamble)s +\begin{document} +\typeout{textwidth=\the\textwidth} +\typeout{columnsep=\the\columnsep} +\makeatletter\if@twocolumn\typeout{columns=2}\fi\makeatother +\end{document} +''' +#need anything else besides textwidth? +def get_latex_textwidth (source): + m = re.search (r'''(?P\\begin\s*{document})''', source) + preamble = source[:m.start (0)] + latex_document = LATEX_DOCUMENT % vars () + parameter_string = filter_pipe (latex_document, latex_filter_cmd) + + columns = 0 + m = re.search ('columns=([0-9.]*)', parameter_string) + if m: + columns = string.atoi (m.group (1)) + + columnsep = 0 + m = re.search ('columnsep=([0-9.]*)pt', parameter_string) + if m: + columnsep = string.atof (m.group (1)) + + textwidth = 0 + m = re.search('textwidth=([0-9.]*)pt', parameter_string) + if m: + textwidth = string.atof (m.group (1)) + if columns: + textwidth = (textwidth - columnsep) / columns + + return textwidth + + +ext2format = { + '.html' : HTML, + '.itely' : TEXINFO, + '.lytex' : LATEX, + '.tely' : TEXINFO, + '.tex': LATEX, + '.texi' : TEXINFO, + '.texinfo' : TEXINFO, + '.xml' : HTML, + } + +format2ext = { + HTML: '.html', + #TEXINFO: '.texinfo', + TEXINFO: '.texi', + LATEX: '.tex', + } - if c[0] == 'lilypond': - newchunks += format_lilypond_block (c) +def do_file (input_filename): + #ugh + global format + if not format: + e = os.path.splitext (input_filename)[1] + if e in ext2format.keys (): + #FIXME + format = ext2format[e] else: - newchunks.append (c) - - return newchunks + ly.error (_ ("cannot determine format for: %s" \ + % input_filename)) - - -def process_lilypond_blocks (chunks):#ugh rename - newchunks = [] - # Count sections/chapters. - for c in chunks: - if c[0] == 'lilypond': - c = schedule_lilypond_block (c) - elif c[0] == 'numcols': - paperguru.m_num_cols = c[2] - elif c[0] == 'multicols': - paperguru.m_multicols = c[2] - - newchunks.append (c) - - return newchunks - -def process_ly2dvi_blocks (chunks): + ly.progress (_ ("Reading %s...") % input_filename) + if not input_filename or input_filename == '-': + ih = sys.stdin + else: + ih = open (input_filename) + source = ih.read () + ly.progress ('\n') + + ly.progress (_ ("Dissecting...")) + #snippets = find_toplevel_snippets (source, snippet_res[format].keys ()) + snippet_types = ( + 'lilypond-block', + 'verb', + 'verbatim', + 'singleline-comment', + 'multiline-comment', + 'lilypond-file', + 'include', + 'lilypond', ) - def process_ly2dvi_block (chunk): - """ - -Run ly2dvi script on filename specified in CHUNK. -This is only supported for HTML output. - -In HTML output it will leave a download menu with ps/pdf/midi etc. in -a separate HTML file, and a title + preview in the main html file, -linking to the menu. - - """ - (tag, name, opts) = chunk - assert format == 'html' - (content, original_name) = find_file (name) - - original_name = os.path.basename (original_name) - - base = unique_file_name (content) - outname = base + '.ly' - changed = update_file (content, outname) - - preview = base + ".preview.png" - preview_page = base + '-page1.png' - - if changed or not (os.path.isfile (preview) or - os.path.isfile (preview_page)): - - ly.system ('%s --preview --postscript --verbose %s ' % (ly2dvi_binary, base) ) - - ly.make_ps_images (base + '.ps') - ly.system ('gzip -9 - < %s.ps > %s.ps.gz' % (base, base)) - - def size_str (fn): - b = os.stat(fn)[stat.ST_SIZE] - if b < 1024: - return '%d bytes' % b - elif b < (2 << 20): - return '%d kb' % (b >> 10) - else: - return '%d mb' % (b >> 20) - - exts = { - 'pdf' : "Print (PDF, %s)", - 'ps.gz' : "Print (gzipped PostScript, %s)", - 'png' : "View (PNG, %s)", - 'midi' : "Listen (MIDI, %s)", - 'ly' : "View source code (%s)", - } - - menu = '' - page_files = glob.glob ('%s-page*.png' % base) - - for p in page_files: - p = p.strip() - if os.path.isfile (p): - sz = size_str (p) - page = re.sub ('.*page([0-9])+.*', 'View page \\1 (PNG picture, %s)\n', p) - page = page % sz - menu += '
  • %s' % (p, page) - - ext_order = ['ly', 'pdf', 'ps.gz', 'midi'] - for e in ext_order: - fn = base + '.' + e - print 'checking,' , fn - if not os.path.isfile (fn): - continue - - entry = exts[e] % size_str (fn) - - ## TODO: do something like - ## this for texinfo/latex as well ? - - menu += '
  • %s\n\n' % (fn, entry) + snippets = find_toplevel_snippets (source, snippet_types) + ly.progress ('\n') - - explanatory_para = """The pictures are 90dpi -anti-aliased snapshots of the printed output, in PNG format. Both PDF and PS -use scalable fonts and should look OK at any resolution.""" - - separate_menu =r''' -LilyPond example %s - -

    %s

    -

    -

    %s -

    -

      %s
    ''' % (original_name,original_name, preview, explanatory_para, menu) - - open (base + '.html','w'). write (separate_menu) - - inline_menu = '

    %s

    ' % (base, original_name, preview) - - return ('ly2dvi', inline_menu) - - newchunks = [] - for c in chunks: - if c[0] == 'ly2dvi': - c = process_ly2dvi_block (c) - newchunks.append (c) - - return newchunks - -def compile_all_files (chunks): - global foutn - eps = [] - tex = [] - png = [] - - for c in chunks: - if c[0] != 'lilypond': - continue - - base = c[4] - exts = c[3] - for e in exts: - if e == 'eps': - eps.append (base) - elif e == 'tex': - #ugh - if base + '.ly' not in tex: - tex.append (base + '.ly') - elif e == 'png' and g_do_pictures: - png.append (base) - d = os.getcwd () - if g_outdir: - os.chdir (g_outdir) - if tex: - # fixme: be sys-independent. - def incl_opt (x): - if g_outdir and x[0] != '/' : - x = os.path.join (g_here_dir, x) - return ' -I %s' % x - - incs = map (incl_opt, include_path) - lilyopts = string.join (incs) - if do_deps: - lilyopts += ' --dependencies' - if g_outdir: - lilyopts += ' --dep-prefix=' + g_outdir + '/' - lilyopts += ' --header=texidoc' - texfiles = string.join (tex) - cmd = string.join ((lilypond_binary, lilyopts, g_extra_opts, - texfiles)) - - ly.lilypond_version_check (lilypond_binary, '@TOPLEVEL_VERSION@') - - ly.system (cmd, ignore_error = 0, progress_p = 1) - - # - # Ugh, fixing up dependencies for .tex generation - # - if do_deps: - depfiles=map (lambda x: re.sub ('(.*)\.ly', '\\1.dep', - x), tex) - - for i in depfiles: - f =open (i) - text=f.read () - f.close () - text=re.sub ('\n([^:\n]*):', - '\n' + foutn + ':', text) - f = open (i, 'w') - f.write (text) - f.close () - - def to_eps (file): - cmd = r"latex '\nonstopmode \input %s'" % file - # Ugh. (La)TeX writes progress and error messages on stdout - # Redirect to stderr - cmd = '(( %s >&2 ) >&- )' % cmd + global h + if output_name == '-' or not output_name: + h = sys.stdout + output_filename = '-' + else: + if not os.path.isdir (output_name): + os.mkdir (output_name, 0777) + if input_filename == '-': + input_base = 'stdin' + else: + input_base = os.path.splitext (input_filename)[0] + output_filename = output_name + '/' + input_base \ + + format2ext[format] + h = open (output_filename, 'w') + os.chdir (output_name) + + global default_ly_options + textwidth = 0 + if format == LATEX and LINEWIDTH not in default_ly_options.keys (): + textwidth = get_latex_textwidth (source) + default_ly_options[LINEWIDTH] = '''%.0f\pt''' % textwidth + + global index + if filter_cmd: + index = 0 + map (Snippet.filter_code, snippets) + h.write (source[index:]) + elif process_cmd: + outdated = filter (lambda x:x, + map (Snippet.outdated_p, snippets)) + ly.progress (_ ("Writing snippets...")) + map (Snippet.write_ly, snippets) + ly.progress ('\n') - ly.system (cmd) - ly.system ("dvips -Ppdf -u+lilypond.map -E -o %s.eps %s" % (file, file)) - map (to_eps, eps) - - for p in png: - ly.make_ps_images (p + '.eps', resolution=110) - os.chdir (d) - - -def update_file (body, name): - ''' - write the body if it has changed. Return whether BODY has changed. - ''' - same = 0 - try: - f = open (name) - fs = f.read (-1) - same = (fs == body) - except: - pass - - if not same: - f = open (name , 'w') - f.write (body) - f.close () - - return not same - - -def write_deps (fn, target, chunks): - global read_files - sys.stderr.write ('Writing `%s\'\n' % os.path.join (g_outdir, fn)) - f = open (os.path.join (g_outdir, fn), 'w') - f.write ('%s%s: ' % (g_dep_prefix, target)) - for d in read_files: - f.write ('%s ' % d) - - - ## There used to be code to write .tex dependencies, but - ## that is silly: lilypond-book has its own dependency scheme - ## to ensure that all lily-XXX.tex files are there + if outdated: + ly.progress (_ ("Processing...")) + process_snippets (process_cmd, outdated) + else: + ly.progress (_ ("All snippets are up to date...")) + ly.progress ('\n') - - f.write ('\n') - f.close () - read_files = [] - -def check_texidoc (chunks): - ## TODO: put file name in front of texidoc. - ## - n = [] - for c in chunks: - if c[0] == 'lilypond': - (type, body, opts, todo, basename) = c; - pathbase = os.path.join (g_outdir, basename) - if os.path.isfile (pathbase + '.texidoc') \ - and 'notexidoc' not in opts: - n.append( ('input', '\n@include %s.texidoc\n\n' % basename)) - n.append (c) - return n - - -## what's this? Docme --hwn -## -def fix_epswidth (chunks): - newchunks = [] - for c in chunks: - if c[0] != 'lilypond' or 'eps' not in c[2]: - newchunks.append (c) - continue - - mag = 1.0 - for o in c[2]: - m = re.match ('magnification=([0-9.]+)', o) - if m: - mag = string.atof (m.group (1)) - - def replace_eps_dim (match, lmag = mag): - filename = match.group (1) - dims = bounding_box_dimensions (filename) - - return '%fpt' % (dims[0] *lmag) - - body = re.sub (r'''\\lilypondepswidth{(.*?)}''', replace_eps_dim, c[1]) - newchunks.append (('lilypond', body, c[2], c[3], c[4])) - - return newchunks - - -##docme: why global? -foutn="" - -def do_file (input_filename): - chunks = read_doc_file (input_filename) - chunks = chop_chunks (chunks, 'ly2dvi', make_ly2dvi_block, 1) - chunks = chop_chunks (chunks, 'lilypond', make_lilypond, 1) - chunks = chop_chunks (chunks, 'lilypond-file', make_lilypond_file, 1) - chunks = chop_chunks (chunks, 'lilypond-block', make_lilypond_block, 1) - chunks = chop_chunks (chunks, 'singleline-comment', do_ignore, 1) - chunks = chop_chunks (chunks, 'preamble-end', do_preamble_end) - chunks = chop_chunks (chunks, 'numcols', do_columns) - chunks = chop_chunks (chunks, 'multicols', do_multicols) + ly.progress (_ ("Compiling %s...") % output_filename) + index = 0 + map (Snippet.compile_output, snippets) + h.write (source[index:]) + ly.progress ('\n') + + if h != sys.stdout: + h.close () + + def process_include (snippet): + os.chdir (original_dir) + name = snippet.substring ('filename') + ly.progress (_ ('Processing include: %s') % name) + ly.progress ('\n') + do_file (name) + + map (process_include, filter (lambda x: x.type == 'include', snippets)) + +def do_options (): + global format, output_name + global filter_cmd, process_cmd, verbose_p - scan_preamble (chunks) - chunks = process_lilypond_blocks (chunks) - chunks = process_ly2dvi_blocks (chunks) - - # Do It. - global g_run_lilypond - if g_run_lilypond: - compile_all_files (chunks) - chunks = fix_epswidth (chunks) - - - chunks = format_lilypond_output_bodies (chunks) - global format - if format == 'texi': - chunks = check_texidoc (chunks) - - - x = 0 - chunks = completize_preamble (chunks) - - global foutn - - if outname: - my_outname = outname - elif input_filename == '-' or input_filename == "/dev/stdin": - my_outname = '-' - else: - my_outname = os.path.basename (os.path.splitext (input_filename)[0]) + '.' + format - my_depname = my_outname + '.dep' - - if my_outname == '-' or my_outname == '/dev/stdout': - fout = sys.stdout - foutn = "" - global do_deps - do_deps = 0 - else: - foutn = os.path.join (g_outdir, my_outname) - sys.stderr.write ("Writing `%s'\n" % foutn) - fout = open (foutn, 'w') - for c in chunks: - fout.write (c[1]) - fout.close () - # should chmod -w - - if do_deps: - write_deps (my_depname, foutn, chunks) - -outname = '' -try: (sh, long) = ly.getopt_args (option_definitions) - (options, files) = getopt.getopt (sys.argv[1:], sh, long) - -except getopt.error, msg: - sys.stderr.write ('\n') - ly.error (_ ("getopt says: `%s\'" % s)) - sys.stderr.write ('\n') - ly.help () - ly.exit (2) - -do_deps = 0 -for opt in options: - o = opt[0] - a = opt[1] - - if o == '--include' or o == '-I': - include_path.append (a) - elif o == '--version' or o == '-v': - ly.identify (sys.stdout) - sys.exit (0) - elif o == '--verbose' or o == '-V': - verbose_p = 1 - elif o == '--format' or o == '-f': - format = a - if a == 'texi-html': - format = 'texi' - g_make_html = 1 - elif o == '--outname' or o == '-o': - if len (files) > 1: - #HACK - sys.stderr.write ("lilypond-book is confused by --outname on multiple files") - sys.exit (1) - outname = a - elif o == '--help' or o == '-h': + try: + (options, files) = getopt.getopt (sys.argv[1:], sh, long) + except getopt.error, s: + sys.stderr.write ('\n') + ly.error (_ ("getopt says: `%s\'" % s)) + sys.stderr.write ('\n') ly.help () - sys.exit (0) - elif o == '--no-lily' or o == '-n': - g_run_lilypond = 0 - elif o == '--preview-resolution': - preview_resolution = string.atoi (a) - elif o == '--dependencies' or o == '-M': - do_deps = 1 - elif o == '--default-music-fontsize': - default_music_fontsize = string.atoi (a) - elif o == '--default-lilypond-fontsize': - print "--default-lilypond-fontsize is deprecated, use --default-music-fontsize" - default_music_fontsize = string.atoi (a) - elif o == '--extra-options': - g_extra_opts = a - elif o == '--force-music-fontsize': - g_force_music_fontsize = string.atoi (a) - elif o == '--force-lilypond-fontsize': - print "--force-lilypond-fontsize is deprecated, use --default-lilypond-fontsize" - g_force_music_fontsize = string.atoi (a) - elif o == '--dep-prefix': - g_dep_prefix = a - elif o == '--no-pictures': - g_do_pictures = 0 - elif o == '--no-music': - g_do_music = 0 - elif o == '--outdir': - g_outdir = a - elif o == '--warranty' or o == '-w': - #status = os.system ('lilypond -w') - if 1 or status: - ly.warranty () - sys.exit (0) - -ly.identify (sys.stderr) - -if g_outdir: - if os.path.isfile (g_outdir): - error ("outdir is a file: %s" % g_outdir) - if not os.path.exists (g_outdir): - os.mkdir (g_outdir) - -if not files: - ly.help () - ly.error (_ ("no files specified on command line")) - ly.exit (2) - -ly.setup_environment () + ly.exit (2) + for opt in options: + o = opt[0] + a = opt[1] -for input_filename in files: - do_file (input_filename) - - -# -# Petr, ik zou willen dat ik iets zinvoller deed, -# maar wat ik kan ik doen, het verandert toch niets? -# --hwn 20/aug/99 + if 0: + pass + elif o == '--filter' or o == '-F': + filter_cmd = a + process_cmd = 0 + elif o == '--format' or o == '-f': + format = a + if a == 'texi-html' or a == 'texi': + format = TEXINFO + elif o == '--help' or o == '-h': + ly.help () + sys.exit (0) + elif o == '--include' or o == '-I': + include_path.append (os.path.join (original_dir, + ly.abspath (a))) + elif o == '--output' or o == '-o': + output_name = a + elif o == '--outdir': + output_name = a + elif o == '--process' or o == '-P': + process_cmd = a + filter_cmd = 0 + elif o == '--version' or o == '-v': + ly.identify (sys.stdout) + sys.exit (0) + elif o == '--verbose' or o == '-V': + verbose_p = 1 + elif o == '--warranty' or o == '-w': + if 1 or status: + ly.warranty () + sys.exit (0) + return files + +def main (): + files = do_options () + ly.identify (sys.stderr) + ly.setup_environment () + if files: + do_file (files[0]) + +if __name__ == '__main__': + main () diff --git a/scripts/old-lilypond-book.py b/scripts/old-lilypond-book.py new file mode 100644 index 0000000000..ab4bc7b796 --- /dev/null +++ b/scripts/old-lilypond-book.py @@ -0,0 +1,1656 @@ +#!@PYTHON@ +# vim: set noexpandtab: + +""" + + TODO: + * junk --outdir for--output + * Figure out clean set of options. + * + * texinfo: add support for @pagesize + + todo: dimension handling (all the x2y) is clumsy. (tca: Thats + because the values are taken directly from texinfo.tex, + geometry.sty and article.cls. Give me a hint, and I'll + fix it.) + + + TODO: magnification support should also work for texinfo -> html: eg. add as option to dvips. + + + + This is a slightly hairy program. The general approach is as follows + The input string is chopped up in chunks, i.e. , a list of tuples + + with the format (TAG_STR, MAIN_STR, OPTIONS, TODO, BASE) + + This list is built step by step: first ignore and verbatim commands + are handled, delivering a list of chunks. + + then all chunks containing lilypond commands are chopped up + + when all chunks have their final form, all bodies from lilypond blocks are + extracted, and if applicable, written do disk and run through lilypond. + + +tags supported + + ignore + lilypond + input + verb + verbatim + multicols + numcols + + + + +""" + +# This is was the idea for handling of comments: +# Multiline comments, @ignore .. @end ignore is scanned for +# in read_doc_file, and the chunks are marked as 'ignore', so +# lilypond-book will not touch them any more. The content of the +# chunks are written to the output file. Also 'include' and 'input' +# regex has to check if they are commented out. +# + +# Then it is scanned for 'lilypond', 'lilypond-file' and 'lilypond-block'. +# These three regex's has to check if they are on a commented line, +# % for latex, @c for texinfo. +# +# Then lines that are commented out with % (latex) and @c (Texinfo) +# are put into chunks marked 'ignore'. This cannot be done before +# searching for the lilypond-blocks because % is also the comment character +# for lilypond. +# +# The the rest of the rexeces are searched for. They don't have to test +# if they are on a commented out line. + +import glob +import stat +import string + + +################################################################ +# Users of python modules should include this snippet +# and customize variables below. + +# We'll suffer this path init stuff as long as we don't install our +# python packages in /lib/pythonx.y (and don't kludge around +# it as we do with teTeX on Red Hat Linux: set some environment var +# (PYTHONPATH) in profile) + +# If set, LILYPONDPREFIX must take prevalence +# if datadir is not set, we're doing a build and LILYPONDPREFIX +import getopt, os, sys +datadir = '@local_lilypond_datadir@' +if not os.path.isdir (datadir): + datadir = '@lilypond_datadir@' +if os.environ.has_key ('LILYPONDPREFIX') : + datadir = os.environ['LILYPONDPREFIX'] + while datadir[-1] == os.sep: + datadir= datadir[:-1] + +sys.path.insert (0, os.path.join (datadir, 'python')) + +# Customize these +#if __name__ == '__main__': + +import lilylib as ly +global _;_=ly._ +global re;re = ly.re + +# lilylib globals +program_version = '@TOPLEVEL_VERSION@' +program_name = 'lilypond-book' +verbose_p = 0 +pseudo_filter_p = 0 +original_dir = os.getcwd () + + +preview_resolution = 90 + +## FIXME +## do -P or -p by default? +##help_summary = _ ("Run LilyPond using LaTeX for titling") +help_summary = _ ("Process LilyPond snippets in hybrid html, LaTeX or texinfo document") +copyright = ('Tom Cato Amundsen ', + 'Han-Wen Nienhuys ') + +option_definitions = [ + (_ ("EXT"), 'f', 'format', _ ("use output format EXT (texi [default], texi-html, latex, html)")), + (_ ("DIM"), '', 'default-music-fontsize', _ ("default fontsize for music. DIM is assumed to be in points")), + (_ ("DIM"), '', 'default-lilypond-fontsize', _ ("deprecated, use --default-music-fontsize")), + (_ ("OPT"), '', 'extra-options', _ ("pass OPT quoted to the lilypond command line")), + (_ ("DIM"), '', 'force-music-fontsize', _ ("force fontsize for all inline lilypond. DIM is assumed to be in points")), + (_ ("DIM"), '', 'force-lilypond-fontsize', _ ("deprecated, use --force-music-fontsize")), + ('', 'h', 'help', _ ("print this help")), + (_ ("DIR"), 'I', 'include', _ ("include path")), + ('', 'M', 'dependencies', _ ("write dependencies")), + (_ ("PREF"), '', 'dep-prefix', _ ("prepend PREF before each -M dependency")), + ('', 'n', 'no-lily', _ ("don't run lilypond")), + ('', '', 'no-pictures', _ ("don't generate pictures")), + ('', '', 'no-music', _ ("strip all lilypond blocks from output")), + (_ ("FILE"), 'o', 'outname', _ ("filename main output file")), + (_ ("FILE"), '', 'outdir', _ ("where to place generated files")), + (_ ('RES'), '', 'preview-resolution', + _ ("set the resolution of the preview to RES")), + ('', 'V', 'verbose', _ ("be verbose")), + ('', 'v', 'version', _ ("print version information")), + ('', 'w', 'warranty', _ ("show warranty and copyright")), + ] + +# format specific strings, ie. regex-es for input, and % strings for output + +# global variables + +include_path = [os.getcwd ()] + +#lilypond_binary = 'valgrind --suppressions=/home/hanwen/usr/src/guile-1.6.supp --num-callers=10 /home/hanwen/usr/src/lilypond/lily/out/lilypond' + +lilypond_binary = os.path.join ('@bindir@', 'lilypond-bin') + +# only use installed binary when we're installed too. +if '@bindir@' == ('@' + 'bindir@') or not os.path.exists (lilypond_binary): + lilypond_binary = 'lilypond-bin' + + + +ly2dvi_binary = os.path.join ('@bindir@', 'ly2dvi') + +# only use installed binary when we're installed too. +if '@bindir@' == ('@' + 'bindir@') or not os.path.exists (lilypond_binary): + ly2dvi_binary = 'ly2dvi' + + + +g_extra_opts = '' +g_here_dir = os.getcwd () +g_dep_prefix = '' +g_outdir = '' +g_force_music_fontsize = 0 +g_do_pictures = 1 +g_do_music = 1 +g_make_html = 0 + +format = '' +g_run_lilypond = 1 +no_match = 'a\ba' + +default_music_fontsize = 16 +default_text_fontsize = 12 +paperguru = None + +################################################################ +# Dimension handling for LaTeX. +# +class LatexPaper: + def __init__ (self): + self.m_document_preamble = [] + self.m_num_cols = 1 + self.m_multicols = 1 + + def find_latex_dims (self): + if g_outdir: + fname = os.path.join (g_outdir, "lily-tmp.tex") + else: + fname = "lily-tmp.tex" + try: + f = open (fname, "w") + except IOError: + error ("Error creating temporary file '%s'" % fname) + + for s in self.m_document_preamble: + f.write (s) + f.write (r""" +\begin{document} +\typeout{---} +\typeout{\columnsep \the\columnsep} +\typeout{\textwidth \the\textwidth} +\typeout{---} +\end{document} + """) + f.close () + re_dim = re.compile (r"\\(\w+)\s+(\d+\.\d+)") + + cmd = "latex '\\nonstopmode \input %s'" % fname + # Ugh. (La)TeX writes progress and error messages on stdout + # Redirect to stderr + cmd = '(( %s >&2 ) >&- )' % cmd + status = ly.system (cmd, ignore_error = 1) + signal = 0xf & status + exit_status = status >> 8 + + if status: + ly.error (_ ("LaTeX failed.")) + ly.error (_ ("The error log is as follows:")) + + #URG see lilypond + try: + lns = open ('lily-tmp.log').readlines () + except: + lns = '' + countdown = -3 + for ln in lns: + sys.stderr.write (ln) + if re.match ('^!', ln): + countdown = 3 + + if countdown == 0: + break + + if countdown > 0: + countdown = countdown -1 + + sys.stderr.write (" ... (further messages elided)...\n") + sys.exit (1) + + lns = open ('lily-tmp.log').readlines () + for ln in lns: + ln = string.strip (ln) + m = re_dim.match (ln) + if m: + if m.groups ()[0] in ('textwidth', 'columnsep'): + self.__dict__['m_%s' % m.groups ()[0]] = float (m.groups ()[1]) + + try: + os.remove (fname) + os.remove (os.path.splitext (fname)[0]+".aux") + os.remove (os.path.splitext (fname)[0]+".log") + except: + pass + + if not self.__dict__.has_key ('m_textwidth'): + raise 'foo!' + + def get_linewidth (self): + if self.m_num_cols == 1: + w = self.m_textwidth + else: + w = (self.m_textwidth - self.m_columnsep)/2 + if self.m_multicols > 1: + return (w - self.m_columnsep* (self.m_multicols-1)) \ + / self.m_multicols + return w + + +class HtmlPaper: + def __init__ (self): + self.m_papersize = 'letterpaper' + self.m_fontsize = 12 + def get_linewidth (self): + return html_linewidths[self.m_papersize][self.m_fontsize] + +class TexiPaper: + def __init__ (self): + self.m_papersize = 'letterpaper' + self.m_fontsize = 12 + def get_linewidth (self): + return texi_linewidths[self.m_papersize][self.m_fontsize] + +def mm2pt (x): + return x * 2.8452756 +def in2pt (x): + return x * 72.26999 +def em2pt (x, fontsize = 10): + return {10: 10.00002, 11: 10.8448, 12: 11.74988}[fontsize] * x +def ex2pt (x, fontsize = 10): + return {10: 4.30554, 11: 4.7146, 12: 5.16667}[fontsize] * x + +def pt2pt (x): + return x + +dimension_conversion_dict ={ + 'mm': mm2pt, + 'cm': lambda x: mm2pt (10*x), + 'in': in2pt, + 'em': em2pt, + 'ex': ex2pt, + 'pt': pt2pt + } + +# Convert numeric values, with or without specific dimension, to floats. +# Keep other strings +def conv_dimen_to_float (value): + if type (value) == type (""): + m = re.match ("([0-9.]+)(cm|in|pt|mm|em|ex)",value) + if m: + unit = m.group (2) + num = string.atof (m.group (1)) + conv = dimension_conversion_dict[m.group (2)] + + value = conv (num) + + elif re.match ("^[0-9.]+$",value): + value = float (value) + + return value + +texi_linewidths = { + 'afourpaper': {12: mm2pt (160)}, + 'afourwide': {12: in2pt (6.5)}, + 'afourlatex': {12: mm2pt (150)}, + 'smallbook': {12: in2pt (5)}, + 'letterpaper': {12: in2pt (6)}} + +html_linewidths = { + 'afourpaper': {12: mm2pt (160)}, + 'afourwide': {12: in2pt (6.5)}, + 'afourlatex': {12: mm2pt (150)}, + 'smallbook': {12: in2pt (5)}, + 'letterpaper': {12: in2pt (6)}} + + +################################################################ +# How to output various structures. +output_dict= { + + + 'html' : { + + 'output-filename' : r''' + +''', + ## maybe


    ? + 'pagebreak': None, + # Verbatim text is always finished with \n. FIXME: For HTML, + # this newline should be removed. + 'output-verbatim': r'''
    +%s
    ''', + # Verbatim text is always finished with \n. FIXME: For HTML, + # this newline should be removed. + 'output-small-verbatim': r'''
    +%s
    ''', + ## Ugh we need to differentiate on origin: + ## lilypond-block origin wants an extra

    , but + ## inline music doesn't. + ## possibly other center options? + 'output-html': r''' +%(htmlimages)s''', + }, + + + 'latex': { + + 'output-lilypond-fragment' : r'''\begin[singleline,%s]{lilypond} + \context Voice{ + %s + } +\end{lilypond}''', + 'output-filename' : r'''\verb+%s+:\\ +%% %s +%% %s +''', + + # verbatim text is always finished with \n + 'output-verbatim': r'''\begin{verbatim} +%s\end{verbatim} +''', + # verbatim text is always finished with \n + 'output-small-verbatim': r'''{\small\begin{verbatim} +%s\end{verbatim}} +''', + 'output-default-post': "\\def\postLilyPondExample{}\n", + 'output-default-pre': "\\def\preLilyPondExample{}\n", + 'usepackage-graphics': '\\usepackage{graphics}\n', + 'output-eps': '\\noindent\includegraphics{%(fn)s}', + 'output-noinline': r''' +%% generated: %(fn)s.eps +''', + 'output-latex-quoted': r'''{\preLilyPondExample +\def\lilypondbook{} +\input %(fn)s.tex +\postLilyPondExample}''', + 'output-latex-noquote': r'''{\parindent 0pt +\preLilyPondExample +\def\lilypondbook{} +\input %(fn)s.tex +\postLilyPondExample}''', + 'pagebreak': r'\pagebreak', + }, + + + 'texi' : { + + + 'output-filename' : r''' +@ifnothtml +@file{%s}:@* +@end ifnothtml +@ifhtml +@uref{%s,@file{%s}} +@end ifhtml +''', + 'output-lilypond-fragment': '''@lilypond[%s] +\context Staff\context Voice{ %s } +@end lilypond ''', + 'output-noinline': r''' +@c generated: %(fn)s.png +''', + 'pagebreak': None, + # verbatim text is always finished with \n + 'output-small-verbatim': r'''@smallexample +%s@end smallexample +''', + # verbatim text is always finished with \n + 'output-verbatim': r'''@example +%s@end example +''', + # do some tweaking: @ is needed in some ps stuff. + # + # ugh, the

    below breaks inline images... + 'output-texi-noquote': r'''@tex +\catcode`\@=12 +\parindent 0pt +\def\lilypondbook{} +\input %(fn)s.tex +\catcode`\@=0 +@end tex +@html +

    %(htmlimages)s +

    +@end html +''', + 'output-texi-quoted': r'''@quotation +@tex +\catcode`\@=12 +\def\lilypondbook{} +\input %(fn)s.tex +\catcode`\@=0 +@end tex +@html +

    %(htmlimages)s +

    +@end html +@end quotation +''', + } + + } + +def output_verbatim (body, small): + global format + if format == 'html': + body = re.sub ('&', '&', body) + body = re.sub ('>', '>', body) + body = re.sub ('<', '<', body) + elif format == 'texi': + # clumsy workaround for python 2.2 pre bug. + body = re.sub ('@', '@@', body) + body = re.sub ('{', '@{', body) + body = re.sub ('}', '@}', body) + + if small: + key = 'output-small-verbatim' + else: + key = 'output-verbatim' + return get_output (key) % body + + +################################################################ +# Recognize special sequences in the input + + +# Warning: This uses extended regular expressions. Tread with care. +# +# legenda +# +# (?Pregex) -- assign result of REGEX to NAME +# *? -- match non-greedily. +# (?m) -- multiline regex: make ^ and $ match at each line +# (?s) -- make the dot match all characters including newline +re_dict = { + 'html': { + 'include': no_match, + 'input': no_match, + 'header': no_match, + 'preamble-end': no_match, + 'landscape': no_match, + 'verbatim': r'''(?s)(?P

    \s.*?
    \s)''', + 'verb': r'''(?P
    .*?
    )''', + 'lilypond-file': r'(?m)(?P[^>]+)?>\s*(?P[^<]+)\s*)', + 'lilypond' : '(?m)(?P[^:]*):)(?P.*?)/>)', + 'lilypond-block': r'''(?ms)(?P[^>]+)?>(?P.*?))''', + 'option-sep' : '\s*', + 'intertext': r',?\s*intertext=\".*?\"', + 'multiline-comment': r"(?sm)\s*(?!@c\s+)(?P)\s", + 'singleline-comment': no_match, + 'numcols': no_match, + 'multicols': no_match, + 'ly2dvi': r'(?m)(?P[^>]+)?>\s*(?P[^<]+)\s*)', + }, + + 'latex': { + 'input': r'(?m)^[^%\n]*?(?P\\mbinput{?([^}\t \n}]*))', + 'include': r'(?m)^[^%\n]*?(?P\\mbinclude{(?P[^}]+)})', + 'option-sep' : ',\s*', + 'header': r"\n*\\documentclass\s*(\[.*?\])?", + 'preamble-end': r'(?P\\begin\s*{document})', + 'verbatim': r"(?s)(?P\\begin\s*{verbatim}.*?\\end{verbatim})", + 'verb': r"(?P\\verb(?P.).*?(?P=del))", + 'lilypond-file': r'(?m)^[^%\n]*?(?P\\lilypondfile\s*(\[(?P.*?)\])?\s*\{(?P.+)})', + 'lilypond' : r'(?m)^[^%\n]*?(?P\\lilypond\s*(\[(?P.*?)\])?\s*{(?P.*?)})', + 'lilypond-block': r"(?sm)^[^%\n]*?(?P\\begin\s*(\[(?P.*?)\])?\s*{lilypond}(?P.*?)\\end{lilypond})", + 'def-post-re': r"\\def\\postLilyPondExample", + 'def-pre-re': r"\\def\\preLilyPondExample", + 'usepackage-graphics': r"\usepackage\s*{graphics}", + 'intertext': r',?\s*intertext=\".*?\"', + 'multiline-comment': no_match, + 'singleline-comment': r"(?m)^.*?(?P(?P^%.*$\n+))", + 'numcols': r"(?P\\(?Pone|two)column)", + 'multicols': r"(?P\\(?Pbegin|end)\s*{multicols}({(?P\d+)?})?)", + 'ly2dvi': no_match, + + }, + + # why do we have distinction between @mbinclude and @include? + + 'texi': { + 'include': '(?m)^[^%\n]*?(?P@mbinclude\s+(?P\S*))', + 'input': no_match, + 'header': no_match, + 'preamble-end': no_match, + 'landscape': no_match, + 'verbatim': r'''(?s)(?P@example\s.*?@end example\s)''', + 'verb': r'''(?P@code{.*?})''', + 'lilypond-file': '(?m)^(?P@lilypondfile(\[(?P[^]]*)\])?{(?P[^}]+)})', + 'lilypond' : '(?m)^(?P@lilypond(\[(?P[^]]*)\])?{(?P.*?)})', + 'lilypond-block': r'''(?ms)^(?P@lilypond(\[(?P[^]]*)\])?\s(?P.*?)@end lilypond)\s''', + 'option-sep' : ',\s*', + 'intertext': r',?\s*intertext=\".*?\"', + 'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P@ignore\s.*?@end ignore)\s", + 'singleline-comment': r"(?m)^.*?(?P(?P@c.*$\n+))", + 'numcols': no_match, + 'multicols': no_match, + 'ly2dvi': no_match, + } + } + + +for r in re_dict.keys (): + olddict = re_dict[r] + newdict = {} + for k in olddict.keys (): + try: + newdict[k] = re.compile (olddict[k]) + except: + print 'invalid regexp: %s' % olddict[k] + + ## we'd like to catch and reraise a more + ## detailed error, but alas, the exceptions + ## changed across the 1.5/2.1 boundary. + + raise "Invalid re" + re_dict[r] = newdict + + +def uniq (list): + list.sort () + s = list + list = [] + for x in s: + if x not in list: + list.append (x) + return list + + +def get_output (name): + return output_dict[format][name] + +def get_re (name): + return re_dict[format][name] + +def bounding_box_dimensions (fname): + if g_outdir: + fname = os.path.join (g_outdir, fname) + try: + fd = open (fname) + except IOError: + error ("Error opening `%s'" % fname) + str = fd.read () + s = re.search ('%%BoundingBox: ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)', str) + if s: + + gs = map (lambda x: string.atoi (x), s.groups ()) + return (int (gs[2] - gs[0] + 0.5), + int (gs[3] - gs[1] + 0.5)) + else: + return (0,0) + +def error (str): + sys.stderr.write ("\n\n" + str + "\nExiting ... \n\n") + raise 'Exiting.' + + +def compose_full_body (body, opts): + '''Construct the lilypond code to send to LilyPond. + Add stuff to BODY using OPTS as options.''' + music_size = default_music_fontsize + if g_force_music_fontsize: + music_size = g_force_music_fontsize + indent = '' + linewidth = '' + notime = '' + for o in opts: + if not g_force_music_fontsize: + m = re.match ('([0-9]+)pt', o) + if m: + music_size = string.atoi (m.group (1)) + + m = re.match ('indent=([-.0-9]+)(cm|in|mm|pt)', o) + if m: + f = float (m.group (1)) + indent = 'indent = %f\\%s' % (f, m.group (2)) + + m = re.match ('linewidth=([-.0-9]+)(cm|in|mm|pt)', o) + if m: + f = float (m.group (1)) + linewidth = 'linewidth = %f\\%s' % (f, m.group (2)) + + if re.search ('\\\\score', body): + is_fragment = 0 + else: + is_fragment = 1 + if 'fragment' in opts: + is_fragment = 1 + if 'nofragment' in opts: + is_fragment = 0 + + if is_fragment and not 'multiline' in opts: + opts.append ('singleline') + + if 'raggedright' in opts or 'singleline' in opts: + if not linewidth: + linewidth = 'raggedright = ##t' + if not indent: + indent = 'indent = 0.0\mm' + elif not linewidth: + global paperguru + l = paperguru.get_linewidth () + linewidth = 'linewidth = %f\pt' % l + + if 'noindent' in opts: + indent = 'indent = 0.0\mm' + + if 'notime' in opts: + notime = r''' +\translator { + \StaffContext + \remove Time_signature_engraver +} +''' + + orig_name = '' + for o in opts: + m= re.search ('relative(.*)', o) + v = 0 + if m: + try: + v = string.atoi (m.group (1)) + except ValueError: + pass + + v = v + 1 + pitch = 'c' + if v < 0: + pitch = pitch + '\,' * v + elif v > 0: + pitch = pitch + '\'' * v + + body = '\\relative %s { %s }' % (pitch, body) + m =re.search ("filename=(.*)", o) + if m: + orig_name = m.group (1) + + if is_fragment: + body = r''' +\score { + \notes { +%s + } +} +''' % body + + opts = uniq (opts) + optstring = string.join (opts, ' ') + optstring = re.sub ('\n', ' ', optstring) + body = r''' +%% Generated automatically by: lilypond-book.py +%% options are %s +#(set-global-staff-size %d) + +\paper { + %s + %s + %s +} +''' % (optstring, music_size, linewidth, indent, notime) + body + + if orig_name: + body = '\\renameinput \"%s\"\n%s' % (orig_name, body) + + + # ughUGH not original options + return body + +def scan_html_preamble (chunks): + return + +def scan_latex_preamble (chunks): + # First we want to scan the \documentclass line + # it should be the first non-comment line. + # The only thing we really need to know about the \documentclass line + # is if there are one or two columns to begin with. + idx = 0 + while 1: + if chunks[idx][0] == 'ignore': + idx = idx + 1 + continue + m = get_re ('header').match (chunks[idx][1]) + if not m: + error ("Latex documents must start with a \documentclass command") + if m.group (1): + options = re.split (r',\s*', m.group (1)[1:-1]) + else: + options = [] + if 'twocolumn' in options: + paperguru.m_num_cols = 2 + break + + + # Then we add everything before \begin{document} to + # paperguru.m_document_preamble so that we can later write this header + # to a temporary file in find_latex_dims() to find textwidth. + while idx < len (chunks) and chunks[idx][0] != 'preamble-end': + if chunks[idx] == 'ignore': + idx = idx + 1 + continue + paperguru.m_document_preamble.append (chunks[idx][1]) + idx = idx + 1 + + if len (chunks) == idx: + error ("Didn't find end of preamble (\\begin{document})") + + paperguru.find_latex_dims () + +def scan_texi_preamble (chunks): + # this is not bulletproof..., it checks the first 10 chunks + for c in chunks[:10]: + if c[0] == 'input': + for s in ('afourpaper', 'afourwide', 'letterpaper', + 'afourlatex', 'smallbook'): + if string.find (c[1], "@%s" % s) != -1: + paperguru.m_papersize = s + + +def scan_preamble (chunks): + global format + if format == 'html': + scan_html_preamble (chunks) + elif format == 'latex': + scan_latex_preamble (chunks) + elif format == 'texi': + scan_texi_preamble (chunks) + + +def completize_preamble (chunks): + global format + if format != 'latex': + return chunks + pre_b = post_b = graphics_b = None + for chunk in chunks: + if chunk[0] == 'preamble-end': + break + if chunk[0] == 'input': + m = get_re ('def-pre-re').search (chunk[1]) + if m: + pre_b = 1 + if chunk[0] == 'input': + m = get_re ('def-post-re').search (chunk[1]) + if m: + post_b = 1 + + if chunk[0] == 'input': + m = get_re ('usepackage-graphics').search (chunk[1]) + if m: + graphics_b = 1 + x = 0 + while x < len (chunks) and chunks[x][0] != 'preamble-end': + x = x + 1 + + if x == len (chunks): + return chunks + + if not pre_b: + chunks.insert (x, ('input', get_output ('output-default-pre'))) + if not post_b: + chunks.insert (x, ('input', get_output ('output-default-post'))) + if not graphics_b: + chunks.insert (x, ('input', get_output ('usepackage-graphics'))) + + return chunks + + +read_files = [] +def find_file (name): + ''' + Search the include path for NAME. If found, return the (CONTENTS, PATH) of the file. + ''' + + if name == '-': + return (sys.stdin.read (), '') + f = None + nm = '' + for a in include_path: + try: + nm = os.path.join (a, name) + f = open (nm) + global read_files + read_files.append (nm) + break + except IOError: + pass + if f: + sys.stderr.write ("Reading `%s'\n" % nm) + return (f.read (), nm) + else: + error ("File not found `%s'\n" % name) + return ('', '') + +def do_ignore (match_object): + return [('ignore', match_object.group ('code'))] +def do_preamble_end (match_object): + return [('preamble-end', match_object.group ('code'))] + +def make_verbatim (match_object): + return [('verbatim', match_object.group ('code'))] + +def make_verb (match_object): + return [('verb', match_object.group ('code'))] + +def do_include_file (m): + "m: MatchObject" + return [('input', get_output ('pagebreak'))] \ + + read_doc_file (m.group ('filename')) \ + + [('input', get_output ('pagebreak'))] + +def do_input_file (m): + return read_doc_file (m.group ('filename')) + +def make_lilypond (m): + if m.group ('options'): + options = m.group ('options') + else: + options = '' + return [('input', get_output ('output-lilypond-fragment') % + (options, m.group ('code')))] + +def make_lilypond_file (m): + ''' + + Find @lilypondfile{bla.ly} occurences and substitute bla.ly + into a @lilypond .. @end lilypond block. + + ''' + + if m.group ('options'): + options = get_re ('option-sep').split (m.group ('options')) + else: + options = [] + (content, nm) = find_file (m.group ('filename')) + options.append ("filename=%s" % nm) + (path, base) = os.path.split (nm) + + if path not in include_path: + include_path.append (path) + + return [('lilypond', content, options)] + + +def make_ly2dvi_block (m): + ''' + + Find + ''' + + return [('ly2dvi', m.group ('filename'), m.group ('options'))] + + +def make_lilypond_block (m): + if not g_do_music: + return [] + + if m.group ('options'): + options = get_re ('option-sep').split (m.group ('options')) + else: + options = [] + options = filter (lambda s: s != '', options) + return [('lilypond', m.group ('code'), options)] + + +def do_columns (m): + global format + if format != 'latex': + return [] + if m.group ('num') == 'one': + return [('numcols', m.group ('code'), 1)] + if m.group ('num') == 'two': + return [('numcols', m.group ('code'), 2)] + +def do_multicols (m): + global format + if format != 'latex': + return [] + if m.group ('be') == 'begin': + return [('multicols', m.group ('code'), int (m.group ('num')))] + else: + return [('multicols', m.group ('code'), 1)] + return [] + +def chop_chunks (chunks, re_name, func, use_match=0): + newchunks = [] + for c in chunks: + if c[0] == 'input': + str = c[1] + while str: + m = get_re (re_name).search (str) + if m == None: + newchunks.append (('input', str)) + str = '' + else: + if use_match: + newchunks.append (('input', str[:m.start ('match')])) + else: + newchunks.append (('input', str[:m.start (0)])) + #newchunks.extend (func (m)) + # python 1.5 compatible: + newchunks = newchunks + func (m) + str = str [m.end (0):] + else: + newchunks.append (c) + return newchunks + +def determine_format (str): + """ + + SIDE EFFECT! This sets FORMAT and PAPERGURU + + """ + + global format + if format == '': + html = re.search ('(?i)<[dh]tml', str[:200]) + latex = re.search (r'''\\document''', str[:200]) + texi = re.search ('@node|@setfilename', str[:200]) + + f = '' + g = None + + if html and not latex and not texi: + f = 'html' + elif latex and not html and not texi: + f = 'latex' + elif texi and not html and not latex: + f = 'texi' + else: + error ("can't determine format, please specify") + format = f + + global paperguru + if paperguru == None: + if format == 'html': + g = HtmlPaper () + elif format == 'latex': + g = LatexPaper () + elif format == 'texi': + g = TexiPaper () + + paperguru = g + + +def read_doc_file (filename): + '''Read the input file, find verbatim chunks and do \input and \include + ''' + (str, path) = find_file (filename) + determine_format (str) + + chunks = [('input', str)] + + # we have to check for verbatim before doing include, + # because we don't want to include files that are mentioned + # inside a verbatim environment + chunks = chop_chunks (chunks, 'verbatim', make_verbatim) + + chunks = chop_chunks (chunks, 'verb', make_verb) + chunks = chop_chunks (chunks, 'multiline-comment', do_ignore) + #ugh fix input + chunks = chop_chunks (chunks, 'include', do_include_file, 1) + chunks = chop_chunks (chunks, 'input', do_input_file, 1) + return chunks + + +taken_file_names = {} + +def unique_file_name (body): + return 'lily-' + `abs (hash (body))` + +def schedule_lilypond_block (chunk): + '''Take the body and options from CHUNK, figure out how the + real .ly should look. The .ly is written, and scheduled in + TODO. + + Return: a single chunk. + + The chunk pertaining to the lilypond output + has the format (TYPE_STR, MAIN_STR, OPTIONS, TODO, BASE), + where TODO has format [basename, extension, extension, ... ] + ''' + + (type, body, opts) = chunk + assert type == 'lilypond' + file_body = compose_full_body (body, opts) + ## Hmm, we should hash only lilypond source, and skip the + ## %options are ... + ## comment line + basename = unique_file_name (file_body) + for o in opts: + m = re.search ('filename="(.*?)"', o) + if m: + basename = m.group (1) + if not taken_file_names.has_key (basename): + taken_file_names[basename] = 0 + else: + taken_file_names[basename] = taken_file_names[basename] + 1 + basename = basename + "-t%i" % taken_file_names[basename] + update_file (file_body, os.path.join (g_outdir, basename) + '.ly') + needed_filetypes = ['tex'] + + if format == 'html' or g_make_html: + needed_filetypes.append ('eps') + needed_filetypes.append ('png') + if 'eps' in opts and not ('eps' in needed_filetypes): + needed_filetypes.append ('eps') + + pathbase = os.path.join (g_outdir, basename) + def must_rebuild (base, ext1, ext2): + + f2 = base + ext2 + f1 = base + ext1 + fp2 = base + '-page1' + ext2 + + isfile2 = os.path.isfile (f2) + + if not isfile2 and os.path.isfile (fp2): + f2 = fp2 + isfile2 = os.path.isfile (fp2) + + if (os.path.isfile (f2) and isfile2 and + os.stat (f1)[stat.ST_MTIME] > + os.stat (f2)[stat.ST_MTIME]) or \ + not isfile2: + + return 1 + + todo = [] + if 'tex' in needed_filetypes and must_rebuild (pathbase, '.ly', '.tex'): + todo.append ('tex') + if 'eps' in needed_filetypes and must_rebuild (pathbase, '.tex', '.eps'): + todo.append ('eps') + if 'png' in needed_filetypes and must_rebuild (pathbase, '.eps', '.png'): + todo.append ('png') + + return ('lilypond', body, opts, todo, basename) + +def format_lilypond_block (chunk): + """ + + Figure out what should be left MAIN_STR (meant + for the main file) from a lilypond chunk: process + verbatim, and other options. Return: multiple chunks. + + + """ + + + return_chunks = [] + + (type, body, opts, todo, basename) = chunk + assert type == 'lilypond' + + + newbody = '' + filename_chunk = None + if 'printfilename' in opts: + for o in opts: + m= re.match ("filename=(.*)", o) + if m: + template = get_output ("output-filename") + b = basename + '.ly' + human_base = os.path.basename (m.group (1)) + + ## todo: include path, but strip + ## first part of the path. + filename_chunk = ('input', template % (human_base, b,human_base)) + break + + + if 'smallverbatim' in opts: + newbody += output_verbatim (body, 1) + elif 'verbatim' in opts: + newbody += output_verbatim (body, 0) + + for o in opts: + m = re.search ('intertext="(.*?)"', o) + if m: + newbody = newbody + "\n" + if format == 'texi': + newbody = newbody + "@noindent\n" + elif format == 'latex': + newbody = newbody + "\\noindent\n" + newbody = newbody + m.group (1) + "\n" + + if 'noinline' in opts: + s = 'output-noinline' + elif format == 'latex': + if 'quote' in opts: + s = 'output-latex-quoted' + elif 'eps' in opts: + s = 'output-eps' + else: + s = 'output-latex-noquote' + elif format == 'texi': + if 'quote' in opts: + s = 'output-texi-quoted' + else: + s = 'output-texi-noquote' + else: # format == 'html' + s = 'output-html' + + def html_pages (basename): + pat = os.path.join (g_outdir, "%s-page*.png"% basename) + + files = glob.glob (pat) + + + template = '''[picture of music]''' + + str = '' + if files == []: + files = [basename+'.png' ] + else: + files = map (os.path.basename, files) + + for f in files: + str += template % f + + str = '%s' % (basename, str) + + return str + + + newbody = newbody + get_output (s) % {'fn': basename, + 'htmlimages': html_pages(basename) + } + + if filename_chunk: + return_chunks += [filename_chunk] + + return_chunks += [('lilypond', newbody, opts, todo, basename)] + + return return_chunks + +def format_lilypond_output_bodies (chunks): + newchunks = [] + for c in chunks: + + if c[0] == 'lilypond': + newchunks += format_lilypond_block (c) + else: + newchunks.append (c) + + return newchunks + + + +def process_lilypond_blocks (chunks):#ugh rename + newchunks = [] + # Count sections/chapters. + for c in chunks: + if c[0] == 'lilypond': + c = schedule_lilypond_block (c) + elif c[0] == 'numcols': + paperguru.m_num_cols = c[2] + elif c[0] == 'multicols': + paperguru.m_multicols = c[2] + + newchunks.append (c) + + return newchunks + +def process_ly2dvi_blocks (chunks): + + def process_ly2dvi_block (chunk): + """ + +Run ly2dvi script on filename specified in CHUNK. +This is only supported for HTML output. + +In HTML output it will leave a download menu with ps/pdf/midi etc. in +a separate HTML file, and a title + preview in the main html file, +linking to the menu. + + """ + (tag, name, opts) = chunk + assert format == 'html' + (content, original_name) = find_file (name) + + original_name = os.path.basename (original_name) + + base = unique_file_name (content) + outname = base + '.ly' + changed = update_file (content, outname) + + preview = base + ".preview.png" + preview_page = base + '-page1.png' + + if changed or not (os.path.isfile (preview) or + os.path.isfile (preview_page)): + + ly.system ('%s --preview --postscript --verbose %s ' % (ly2dvi_binary, base) ) + + ly.make_ps_images (base + '.ps') + ly.system ('gzip -9 - < %s.ps > %s.ps.gz' % (base, base)) + + def size_str (fn): + b = os.stat(fn)[stat.ST_SIZE] + if b < 1024: + return '%d bytes' % b + elif b < (2 << 20): + return '%d kb' % (b >> 10) + else: + return '%d mb' % (b >> 20) + + exts = { + 'pdf' : "Print (PDF, %s)", + 'ps.gz' : "Print (gzipped PostScript, %s)", + 'png' : "View (PNG, %s)", + 'midi' : "Listen (MIDI, %s)", + 'ly' : "View source code (%s)", + } + + menu = '' + page_files = glob.glob ('%s-page*.png' % base) + + for p in page_files: + p = p.strip() + if os.path.isfile (p): + sz = size_str (p) + page = re.sub ('.*page([0-9])+.*', 'View page \\1 (PNG picture, %s)\n', p) + page = page % sz + menu += '
  • %s' % (p, page) + + ext_order = ['ly', 'pdf', 'ps.gz', 'midi'] + for e in ext_order: + fn = base + '.' + e + print 'checking,' , fn + if not os.path.isfile (fn): + continue + + entry = exts[e] % size_str (fn) + + ## TODO: do something like + ## this for texinfo/latex as well ? + + menu += '
  • %s\n\n' % (fn, entry) + + + explanatory_para = """The pictures are 90dpi +anti-aliased snapshots of the printed output, in PNG format. Both PDF and PS +use scalable fonts and should look OK at any resolution.""" + + separate_menu =r''' +LilyPond example %s + +

    %s

    +

    +

    %s +

    +

      %s
    ''' % (original_name,original_name, preview, explanatory_para, menu) + + open (base + '.html','w'). write (separate_menu) + + inline_menu = '

    %s

    ' % (base, original_name, preview) + + return ('ly2dvi', inline_menu) + + newchunks = [] + for c in chunks: + if c[0] == 'ly2dvi': + c = process_ly2dvi_block (c) + newchunks.append (c) + + return newchunks + +def compile_all_files (chunks): + global foutn + eps = [] + tex = [] + png = [] + + for c in chunks: + if c[0] != 'lilypond': + continue + + base = c[4] + exts = c[3] + for e in exts: + if e == 'eps': + eps.append (base) + elif e == 'tex': + #ugh + if base + '.ly' not in tex: + tex.append (base + '.ly') + elif e == 'png' and g_do_pictures: + png.append (base) + d = os.getcwd () + if g_outdir: + os.chdir (g_outdir) + if tex: + # fixme: be sys-independent. + def incl_opt (x): + if g_outdir and x[0] != '/' : + x = os.path.join (g_here_dir, x) + return ' -I %s' % x + + incs = map (incl_opt, include_path) + lilyopts = string.join (incs) + if do_deps: + lilyopts += ' --dependencies' + if g_outdir: + lilyopts += ' --dep-prefix=' + g_outdir + '/' + lilyopts += ' --header=texidoc' + texfiles = string.join (tex) + cmd = string.join ((lilypond_binary, lilyopts, g_extra_opts, + texfiles)) + + ly.lilypond_version_check (lilypond_binary, '@TOPLEVEL_VERSION@') + + ly.system (cmd, ignore_error = 0, progress_p = 1) + + # + # Ugh, fixing up dependencies for .tex generation + # + if do_deps: + depfiles=map (lambda x: re.sub ('(.*)\.ly', '\\1.dep', + x), tex) + + for i in depfiles: + f =open (i) + text=f.read () + f.close () + text=re.sub ('\n([^:\n]*):', + '\n' + foutn + ':', text) + f = open (i, 'w') + f.write (text) + f.close () + + def to_eps (file): + cmd = r"latex '\nonstopmode \input %s'" % file + # Ugh. (La)TeX writes progress and error messages on stdout + # Redirect to stderr + cmd = '(( %s >&2 ) >&- )' % cmd + + ly.system (cmd) + ly.system ("dvips -Ppdf -u+lilypond.map -E -o %s.eps %s" % (file, file)) + map (to_eps, eps) + + for p in png: + ly.make_ps_images (p + '.eps', resolution=110) + os.chdir (d) + + +def update_file (body, name): + ''' + write the body if it has changed. Return whether BODY has changed. + ''' + same = 0 + try: + f = open (name) + fs = f.read (-1) + same = (fs == body) + except: + pass + + if not same: + f = open (name , 'w') + f.write (body) + f.close () + + return not same + + +def write_deps (fn, target, chunks): + global read_files + sys.stderr.write ('Writing `%s\'\n' % os.path.join (g_outdir, fn)) + f = open (os.path.join (g_outdir, fn), 'w') + f.write ('%s%s: ' % (g_dep_prefix, target)) + for d in read_files: + f.write ('%s ' % d) + + + ## There used to be code to write .tex dependencies, but + ## that is silly: lilypond-book has its own dependency scheme + ## to ensure that all lily-XXX.tex files are there + + + f.write ('\n') + f.close () + read_files = [] + +def check_texidoc (chunks): + ## TODO: put file name in front of texidoc. + ## + n = [] + for c in chunks: + if c[0] == 'lilypond': + (type, body, opts, todo, basename) = c; + pathbase = os.path.join (g_outdir, basename) + if os.path.isfile (pathbase + '.texidoc') \ + and 'notexidoc' not in opts: + n.append( ('input', '\n@include %s.texidoc\n\n' % basename)) + n.append (c) + return n + + +## what's this? Docme --hwn +## +def fix_epswidth (chunks): + newchunks = [] + for c in chunks: + if c[0] != 'lilypond' or 'eps' not in c[2]: + newchunks.append (c) + continue + + mag = 1.0 + for o in c[2]: + m = re.match ('magnification=([0-9.]+)', o) + if m: + mag = string.atof (m.group (1)) + + def replace_eps_dim (match, lmag = mag): + filename = match.group (1) + dims = bounding_box_dimensions (filename) + + return '%fpt' % (dims[0] *lmag) + + body = re.sub (r'''\\lilypondepswidth{(.*?)}''', replace_eps_dim, c[1]) + newchunks.append (('lilypond', body, c[2], c[3], c[4])) + + return newchunks + + +##docme: why global? +foutn="" + +def do_file (input_filename): + chunks = read_doc_file (input_filename) + chunks = chop_chunks (chunks, 'ly2dvi', make_ly2dvi_block, 1) + chunks = chop_chunks (chunks, 'lilypond', make_lilypond, 1) + chunks = chop_chunks (chunks, 'lilypond-file', make_lilypond_file, 1) + chunks = chop_chunks (chunks, 'lilypond-block', make_lilypond_block, 1) + chunks = chop_chunks (chunks, 'singleline-comment', do_ignore, 1) + chunks = chop_chunks (chunks, 'preamble-end', do_preamble_end) + chunks = chop_chunks (chunks, 'numcols', do_columns) + chunks = chop_chunks (chunks, 'multicols', do_multicols) + + scan_preamble (chunks) + chunks = process_lilypond_blocks (chunks) + chunks = process_ly2dvi_blocks (chunks) + + # Do It. + global g_run_lilypond + if g_run_lilypond: + compile_all_files (chunks) + chunks = fix_epswidth (chunks) + + + chunks = format_lilypond_output_bodies (chunks) + global format + if format == 'texi': + chunks = check_texidoc (chunks) + + + x = 0 + chunks = completize_preamble (chunks) + + global foutn + + if outname: + my_outname = outname + elif input_filename == '-' or input_filename == "/dev/stdin": + my_outname = '-' + else: + my_outname = os.path.basename (os.path.splitext (input_filename)[0]) + '.' + format + my_depname = my_outname + '.dep' + + if my_outname == '-' or my_outname == '/dev/stdout': + fout = sys.stdout + foutn = "" + global do_deps + do_deps = 0 + else: + foutn = os.path.join (g_outdir, my_outname) + sys.stderr.write ("Writing `%s'\n" % foutn) + fout = open (foutn, 'w') + for c in chunks: + fout.write (c[1]) + fout.close () + # should chmod -w + + if do_deps: + write_deps (my_depname, foutn, chunks) + +outname = '' +try: + (sh, long) = ly.getopt_args (option_definitions) + (options, files) = getopt.getopt (sys.argv[1:], sh, long) + +except getopt.error, msg: + sys.stderr.write ('\n') + ly.error (_ ("getopt says: `%s\'" % s)) + sys.stderr.write ('\n') + ly.help () + ly.exit (2) + +do_deps = 0 +for opt in options: + o = opt[0] + a = opt[1] + + if o == '--include' or o == '-I': + include_path.append (a) + elif o == '--version' or o == '-v': + ly.identify (sys.stdout) + sys.exit (0) + elif o == '--verbose' or o == '-V': + verbose_p = 1 + elif o == '--format' or o == '-f': + format = a + if a == 'texi-html': + format = 'texi' + g_make_html = 1 + elif o == '--outname' or o == '-o': + if len (files) > 1: + #HACK + sys.stderr.write ("lilypond-book is confused by --outname on multiple files") + sys.exit (1) + outname = a + elif o == '--help' or o == '-h': + ly.help () + sys.exit (0) + elif o == '--no-lily' or o == '-n': + g_run_lilypond = 0 + elif o == '--preview-resolution': + preview_resolution = string.atoi (a) + elif o == '--dependencies' or o == '-M': + do_deps = 1 + elif o == '--default-music-fontsize': + default_music_fontsize = string.atoi (a) + elif o == '--default-lilypond-fontsize': + print "--default-lilypond-fontsize is deprecated, use --default-music-fontsize" + default_music_fontsize = string.atoi (a) + elif o == '--extra-options': + g_extra_opts = a + elif o == '--force-music-fontsize': + g_force_music_fontsize = string.atoi (a) + elif o == '--force-lilypond-fontsize': + print "--force-lilypond-fontsize is deprecated, use --default-lilypond-fontsize" + g_force_music_fontsize = string.atoi (a) + elif o == '--dep-prefix': + g_dep_prefix = a + elif o == '--no-pictures': + g_do_pictures = 0 + elif o == '--no-music': + g_do_music = 0 + elif o == '--outdir': + g_outdir = a + elif o == '--warranty' or o == '-w': + #status = os.system ('lilypond -w') + if 1 or status: + ly.warranty () + sys.exit (0) + +ly.identify (sys.stderr) + +if g_outdir: + if os.path.isfile (g_outdir): + error ("outdir is a file: %s" % g_outdir) + if not os.path.exists (g_outdir): + os.mkdir (g_outdir) + +if not files: + ly.help () + ly.error (_ ("no files specified on command line")) + ly.exit (2) + +ly.setup_environment () + + +for input_filename in files: + do_file (input_filename) + + +# +# Petr, ik zou willen dat ik iets zinvoller deed, +# maar wat ik kan ik doen, het verandert toch niets? +# --hwn 20/aug/99