On 6/29/21, 11:33 AM, "lilypond-user on behalf of Aaron Hill" 
<lilypond-user-bounces+carl.d.sorensen=gmail....@gnu.org on behalf of 
lilyp...@hillvisions.com> wrote:

    On 2021-06-29 9:43 am, Jean Abou Samra wrote:
    > However, this problem can be solved by writing
    > an engraver (those are the powerful tools that
    > \applyOutput uses under the hood).
    > 
    > \version "2.22.0"
    > 
    > \layout {
    >   \context {
    >     \Score
    >     \consists
    >       #(lambda (context)
    >          (make-engraver
    >            (acknowledgers
    >              ((grob-interface engraver grob source-engraver)
    >                 (set! (ly:grob-property grob 'output-attributes)
    >                       `((class . ,(grob::name grob))))))))
    >   }
    > }
    > 
    > <<
    >   { c d e f }
    >   \\
    >   { g a b c' }
    >>> 
    
    NOTE: You might want this engraver to *append* to the class attribute, 
    so you can still specify classes on an individual basis:

Great idea, and nice implementation, Aaron!
    
    %%%%
    \version "2.22.0"
    
    SvgAddClassName =
    #(lambda (ctxt)
       (define (add-class-name grob)
        (let* ((attribs (ly:grob-property grob 'output-attributes '()))
               (class (ly:assoc-get 'class attribs '()))
               (name (grob::name grob)))
         (set! class (if (null? class) name (format #f "~a ~a" class name)))
         (set! attribs (assoc-set! attribs 'class class))
         (ly:grob-set-property! grob 'output-attributes attribs)))
       (make-engraver
        (acknowledgers
         ((grob-interface engraver grob source)
          (add-class-name grob)))))
    
    \layout { \context { \Score \consists \SvgAddClassName } }
    
    { \tweak output-attributes #'((class . foo)) b'4 }
    %%%%
    
When I learned Scheme 36 years ago from the CS guys at MIT, they really frowned 
on using set! (side-effects of code were avoided as much as possible).

So I rewrote the code using only the necessary set! functions

%%%%
\version "2.20.0"

SvgAddClassName =
#(lambda (ctxt)
   (define (add-class-name grob)
    (let* ((attribs (ly:grob-property grob 'output-attributes '()))
           (class (ly:assoc-get 'class attribs '()))
           (name (grob::name grob))
           (grob-class-name (if (null? class)
                                name
                                (format #f "~a ~a" class name))))
     (ly:grob-set-property! grob 'output-attributes (assoc-set! attribs 'class 
grob-class-name))))
   (make-engraver
    (acknowledgers
     ((grob-interface engraver grob source)
      (add-class-name grob)))))

\layout { \context { \Score \consists \SvgAddClassName } }

{ \tweak output-attributes #'((class . foo)) b'4 }
%%%%

I believe that the logical implications of side-effects are not very concerning 
when local variables are set!, so there's probably very little or no downside 
to the set!s in Aaron's code.  In fact, it's possible that Aaron's code will 
use less heap space by re-using class instead of adding a new variable 
grob-class-name.  But I can't help myself; I want to avoid the grief  Sussman 
would give me over two unneeded set! calls.....

Carl



Reply via email to