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 > >
