lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: learning (names of) markup commands in scheme: documentation


From: Jean Abou Samra
Subject: Re: learning (names of) markup commands in scheme: documentation
Date: Fri, 21 Jan 2022 19:30:31 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.5.0

Le 21/01/2022 à 08:57, Bernhard Fisseni a écrit :
Good morning,

trying to understand the programming a bit better, I managed to transform the mixed command definitions to scheme code (see below).

I've learnt the following in the process; should some of it be made more explicit in the manual?  (If so, I could try to think of suggestions.)

- In my opinion writing the scheme code is much easier than mixing Lilypond and Scheme.

- For every markup command and every markup list command \CMD, there is a corresponding scheme function make-CMD-markup.


<http://lilypond.org/doc/v2.22/Documentation/extending/markup-construction-in-scheme> uses this implicitly in the last paragraphs, but an explicit remark might be helpful.


<http://lilypond.org/doc/v2.22/Documentation/extending/how-markups-work-internally> explains the correspondence with one example, but does not mention markup list commands; furthermore, the heading and the wording mislead me so that I only understood the generality of this paragraph afterwards. Maybe "How Markups Work Internally: Lilypond Commands and Corresponding Scheme Commands" might be more explicit?

  Consequence: There is no collision between an auxiliary function CMD and a homonymous markup command \CMD, as they are (CMD ...) and (make-CMD-markup ...), respectively, in scheme.


Yes, and not only make-CMD-markup, but more importantly
CMD-markup which is the function into which your definition
gets turned into, in charge of doing the markup interpretation.
make-CMD-markup is then essentially defined as

(define (make-CMD-markup . args)
  (cons CMD-markup args))

A simplified version of interpret-markup would be:

(define (interpret-markup layout props mkup)
  (apply (car mkup)
         layout
         props
         (cdr mkup)))


  Question: Do similar correspondences exist for music functions and event functions? It looks as if they might me make-CMD-music and make-CMD-event, but I find no dokumentation for this. (May be my fault.)


No, there is no such thing. A music function is just
a music function, called by its name, which is the same
in the LilyPond namespace and in the Scheme namespace
-- these are actually the same. Try

#(display relative)

So music functions are first-class objects. Same with
other syntax functions (all those you create with
define-{music,event,scheme,void}-function). You can
even call them in Scheme:

$(relative #{ c' #} #{ c'1 d e #})

(about # vs $ see
https://lilypond.org/doc/v2.23/Documentation/extending/lilypond-scheme-syntax
and
https://extending-lilypond.readthedocs.io/en/latest/lily-and-scheme.html#hash-vs-dollar).

Markups are very special. They are not implemented
as a type of objets, but as mere lists whose car
is a markup command, namely a procedure (the CMD-markup
one) that bears a bunch of object properties
("attributes") like its signature. The \markup syntax
does not look up objects in the namespace normally,
but transforms the names to add "-markup" at the
end.

If you want my opinion, markup internals are not the
best-designed part of LilyPond. I have plans to
change that, but I also have uncountably many
plans of similar scope, and work on LilyPond as a
hobby in otherwise already LilyPond development
is for me a hobby in already otherwise busy weeks.



- A (list ...) of markups is indeed a markup list, and markup lists can be treated like just a list (map, length, car, cdr etc.).  (Actually, I had expected that there were specialised conversions and accessor functions.)

  Given that lists are so fundamental, this might be stated somewhere.


Yes, but careful: not every markup list is a list
of markups, even though it is true that a list of
markups constitutes a markup list. The other way to
have a markup list is to apply a markup list command.
For example: \table-of-contents.

#(display #{ \markup \table-of-contents #})

Markup list commands are listed at
https://lilypond.org/doc/v2.23/Documentation/notation/text-markup-list-commands



- There is a point in processing when one has to convert every "line" (in my example) to markup, although the interpretation happens automatically in other places (see interpret-markup-list in apply-last-strut).


I'm not sure what you mean here. Can you clarify?




[snipped]



[Lukas]
Isn't this just

#(define-markup-command (strut-line layout props line)
  (markup?)
  "add strut to the end of a line to ensure correct line spacing"
  (interpret-markup layout props
   (markup #:combine line #:transparent "Ij")))

?


Well, we have four ways to create markups in Scheme.

#{ \markup \bold "a" #}
(make-bold-markup "a")
(markup #:bold "a")
(list bold-markup "a")

The fourth one relies on markup internals, and I would
recommend against using it since, as said above, we
could want to move away from this representation at
some point.

Between the three former ones, the choice is
mostly a matter of taste. The markup macro has
the caveats mentioned in the documentation that
you point out, and it should also be avoided within
the Scheme source files of LilyPond itself because
it is not compatible with Guile 2 byte-compilation
at the moment.



I would agree that the explanations regarding markups vs. markup lists, markup vs. stencils, markup in scheme etc. in the Documentation might be improved.


For what it's worth, a step has been made
just a few weeks ago with

https://gitlab.com/lilypond/lilypond/-/merge_requests/1089

That merge request revised the Notation Reference
material about markups (though not the Extending
Manual material) so that the interplay between
markups and markup lists would be clearer. Part
of my motivation for doing this is that it took
myself ages even as a developer to discover the
way applying a markup command taking a markup as
last argument to a markup list as last arguments
"maps" it as in your examples.

------------------------------------------------

Regarding the problem at hand, I believe it can
be solved by defining a slightly tweaked version
of \column that allows turning off the behavior
that avoids overlap between lines:

\version "2.22.1"

#(define-markup-command (better-column layout props args)
  (markup-list?)
  #:properties ((baseline-skip)
                (padding 0.0))
  "Like \\column, but accepts the padding property to control
the minimum space between the corners of the markup elements.
\\column hardcodes it at 0.0, meaning that markups are stacked
at fixed distances according to their baselines, unless they
overlap, in which case it moves them further apart so that
they don't overlap. Use a negative padding to allow some amount
of overlap. Use -inf.0 to space strictly according to baselines."
  (let ((arg-stencils (interpret-markup-list layout props args)))
    (stack-lines -1 padding baseline-skip arg-stencils)))


#(set-default-paper-size "a6") % just to make alignment more obvious
melody = \relative {
  c'4 c c c | d d d d
}

text = \lyricmode {
  \set stanza = "1." This is verse one.
  It has two lines.
}

\score{ <<
    \new Voice = "one" { \melody }
    \new Lyrics \lyricsto "one" \text
   >>
  \layout { }
}

\markup \override #'(padding . -inf.0) {
  \fill-line {
    \hspace #0.1 % moves the column off the left margin;
     % can be removed if space on the page is tight
     \better-column {
      \line { \bold "2."
        \better-column {
          "q This is verse two."
          "q It has two lines."
        }
      }
      \combine \null \vspace #0.1 % adds vertical spacing between verses
      \line { \bold "3."
        \better-column {
          "q This is verse three."
          "q It has two lines."
        }
      }
    }
    \hspace #0.1 % adds horizontal spacing between columns;
    \better-column {
      \line { \bold "4."
        \better-column {
          "This is verse four."
          "It has two lines."
        }
      }
      \combine \null \vspace #0.1 % adds vertical spacing between verses
      \line { \bold "5."
        \better-column {
          "This is verse five."
          "It has two lines."
        }
      }
    }
  \hspace #0.1 % gives some extra space on the right margin;
  % can be removed if page space is tight
  }
}



Homework for me: figure out why this does not result
in constant spacing regardless of the heights of
the markups (that part of the code is rather complicated).

Regards,
Jean



reply via email to

[Prev in Thread] Current Thread [Next in Thread]