Jump to content

Implementing a counter in markup text

From LilyPond wiki

This snippet shows how to implement a counter in LilyPond for use in markup texts. Whenever you call the \counter #"name" markup function, the counter named name will be increased by one and the new value will be printed as a text markup. The first call will print “1” by default. Example:

\markup { Initial value of the counter: \counter #"mycounter". Second call: \counter #"mycounter" }

The snippet also implements a \setcounter #"name" newvalue markup command to set the the counter to a specific value and print it out.

One can have an arbitrary number of simultaneous counters, each indicated by its own name (as a string).

The storage of the counter values is implemented as a global alist counter-alist (Scheme/Guile's concept of a hash), where the counter command simply extracts the current value, increases it by one and stores it back in the alist.

\version "2.24.0"

%% http://lsr.di.unimi.it/LSR/Item?id=543

\paper { tagline = ##f }

%here starts the snippet:

#(define counter-alist '())

#(define-markup-command (counter layout props name) (string?)
  "Increases and prints out the value of the given counter named @var{name}.
  If the counter does not yet exist, it is initialized with 1."
  (let* ((oldval (assoc-ref counter-alist name))
         (newval (if (number? oldval) (+ oldval 1) 1)))
  (set! counter-alist (assoc-set! counter-alist name newval))
  (interpret-markup layout props
    (markup (number->string newval)))))

#(define-markup-command (setcounter layout props name value) (string? number?)
  "Set the given counter named @var{name} to the given @var{value} and prints
  out the value. The counter does not yet have to exist."
  (set! counter-alist (assoc-set! counter-alist name (- value 1)))
  (interpret-markup layout props (make-counter-markup name)))

\markup { Initial value of the counter: \counter #"mycounter". Second call: \counter #"mycounter" }
\markup { It is increasing: \counter #"mycounter" }
\markup { A second counter: \counter #"myothercounter" }
\markup { First counter is increasing: \counter #"mycounter" }
\markup { Second counter is increasing: \counter #"myothercounter" }
\markup { Setting to a specific value works, too: }
\markup { Set first counter to 15: \setcounter #"mycounter" #15 }
\markup { It is increasing: \counter #"mycounter" }
\markup { It is increasing: \counter #"mycounter" }
\markup { It is increasing: \counter #"mycounter" }
\markup { It is increasing: \counter #"mycounter" }
\markup { It is increasing: \counter #"mycounter" }
\markup { Second counter is increasing: \counter #"myothercounter" }