Markup command definition syntax

New markup commands can be defined using the define-markup-command Scheme macro, at top-level.

(define-markup-command (command-name layout props arg1 arg2 …)
    (arg1-type? arg2-type? …)
    [ #:properties ((property1 default-value1)
                    …) ]
    [ #:as-string expression ]
  …command body…)

The arguments are


the markup command name


the ‘layout’ definition.


a list of associative lists, containing all active properties.


ith command argument


a type predicate for the ith argument

If the command uses properties from the props arguments, the #:properties keyword can be used to specify which properties are used along with their default values.

Arguments are distinguished according to their type:

There is no limitation on the order of arguments (after the standard layout and props arguments). However, markup functions taking a markup as their last argument are somewhat special as you can apply them to a markup list, and the result is a markup list where the markup function (with the specified leading arguments) has been applied to every element of the original markup list.

Since replicating the leading arguments for applying a markup function to a markup list is cheap mostly for Scheme arguments, you avoid performance pitfalls by just using Scheme arguments for the leading arguments of markup functions that take a markup as their last argument.

Markup commands have a rather complex life cycle. The body of a markup command definition is responsible for converting the arguments of the markup command into a stencil expression which is returned. Quite often this is accomplished by calling the interpret-markup function on a markup expression, passing the layout and props arguments on to it. Those arguments are usually only known at a very late stage in typesetting. Markup expressions have their components assembled into markup expressions already when \markup in a LilyPond expression or the markup macro in Scheme is expanded. The evaluation and typechecking of markup command arguments happens at the time \markup/markup are interpreted.

But the actual conversion of markup expressions into stencil expressions by executing the markup function bodies only happens when interpret-markup is called on a markup expression.

Extending LilyPond v2.25.17 (development-branch).