> ```
>        (let* ((bound-details (ly:grob-property grob 'bound-details))
>               (left (assoc-get 'left bound-details))
>               (left (assoc-set!
>                      left
> ```

If you add another red text spanner, you will see that it gets the text "foo" 
in spite of \once. The reason is that you're mutating the default 
'bound-details value shared by all TextSpanner grobs.

In fact, nothing guarantees that the default value is even mutable. Mutating a 
constant, as created by a quote expression, is disallowed. (In recent Guile 
versions, it can even lead to true "nasal demons" undefined behavior ­— when 
you enable byte-compilation and optimizations, `(set-car! '(1 . 2) 3)` outright 
segfaults. The time I looked at the bug, I couldn't understand where it was 
coming from.)

Better use alist-copy here. Also, there is no need for mutating the grob in 
before-line-breaking, you can use the more functional approach with 
grob-transformer:

```
\version "2.24"

{
  \once \override TextSpanner.bound-details =
    #(grob-transformer
      'bound-details
      (lambda (grob orig)
        (assoc-set! (alist-copy orig)
                    'left
                    (assoc-set! (alist-copy (assoc-ref orig 'left))
                                'text
                                (if (equal? red (ly:grob-property grob 'color))
                                    "foo" "bar")))))
  c'1
  - \tweak color #red
  \startTextSpan
  c'1
  \stopTextSpan
  c'1\tweak color #red \startTextSpan c'1\stopTextSpan
}
```


Best,

Jean

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

Reply via email to