In my LilyPond file (which is a minimal excerpt in a recent project I am working on), I created a Scheme-based music function to set grob properties by passing an `alist`. The method works by merging the given property `alist` to the `details` grob property. In order not to get confused with the builtin props I added a prefix.

The key code is in the `useScore` variable definition. WHen I am adding properties for different grobs separately, It works with no problem. However, when I put all properties in a hash table and and use a `hash-for-each` to traverse all the property entries and assign them to the corresponding grobs, I got an error. I don't know why this error occurs. So what is wrong with my program?
\version "2.24.4"

#(define (alist-prop-updater prop new-data)
  (grob-transformer prop 
    (lambda (grob original)
      (if (or (null? original) (eq? original #f))
        (alist-copy new-data)
        (begin
          (for-each
            (lambda (entry)
              (let*
                (
                  (k (car entry)) (v (cdr entry))
                  (original-entry (sloppy-assoc k original))
                )
                (if original-entry
                  (set-cdr! original-entry v)
                  (append! original `(,entry))
                )
              )
            )
            new-data
          )
          original
        )
      )
    )
  )
)

#(define score-config-prefixer (symbol-prefix-proc 'SCORE:))

alistPropUpdate = #(define-music-function 
  (grobsym prop new-data) (symbol? symbol? list?)
  #{
    \propertyTweak $prop #(alist-prop-updater prop new-data) $grobsym
  #}
)

configScore = #(define-music-function
  (grobsym config-table) (symbol? list?)
  #{
    \alistPropUpdate $grobsym details 
    #(map
      (lambda (entry)
        (let*
          (
            (k (car entry)) (v (cdr entry))
            (prefixed-k (score-config-prefixer k))
          )
          (cons prefixed-k v)
        )
      )
      config-table
    )
  #}
)

% a hash table containing all configurations

"SCORE:global-config" = #(alist->hash-table '(
  (Clef . (
    (line-thickness . .075)
    (change-clef-size . .84)
  ))
  (Notehead . (
    (line-thickness . .1)
  ))
  (Rest . (
    (slope . .32)
    (line-thickness . .09)
    (max-h-span . 1)
    (tip-edges . 12)
    (tip-offset . (0.23 . 0.51))
    (tip-radius . 0.24)
  ))
  (Accidental . (
    (use-double-sharp . #t)
    (line-thickness . 0.08)
    (symbol-pad . 0.1)
    (paren-pad . 0.2)
  ))
))

useScore = {
  % This works ...
  %{
  \configScore Clef #'(
    (line-thickness . .075)
    (change-clef-size . .84)
  )
  \configScore NoteHead #'(
    (line-thickness . .1)
  )
  \configScore Rest #'(
    (slope . .32)
    (line-thickness . .09)
    (max-h-span . 1)
    (tip-edges . 12)
    (tip-offset . (0.23 . 0.51))
    (tip-radius . 0.24)
  )
  \configScore Accidental #'(
    (use-double-sharp . #t)
    (line-thickness . 0.08)
    (symbol-pad . 0.1)
    (paren-pad . 0.2)
  )
  %}
  
  % but this will cause an error
  % error message:
  %{
    test-scheme.ly:36:70: error: bad grob property path (Notehead details)
    \propertyTweak #prop #(alist-prop-updater prop new-data) $grobsy
    test-scheme.ly:112:4: error: error in #{ ... #}
    #
     (hash-for-each 
    ...
  %}
  #(hash-for-each 
    (lambda (grobsym config-table)
      #{
        \configScore $grobsym #(alist-copy config-table)
      #}
    ) 
    SCORE:global-config
  )
}

\layout {
  \context { \Score \useScore }
}

\score {
  \new Staff {
    \relative c' {
      c d e f g f e d c
    }
  }
}

Reply via email to