@menu
* Setting up::
+* Git for the impatient::
* Downloading remote branches::
@end menu
git config --global core.editor @var{nano}
@end example
+Finally, and in some ways most importantly, let's make sure that
+we know what branch we're on. If you're not using lilydev, add
+this to your @file{~/.bashrc}:
+
+@verbatim
+export PS1="\u@\h \w\$(__git_ps1)$ "
+@end verbatim
+
+If you are not using lilydev, you may need to install the
+additional @code{git-completion} package, but it is definitely
+worth it.
+
+
@subsubheading Technical details
Git stores the information entered with
in this manual.
+@node Git for the impatient
+@subsection Git for the impatient
+
+@advanced{The intent of this subsection is to get you working on lilypond as
+soon as possible. If you want to learn about git, go read
+@ref{Other Git documentation}.
+@*
+Also, these instructions are designed to eliminate the most common
+problems we have found in using git. If you already know git and
+have a different way of working, great! Feel free to ignore the
+advice in this subsection.}
+
+
+Ok, so you've been using @command{lily-git.tcl} for a while, but
+it's time to take the next step. Since our review process delays
+patches by 60-120 hours, and you want to be able to work on other
+stuff while your previous work is getting reviewed, you're going
+to use @strong{branches}.
+
+You can think of a branch as being a separate copy of the source
+code. But don't worry about it.
+
+@subsubheading Start work: make a new branch
+
+Let's pretend you want to add a section to the Contributor's Guide
+about using branches.
+
+Start by updating the repository, then making a new branch. Call
+the branch anything you want as long as the name starts with
+@code{dev/}. Branch names that don't begin with @code{dev/} are
+reserved for special things in lilypond.
+
+@example
+git checkout master
+git pull -r origin master
+git branch dev/cg
+@end example
+
+@subsubheading Switch to that branch
+
+Nothing has happened to the files yet. Let's change into the new
+branch. You can think of this as @qq{loading a file}, although in
+this case it's really @qq{loading a directory and subdirectories
+full of files}.
+
+@example
+git checkout dev/cg
+@end example
+
+Your prompt now shows you that you're on the other branch:
+
+@example
+gperciva@@lilydev:~/lilypond-git (dev/cg)$
+@end example
+
+To be able to manage multiple lilypond issues at once, you'll need to switch
+branches. You should have each lilypond issue on a separate branch.
+Switching branches is easy:
+
+@example
+git checkout master
+git checkout origin/staging
+git checkout origin/release/unstable
+git checkout dev/cg
+@end example
+
+Branches that begin with @code{origin/} are part of the remote repository,
+rather than your local repository, so when you check them out you get a
+temporary local branch. You should never make changes directly on a
+branch beginning with @code{origin/}. You get changes into the remote
+repository by making them in local branches, and then pushing them to
+@code{origin/staging} as described below.
+
+@subsubheading Make your changes
+
+Edit files, then commit them.
+
+@example
+git commit -a
+@end example
+
+
+Remember how I said that switching to a branch was like
+@qq{loading a directory}? Well, you've just @qq{saved a
+directory}, so that you can @qq{load} it later.
+
+@advanced{If you have used @command{cvs} or @command{svn}, you may
+be very confused: those programs use @qq{commit} to mean
+@qq{upload my changes to the shared source repository}.
+Unfortunately, just to be different, @w{@command{git commit}}
+means @qq{save my changes to the files}.}
+
+When you create a new file, you need to add it to git, then commit it:
+
+@example
+git add input/regression/avoid-crash-on-condition.ly
+git commit -a
+@end example
+
+
+Edit more files. Commit them again. Edit yet more files, commit
+them again. Go eat dinner. Switch to @code{master} so you can
+play with the latest changes from other developers. Switch back
+to your branch and edit some more. Commit those changes.
+
+At this stage, don't worry about how many commits you have.
+
+
+@subsubheading Save commits to external files
+
+Branches are nerve-wracking until you get used to them. You can
+save your hard work as individual @file{.patch} files. Be sure to
+commit your chages first.
+
+@example
+git commit -a
+git format-patch master
+@end example
+
+I personally have between 4 and 20 of those files saved in a
+special folder at any point in time. Git experts might laugh as
+that behavior, but I feel a @emph{lot} better knowing that I've
+got those backups.
+
+
+@subsubheading Prepare your branch for review
+
+After committing, you can update your branch with the latest master:
+
+@example
+git commit -a
+git checkout master
+git pull -r origin master
+git checkout dev/cg
+git rebase master
+@end example
+
+
+Due to the speed of lilypond development, sometimes
+@code{master} has changed so much that your branch can no
+longer be applied to it. In that happens, you will have a merge
+conflict. Stop for a moment to either cry or have a stiff drink,
+then proceed to @ref{Merge conflicts}.
+
+
+@subsubheading Upload your branch
+
+Finally, you're finished your changes. Time to upload for review.
+Make sure that you're on your branch, then upload:
+
+@example
+git checkout dev/cg
+git-cl upload master
+@end example
+
+
+@subsubheading Wait for reviews
+
+While you're waiting for a countdown and reviews, go back to
+master, make a @code{dev/doc-beams} branch, and start adding doc
+suggestions from issue 12345 from the tracker. Or make a
+@code{dev/page-breaks} and fix bug in page breaking. Or whatever.
+Don't worry, your @code{dev/cg} is safe.
+
+
+@subsubheading Combining commits (optional unless you have broken commits)
+
+Does the history of your branch look good?
+
+@example
+gitk
+@end example
+
+If you have a lot of commits on your branch, you might want to
+combine some of them. Alternately, you may like your commits, but
+want to edit the commit messages.
+
+@example
+git rebase -i master
+@end example
+
+Follow instructions on the screen.
+
+@warning{This step gives you the power to completely lose your
+work. Make a backup of your commits by saving them to
+@file{.patch} files before playing with this. If you do lose
+your work, don't despair. You can get it back by using @code{git reflog}.
+The use of @code{git reflog} is not covered here.}
+
+@warning{If any of the commits on your branch represent partial work that will
+not pass @var{make && make doc}, you @strong{must} squash these
+commits into a working commit. Otherwise, your push will break staging
+and will not be able to be merged to master. In general, you will
+be safer to have one commit per push.}
+
+
+@subsubheading Push to staging
+
+When you've got the coveted @code{Patch-push} status, time to
+prepare your upload:
+
+@example
+git fetch
+git rebase origin/staging dev/cg~0
+gitk HEAD
+@end example
+
+@warning{Do not skip the @command{gitk} step; a quick 5-second
+check of the visual history can save a great deal of frustration
+later on. You should see a set of your commits that are ahead of
+@code{origin/staging}, with no label for the top commit -- only a
+SHA1 id.}
+
+@warning{If @code{origin/staging} and @code{origin/master} are the
+same commit, your branch (@code{dev/cg} in the example) will also
+be at the top of the @code{gitk} tree. This is normal.}
+
+If everything looks good, push it:
+
+@example
+git push origin HEAD:staging
+@end example
+
+Then change back to your working branch:
+
+@example
+git checkout dev/cg
+@end example
+
+@warning{It is a best practice to avoid rebasing any of your branches
+to @code{origin/staging}. If @code{origin/staging} is broken, it
+will be deleted and rebuilt. If you have rebased one of your branches
+to @code{origin/staging}, the broken commits can end up in your branch.
+The commands given above do the rebase on a temporary branch, and avoid
+changing your working branch.}
+
+
+@subsubheading Delete your branch (safe)
+
+After a few hours, if there's nothing wrong with your branch, it
+should be automatically moved to @code{origin/master}. Update,
+then try removing your branch:
+
+@example
+git checkout master
+git pull -r origin master
+git branch -d dev/cg
+@end example
+
+The last command will fail if the contents of @code{dev/cg} are
+not present in @code{origin/master}.
+
+
+@subsubheading Delete your branch (UNSAFE)
+
+@c don't give explicit commands here -- this is too dangerous to copy and paste
+Sometimes everything goes wrong. If you want to remove a branch even though
+it will cause your work to be lost (that is, if the contents of @code{dev/cg}
+are @strong{not} present in master), follow the instructions in @qq{Delete
+your branch (safe)}, but replace the @code{-d} on the final line with
+a @code{-D}.
+
+
@node Downloading remote branches
@subsection Downloading remote branches
@menu
+* Merge conflicts::
* Advanced Git concepts::
* Resolving conflicts::
* Reverting all local changes::
@end menu
+@node Merge conflicts
+@subsection Merge conflicts
+
+To be filled in later, and/or moved to a different section. I
+just wanted to make sure that I had a stub ready somewhere.
+
+
@node Advanced Git concepts
@subsection Advanced Git concepts
@item
Book about git: @uref{http://progit.org/,Pro Git}
+
+@item
+Github help: @uref{http://help.github.com/}
+(very highly recommended by Graham)
+
@end itemize
@end lilypond
@funindex \tabChordRepetition
-@cindex Chord, repetiton
-@cindex repetiton, using @code{q}
+@cindex Chord, repetition
+@cindex repetition, using @code{q}
Chord constructs can be repeated by the chord repetition symbol
@code{q}. To use this feature in combination with tablature,
@node Automatic footnotes
@unnumberedsubsubsec Automatic footnotes
-Of the two commands used to create automatic footnotes, use
-@code{\footnoteGrob} for individual grobs (i.e. note heads, stems,
-slurs, dynamics and @code{\markup} when using @code{TextScripts});
-and @code{\footnote} for annotating chorded notes.
-
-Both commands take three arguments; the @var{Layout Object} to be
+Automatic footnotes take three arguments; the @var{Layout Object} to be
annotated, the @var{(x . y)} position of the indicator and a
@code{\markup} that will appear in the footnote at the bottom of the
page.
-The command @code{\footnoteGrob} must come @emph{before} the grob
-that the footnote is being attached to:
+The command @code{\footnote} must come @emph{before} the grob that the
+footnote is being attached to:
@lilypond[verbatim,quote,ragged-right,papersize=a8]
\book {
}
@end lilypond
-To annotate chorded notes, the @code{\footnote} must come
-@emph{after} the note to which the footnote is being attached as a
-@code{TextScript}:
+To annotate chorded notes, the @code{\footnote} must come @emph{after}
+he note to which the footnote is being attached as a @code{TextScript}:
@lilypond[verbatim,quote,ragged-right,papersize=a8]
\book {
are printed in order of descendancy; the higher the footnote, the
higher up in the list.}
-Here are some examples of automatically footnoted grobs, also showing
-the relative position of the footnotes to the tagline and copyright.
+Here are some more examples of footnoted grobs, also showing the
+relative position of the footnotes to the tagline and copyright.
@lilypond[verbatim,quote,ragged-right,papersize=a8]
\book {
@node Manual footnotes
@unnumberedsubsubsec Manual footnotes
-@funindex \footnote
-@funindex \footnoteGrob
@cindex footnotes, manual
-There are two commands used to create manual footnotes; @code{\footnote}
-for top-level @code{\markup} and chorded notes; and @code{\footnoteGrob}
-for individual grobs (and @code{\markup} when using @code{TextScripts}).
-
-When annotating grobs, the @code{\footnote} command takes four
-arguments; the @var{Layout Object} to be annotated, the @var{(x . y)}
-position of the indicator and two @code{\markup} commands; the first is
-the indicator attached to the note or grob and the second is the
-footnote at the bottom of the page.
+Manual footnotes takes four arguments; the @var{Layout Object} to be
+annotated, the @var{(x . y)} position of the indicator and two
+@code{\markup} commands; the first is the indicator attached to the note
+or grob and the second is the footnote at the bottom of the page.
-The command @code{\footnoteGrob} must come @emph{after} the grob that
-the footnote is annotating and attached as a @code{TextScript}:
+Like automatic footnotes, manual @code{\footnote} commands must come
+@emph{after} the grob that the footnote is annotating and attached as a
+@code{TextScript}:
@lilypond[verbatim,quote,ragged-right,papersize=a8]
\book {
}
@end lilypond
-To annotate chorded notes, the @code{\footnote} must come @emph{after}
-the note that the footnote is annotating and attached as a
-@code{TextScript}:
+To annotate chorded notes with manual footnotes:
@lilypond[verbatim,quote,ragged-right,papersize=a8]
\book {
c4
\footnote
- \markup \concat \teeny { "sharp (v)" } #'(0 . 0.5) #'AccidentalCautionary
+ \markup \concat \teeny { "sharp (v)" }
+ #'(0 . 0.5) #'AccidentalCautionary
\markup \italic { v. A cautionary accidental }
\footnote
\breathe
\footnote
- \markup { \teeny \musicglyph #"rests.4" } #'(1.5 . -0.25) #'BreathingSign
+ \markup { \teeny \musicglyph #"rests.4" }
+ #'(1.5 . -0.25) #'BreathingSign
\markup { \null }
}
}
Dash pattern definitions for ties have the same structure as dash
pattern definitions for slurs. For more information about complex dash
-patterns, see @rlsr{slurs}.
+patterns, see @ref{Slurs}.
Override @var{whiteout} and @var{layer} layout properties for ties that
collide with other objects in a staff.
@ref{Automatic note splitting}.
Snippets:
-@rlsr{slurs},
+@rlsr{Expressive marks},
@rlsr{Rhythms}.
Internals Reference:
-%% DO NOT EDIT this file manually; it is automatically
-%% generated from LSR http://lsr.dsi.unimi.it
-%% Make any changes in LSR itself, or in Documentation/snippets/new/ ,
-%% and then run scripts/auxiliar/makelsr.py
-%%
-%% This file is in the public domain.
-\version "2.14.0"
+% DO NOT EDIT this file manually; it is automatically
+% generated from Documentation/snippets/new
+% Make any changes in Documentation/snippets/new/
+% and then run scripts/auxiliar/makelsr.py
+%
+% This file is in the public domain.
+%% Note: this file works from version 2.15.27
+\version "2.15.27"
\header {
- lsrtags = "pitches"
-
%% Translation of GIT committish: 6977ddc9a3b63ea810eaecb864269c7d847ccf98
texidoces = "
En una música que tenga muchas apariciones de la
"
doctitlees = "Crear una secuencia de notas a distintas alturas"
+ lsrtags = "pitches"
+
texidoc = "
In music that contains many occurrences of the same sequence of notes
at different pitches, the following music function may prove useful.
doctitle = "Creating a sequence of notes on various pitches"
} % begin verbatim
-#(define (make-note-req p d)
- (make-music 'NoteEvent
- 'duration d
- 'pitch p))
-
-#(define (make-note p d)
- (make-music 'EventChord
- 'elements (list (make-note-req p d))))
-
-#(define (make-triplet elt)
- (make-music 'TimeScaledMusic
- 'denominator 3
- 'numerator 2
- 'element elt))
rhythm =
-#(define-music-function (parser location note) (ly:music?)
- "Make the rhythm in Mars (the Planets) at the given note's pitch"
- (let ((p (ly:music-property
- (car (ly:music-property note 'elements))
- 'pitch)))
- (make-sequential-music
- (list
- (make-triplet (make-sequential-music
- (list
- (make-note p (ly:make-duration 3 0 2 3))
- (make-note p (ly:make-duration 3 0 2 3))
- (make-note p (ly:make-duration 3 0 2 3)))))
- (make-note p (ly:make-duration 2 0))
- (make-note p (ly:make-duration 2 0))
- (make-note p (ly:make-duration 3 0))
- (make-note p (ly:make-duration 3 0))
- (make-note p (ly:make-duration 2 0))))))
+#(define-music-function (parser location p) (ly:pitch?)
+ "Make the rhythm in Mars (the Planets) at the given pitch"
+ #{ \times 2/3 { $p 8 $p $p } $p 4 $p $p 8 $p $p 4 #})
\new Staff {
\time 5/4
--- /dev/null
+\version "2.15.27"
+
+\header {
+ lsrtags = "pitches"
+
+ texidoc = "
+In music that contains many occurrences of the same sequence of notes
+at different pitches, the following music function may prove useful.
+It takes a note, of which only the pitch is used. This example
+creates the rhythm used throughout Mars, from Gustav Holst's The
+Planets.
+
+"
+ doctitle = "Creating a sequence of notes on various pitches"
+}
+
+rhythm =
+#(define-music-function (parser location p) (ly:pitch?)
+ "Make the rhythm in Mars (the Planets) at the given pitch"
+ #{ \times 2/3 { $p 8 $p $p } $p 4 $p $p 8 $p $p 4 #})
+
+\new Staff {
+ \time 5/4
+ \rhythm c'
+ \rhythm c''
+ \rhythm g
+}
@code{\bookpart} blocks are used, the titles and first system of every
@code{\bookpart} will appear in the output.
-An additional file in the form @code{myFile.preview.extensio} is
+An additional file in the form @code{myFile.preview.extension} is
generated, to avoid this use the additional @option{-dprint-pages} or
@option{-dno-print-pages} options according to your requirements.
@end table
@cindex Scheme, expression evaluation
-@cindex expression evalusation, Scheme
+@cindex expression evaluation, Scheme
@item -e,--evaluate=@var{expr}
Evaluate the Scheme @var{expr} before parsing any @file{.ly} files.
LilyPond needs to read a number of files while running. All these files
are to be copied into the jail, under the same path they appear in the
real root filesystem. The entire content of the LilyPond installation
-(e.g., @file{/usr/share/lilypond})
-should be copied.
+(e.g., @file{/usr/share/lilypond}) should be copied.
If problems arise, the simplest way to trace them down is to run
LilyPond using @command{strace}, which will allow you to determine which
files are missing.
@item Running LilyPond
-In a jail mounted with @code{noexec} it is impossible to execute any external
-program. Therefore LilyPond must be run with a backend that does not
-require any such program. As we already mentioned, it must be also run
-with superuser privileges (which, of course, it will lose immediately),
-possibly using @command{sudo}. It is a good idea to limit the number of
-seconds of CPU time LilyPond can use (e.g., using @command{ulimit
--t}), and, if your operating system supports it, the amount of memory
-that can be allocated.
+In a jail mounted with @code{noexec} it is impossible to execute any
+external program. Therefore LilyPond must be run with a backend that
+does not require any such program. As we already mentioned, it must be
+also run with superuser privileges (which, of course, it will lose
+immediately), possibly using @command{sudo}. It is a good idea to limit
+the number of seconds of CPU time LilyPond can use (e.g., using
+@command{ulimit@tie{}-t}), and, if your operating system supports it,
+the amount of memory that can be allocated.
@end table
@end example
@noindent
-This will create a new group for the @code{lily} user as well, and a home folder,
-@code{/home/lily}
+This will create a new group for the @code{lily} user as well, and a
+home folder, @code{/home/lily}
@item In the home folder of the @code{lily} user create a file to use as a
separate filesystem:
@end table
@cindex errors, message format
-If warnings and errors can
-be linked to some part of the input file, then error messages have the
-following form
+If warnings and errors can be linked to some part of the input file,
+then error messages have the following form
@example
@var{filename}:@var{lineno}:@var{columnno}: @var{message}
@c This file is part of lilypond-web.texi and community.itexi
@c when you add a new item, consider moving the lowest item(s)
-@c into news-old.itexi.
+@c into news.itexi.
@c keep two blank lines between news entries
@c used for news about the upcoming release; see CG 10.2
-@newsItem
-@subsubheading LilyPond 2.15.26 released! @emph{Jan 16, 2012}
-
-We are happy to announce the release of LilyPond 2.15.26. This
-release contains the usual number of bugfixes.
-
-It is strongly recommended that normal users do @strong{not} use
-this release, and instead use the stable 2.14 version. Please
-note that due to a few Critical bugs, this is not the next release
-candidate.
-
-The 2.15.25 has been skipped due to build problems.
-
-@newsEnd
-
@newsItem
-@subsubheading LilyPond 2.15.24 released! @emph{Jan 07, 2012}
+@subsubheading LilyPond 2.15.27 released! @emph{Jan 24, 2012}
-We are happy to announce the release of LilyPond 2.15.24. This
+We are happy to announce the release of LilyPond 2.15.27. This
release contains the usual number of bugfixes.
It is strongly recommended that normal users do @strong{not} use
@newsItem
-@subsubheading LilyPond 2.15.23 released! @emph{Dec 21, 2011}
+@subsubheading The LilyPond Report #23. @emph{Jan 20, 2012}
-We are happy to announce the release of LilyPond 2.15.23. This
-release contains the usual number of bugfixes.
+The @emph{LilyPond Report} is back, with developer
+David Kastrup as a new editor! This issue features
+an exposé on some of the new, handy commands
+recently added to LilyPond, as well as an interview
+with LilyPond contributor and composer Mike Solomon.
-It is strongly recommended that normal users do @strong{not} use
-this release, and instead use the stable 2.14 version. Please
-note that due to a few Critical bugs, this is not the next release
-candidate.
+Come
+@uref{http://news.lilynet.net/?The-LilyPond-Report-23, read
+LilyPond Report 23} now; comments and contributions are
++warmly encouraged!
@newsEnd
@newsItem
-@subsubheading LilyPond 2.15.22 released! @emph{Dec 15, 2011}
-
-We are happy to announce the release of LilyPond 2.15.22. This
-release contains the usual number of bugfixes.
-
-It is strongly recommended that normal users do @strong{not} use
-this release, and instead use the stable 2.14 version. Please
-note that due to a few Critical bugs, this is not the next release
-candidate.
-
-@newsEnd
-
-
-@newsItem
-@subsubheading LilyPond 2.15.21 released! @emph{Dec 6, 2011}
-
-We are happy to announce the release of LilyPond 2.15.21. This
-release contains the usual number of bugfixes.
-
-It is strongly recommended that normal users do @strong{not} use
-this release, and instead use the stable 2.14 version. Please
-note that due to a few Critical bugs, this is not the next release
-candidate.
-
-@newsEnd
-
-
-@newsItem
-@subsubheading LilyPond 2.15.20 released! @emph{Nov 24, 2011}
-
-We are happy to announce the release of LilyPond 2.15.20. This
-release contains the usual number of bugfixes.
-
-It is strongly recommended that normal users do @strong{not} use
-this release, and instead use the stable 2.14 version. Please
-note that due to a few Critical bugs, this is not the next release
-candidate.
-
-@newsEnd
-
-
-@newsItem
-@subsubheading LilyPond 2.15.19 released! @emph{Nov 18, 2011}
-
-We are happy to announce the release of LilyPond 2.15.19. This
-release contains the usual number of bugfixes.
-
-It is strongly recommended that normal users do @strong{not} use
-this release, and instead use the stable 2.14 version. Please
-note that due to a few Critical bugs, this is not the next release
-candidate.
-
-@newsEnd
-
-
-@newsItem
-@subsubheading LilyPond 2.15.18 released! @emph{Nov 12, 2011}
-
-We are happy to announce the release of LilyPond 2.15.18. This
-release contains the usual number of bugfixes.
-
-It is strongly recommended that normal users do @strong{not} use
-this release, and instead use the stable 2.14 version. Please
-note that due to a few Critical bugs, this is not the next release
-candidate.
-
-@newsEnd
-
-
-@newsItem
-@subsubheading LilyPond 2.15.17 released! @emph{Nov 10, 2011}
-
-We are happy to announce the release of LilyPond 2.15.17. This
-release contains the usual number of bugfixes.
-
-It is strongly recommended that normal users do @strong{not} use
-this release, and instead use the stable 2.14 version. Please
-note that due to a few Critical bugs, this is not the next release
-candidate.
-
-@newsEnd
-
-
-@newsItem
-@subsubheading LilyPond 2.15.16 released! @emph{October 28, 2011}
+@subsubheading LilyPond 2.15.26 released! @emph{Jan 16, 2012}
-We are happy to announce the release of LilyPond 2.15.16. This
+We are happy to announce the release of LilyPond 2.15.26. This
release contains the usual number of bugfixes.
It is strongly recommended that normal users do @strong{not} use
note that due to a few Critical bugs, this is not the next release
candidate.
-@newsEnd
-
-
-@newsItem
-@subsubheading LilyPond 2.15.15 released! @emph{October 24, 2011}
-
-We are happy to announce the release of LilyPond 2.15.15. This
-release contains the usual number of bugfixes.
-
-It is strongly recommended that normal users do @strong{not} use
-this release, and instead use the stable 2.14 version. Please
-note that due to a few Critical bugs, this is not the next release
-candidate.
+The 2.15.25 has been skipped due to build problems.
@newsEnd
@newsItem
-@subsubheading LilyPond 2.15.14 released! @emph{October 7, 2011}
+@subsubheading LilyPond 2.15.24 released! @emph{Jan 07, 2012}
-We are happy to announce the release of LilyPond 2.15.14. This
+We are happy to announce the release of LilyPond 2.15.24. This
release contains the usual number of bugfixes.
It is strongly recommended that normal users do @strong{not} use
@newsItem
-@subsubheading LilyPond 2.15.13 released! @emph{September 27, 2011}
+@subsubheading LilyPond 2.15.23 released! @emph{Dec 21, 2011}
-We are happy to announce the release of LilyPond 2.15.13. This
+We are happy to announce the release of LilyPond 2.15.23. This
release contains the usual number of bugfixes.
It is strongly recommended that normal users do @strong{not} use
@newsEnd
-@newsItem
-@subsubheading Release candidate 2 cancelled @emph{Sep 23, 2011}
-
-The release countdown is cancelled due to the discovery of a
-Critical regression.
-
-@newsEnd
-
-
-@newsItem
-@subsubheading Release candidate 2 of 2.16 - LilyPond 2.15.12 released! @emph{Sep 20, 2011}
-
-LilyPond 2.15.12 is out; this is the second release candidate of
-the upcoming 2.16 stable release. All users are invited to
-experiment with this version. New features since 2.14.2 are
-listed in the @qq{Changes} manual on the website section about
-@ref{Development}.
-
-There are no known Critical issues with this release. If no
-Critical bugs are found, then the official 2.16.0 release will be
-on 27 Sep 2011. If you discover any problems, please send us
-@ref{Bug reports}.
-
-@newsEnd
-
-
-@newsItem
-@subsubheading LilyPond 2.15.11 released! @emph{September 11, 2011}
-
-We are happy to announce the release of LilyPond 2.15.11. This
-release contains the usual number of bugfixes.
-
-It is strongly recommended that normal users do @strong{not} use
-this release, and instead use the stable 2.14 version. Please
-note that due to the possibility of a few Critical bugs, this is
-not the next release candidate.
-
-@newsEnd
-
-
* don't duplicate entries from news-front.itexi
@end ignore
+
+@newsItem
+@subsubheading LilyPond 2.15.22 released! @emph{Dec 15, 2011}
+
+We are happy to announce the release of LilyPond 2.15.22. This
+release contains the usual number of bugfixes.
+
+It is strongly recommended that normal users do @strong{not} use
+this release, and instead use the stable 2.14 version. Please
+note that due to a few Critical bugs, this is not the next release
+candidate.
+
+@newsEnd
+
+
+@newsItem
+@subsubheading LilyPond 2.15.21 released! @emph{Dec 6, 2011}
+
+We are happy to announce the release of LilyPond 2.15.21. This
+release contains the usual number of bugfixes.
+
+It is strongly recommended that normal users do @strong{not} use
+this release, and instead use the stable 2.14 version. Please
+note that due to a few Critical bugs, this is not the next release
+candidate.
+
+@newsEnd
+
+
+@newsItem
+@subsubheading LilyPond 2.15.20 released! @emph{Nov 24, 2011}
+
+We are happy to announce the release of LilyPond 2.15.20. This
+release contains the usual number of bugfixes.
+
+It is strongly recommended that normal users do @strong{not} use
+this release, and instead use the stable 2.14 version. Please
+note that due to a few Critical bugs, this is not the next release
+candidate.
+
+@newsEnd
+
+
+@newsItem
+@subsubheading LilyPond 2.15.19 released! @emph{Nov 18, 2011}
+
+We are happy to announce the release of LilyPond 2.15.19. This
+release contains the usual number of bugfixes.
+
+It is strongly recommended that normal users do @strong{not} use
+this release, and instead use the stable 2.14 version. Please
+note that due to a few Critical bugs, this is not the next release
+candidate.
+
+@newsEnd
+
+
+@newsItem
+@subsubheading LilyPond 2.15.18 released! @emph{Nov 12, 2011}
+
+We are happy to announce the release of LilyPond 2.15.18. This
+release contains the usual number of bugfixes.
+
+It is strongly recommended that normal users do @strong{not} use
+this release, and instead use the stable 2.14 version. Please
+note that due to a few Critical bugs, this is not the next release
+candidate.
+
+@newsEnd
+
+
+@newsItem
+@subsubheading LilyPond 2.15.17 released! @emph{Nov 10, 2011}
+
+We are happy to announce the release of LilyPond 2.15.17. This
+release contains the usual number of bugfixes.
+
+It is strongly recommended that normal users do @strong{not} use
+this release, and instead use the stable 2.14 version. Please
+note that due to a few Critical bugs, this is not the next release
+candidate.
+
+@newsEnd
+
+
+@newsItem
+@subsubheading LilyPond 2.15.16 released! @emph{October 28, 2011}
+
+We are happy to announce the release of LilyPond 2.15.16. This
+release contains the usual number of bugfixes.
+
+It is strongly recommended that normal users do @strong{not} use
+this release, and instead use the stable 2.14 version. Please
+note that due to a few Critical bugs, this is not the next release
+candidate.
+
+@newsEnd
+
+
+@newsItem
+@subsubheading LilyPond 2.15.15 released! @emph{October 24, 2011}
+
+We are happy to announce the release of LilyPond 2.15.15. This
+release contains the usual number of bugfixes.
+
+It is strongly recommended that normal users do @strong{not} use
+this release, and instead use the stable 2.14 version. Please
+note that due to a few Critical bugs, this is not the next release
+candidate.
+
+@newsEnd
+
+
+@newsItem
+@subsubheading LilyPond 2.15.14 released! @emph{October 7, 2011}
+
+We are happy to announce the release of LilyPond 2.15.14. This
+release contains the usual number of bugfixes.
+
+It is strongly recommended that normal users do @strong{not} use
+this release, and instead use the stable 2.14 version. Please
+note that due to a few Critical bugs, this is not the next release
+candidate.
+
+@newsEnd
+
+
+@newsItem
+@subsubheading LilyPond 2.15.13 released! @emph{September 27, 2011}
+
+We are happy to announce the release of LilyPond 2.15.13. This
+release contains the usual number of bugfixes.
+
+It is strongly recommended that normal users do @strong{not} use
+this release, and instead use the stable 2.14 version. Please
+note that due to a few Critical bugs, this is not the next release
+candidate.
+
+@newsEnd
+
+
+@newsItem
+@subsubheading Release candidate 2 cancelled @emph{Sep 23, 2011}
+
+The release countdown is cancelled due to the discovery of a
+Critical regression.
+
+@newsEnd
+
+
+@newsItem
+@subsubheading Release candidate 2 of 2.16 - LilyPond 2.15.12 released! @emph{Sep 20, 2011}
+
+LilyPond 2.15.12 is out; this is the second release candidate of
+the upcoming 2.16 stable release. All users are invited to
+experiment with this version. New features since 2.14.2 are
+listed in the @qq{Changes} manual on the website section about
+@ref{Development}.
+
+There are no known Critical issues with this release. If no
+Critical bugs are found, then the official 2.16.0 release will be
+on 27 Sep 2011. If you discover any problems, please send us
+@ref{Bug reports}.
+
+@newsEnd
+
+
+@newsItem
+@subsubheading LilyPond 2.15.11 released! @emph{September 11, 2011}
+
+We are happy to announce the release of LilyPond 2.15.11. This
+release contains the usual number of bugfixes.
+
+It is strongly recommended that normal users do @strong{not} use
+this release, and instead use the stable 2.14 version. Please
+note that due to the possibility of a few Critical bugs, this is
+not the next release candidate.
+
+@newsEnd
+
+
@newsItem
@subsubheading LilyPond 2.15.10 released! @emph{September 6, 2011}
# For both online and offline docs, issue `make doc WEB_TARGETS="offline online"'
WEB_TARGETS = offline
+WEB_ROOT_FILES = $(WEB_TARGETS:%=$(outdir)/%-root/index.html)
+
WEB_EXAMPLE_FILES = $(wildcard input/$(outdir)/*.ly) \
$(wildcard input/*/$(outdir)/*.ly) \
$(wildcard input/*/*/$(outdir)/*.ly)
-WEB_TRACKED_FILES = $(wildcard $(outdir)/*.{midi,html,pdf,png,jpg,jpeg,txt,ly,ily,signature,css,zip,js,idx,php}) \
- $(wildcard input/$(outdir)/*.{midi,html,pdf,png,jpg,jpeg,txt,ly,ily,signature,css,zip,js,idx,php}) \
- $(wildcard input/*/$(outdir)/*.{midi,html,pdf,png,jpg,jpeg,txt,ly,ily,signature,css,zip,js,idx,php}) \
- $(wildcard Documentation/$(outdir)/*.{midi,html,pdf,png,jpg,jpeg,txt,ly,ily,signature,css,zip,js,idx,php}) \
- $(wildcard Documentation/$(outdir)/*/*.{midi,html,pdf,png,jpg,jpeg,txt,ly,ily,signature,css,zip,js,idx,php})
+WEB_TRACKED_FILES = $(filter-out $(outdir)/index.html, \
+ $(shell bash -O nullglob -c "echo $(outdir)/*.{midi,html,pdf,png,jpg,jpeg,txt,ly,ily,signature,css,zip,js,idx,php}")) \
+ $(shell bash -O nullglob -c "echo input/$(outdir)/*.{midi,html,pdf,png,jpg,jpeg,txt,ly,ily,signature,css,zip,js,idx,php}") \
+ $(shell bash -O nullglob -c "echo input/*/$(outdir)/*.{midi,html,pdf,png,jpg,jpeg,txt,ly,ily,signature,css,zip,js,idx,php}") \
+ $(shell bash -O nullglob -c "echo Documentation/$(outdir)/*.{midi,html,pdf,png,jpg,jpeg,txt,ly,ily,signature,css,zip,js,idx,php}") \
+ $(shell bash -O nullglob -c "echo Documentation/$(outdir)/*/*.{midi,html,pdf,png,jpg,jpeg,txt,ly,ily,signature,css,zip,js,idx,php}")
-WWW-post: $(top-build-dir)/.htaccess $(outdir)/examples.html $(outdir)/offline-root/index.html
+WWW-post: $(top-build-dir)/.htaccess $(outdir)/examples.html $(WEB_ROOT_FILES)
# need UTF8 setting in case this is hosted on a website.
$(top-build-dir)/.htaccess:
$(buildscript-dir)/mutopia-index -o $(outdir)/examples.html input/
$(outdir)/offline-root/index.html: $(WEB_TRACKED_FILES)
- $(buildscript-dir)/www_post $(PACKAGE_NAME) $(TOPLEVEL_VERSION) $(outdir) "$(WEB_TARGETS)"
+ $(buildscript-dir)/www_post $(PACKAGE_NAME) $(TOPLEVEL_VERSION) $(outdir) offline
find $(outdir)/offline-root -type l | xargs rm -f
+
+$(outdir)/online-root/index.html: $(WEB_TRACKED_FILES)
+ $(buildscript-dir)/www_post $(PACKAGE_NAME) $(TOPLEVEL_VERSION) $(outdir) online
endif # ifeq ($(out),www)
# For those who cannot for the life in them remember to type
PACKAGE_NAME=LilyPond
MAJOR_VERSION=2
MINOR_VERSION=15
-PATCH_LEVEL=27
+PATCH_LEVEL=28
MY_PATCH_LEVEL=
VERSION_STABLE=2.14.2
-VERSION_DEVEL=2.15.26
+VERSION_DEVEL=2.15.27
\header {
- texidoc = "Excercise all output functions"
+ texidoc = "Exercise all output functions"
}
\version "2.14.0"
{
<f' g'>4. s8 \small <f' g'>4. s8 <g' a'>4. s8 <a' b'>4. s8
+ <<<f' g'>4 \\ <b' c''>4. >> s8 <<<f' g'>4 \\ b'4. >> s8
}
--- /dev/null
+\version "2.15.27"
+
+\header {
+ texidoc = "Dot columns should not trigger vertical spacing before
+line breaking. If the regtest issues a programming_error saying that
+vertical spacing has been called before line breaking, it has failed.
+"
+}
+
+\context Staff <<
+ \new Voice { \voiceOne f''8.[ e''16] }
+ \new Voice { \voiceThree r8. a'16}
+>>
\header {
- texidoc = "in collisions, the stems of outer voice are added to the
- dot support of the inner voices."
+ texidoc = "in collisions, the dots of outer voices avoid
+ stems and flags of the inner voices."
}
\key e \major \time 3/4
\relative c'' {
<< { dis4. } \\
- { fis,4 } \\ { b4 } >>
+ { fis,4 } \\ { b8 } >>
}
}
--- /dev/null
+\version "2.15.27"
+
+\header {
+ texidoc = "Shows the id property of a grob being set. This should have
+no effect in the PS backend.
+"
+}
+
+{ \override NoteHead #'id = #"foo" c }
%{
-For maintenance reasons, we don't excercise the entire markup command set.
+For maintenance reasons, we don't exercise the entire markup command set.
%}
fis[ g gis]
a[ bes b]\!
- %% EB does the slur in the Rondo differently from the 1st adn 2nd time.
+ %% EB does the slur in the Rondo differently from the 1st and 2nd time.
%% why. Should check with MS.
<<
\rondotheme
Texts may be added to the multi-measure rests.
By setting the appropriate @code{spacing-procedure}, we can make
-measures stretch to accomodate wide texts.
+measures stretch to accommodate wide texts.
"
{
texidoc = "
-Nested fill-lines should work properly. In this example, both occurences
+Nested fill-lines should work properly. In this example, both occurrences
of FOO should be centered.
"
\header {
texidoc = "Page labels may be placed inside music or at top-level,
-and refered to in markups."
+and referred to in markups."
}
#(set-default-paper-size "a6")
texidoc = "Rests avoid notes. Each rest is moved in the direction
of the stems in its voice. Rests may overlap other rests in voices
with the same stem direction, in which case a warning is given, but
-is supressed if the rest has a pitch."
+is suppressed if the rest has a pitch."
}
texidoc = "Notes that are shorter than the common shortest note get a
space (i.e. without the space needed for the note) proportional to
-their duration. So, the 16th notes get 1/2 of the space of an eigth note.
+their duration. So, the 16th notes get 1/2 of the space of an eighth note.
The total distance for a 16th (which includes note head) is 3/4 of the
eighth note. "
@item short ties are vertically centered in the space, as well those
that otherwise don't fit in a space
-@item extremely short ties are put over the noteheads, instead of inbetween.
+@item extremely short ties are put over the noteheads, instead of between.
@end itemize
"
+++ /dev/null
-/*
- This file is part of LilyPond, the GNU music typesetter.
-
- Copyright (C) 2011--2012 Mike Solomon <mike@apollinemike.com>
-
- LilyPond is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- LilyPond is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <cstdio>
-
-#include "column-description.hh"
-#include "paper-column.hh"
-#include "simple-spacer.hh"
-#include "spaceable-grob.hh"
-#include "spring.hh"
-
-static Grob *
-next_spaceable_column (vector<Grob *> const &list, vsize starting)
-{
- for (vsize i = starting + 1; i < list.size (); i++)
- if (!Paper_column::is_loose (list[i]))
- return list[i];
- return 0;
-}
-
-Column_description
-Column_description::get_column_description (vector<Grob *> const &cols, vsize col_index, bool line_starter)
-{
- Grob *col = cols[col_index];
- if (line_starter)
- col = Item::maybe_find_prebroken_piece (dynamic_cast<Item *> (col), RIGHT);
-
- Column_description description;
- Grob *next_col = next_spaceable_column (cols, col_index);
- if (next_col)
- description.spring_ = Spaceable_grob::get_spring (col, next_col);
-
- Grob *end_col = dynamic_cast<Item *> (cols[col_index + 1])->find_prebroken_piece (LEFT);
- if (end_col)
- description.end_spring_ = Spaceable_grob::get_spring (col, end_col);
-
- for (SCM s = Spaceable_grob::get_minimum_distances (col);
- scm_is_pair (s); s = scm_cdr (s))
- {
- Grob *other = unsmob_grob (scm_caar (s));
- vsize j = binary_search (cols, other, Paper_column::less_than, col_index);
- if (j != VPOS)
- {
- if (cols[j] == other)
- description.rods_.push_back (Rod_description (j, scm_to_double (scm_cdar (s))));
- else /* it must end at the LEFT prebroken_piece */
- description.end_rods_.push_back (Rod_description (j, scm_to_double (scm_cdar (s))));
- }
- }
-
- if (!line_starter && to_boolean (col->get_property ("keep-inside-line")))
- description.keep_inside_line_ = col->extent (col, X_AXIS);
-
- description.break_permission_ = col->get_property ("line-break-permission");
- return description;
-}
\ No newline at end of file
breaks_ = pscore_->get_break_indices ();
all_ = pscore_->root_system ()->used_columns ();
lines_.resize (breaks_.size (), breaks_.size (), Line_details ());
- vector<Simple_spacer> spacers
- = pscore_->root_system ()->get_simple_spacers (other_lines.length (),
- other_lines.length () - first_line.length (),
- ragged_right_);
+ vector<Real> forces = get_line_forces (all_,
+ other_lines.length (),
+ other_lines.length () - first_line.length (),
+ ragged_right_);
for (vsize i = 0; i + 1 < breaks_.size (); i++)
{
for (vsize j = i + 1; j < breaks_.size (); j++)
bool ragged = ragged_right_ || (last && ragged_last_);
Line_details &line = lines_.at (j, i);
- line.force_ = spacers[i * breaks_.size () + j].force_penalty (ragged_right_);
- if (!spacers[i * breaks_.size () + j].fits ())
- {
- if (spacers[i * breaks_.size () + j].minimal_)
- line.force_ = -200000;
- else
- line.force_ = infinity_f;
- }
+ line.force_ = forces[i * breaks_.size () + j];
if (ragged && last && !isinf (line.force_))
line.force_ = (line.force_ < 0 && j > i + 1) ? infinity_f : 0;
- if (!line.force_ && !spacers[i * breaks_.size () + j].line_len ())
- line.force_ = infinity_f;
if (isinf (line.force_))
break;
y.add_point (y1);
y.add_point (y2);
+
+ stems.insert (s);
}
else if (Note_head::has_interface (s))
- y = Interval (-1, 1);
+ y = Interval (-1.1, 1.1);
else
{
programming_error ("unknown grob in dot col support");
continue;
}
- y *= 2 / ss;
y += Staff_symbol_referencer::get_position (s);
Box b (s->extent (commonx, X_AXIS), y);
}
}
- vector_sort (dots, position_less);
+ /*
+ The use of pure_position_less and pure_get_rounded_position below
+ are due to the fact that this callback is called before line breaking
+ occurs. Because dots' actual Y posiitons may be linked to that of
+ beams (dots are attached to rests, which are shifted to avoid beams),
+ we instead must use their pure Y positions.
+ */
+ vector_sort (dots, pure_position_less);
for (vsize i = dots.size (); i--;)
{
if (!dots[i]->is_live ())
dp.x_extent_ = note->extent (commonx, X_AXIS);
}
- int p = Staff_symbol_referencer::get_rounded_position (dp.dot_);
+ int p = Staff_symbol_referencer::pure_get_rounded_position (dp.dot_);
/* icky, since this should go via a Staff_symbol_referencer
offset callback but adding a dot overwrites Y-offset. */
/*
Junkme?
*/
- Staff_symbol_referencer::set_position (i->second.dot_, i->first);
+ Staff_symbol_referencer::pure_set_position (i->second.dot_, i->first);
}
me->translate_axis (cfg.x_offset () - me->relative_coordinate (commonx, X_AXIS),
Dot_formatting_problem::Dot_formatting_problem (vector<Box> const &boxes,
Interval base_x)
- : head_skyline_ (boxes, 0.0, Y_AXIS, RIGHT)
+ : head_skyline_ (boxes, 0.2, Y_AXIS, RIGHT)
{
best_ = 0;
head_skyline_.set_minimum_height (base_x[RIGHT]);
= *unsmob_stencil (scm_call_1 (ly_lily_module_constant ("stencil-whiteout"),
retval.smobbed_copy ()));
}
+
+ SCM id = get_property ("id");
+ if (scm_is_string (id))
+ {
+ SCM expr = scm_list_3 (ly_symbol2scm ("id"),
+ id,
+ retval.expr ());
+
+ retval = Stencil (retval.extent_box (), expr);
+ }
+
}
return retval;
"cause "
"color "
"cross-staff "
+ "id "
"extra-X-extent "
"extra-Y-extent "
"extra-offset "
+++ /dev/null
-/*
- This file is part of LilyPond, the GNU music typesetter.
-
- Copyright (C) 2011--2012 Mike Solomon <mike@apollinemike.com>
-
- LilyPond is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- LilyPond is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef COLUMN_DESCRIPTION_HH
-#define COLUMN_DESCRIPTION_HH
-
-#include "lily-proto.hh"
-#include "smobs.hh"
-#include "spring.hh"
-
-struct Rod_description
-{
- vsize r_;
- Real dist_;
-
- bool operator < (const Rod_description r)
- {
- return r_ < r.r_;
- }
-
- Rod_description ()
- {
- r_ = 0;
- dist_ = 0;
- }
-
- Rod_description (vsize r, Real d)
- {
- r_ = r;
- dist_ = d;
- }
-};
-
-struct Column_description
-{
- vector<Rod_description> rods_;
- vector<Rod_description> end_rods_; /* use these if they end at the last column of the line */
- Spring spring_;
- Spring end_spring_;
-
- SCM break_permission_;
- Interval keep_inside_line_;
-
- Column_description ()
- {
- break_permission_ = SCM_EOL;
- }
- static Column_description get_column_description (vector<Grob *> const &cols, vsize col_index, bool line_starter);
-};
-
-#endif /* COLUMN_DESCRIPTION_HH */
static bool is_non_musical (Grob *);
static bool break_visible (Grob *);
- static Item *maybe_find_prebroken_piece (Item *g, Direction d);
+
bool is_broken () const;
virtual bool pure_is_visible (int start, int end) const;
DECLARE_GROB_INTERFACE ();
static int get_rank (Grob const *);
- static bool is_loose (Grob *);
static bool is_musical (Grob *);
static Moment when_mom (Grob *);
static bool is_used (Grob *);
public:
Simple_spacer ();
- bool minimal_;
-
void solve (Real line_len, bool ragged);
void add_rod (int l, int r, Real dist);
void add_spring (Spring const &);
void set_force (Real force);
Real force () const;
- Real line_len () const;
Real force_penalty (bool ragged) const;
bool fits () const;
DECLARE_SIMPLE_SMOBS (Simple_spacer);
private:
-
Real expand_line ();
Real compress_line ();
Real rod_force (int l, int r, Real dist);
bool fits_;
};
+/* returns a vector of dimensions breaks.size () * breaks.size () */
+vector<Real> get_line_forces (vector<Grob *> const &columns,
+ Real line_len,
+ Real indent,
+ bool ragged);
+
Column_x_positions get_line_configuration (vector<Grob *> const &columns,
Real line_len,
Real indent,
DECLARE_GROB_INTERFACE ();
static bool ugly_hack (Grob *);
static void set_position (Grob *, Real);
+ static void pure_set_position (Grob *, Real);
DECLARE_SCHEME_CALLBACK (callback, (SCM element));
/**
static bool on_staff_line (Grob *, int);
static int line_count (Grob *);
static Real get_position (Grob *);
+ static Real pure_get_position (Grob *);
static Real staff_radius (Grob *);
static int get_rounded_position (Grob *);
+ static int pure_get_rounded_position (Grob *);
static Interval extent_in_staff (Grob *);
+
+private:
+ static void internal_set_position (Grob *, Real, bool);
+ static Real internal_get_position (Grob *, bool);
};
int compare_position (Grob *const &, Grob *const &);
bool position_less (Grob *const &, Grob *const &);
+bool pure_position_less (Grob *const &, Grob *const &);
#endif /* STAFF_SYMBOL_REFERENCER_HH */
Stream_event ();
VIRTUAL_COPY_CONSTRUCTOR (Stream_event, Stream_event);
- Stream_event (SCM event_class, SCM mutable_props = SCM_EOL);
+ Stream_event (SCM event_class, SCM immutable_props = SCM_EOL);
Stream_event (SCM class_name, Input *);
Input *origin () const;
void set_spot (Input *i);
bool internal_in_event_class (SCM class_name);
+ void make_transposable ();
virtual SCM copy_mutable_properties () const;
class System : public Spanner
{
int rank_;
- vector<Simple_spacer> simple_spacers_;
Grob_array *all_elements_;
void init_elements ();
friend class Paper_score; // ugh.
Grob *get_pure_bound (Direction dir, int start, int end);
Grob *get_maybe_pure_bound (Direction dir, bool pure, int start, int end);
int get_rank () const;
- vector<Simple_spacer> get_simple_spacers (Real line_len, Real indent, bool ragged);
- void gen_simple_spacers (Real line_len, Real indent, bool ragged);
vector<Real> get_footnote_heights_in_range (vsize st, vsize end);
vector<Real> get_in_note_heights_in_range (vsize st, vsize end);
vector<Real> internal_get_note_heights_in_range (vsize st, vsize end, bool foot);
return 0;
}
-Item *
-Item::maybe_find_prebroken_piece (Item *g, Direction d)
-{
- Item *ret = g->find_prebroken_piece (d);
- if (ret)
- return ret;
- return g;
-}
-
Item *
Item::find_prebroken_piece (Direction d) const
{
for (; scm_is_pair (art_mus); art_mus = scm_cdr (art_mus))
{
Music *m = unsmob_music (scm_car (art_mus));
- SCM ev = m ? m->to_event ()->unprotect () : scm_car (art_mus);
- art_ev = scm_cons (ev, art_ev);
+ art_ev = scm_cons (m->to_event ()->unprotect (), art_ev);
}
e->set_property ("articulations", scm_reverse_x (art_ev, SCM_EOL));
}
shift_amount *= 0.75;
}
- /* If the dotted notes ended up on the left, and there are collisions,
- tell the Dot_Columnn to avoid the notes on the right.
+ /* If any dotted notes ended up on the left,
+ tell the Dot_Columnn to avoid the note heads on the right.
*/
- if (full_collide || close_half_collide || distant_half_collide)
+ if (shift_amount < -1e-6
+ && Rhythmic_head::dot_count (head_up))
{
- if (shift_amount < -1e-6
- && Rhythmic_head::dot_count (head_up)
- && !Rhythmic_head::dot_count (head_down))
+ Grob *d = unsmob_grob (head_up->get_object ("dot"));
+ Grob *parent = d->get_parent (X_AXIS);
+ if (Dot_column::has_interface (parent))
+ Side_position_interface::add_support (parent, head_down);
+ }
+ else if (Rhythmic_head::dot_count (head_down))
+ {
+ Grob *d = unsmob_grob (head_down->get_object ("dot"));
+ Grob *parent = d->get_parent (X_AXIS);
+ if (Dot_column::has_interface (parent))
{
- Grob *d = unsmob_grob (head_up->get_object ("dot"));
- Grob *parent = d->get_parent (X_AXIS);
- if (Dot_column::has_interface (parent))
- Side_position_interface::add_support (parent, head_down);
+ Grob *stem = unsmob_grob (head_up->get_object ("stem"));
+ // Loop over all heads on an up-pointing-stem to see if dots
+ // need to clear any heads suspended on its right side.
+ extract_grob_set (stem, "note-heads", heads);
+ for (vsize i = 0; i < heads.size (); i++)
+ Side_position_interface::add_support (parent, heads[i]);
}
- else if (Rhythmic_head::dot_count (head_down)
- && !Rhythmic_head::dot_count (head_up))
+ }
+
+ // In meshed chords with dots on the left, adjust dot direction
+ if (shift_amount > 1e-6
+ && Rhythmic_head::dot_count (head_down))
+ {
+ Grob *dot_down = unsmob_grob (head_down->get_object ("dot"));
+ Grob *col_down = dot_down->get_parent (X_AXIS);
+ Direction dir = UP;
+ if (Rhythmic_head::dot_count (head_up))
{
- Grob *d = unsmob_grob (head_down->get_object ("dot"));
- Grob *parent = d->get_parent (X_AXIS);
- if (Dot_column::has_interface (parent))
- {
- Grob *stem = unsmob_grob (head_up->get_object ("stem"));
- extract_grob_set (stem, "note-heads", heads);
- for (vsize i = 0; i < heads.size (); i++)
- Side_position_interface::add_support (parent, heads[i]);
- }
+ Grob *dot_up = unsmob_grob (head_up->get_object ("dot"));
+ Grob *col_up = dot_up->get_parent (X_AXIS);
+ if (col_up == col_down) // let the common DotColumn arrange dots
+ dir = CENTER;
+ else // conform to the dot direction on the up-stem chord
+ dir = robust_scm2dir (dot_up->get_property ("direction"), UP);
+ }
+ if (dir != CENTER)
+ {
+ Grob *stem = unsmob_grob (head_down->get_object ("stem"));
+ extract_grob_set (stem, "note-heads", heads);
+ for (vsize i = 0; i < heads.size (); i++)
+ unsmob_grob (heads[i]->get_object ("dot"))
+ ->set_property ("direction", scm_from_int (dir));
}
}
return Moment (0);
}
-bool
-Paper_column::is_loose (Grob *g)
-{
- return (scm_is_pair (g->get_object ("between-cols")));
-}
-
bool
Paper_column::is_musical (Grob *me)
{
Pitch diff = pitch_interval (qp, mp);
ev = ev->clone ();
+ ev->make_transposable ();
transpose_mutable (ev->get_property_alist (true), diff);
transposed_musics_ = scm_cons (ev->unprotect (), transposed_musics_);
#include <cstdio>
-#include "column-description.hh"
#include "column-x-positions.hh"
#include "dimensions.hh"
#include "international.hh"
return force_;
}
-Real
-Simple_spacer::line_len () const
-{
- return line_len_;
-}
-
bool
Simple_spacer::fits () const
{
/****************************************************************/
+struct Rod_description
+{
+ vsize r_;
+ Real dist_;
+
+ bool operator < (const Rod_description r)
+ {
+ return r_ < r.r_;
+ }
+
+ Rod_description ()
+ {
+ r_ = 0;
+ dist_ = 0;
+ }
+
+ Rod_description (vsize r, Real d)
+ {
+ r_ = r;
+ dist_ = d;
+ }
+};
+
+struct Column_description
+{
+ vector<Rod_description> rods_;
+ vector<Rod_description> end_rods_; /* use these if they end at the last column of the line */
+ Spring spring_;
+ Spring end_spring_;
+
+ SCM break_permission_;
+ Interval keep_inside_line_;
+
+ Column_description ()
+ {
+ break_permission_ = SCM_EOL;
+ }
+};
+
+static bool
+is_loose (Grob *g)
+{
+ return (scm_is_pair (g->get_object ("between-cols")));
+}
+
+static Grob *
+maybe_find_prebroken_piece (Grob *g, Direction d)
+{
+ Grob *ret = dynamic_cast<Item *> (g)->find_prebroken_piece (d);
+ if (ret)
+ return ret;
+ return g;
+}
+
+static Grob *
+next_spaceable_column (vector<Grob *> const &list, vsize starting)
+{
+ for (vsize i = starting + 1; i < list.size (); i++)
+ if (!is_loose (list[i]))
+ return list[i];
+ return 0;
+}
+
+static Column_description
+get_column_description (vector<Grob *> const &cols, vsize col_index, bool line_starter)
+{
+ Grob *col = cols[col_index];
+ if (line_starter)
+ col = maybe_find_prebroken_piece (col, RIGHT);
+
+ Column_description description;
+ Grob *next_col = next_spaceable_column (cols, col_index);
+ if (next_col)
+ description.spring_ = Spaceable_grob::get_spring (col, next_col);
+
+ Grob *end_col = dynamic_cast<Item *> (cols[col_index + 1])->find_prebroken_piece (LEFT);
+ if (end_col)
+ description.end_spring_ = Spaceable_grob::get_spring (col, end_col);
+
+ for (SCM s = Spaceable_grob::get_minimum_distances (col);
+ scm_is_pair (s); s = scm_cdr (s))
+ {
+ Grob *other = unsmob_grob (scm_caar (s));
+ vsize j = binary_search (cols, other, Paper_column::less_than, col_index);
+ if (j != VPOS)
+ {
+ if (cols[j] == other)
+ description.rods_.push_back (Rod_description (j, scm_to_double (scm_cdar (s))));
+ else /* it must end at the LEFT prebroken_piece */
+ description.end_rods_.push_back (Rod_description (j, scm_to_double (scm_cdar (s))));
+ }
+ }
+
+ if (!line_starter && to_boolean (col->get_property ("keep-inside-line")))
+ description.keep_inside_line_ = col->extent (col, X_AXIS);
+
+ description.break_permission_ = col->get_property ("line-break-permission");
+ return description;
+}
+
+vector<Real>
+get_line_forces (vector<Grob *> const &columns,
+ Real line_len, Real indent, bool ragged)
+{
+ vector<vsize> breaks;
+ vector<Real> force;
+ vector<Grob *> non_loose;
+ vector<Column_description> cols;
+ SCM force_break = ly_symbol2scm ("force");
+
+ for (vsize i = 0; i < columns.size (); i++)
+ if (!is_loose (columns[i]) || Paper_column::is_breakable (columns[i]))
+ non_loose.push_back (columns[i]);
+
+ breaks.clear ();
+ breaks.push_back (0);
+ cols.push_back (Column_description ());
+ for (vsize i = 1; i + 1 < non_loose.size (); i++)
+ {
+ if (Paper_column::is_breakable (non_loose[i]))
+ breaks.push_back (cols.size ());
+
+ cols.push_back (get_column_description (non_loose, i, false));
+ }
+ breaks.push_back (cols.size ());
+ force.resize (breaks.size () * breaks.size (), infinity_f);
+
+ for (vsize b = 0; b + 1 < breaks.size (); b++)
+ {
+ cols[breaks[b]] = get_column_description (non_loose, breaks[b], true);
+ vsize st = breaks[b];
+
+ for (vsize c = b + 1; c < breaks.size (); c++)
+ {
+ vsize end = breaks[c];
+ Simple_spacer spacer;
+
+ for (vsize i = breaks[b]; i < end - 1; i++)
+ spacer.add_spring (cols[i].spring_);
+ spacer.add_spring (cols[end - 1].end_spring_);
+
+ for (vsize i = breaks[b]; i < end; i++)
+ {
+ for (vsize r = 0; r < cols[i].rods_.size (); r++)
+ if (cols[i].rods_[r].r_ < end)
+ spacer.add_rod (i - st, cols[i].rods_[r].r_ - st, cols[i].rods_[r].dist_);
+ for (vsize r = 0; r < cols[i].end_rods_.size (); r++)
+ if (cols[i].end_rods_[r].r_ == end)
+ spacer.add_rod (i - st, end - st, cols[i].end_rods_[r].dist_);
+ if (!cols[i].keep_inside_line_.is_empty ())
+ {
+ spacer.add_rod (i - st, end - st, cols[i].keep_inside_line_[RIGHT]);
+ spacer.add_rod (0, i - st, -cols[i].keep_inside_line_[LEFT]);
+ }
+ }
+ spacer.solve ((b == 0) ? line_len - indent : line_len, ragged);
+ force[b * breaks.size () + c] = spacer.force_penalty (ragged);
+
+ if (!spacer.fits ())
+ {
+ if (c == b + 1)
+ force[b * breaks.size () + c] = -200000;
+ else
+ force[b * breaks.size () + c] = infinity_f;
+ break;
+ }
+ if (end < cols.size () && cols[end].break_permission_ == force_break)
+ break;
+ }
+ }
+ return force;
+}
+
Column_x_positions
get_line_configuration (vector<Grob *> const &columns,
Real line_len,
ret.cols_.push_back (dynamic_cast<Item *> (columns[0])->find_prebroken_piece (RIGHT));
for (vsize i = 1; i + 1 < columns.size (); i++)
{
- if (Paper_column::is_loose (columns[i]))
+ if (is_loose (columns[i]))
ret.loose_cols_.push_back (columns[i]);
else
ret.cols_.push_back (columns[i]);
the end_XXX_ fields of our column_description */
for (vsize i = 0; i + 1 < ret.cols_.size (); i++)
{
- cols.push_back (Column_description::get_column_description (ret.cols_, i, i == 0));
+ cols.push_back (get_column_description (ret.cols_, i, i == 0));
spacer.add_spring (cols[i].spring_);
}
for (vsize i = 0; i < cols.size (); i++)
return ret;
}
+
#include "ly-smobs.icc"
IMPLEMENT_SIMPLE_SMOBS (Simple_spacer);
{
if (make_spanbar_)
{
- Grob *vag = Grob::get_root_vertical_alignment (bars_[0]);
- if (vag)
- vector_sort (bars_, Grob::pure_vertical_less);
spanbar_ = make_item ("SpanBar", SCM_EOL);
spanbar_->set_parent (bars_[0], X_AXIS);
Real
Staff_symbol_referencer::get_position (Grob *me)
+{
+ return internal_get_position (me, false);
+}
+
+Real
+Staff_symbol_referencer::pure_get_position (Grob *me)
+{
+ return internal_get_position (me, true);
+}
+
+Real
+Staff_symbol_referencer::internal_get_position (Grob *me, bool pure)
{
Real p = 0.0;
Grob *st = get_staff_symbol (me);
Grob *c = st ? me->common_refpoint (st, Y_AXIS) : 0;
if (st && c)
{
- Real y = me->relative_coordinate (c, Y_AXIS)
+ Real y = (pure
+ ? me->pure_relative_y_coordinate (c, 0, INT_MAX)
+ : me->relative_coordinate (c, Y_AXIS))
- st->relative_coordinate (c, Y_AXIS);
Real space = Staff_symbol::staff_space (st);
p = (space == 0) ? 0 : 2.0 * y / space;
return int (rint (get_position (me)));
}
+int
+Staff_symbol_referencer::pure_get_rounded_position (Grob *me)
+{
+ return int (rint (pure_get_position (me)));
+}
+
MAKE_SCHEME_CALLBACK (Staff_symbol_referencer, callback, 1);
SCM
Staff_symbol_referencer::callback (SCM smob)
void
Staff_symbol_referencer::set_position (Grob *me, Real p)
+{
+ internal_set_position (me, p, false);
+}
+
+void
+Staff_symbol_referencer::pure_set_position (Grob *me, Real p)
+{
+ internal_set_position (me, p, true);
+}
+
+void
+Staff_symbol_referencer::internal_set_position (Grob *me, Real p, bool pure)
{
Grob *st = get_staff_symbol (me);
Real oldpos = 0.0;
if (st && me->common_refpoint (st, Y_AXIS))
{
- oldpos = get_position (me);
+ oldpos = pure ? pure_get_position (me) : get_position (me);
}
Real ss = Staff_symbol_referencer::staff_space (me);
< Staff_symbol_referencer::get_position (b);
}
+bool
+pure_position_less (Grob *const &a, Grob *const &b)
+{
+ return Staff_symbol_referencer::pure_get_position (a)
+ < Staff_symbol_referencer::pure_get_position (b);
+}
+
ADD_INTERFACE (Staff_symbol_referencer,
"An object whose Y@tie{}position is meant relative to a staff"
" symbol. These usually"
interpret_stencil_expression (scm_caddr (expr), func, func_arg, o);
(*func) (func_arg, scm_list_1 (ly_symbol2scm ("resetcolor")));
+ return;
+ }
+ else if (head == ly_symbol2scm ("id"))
+ {
+ SCM id = scm_cadr (expr);
+
+ (*func) (func_arg, scm_list_2 (ly_symbol2scm ("start-enclosing-id-node"), id));
+ interpret_stencil_expression (scm_caddr (expr), func, func_arg, o);
+ (*func) (func_arg, scm_list_1 (ly_symbol2scm ("end-enclosing-id-node")));
+
return;
}
else if (head == ly_symbol2scm ("rotate-stencil"))
#include "ly-smobs.icc"
#include "context.hh"
#include "input.hh"
-#include "input.hh"
+#include "music.hh"
+#include "pitch.hh"
/* TODO: Rename Stream_event -> Event */
{
}
-Stream_event::Stream_event (SCM event_class, SCM mutable_props)
+Stream_event::Stream_event (SCM event_class, SCM immutable_props)
: Prob (ly_symbol2scm ("Stream_event"),
- scm_list_1 (scm_cons (ly_symbol2scm ("class"), event_class)))
+ scm_acons (ly_symbol2scm ("class"), event_class, immutable_props))
{
- mutable_property_alist_ = mutable_props;
}
Stream_event::Stream_event (SCM class_name, Input *origin)
MAKE_SCHEME_CALLBACK (Stream_event, undump, 1);
MAKE_SCHEME_CALLBACK (Stream_event, dump, 1);
+void
+Stream_event::make_transposable ()
+{
+ /* This is in preparation for transposing stuff
+ that may be defined in the immutable part */
+
+ for (SCM s = immutable_property_alist_; scm_is_pair (s); s = scm_cdr (s))
+ {
+ SCM entry = scm_car (s);
+ SCM prop = scm_car (entry);
+ SCM val = scm_cdr (entry);
+
+ if ((unsmob_pitch (val)
+ || (prop == ly_symbol2scm ("element") && unsmob_music (val))
+ || (prop == ly_symbol2scm ("elements") && scm_is_pair (val))
+ || (prop == ly_symbol2scm ("pitch-alist") && scm_is_pair (val)))
+ && scm_is_false (scm_assq (prop, mutable_property_alist_)))
+ mutable_property_alist_ =
+ scm_acons (prop, ly_music_deep_copy (val), mutable_property_alist_);
+ }
+}
+
+
SCM
Stream_event::dump (SCM self)
{
#include "all-font-metrics.hh"
#include "axis-group-interface.hh"
#include "break-align-interface.hh"
-#include "column-description.hh"
#include "grob-array.hh"
#include "hara-kiri-group-spanner.hh"
#include "international.hh"
return 0;
}
-vector<Simple_spacer>
-System::get_simple_spacers (Real line_len, Real indent, bool ragged)
-{
- if (!simple_spacers_.size ())
- gen_simple_spacers (line_len, indent, ragged);
-
- return simple_spacers_;
-}
-
-void
-System::gen_simple_spacers (Real line_len, Real indent, bool ragged)
-{
- vector<vsize> breaks;
- vector<Grob *> non_loose;
- vector<Column_description> cols;
- SCM force_break = ly_symbol2scm ("force");
- vector<Grob *> columns = used_columns ();
-
- for (vsize i = 0; i < columns.size (); i++)
- if (!Paper_column::is_loose (columns[i])
- || Paper_column::is_breakable (columns[i]))
- non_loose.push_back (columns[i]);
-
- breaks.clear ();
- breaks.push_back (0);
- cols.push_back (Column_description ());
- for (vsize i = 1; i + 1 < non_loose.size (); i++)
- {
- if (Paper_column::is_breakable (non_loose[i]))
- breaks.push_back (cols.size ());
-
- cols.push_back (Column_description::get_column_description (non_loose, i, false));
- }
- breaks.push_back (cols.size ());
- simple_spacers_.resize (breaks.size () * breaks.size (), Simple_spacer ());
-
- for (vsize b = 0; b + 1 < breaks.size (); b++)
- {
- cols[breaks[b]] = Column_description::get_column_description (non_loose, breaks[b], true);
- vsize st = breaks[b];
-
- for (vsize c = b + 1; c < breaks.size (); c++)
- {
- vsize end = breaks[c];
- Simple_spacer spacer;
-
- for (vsize i = breaks[b]; i < end - 1; i++)
- spacer.add_spring (cols[i].spring_);
- spacer.add_spring (cols[end - 1].end_spring_);
-
- for (vsize i = breaks[b]; i < end; i++)
- {
- for (vsize r = 0; r < cols[i].rods_.size (); r++)
- if (cols[i].rods_[r].r_ < end)
- spacer.add_rod (i - st, cols[i].rods_[r].r_ - st, cols[i].rods_[r].dist_);
- for (vsize r = 0; r < cols[i].end_rods_.size (); r++)
- if (cols[i].end_rods_[r].r_ == end)
- spacer.add_rod (i - st, end - st, cols[i].end_rods_[r].dist_);
- if (!cols[i].keep_inside_line_.is_empty ())
- {
- spacer.add_rod (i - st, end - st, cols[i].keep_inside_line_[RIGHT]);
- spacer.add_rod (0, i - st, -cols[i].keep_inside_line_[LEFT]);
- }
- }
- spacer.solve ((b == 0) ? line_len - indent : line_len, ragged);
- spacer.minimal_ = c == b + 1;
- simple_spacers_[b * breaks.size () + c] = spacer;
-
- if (!spacer.fits ()
- || (end < cols.size ()
- && cols[end].break_permission_ == force_break))
- break;
- }
- }
-}
-
Interval
System::pure_refpoint_extent (vsize start, vsize end)
{
number->extent (commony, Y_AXIS)[dir]));
}
- if (to_boolean (me->get_property ("avoid-scripts")))
+ if (to_boolean (me->get_property ("avoid-scripts"))
+ && !scm_is_number (me->get_property ("outside-staff-priority")))
{
extract_grob_set (me, "scripts", scripts);
for (vsize i = 0; i < scripts.size (); i++)
{
if (!scripts[i]->is_live ())
continue;
+ if (scm_is_number (scripts[i]->get_property ("outside-staff-priority")))
+ continue;
Interval script_x (scripts[i]->extent (commonx, X_AXIS));
Interval script_y (scripts[i]->extent (commony, Y_AXIS));
\consists "Font_size_engraver"
\consists "Separating_line_group_engraver"
- \consists "Dot_column_engraver"
\consists "Staff_collecting_engraver"
%% perhaps move to Voice context?
\consists "Breathing_sign_engraver"
\consists "Note_heads_engraver"
\consists "Dots_engraver"
+ \consists "Dot_column_engraver"
\consists "Rest_engraver"
\consists "Tweak_engraver"
\consists "Footnote_engraver"
DOCBOOK_FILES = $(call src-wildcard,*.lyxml)
OUT_HTML_FILES = ${HTML_FILES:%.html=$(outdir)/%.html}
-OUT_HTMLY_FILES = ${HTML_FILES:%.htmly=$(outdir)/%.html}
+OUT_HTMLY_FILES = ${HTMLY_FILES:%.htmly=$(outdir)/%.html}
OUT_XML_FILES = ${XML_FILES:%.xml=$(outdir)/%.html}
# If we have pdflatex, create the pdf, otherwise only the .tex file!
ifeq (,$(findstring dblatex,$(MISSING_OPTIONAL)))
$(outdir)/%.midi: %.ly $(LILYPOND_BINARY)
touch $(foreach f, $(HEADER_FIELDS), $(outdir)/$*.$f)
$(LILYPOND_BINARY) $(HEADER_FIELDS:%=-H %) -o $(outdir) $<
+ cp $< $(outdir)
$(outdir)/%-midi.ly: $(outdir)/%.midi $(MIDI2LY)
(echo '\header {'; for f in $(HEADER_FIELDS); do echo -n $$f'="'; cat $(outdir)/$*.$$f; echo '"'; done; echo '}') > $(outdir)/$*.header
out_f.write (page_flavors[k][1])
out_f.close()
# if the page is translated, a .en.html symlink is necessary for content negotiation
- if target == 'online' and ext_list != ['']:
+ if target == 'online' and ext_list != [''] and not os.path.lexists (name_filter (prefix + '.en.html')):
os.symlink (os.path.basename (prefix) + '.html', name_filter (prefix + '.en.html'))
\fi
}''',
- PRINTFILENAME: '''\\texttt{%(filename)s}
+ PRINTFILENAME: r'''\texttt{%(filename)s}
+\linebreak
''',
QUOTE: r'''\begin{quote}
str = ''
rep = snippet.get_replacements ();
rep['base'] = basename.replace ('\\', '/')
- str += self.output_print_filename (basename, snippet)
+ rep['filename'] = os.path.basename (snippet.filename).replace ('\\', '/')
+ rep['ext'] = snippet.ext
+ if PRINTFILENAME in snippet.option_dict:
+ str += self.output[PRINTFILENAME] % rep
if VERBATIM in snippet.option_dict:
rep['verb'] = snippet.verb_ly ()
str += self.output[VERBATIM] % rep
},
##
+ # TODO: Remove the 1mm additional padding in the line-width
+ # once lilypond creates tighter cropped images!
PAPER: {
PAPERSIZE: r'''#(set-paper-size "%(papersize)s")''',
INDENT: r'''indent = %(indent)s''',
- LINE_WIDTH: r'''line-width = %(line-width)s''',
- QUOTE: r'''line-width = %(line-width)s - 2.0 * %(exampleindent)s''',
+ LINE_WIDTH: r'''line-width = %(line-width)s
+ %% offset the left padding, also add 1mm as lilypond creates cropped
+ %% images with a little space on the right
+ line-width = #(- line-width (* mm %(padding_mm)f) (* mm 1))''',
+ QUOTE: r'''line-width = %(line-width)s - 2.0 * %(exampleindent)s
+ %% offset the left padding, also add 1mm as lilypond creates cropped
+ %% images with a little space on the right
+ line-width = #(- line-width (* mm %(padding_mm)f) (* mm 1))''',
RAGGED_RIGHT: r'''ragged-right = ##t''',
NORAGGED_RIGHT: r'''ragged-right = ##f''',
},
return (None, None)
-# TODO: Remove the 1mm additional padding in the line-width, once lilypond
-# creates tighter cropped images!
PREAMBLE_LY = '''%%%% Generated by %(program_name)s
%%%% Options: [%(option_string)s]
\\include "lilypond-book-preamble.ly"
\paper {
%(paper_string)s
- %% offset the left padding, also add 1mm as lilypond creates cropped
- %% images with a little space on the right
- line-width = #(- line-width (* mm %(padding_mm)f) (* mm 1))
}
\layout {
class LilypondSnippet (Snippet):
def __init__ (self, type, match, formatter, line_number, global_options):
Snippet.__init__ (self, type, match, formatter, line_number, global_options)
+ self.filename = ''
+ self.ext = '.ly'
os = match.group ('options')
self.parse_snippet_options (os, self.type)
override[EXAMPLEINDENT] = r'0.4\in'
override[LINE_WIDTH] = '5\\in'
override.update (self.formatter.default_snippet_options)
+ override['padding_mm'] = self.global_options.padding_mm
option_string = ','.join (self.get_outputrelevant_option_strings ())
compose_dict = {}
def additional_files_to_consider (self, base, full):
return []
def additional_files_required (self, base, full):
- return []
+ result = [];
+ if self.ext != '.ly':
+ result.append (base + self.ext)
+ return result
def all_output_files (self, output_dir, output_dir_files):
map (consider_file, [base + '.tex',
base + '.eps',
+ base + '.pdf',
base + '.texidoc',
base + '.doctitle',
base + '-systems.texi',
def __init__ (self, type, match, formatter, line_number, global_options):
LilypondSnippet.__init__ (self, type, match, formatter, line_number, global_options)
self.filename = self.substring ('filename')
- self.ext = os.path.splitext (os.path.basename (self.filename))[1]
self.contents = file (BookBase.find_file (self.filename,
global_options.include_path, global_options.original_dir)).read ()
LilypondFileSnippet.__init__ (self, type, match, formatter, line_number, global_options)
self.compressed = False
self.converted_ly = None
+ self.ext = os.path.splitext (os.path.basename (self.filename))[1]
self.musicxml_options_dict = {
'verbose': '--verbose',
'lxml': '--lxml',
return ('\\sourcefilename \"%s\"\n\\sourcefileline 0\n%s'
% (name, self.converted_ly))
- def additional_files_required (self, base, full):
- result = [];
- if self.compressed:
- result.append (base + '.mxl')
- else:
- result.append (base + '.xml')
- return result
-
def write_ly (self):
base = self.basename ()
path = os.path.join (self.global_options.lily_output_dir, base)
OUTPUTIMAGE: r'''@noindent
@ifinfo
-@image{%(info_image_path)s,,,%(alt)s,%(ext)s}
+@image{%(info_image_path)s,,,%(alt)s,}
@end ifinfo
@html
<p>
def output_info (self, basename, snippet):
str = ''
rep = snippet.get_replacements ();
+ rep['base'] = basename
+ rep['filename'] = os.path.basename (snippet.filename)
+ rep['ext'] = snippet.ext
for image in snippet.get_images ():
rep1 = copy.copy (rep)
- (rep1['base'], rep1['ext']) = os.path.splitext (image)
+ rep1['base'] = os.path.splitext (image)[0]
rep1['image'] = image
-
- # URG, makeinfo implicitly prepends dot to extension.
- # Specifying no extension is most robust.
- rep1['ext'] = ''
rep1['alt'] = snippet.option_dict[ALT]
rep1['info_image_path'] = os.path.join (self.global_options.info_images_dir, rep1['base'])
str += self.output[OUTPUTIMAGE] % rep1
- rep['base'] = basename
str += self.output[OUTPUT] % rep
return str
def snippet_output (self, basename, snippet):
- str = self.output_print_filename (basename, snippet)
+ str = ''
base = basename
if DOCTITLE in snippet.option_dict:
doctitle = base + '.doctitle'
translated_doctitle = doctitle + self.document_language
if os.path.exists (translated_doctitle):
- str += '@lydoctitle %s\n\n' % open (translated_doctitle).read ()
+ str += '\n@lydoctitle %s\n\n' % open (translated_doctitle).read ()
elif os.path.exists (doctitle):
- str += '@lydoctitle %s\n\n' % open (doctitle).read ()
+ str += '\n@lydoctitle %s\n\n' % open (doctitle).read ()
if TEXIDOC in snippet.option_dict:
texidoc = base + '.texidoc'
translated_texidoc = texidoc + self.document_language
str += '@include %(translated_texidoc)s\n\n' % vars ()
elif os.path.exists (texidoc):
str += '@include %(texidoc)s\n\n' % vars ()
+ str += self.output_print_filename (basename, snippet)
substr = ''
rep = snippet.get_replacements ();
return str
-@rule ((1, 3, 93), _ ('change property definiton case (eg. onevoice -> oneVoice)'))
+@rule ((1, 3, 93), _ ('change property definition case (eg. onevoice -> oneVoice)'))
def conv (str):
# Ugh, but meaning of \stemup changed too
# maybe we should do \stemup -> \stemUp\slurUp\tieUp ?
;;
;; i
;;
+ (id ,string? "An id string for the grob. Depending on the typestting
+backend being used, this id will be assigned to a group containing all of
+the stencils that comprise a given grob. For example, in the svg backend,
+the string will be assigned to the @code{id} attribute of a group (<g>)
+that encloses the stencils that comprise the grob. In the Postscript
+backend, as there is no way to group items, the setting of the id property
+will have no effect.")
(ignore-collision ,boolean? "If set, don't do note collision
resolution on this @code{NoteColumn}.")
(implicit ,boolean? "Is this an implicit bass figure?")
ellipse
embedded-ps
embedded-svg
+ end-enclosing-id-node
glyph-string
grob-cause
named-glyph
setcolor
setrotation
setscale
+ start-enclosing-id-node
text
unknown
url-link
combine-stencil
delay-stencil-evaluation
footnote
+ id
rotate-stencil
scale-stencil
translate-stencil
"false")
radius thick))
+(define (start-enclosing-id-node s)
+ "")
+
+(define (end-enclosing-id-node)
+ "")
+
(define (dashed-line thick on off dx dy phase)
(ly:format "~4f ~4f ~4f [ ~4f ~4f ] ~4f draw_dashed_line"
dx
"c = close"
(format #f "</~S>\n" entity))
+(define (start-enclosing-id-node s)
+ (string-append "<g id=\"" s "\">\n"))
+
+(define (end-enclosing-id-node)
+ "</g>\n")
+
(define-public (comment s)
(string-append "<!-- " s " -->\n"))
str = ''
if oldnew == 1:
str = '\n'.join ([d.replace ('\n','') for d in self.diff_lines])
- str = '<font size="-2"><pre>%s</pre></font>' % str
+ str = '<font size="-2"><pre>%s</pre></font>' % cgi.escape (str)
return str
class LogFileCompareLink (TextFileCompareLink):
str += '%-8s: %8d (%5.3f)\n' % (k, int (self.results[oldnew][k]),
self.get_ratio (k))
- return '<pre>%s</pre>' % str
+ return '<pre>%s</pre>' % cgi.escape (str)
def get_ratio (self, key):
(v1,v2) = (self.results[0].get (key, -1),
re.sub (r'\\sourcefilename "([^"]+)"',
note_original, open (sf).read ())
else:
- print 'no source for', val
+ print 'no source for', val.file_names[1]
def compare_trees (self, dir1, dir2):
self.compare_directories (dir1, dir2)
sys.exit(1)
for d in dirs:
+ # don't walk the share folders
+ if d.startswith("share"):
+ continue
+
d1 = os.path.join (dir1, d)
d2 = os.path.join (dir2, d)
self.compare_general_files (klasses[ext], f1, f2)
def compare_general_files (self, klass, f1, f2):
+ prefix = os.path.commonprefix ([f1, f2])
name = os.path.split (f1)[1]
+ name = os.path.join (prefix, name)
file_link = klass (f1, f2)
self.file_links[name] = file_link
def compare_signature_files (self, f1, f2):
+ prefix = os.path.commonprefix ([f1, f2])
name = os.path.split (f1)[1]
name = re.sub ('-[0-9]+.signature', '', name)
+ name = os.path.join (prefix, name)
file_link = None
try:
out.write ('%d below threshold\n' % len (below))
out.write ('%d unchanged\n' % len (unchanged))
- def create_text_result_page (self, dir1, dir2, dest_dir, threshold):
+ def create_text_result_page (self, dest_dir, threshold):
self.write_text_result_page (dest_dir + '/index.txt', threshold)
- def create_html_result_page (self, dir1, dir2, dest_dir, threshold):
- dir1 = dir1.replace ('//', '/')
- dir2 = dir2.replace ('//', '/')
-
+ def create_html_result_page (self, dest_dir, threshold):
(changed, below, unchanged) = self.thresholded_results (threshold)
header_row = '''
system ('rm -rf %s '% dest_dir)
data.write_changed (dest_dir, threshold)
- data.create_html_result_page (dir1, dir2, dest_dir, threshold)
- data.create_text_result_page (dir1, dir2, dest_dir, threshold)
+ data.create_html_result_page (dest_dir, threshold)
+ data.create_text_result_page (dest_dir, threshold)
################################################################
# TESTING
lang = ''
# possibly necessary for automatic language selection
file_symlink = file.replace(".html", ".en.html")
- if (not (os.path.exists(file_symlink))):
+ if not os.path.lexists (file_symlink):
os.symlink (file, file_symlink)
elif (len(file_split) == 3):
# it's a translation
for l in symlinks:
p = mirrortree.new_link_path (os.path.normpath (os.readlink (l)), os.path.dirname (l), strip_re)
dest = strip_file_name[t] (l)
- if not os.path.exists (dest):
+ if not os.path.lexists (dest):
os.symlink (p, dest)
lilypond_version_re_str = '\\\\version *\"([0-9.]+)"'
lilypond_version_re = re.compile (lilypond_version_re_str)
+lilypond_version_strict_re_str = '\\\\version *\"([0-9]+[.][0-9]+[.][0-9]+)"'
+lilypond_version_strict_re = re.compile (lilypond_version_strict_re_str)
help_summary = (
_ ('''Update LilyPond input to newer version. By default, update from the
def guess_lilypond_version (input):
- m = lilypond_version_re.search (input)
+ m = lilypond_version_strict_re.search (input)
if m:
return m.group (1)
+ m = lilypond_version_re.search (input)
+ if m:
+ raise InvalidVersion (m.group (1))
else:
return ''
touch $@
# Copy files while tracking their dependencies.
-$(outdir)/%.texi: $(src-dir)/%.texi
+$(outdir)/%.texi: %.texi
mkdir -p $(dir $@)
$(DO_TEXI_DEP) cp -f $< $@
-$(outdir)/%.itexi: $(src-dir)/%.itexi
+$(outdir)/%.itexi: %.itexi
mkdir -p $(dir $@)
$(DO_TEXI_DEP) cp -f $< $@