I mean, \applyContext kind of does accept an optional "which context"
argument in that you can write \context Foo { \applyContext ... } to run
code in a context different than the current one. I'm not sure if it's
specifically used this way in official docs, but there is an example here
https://extending-lilypond.gitlab.io/en/extending/translation.html#accessing-a-context.
Though I guess technically the semantics aren't exactly the same, since
writing \context invokes an iterator and might implicitly create a context.

How would \applyContext Context be different than \applyOutput Context
(with a procedure that ignores the other arguments)? Are they actually the
same?

On Sat, Jan 18, 2025 at 10:01 AM Valentin Petzel <[email protected]> wrote:

> Hello David,
>
> > Neither surprising nor an edge case.
>
> I would say it is quite surprising for most users, and definitely an edge
> case.
> It is essentially a case of `\applyContext` silently behaving differently
> when
> the Voice context was not created yet. And even you are getting this
> wrong:
>
> > That's because at the point of the first call, you haven't yet descended
> > into a Voice or even Staff context from the surrounding Score context.
> > So \applyContext prints the Stem.length setting for the Score context
> > which has not been changed (you only changed the default for every
> > bottom context).
> >
> > If you want to override Stem.length at the Score level, either write
> >
> > \override Score.Stem.length = ...
> >
> > in your \layout block, or write things like described in the docs,
> > namely
> >
> > \layout {
> >   \context {
> >     \Score
> >     \override Stem.length = ...
> >   }
> > }
>
> This creates the same output, because the top context is not Score, but
> Global. At the point in question not even a score context exists, so this
> is
> called in the global context. This we can also see when doing
>
> ```
> testfn =
> #(lambda (context)
>    (display context)
>    (newline))
>
> \score {
>   {
>     \applyContext #testfn
>     4
>     \applyContext #testfn
>   }
> }
> ```
>
> which will display
>
> > #<Global_context Global () >
> > #<Context Voice () >
>
> So actually you’d have to do
>
> ```\override Global.Stem.length = #0```
>
> or
>
> ```\context { \Global ... }```
>
> This makes me wonder one more time if `\applyContext` should take an
> optional
> context argument, allowing to specify which context this should run on,
> and
> fail if this context is not found, such as in this mockup:
>
> ```
> myApplyContext =
> #(define-music-function (name id proc)
>    ((symbol? #f) (string? #f) procedure?)
>    (define (context-find name id ctx)
>      (and
>       ctx
>       (if (and (equal? (ly:context-name ctx) name)
>                (or (not id) (equal? (ly:context-id ctx) id)))
>           ctx
>           (context-find name id (ly:context-parent ctx)))))
>    (applyContext
>     (if name
>         (lambda (ctx)
>           (let ((context (context-find name id ctx)))
>             (if context
>                 (proc context)
>                 (ly:warning-located
>                  (apply format #f "~a:~a:~a:~a"
> (ly:input-file-line-char-column
> (*location*)))
>                  "Context ~a not found"
>                  (if id (format #f "~a = ~a" name id) name)))))
>         proc)))
>
> testfn =
> #(lambda (context)
>    (display context)
>    (display ", ")
>    (display (ly:context-name context))
>    (display ", ")
>    (display (ly:context-id context))
>    (newline))
>
> { \myApplyContext #testfn 4 \myApplyContext #testfn 4 \myApplyContext
> Global
> #testfn }
>
> \new StaffGroup = "outer" \new StaffGroup = "inner" \new Staff
> { s4 \myApplyContext StaffGroup #testfn s4 \myApplyContext StaffGroup
> "outer"
> #testfn }
> ```
>
> which would in the given case
>
> ```
> displayStemLength =
> #(lambda (context)
>    (let* ((grob-def (ly:context-grob-definition context 'Stem))
>           (length (ly:assoc-get 'length grob-def)))
>      (display "+ ")
>      (display length)
>      (newline)))
>
> \score {
>   \relative c'' {
>     \myApplyContext Voice #displayStemLength
>     g4
>     \myApplyContext Voice #displayStemLength
>     g
>   }
>   \layout {
>     \override Stem.length = #0
>   }
> }
> ```
>
> issue a warning for the first call
>
> > [location]: Warning: Context Voice not found
>
> Cheers,
> Valentin
>
>

Reply via email to