> That is indeed a problem, but note that the same problem exists with before-
> line-breaking (you can't write two independent before-line-breaking
> overrides, you need to combine them).

Sure, that is also something where it would be nice to actually have a list of 
procedures. Of course one could hack together something like this

extendGrobProcedure =
#(define-music-function (path proc) (symbol-list-or-symbol? procedure?)
   (let* ((path (check-grob-path path #:default 'Default))
          (ctx (car path))
          (grob (cadr path))
          (property (caddr path)))
     #{
       \applyContext
       #(lambda (context)
          (let* ((context (if (equal? ctx 'Default) context (ly:context-find 
context ctx)))
                 (grob-def (ly:context-grob-definition context grob))
                 (prop (assoc-get property grob-def))
                 (combined-proc (if (procedure? prop)
                                    (lambda (. args)
                                      (apply prop args)
                                      (apply proc args))
                                    proc)))
            (ly:context-pushpop-property context grob property combined-
proc)))
     #}))
\new Voice {
  \extendGrobProcedure NoteHead.before-line-breaking #(lambda (x) (ly:grob-
set-property! x 'font-size 3))
  \extendGrobProcedure NoteHead.before-line-breaking #(lambda (x) (ly:grob-
set-property! x 'color red))
  c
}

but that is rather ugly.

> > Maybe the whole transformer thing should be something that Lilypond
> > supports in it’s core? Like, any grob property may also have a list of
> > transformers that get evaluated on getting the property.
> 
> Yes, it would be quite nice to be able to stack transformers. Defining good
> semantics (e.g., interaction with \temporary and \revert) is not really
> trivial though.

A simple showcase implementation:

#(define ((property-with-transformers property) grob)
   (let* ((details (ly:grob-property grob 'details '()))
          (property (assoc-get property details '()))
          (baseprop (assoc-get 'baseprop property '()))
          (baseprop (if (procedure? baseprop) (baseprop grob) baseprop))
          (transformers (assoc-get 'transformers property '())))
     (fold (lambda (proc prop) (if (procedure? (cdr proc)) ((cdr proc) grob 
prop) prop))
           baseprop transformers)))

{
  \override NoteHead.details.stencil.baseprop = #ly:note-head::print
  \override NoteHead.stencil = #(property-with-transformers 'stencil)
  \override NoteHead.details.stencil.transformers.rotate = #(lambda (grob 
orig) (ly:stencil-rotate orig 90 0 0))
  \override NoteHead.details.stencil.transformers.stretch = #(lambda (grob 
orig) (ly:stencil-scale orig 1 2))
  c d
  \revert NoteHead.details.stencil.transformers.rotate
  e

  \override NoteHead.details.stencil.baseprop = #ly:text-interface::print
  \override NoteHead.text = \markup \vcenter "o"
  f
  % Reset all transformers, \revert does not work here
  \override NoteHead.details.stencil.transformers = #'()
  g
}

although that one does not handle things like execution order intelligently, 
which is also something that could be handled with little effort.

> Relatedly, it would be nice at some point to gain support for callbacks in
> subproperties.

I think for this Lilypond would first need to actually have a concept of 
subproperties rather than just alist entries.

Cheers,
Valentin

Attachment: signature.asc
Description: This is a digitally signed message part.

Reply via email to