]> git.donarmstrong.com Git - lilypond.git/blobdiff - scm/define-markup-commands.scm
* Unify fetaDynamic and fetaNumber into one fetaText encoding
[lilypond.git] / scm / define-markup-commands.scm
index 34541d55487bdf464eae8292de553299c8adc21b..8d4d749770d129975a80113fce9fee9c9d6b5454 100644 (file)
-;;;; define-markup-commands.scm -- markup commands
+;;;; This file is part of LilyPond, the GNU music typesetter.
 ;;;;
-;;;;  source file of the GNU LilyPond music typesetter
-;;;; 
-;;;; (c) 2000--2007  Han-Wen Nienhuys <hanwen@xs4all.nl>
+;;;; Copyright (C) 2000--2010  Han-Wen Nienhuys <hanwen@xs4all.nl>
 ;;;;                  Jan Nieuwenhuizen <janneke@gnu.org>
-
-
-;;; markup commands
-;;;  * each markup function should have a doc string with
-;;     syntax, description and example. 
+;;;;
+;;;; LilyPond is free software: you can redistribute it and/or modify
+;;;; it under the terms of the GNU General Public License as published by
+;;;; the Free Software Foundation, either version 3 of the License, or
+;;;; (at your option) any later version.
+;;;;
+;;;; LilyPond is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;;; GNU General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU General Public License
+;;;; along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
+
+;;;
+;;; Markup commands and markup-list commands definitions.
+;;;
+;;; Markup commands which are part of LilyPond, are defined
+;;; in the (lily) module, which is the current module in this file,
+;;; using the `define-markup-command' macro.
+;;;
+;;; Usage:
+;;;
+;;; (define-markup-command (command-name layout props args...)
+;;;   args-signature
+;;;   [ #:category category ]
+;;;   [ #:properties property-bindings ]
+;;;   documentation-string
+;;;   ..body..)
+;;;
+;;; with:
+;;;   command-name
+;;;     the name of the markup command
+;;;
+;;;   layout and props
+;;;     arguments that are automatically passed to the command when it
+;;;     is interpreted.
+;;;     `layout' is an output def, which properties can be accessed
+;;;     using `ly:output-def-lookup'.
+;;;     `props' is a list of property settings which can be accessed
+;;;     using `chain-assoc-get' (more on that below)
+;;;
+;;;   args...
+;;;     the command arguments. There are restrictions on the
+;;;     possible arguments for a markup command.
+;;;     First, arguments are distinguished according to their type:
+;;;       1) a markup (or a string), corresponding to type predicate `markup?'
+;;;       2) a list of markups, corresponding to type predicate `markup-list?'
+;;;       3) any scheme object, corresponding to type predicates such as
+;;;       `list?', 'number?', 'boolean?', etc.
+;;;     The supported arrangements of arguments, according to their type, are:
+;;;       - no argument
+;;;       - markup
+;;;       - scheme
+;;;       - markup, markup
+;;;       - markup-list
+;;;       - scheme, scheme
+;;;       - scheme, markup
+;;;       - scheme, scheme, markup
+;;;       - scheme, scheme, markup, markup
+;;;       - scheme, markup, markup
+;;;       - scheme, scheme, scheme
+;;;     This combinations are hard-coded in the lexer and in the parser
+;;;     (lily/lexer.ll and lily/parser.yy)
+;;;
+;;;   args-signature
+;;;     the arguments signature, i.e. a list of type predicates which
+;;;     are used to type check the arguments, and also to define the general
+;;;     argument types (markup, markup-list, scheme) that the command is
+;;;     expecting.
+;;;     For instance, if a command expects a number, then a markup, the
+;;;     signature would be: (number? markup?)
+;;;
+;;;   category
+;;;     for documentation purpose, builtin markup commands are grouped by
+;;;     category. This can be any symbol. When documentation is generated,
+;;;     the symbol is converted to a capitalized string, where hyphens are
+;;;     replaced by spaces.
+;;;
+;;;   property-bindings
+;;;     this is used both for documentation generation, and to ease
+;;;     programming the command itself. It is list of
+;;;        (property-name default-value)
+;;;     or (property-name)
+;;;     elements. Each property is looked-up in the `props' argument, and
+;;;     the symbol naming the property is bound to its value.
+;;;     When the property is not found in `props', then the symbol is bound
+;;;     to the given default value. When no default value is given, #f is
+;;;     used instead.
+;;;     Thus, using the following property bindings:
+;;;       ((thickness 0.1)
+;;;        (font-size 0))
+;;;     is equivalent to writing:
+;;;       (let ((thickness (chain-assoc-get 'thickness props 0.1))
+;;;             (font-size (chain-assoc-get 'font-size props 0)))
+;;;         ..body..)
+;;;     When a command `B' internally calls an other command `A', it may
+;;;     desirable to see in `B' documentation all the properties and
+;;;     default values used by `A'. In that case, add `A-markup' to the
+;;;     property-bindings of B. (This is used when generating
+;;;     documentation, but won't create bindings.)
+;;;
+;;;   documentation-string
+;;;     the command documentation string (used to generate manuals)
+;;;
+;;;   body
+;;;     the command body. The function is supposed to return a stencil.
+;;;
+;;; Each markup command definition shall have a documentation string
+;;; with description, syntax and example.
 
 (use-modules (ice-9 regex))
 
 ;; geometric shapes
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(define-builtin-markup-command (draw-line layout props dest)
+(define-markup-command (draw-line layout props dest)
   (number-pair?)
-  graphic
-  ((thickness 1))
+  #:category graphic
+  #:properties ((thickness 1))
   "
 @cindex drawing lines within text
 
@@ -42,22 +145,15 @@ A simple line.
                thickness))
         (x (car dest))
         (y (cdr dest)))
-    (ly:make-stencil
-     `(draw-line
-       ,th
-       0 0
-       ,x ,y)
-     (cons (min x 0) (max x 0))
-     (cons (min y 0) (max y 0)))))
-
-(define-builtin-markup-command (draw-circle layout props radius thickness fill)
+    (make-line-stencil th 0 0 x y)))
+
+(define-markup-command (draw-circle layout props radius thickness filled)
   (number? number? boolean?)
-  graphic
-  ()
+  #:category graphic
   "
 @cindex drawing circles within text
 
-A circle of radius @var{radius}, thickness @var{thickness} and
+A circle of radius @var{radius} and thickness @var{thickness},
 optionally filled.
 
 @lilypond[verbatim,quote]
@@ -67,14 +163,14 @@ optionally filled.
   \\draw-circle #2 #0 ##t
 }
 @end lilypond"
-  (make-circle-stencil radius thickness fill))
+  (make-circle-stencil radius thickness filled))
 
-(define-builtin-markup-command (triangle layout props filled)
+(define-markup-command (triangle layout props filled)
   (boolean?)
-  graphic
-  ((thickness 0.1)
-   (font-size 0)
-   (baseline-skip 2))
+  #:category graphic
+  #:properties ((thickness 0.1)
+               (font-size 0)
+               (baseline-skip 2))
   "
 @cindex drawing triangles within text
 
@@ -98,12 +194,12 @@ A triangle, either filled or empty.
      (cons 0 ex)
      (cons 0 (* .86 ex)))))
 
-(define-builtin-markup-command (circle layout props arg)
+(define-markup-command (circle layout props arg)
   (markup?)
-  graphic
-  ((thickness 1)
-   (font-size 0)
-   (circle-padding 0.2))
+  #:category graphic
+  #:properties ((thickness 1)
+               (font-size 0)
+               (circle-padding 0.2))
   "
 @cindex circling text
 
@@ -124,10 +220,9 @@ thickness and padding around the markup.
          (m (interpret-markup layout props arg)))
     (circle-stencil m th pad)))
 
-(define-builtin-markup-command (with-url layout props url arg)
+(define-markup-command (with-url layout props url arg)
   (string? markup?)
-  graphic
-  ()
+  #:category graphic
   "
 @cindex inserting URL links into text
 
@@ -151,10 +246,9 @@ the PDF backend.
 
     (ly:stencil-add (ly:make-stencil url-expr xextent yextent) stil)))
 
-(define-builtin-markup-command (beam layout props width slope thickness)
+(define-markup-command (beam layout props width slope thickness)
   (number? number? number?)
-  graphic
-  ()
+  #:category graphic
   "
 @cindex drawing beams within text
 
@@ -169,7 +263,7 @@ Create a beam with the specified parameters.
         (half (/ thickness 2)))
 
     (ly:make-stencil
-     `(polygon ',(list 
+     `(polygon ',(list
                  0 (/ thickness -2)
                    width (+ (* width slope)  (/ thickness -2))
                    width (+ (* width slope)  (/ thickness 2))
@@ -180,15 +274,15 @@ Create a beam with the specified parameters.
      (cons (+ (- half) (car yext))
           (+ half (cdr yext))))))
 
-(define-builtin-markup-command (underline layout props arg)
+(define-markup-command (underline layout props arg)
   (markup?)
-  font
-  ((thickness 1))
+  #:category font
+  #:properties ((thickness 1))
   "
 @cindex underlining text
 
 Underline @var{arg}.  Looks at @code{thickness} to determine line
-thickness and y offset.
+thickness and y-offset.
 
 @lilypond[verbatim,quote]
 \\markup {
@@ -206,18 +300,15 @@ thickness and y offset.
          (x1 (car (ly:stencil-extent markup X)))
          (x2 (cdr (ly:stencil-extent markup X)))
          (y (* thick -2))
-         (line (ly:make-stencil
-                `(draw-line ,thick ,x1 ,y ,x2 ,y)
-                (cons (min x1 0) (max x2 0))
-                (cons thick thick))))
+         (line (make-line-stencil thick x1 y x2 y)))
     (ly:stencil-add markup line)))
 
-(define-builtin-markup-command (box layout props arg)
+(define-markup-command (box layout props arg)
   (markup?)
-  font
-  ((thickness 1)
-   (font-size 0)
-   (box-padding 0.2))
+  #:category font
+  #:properties ((thickness 1)
+               (font-size 0)
+               (box-padding 0.2))
   "
 @cindex enclosing text within a box
 
@@ -238,10 +329,9 @@ thickness and padding around the markup.
          (m (interpret-markup layout props arg)))
     (box-stencil m th pad)))
 
-(define-builtin-markup-command (filled-box layout props xext yext blot)
+(define-markup-command (filled-box layout props xext yext blot)
   (number-pair? number-pair? number?)
-  graphic
-  ()
+  #:category graphic
   "
 @cindex drawing solid boxes within text
 @cindex drawing boxes with rounded corners
@@ -253,7 +343,7 @@ Draw a box with rounded corners of dimensions @var{xext} and
 @end verbatim
 creates a box extending horizontally from -0.3 to 1.8 and
 vertically from -0.3 up to 1.8, with corners formed from a
-circle of diameter@tie{}0 (i.e. sharp corners).
+circle of diameter@tie{}0 (i.e., sharp corners).
 
 @lilypond[verbatim,quote]
 \\markup {
@@ -267,28 +357,28 @@ circle of diameter@tie{}0 (i.e. sharp corners).
   (ly:round-filled-box
    xext yext blot))
 
-(define-builtin-markup-command (rounded-box layout props arg)
+(define-markup-command (rounded-box layout props arg)
   (markup?)
-  graphic
-  ((thickness 1)
-   (corner-radius 1)
-   (font-size 0)
-   (box-padding 0.5))
-  "@cindex enclosing text in a bow with rounded corners
+  #:category graphic
+  #:properties ((thickness 1)
+               (corner-radius 1)
+               (font-size 0)
+               (box-padding 0.5))
+  "@cindex enclosing text in a box with rounded corners
    @cindex drawing boxes with rounded corners around text
 Draw a box with rounded corners around @var{arg}.  Looks at @code{thickness},
 @code{box-padding} and @code{font-size} properties to determine line
 thickness and padding around the markup; the @code{corner-radius} property
-makes possible to define another shape for the corners (default is 1).
+makes it possible to define another shape for the corners (default is 1).
 
-@lilypond[quote,verbatim,fragment,relative=2]
+@lilypond[quote,verbatim,relative=2]
 c4^\\markup {
   \\rounded-box {
     Overtura
   }
 }
 c,8. c16 c4 r
-@end lilypond" 
+@end lilypond"
   (let ((th (* (ly:output-def-lookup layout 'line-thickness)
                thickness))
         (pad (* (magstep font-size) box-padding))
@@ -296,10 +386,9 @@ c,8. c16 c4 r
     (ly:stencil-add (rounded-box-stencil m th pad corner-radius)
                     m)))
 
-(define-builtin-markup-command (rotate layout props ang arg)
+(define-markup-command (rotate layout props ang arg)
   (number? markup?)
-  align
-  ()
+  #:category align
   "
 @cindex rotating text
 
@@ -318,10 +407,9 @@ Rotate object with @var{ang} degrees around its center.
   (let* ((stil (interpret-markup layout props arg)))
     (ly:stencil-rotate stil ang 0 0)))
 
-(define-builtin-markup-command (whiteout layout props arg)
+(define-markup-command (whiteout layout props arg)
   (markup?)
-  other
-  ()
+  #:category other
   "
 @cindex adding a white background to text
 
@@ -336,15 +424,28 @@ Provide a white background for @var{arg}.
 @end lilypond"
   (stencil-whiteout (interpret-markup layout props arg)))
 
-(define-builtin-markup-command (pad-markup layout props padding arg)
+(define-markup-command (pad-markup layout props amount arg)
   (number? markup?)
-  align
-  ()
+  #:category align
   "
 @cindex padding text
 @cindex putting space around text
 
-Add space around a markup object."
+Add space around a markup object.
+
+@lilypond[verbatim,quote]
+\\markup {
+  \\box {
+    default
+  }
+  \\hspace #2
+  \\box {
+    \\pad-markup #1 {
+      padded
+    }
+  }
+}
+@end lilypond"
   (let*
       ((stil (interpret-markup layout props arg))
        (xext (ly:stencil-extent stil X))
@@ -352,17 +453,16 @@ Add space around a markup object."
 
     (ly:make-stencil
      (ly:stencil-expr stil)
-     (interval-widen xext padding)
-     (interval-widen yext padding))))
+     (interval-widen xext amount)
+     (interval-widen yext amount))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; space
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(define-builtin-markup-command (strut layout props)
-  ()
-  other
+(define-markup-command (strut layout props)
   ()
+  #:category other
   "
 @cindex creating vertical spaces in text
 
@@ -374,22 +474,13 @@ Create a box of the same height as the space in the current font."
                     )))
 
 ;; todo: fix negative space
-(define-builtin-markup-command (hspace layout props amount)
+(define-markup-command (hspace layout props amount)
   (number?)
-  align
-  ()
+  #:category align
   "
 @cindex creating horizontal spaces in text
 
-This produces an invisible object taking horizontal space.  For example,
-
-@example 
-\\markup @{ A \\hspace #2.0 B @}
-@end example
-
-@noindent
-puts extra space between A and@tie{}B, on top of the space that is
-normally inserted before elements on a line.
+Create an invisible object taking up horizontal space @var{amount}.
 
 @lilypond[verbatim,quote]
 \\markup {
@@ -401,27 +492,51 @@ normally inserted before elements on a line.
 }
 @end lilypond"
   (if (> amount 0)
-      (ly:make-stencil "" (cons 0 amount) '(-1 . 1))
-      (ly:make-stencil "" (cons amount amount) '(-1 . 1))))
+      (ly:make-stencil "" (cons 0 amount) '(0 . 0))
+      (ly:make-stencil "" (cons amount amount) '(0 . 0))))
+
+;; todo: fix negative space
+(define-markup-command (vspace layout props amount)
+ (number?)
+ #:category align
+ "
+@cindex creating vertical spaces in text
+
+Create an invisible object taking up vertical space
+of @var{amount} multiplied by 3.
+
+@lilypond[verbatim,quote]
+\\markup {
+    \\center-column {
+    one
+    \\vspace #2
+    two
+    \\vspace #5
+    three
+  }
+}
+@end lilypond"
+  (let ((amount (* amount 3.0)))
+    (if (> amount 0)
+        (ly:make-stencil "" (cons -1 1) (cons 0 amount))
+        (ly:make-stencil "" (cons -1 1) (cons amount amount)))))
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; importing graphics.
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(define-builtin-markup-command (stencil layout props stil)
+(define-markup-command (stencil layout props stil)
   (ly:stencil?)
-  other
-  ()
+  #:category other
   "
 @cindex importing stencils into text
 
 Use a stencil as markup.
 
-@c FIXME works in .ly file, produces empty stencil in docs
 @lilypond[verbatim,quote]
 \\markup {
-  \\stencil #(dimension-arrows '(15 . 0))
+  \\stencil #(make-circle-stencil 2 0 #t)
 }
 @end lilypond"
   stil)
@@ -433,18 +548,17 @@ Use a stencil as markup.
   "Extract the bbox from STRING, or return #f if not present."
   (let*
       ((match (regexp-exec bbox-regexp string)))
-    
+
     (if match
        (map (lambda (x)
               (string->number (match:substring match x)))
             (cdr (iota 5)))
-            
+
        #f)))
 
-(define-builtin-markup-command (epsfile layout props axis size file-name)
+(define-markup-command (epsfile layout props axis size file-name)
   (number? number? string?)
-  graphic
-  ()
+  #:category graphic
   "
 @cindex inlining an Encapsulated PostScript image
 
@@ -464,66 +578,32 @@ Inline an EPS image.  The image is scaled along @var{axis} to
       (eps-file->stencil axis size file-name)
       ))
 
-(define-builtin-markup-command (postscript layout props str)
+(define-markup-command (postscript layout props str)
   (string?)
-  graphic
-  ()
+  #:category graphic
   "
 @cindex inserting PostScript directly into text
-
 This inserts @var{str} directly into the output as a PostScript
-command string.  Due to technicalities of the output backends,
-different scales should be used for the @TeX{} and PostScript backend,
-selected with @code{-f}. 
-
-For the @TeX{} backend, the following string prints a rotated text
-
-@example
-0 0 moveto /ecrm10 findfont 
-1.75 scalefont setfont 90 rotate (hello) show
-@end example
-
-@noindent
-The magical constant 1.75 scales from LilyPond units (staff spaces) to
-@TeX{} dimensions.
-
-For the postscript backend, use the following
-
-@example
-gsave /ecrm10 findfont 
- 10.0 output-scale div 
- scalefont setfont 90 rotate (hello) show grestore 
-@end example
+command string.
 
 @lilypond[verbatim,quote]
-eyeglassesps = #\"
+ringsps = #\"
   0.15 setlinewidth
-  -0.9 0 translate
-  1.1 1.1 scale
-  1.2 0.7 moveto
-  0.7 0.7 0.5 0 361 arc
+  0.9 0.6 moveto
+  0.4 0.6 0.5 0 361 arc
   stroke
-  2.20 0.70 0.50 0 361 arc
+  1.0 0.6 0.5 0 361 arc
   stroke
-  1.45 0.85 0.30 0 180 arc
-  stroke
-  0.20 0.70 moveto
-  0.80 2.00 lineto
-  0.92 2.26 1.30 2.40 1.15 1.70 curveto
-  stroke
-  2.70 0.70 moveto
-  3.30 2.00 lineto
-  3.42 2.26 3.80 2.40 3.65 1.70 curveto
-  stroke\"
+  \"
 
-eyeglasses = \\markup {
-  \\with-dimensions #'(0 . 4.4) #'(0 . 2.5)
-  \\postscript #eyeglassesps
+rings = \\markup {
+  \\with-dimensions #'(-0.2 . 1.6) #'(0 . 1.2)
+  \\postscript #ringsps
 }
 
 \\relative c'' {
-  c2^\\eyeglasses
-  a2_\\eyeglasses
+  c2^\\rings
+  a2_\\rings
 }
 @end lilypond"
   ;; FIXME
@@ -538,10 +618,10 @@ grestore
                 str))
    '(0 . 0) '(0 . 0)))
 
-(define-builtin-markup-command (score layout props score)
+(define-markup-command (score layout props score)
   (ly:score?)
-  music
-  ()
+  #:category music
+  #:properties ((baseline-skip))
   "
 @cindex inserting music into text
 
@@ -586,19 +666,20 @@ Inline an image of music.
   }
 }
 @end lilypond"
-  (let* ((output (ly:score-embedded-format score layout)))
+  (let ((output (ly:score-embedded-format score layout)))
 
     (if (ly:music-output? output)
-       (paper-system-stencil
-        (vector-ref (ly:paper-score-paper-systems output) 0))
+       (stack-stencils Y DOWN baseline-skip
+                       (map paper-system-stencil
+                            (vector->list
+                             (ly:paper-score-paper-systems output))))
        (begin
          (ly:warning (_"no systems found in \\score markup, does it have a \\layout block?"))
          empty-stencil))))
 
-(define-builtin-markup-command (null layout props)
-  ()
-  other
+(define-markup-command (null layout props)
   ()
+  #:category other
   "
 @cindex creating empty text objects
 
@@ -615,10 +696,9 @@ An empty markup with extents of a single point.
 ;; basic formatting.
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(define-builtin-markup-command (simple layout props str)
+(define-markup-command (simple layout props str)
   (string?)
-  font
-  ()
+  #:category font
   "
 @cindex simple text strings
 
@@ -637,10 +717,9 @@ the use of @code{\\simple} is unnecessary.
 @end lilypond"
   (interpret-markup layout props str))
 
-(define-builtin-markup-command (tied-lyric layout props str)
+(define-markup-command (tied-lyric layout props str)
   (string?)
-  music
-  ()
+  #:category music
   "
 @cindex simple text strings with tie characters
 
@@ -659,7 +738,7 @@ Like simple-markup, but use tie characters for @q{~} tilde symbols.
           (join-stencil (interpret-markup layout props tie-str))
           )
 
-       (interpret-markup layout 
+       (interpret-markup layout
                          (prepend-alist-chain
                           'word-space
                           (/ (interval-length (ly:stencil-extent join-stencil X)) -3.5)
@@ -682,10 +761,10 @@ Like simple-markup, but use tie characters for @q{~} tilde symbols.
        Return a list of paddings."
   (cond
    ((null? text-widths) '())
-   
+
    ;; special case first padding
    ((= (length text-widths) word-count)
-    (cons 
+    (cons
      (- (- (/ line-width (1- word-count)) (car text-widths))
        (/ (car (cdr text-widths)) 2))
      (get-fill-space word-count line-width (cdr text-widths))))
@@ -694,17 +773,17 @@ Like simple-markup, but use tie characters for @q{~} tilde symbols.
     (list (- (/ line-width (1- word-count))
             (+ (/ (car text-widths) 2) (car (cdr text-widths)))) 0))
    (else
-    (cons 
+    (cons
      (- (/ line-width (1- word-count))
        (/ (+ (car text-widths) (car (cdr text-widths))) 2))
      (get-fill-space word-count line-width (cdr text-widths))))))
 
-(define-builtin-markup-command (fill-line layout props markups)
+(define-markup-command (fill-line layout props args)
   (markup-list?)
-  align
-  ((text-direction RIGHT)
-   (word-space 1)
-   (line-width #f))
+  #:category align
+  #:properties ((text-direction RIGHT)
+               (word-space 1)
+               (line-width #f))
   "Put @var{markups} in a horizontal line of width @var{line-width}.
 The markups are spaced or flushed to fill the entire line.
 If there are no arguments, return an empty stencil.
@@ -726,7 +805,7 @@ If there are no arguments, return an empty stencil.
   }
 }
 @end lilypond"
-  (let* ((orig-stencils (interpret-markup-list layout props markups))
+  (let* ((orig-stencils (interpret-markup-list layout props args))
         (stencils
          (map (lambda (stc)
                 (if (ly:stencil-empty? stc)
@@ -740,18 +819,17 @@ If there are no arguments, return an empty stencil.
               stencils))
         (text-width (apply + text-widths))
         (word-count (length stencils))
-        (prop-line-width (chain-assoc-get 'line-width props #f))
         (line-width (or line-width (ly:output-def-lookup layout 'line-width)))
         (fill-space
                (cond
-                       ((= word-count 1) 
+                       ((= word-count 1)
                                (list
                                        (/ (- line-width text-width) 2)
                                        (/ (- line-width text-width) 2)))
                        ((= word-count 2)
                                (list
                                        (- line-width text-width)))
-                       (else 
+                       (else
                                (get-fill-space word-count line-width text-widths))))
         (fill-space-normal
          (map (lambda (x)
@@ -759,7 +837,7 @@ If there are no arguments, return an empty stencil.
                     word-space
                     x))
               fill-space))
-                                       
+
         (line-stencils (if (= word-count 1)
                            (list
                             point-stencil
@@ -772,21 +850,24 @@ If there are no arguments, return an empty stencil.
 
     (if (null? (remove ly:stencil-empty? orig-stencils))
        empty-stencil
-       (stack-stencils-padding-list X
-                                    RIGHT fill-space-normal line-stencils))))
-       
-(define-builtin-markup-command (line layout props args)
+       (ly:stencil-translate-axis
+         (stack-stencils-padding-list X
+                                      RIGHT fill-space-normal line-stencils)
+         (- (car (ly:stencil-extent (car stencils) X)))
+         X))))
+
+(define-markup-command (line layout props args)
   (markup-list?)
-  align
-  ((word-space)
-   (text-direction RIGHT))
+  #:category align
+  #:properties ((word-space)
+               (text-direction RIGHT))
   "Put @var{args} in a horizontal line.  The property @code{word-space}
-determines the space between each markup in @var{args}.
+determines the space between markups in @var{args}.
 
 @lilypond[verbatim,quote]
 \\markup {
   \\line {
-    A simple line of text
+    one two three
   }
 }
 @end lilypond"
@@ -797,28 +878,24 @@ determines the space between each markup in @var{args}.
      word-space
      (remove ly:stencil-empty? stencils))))
 
-(define-builtin-markup-command (concat layout props args)
+(define-markup-command (concat layout props args)
   (markup-list?)
-  align
-  ()
+  #:category align
   "
 @cindex concatenating text
 @cindex ligatures in text
 
-Concatenate @var{args} in a horizontal line, without spaces inbetween.
+Concatenate @var{args} in a horizontal line, without spaces in between.
 Strings and simple markups are concatenated on the input level, allowing
 ligatures.  For example, @code{\\concat @{ \"f\" \\simple #\"i\" @}} is
 equivalent to @code{\"fi\"}.
 
 @lilypond[verbatim,quote]
 \\markup {
-  \\bold {
-    au
-    \\concat {
-      Mouv
-      \\super
-      t
-    }
+  \\concat {
+    one
+    two
+    three
   }
 }
 @end lilypond"
@@ -843,7 +920,7 @@ equivalent to @code{\"fi\"}.
 
 (define (wordwrap-stencils stencils
                           justify base-space line-width text-dir)
-  "Perform simple wordwrap, return stencil of each line."  
+  "Perform simple wordwrap, return stencil of each line."
   (define space (if justify
                     ;; justify only stretches lines.
                    (* 0.7 base-space)
@@ -873,7 +950,7 @@ equivalent to @code{\"fi\"}.
                                         line-stencils))))
           (line-word-space (cond ((not justify) space)
                                   ;; don't stretch last line of paragraph.
-                                  ;; hmmm . bug - will overstretch the last line in some case. 
+                                  ;; hmmm . bug - will overstretch the last line in some case.
                                   ((null? (cdr line-break))
                                    base-space)
                                   ((null? line-stencils) 0.0)
@@ -895,11 +972,11 @@ equivalent to @code{\"fi\"}.
                        X)))
             (reverse (cons line lines)))))))
 
-(define-builtin-markup-list-command (wordwrap-internal layout props justify args)
+(define-markup-list-command (wordwrap-internal layout props justify args)
   (boolean? markup-list?)
-  ((line-width #f)
-   (word-space)
-   (text-direction RIGHT))
+  #:properties ((line-width #f)
+               (word-space)
+               (text-direction RIGHT))
   "Internal markup list command used to define @code{\\justify} and @code{\\wordwrap}."
   (wordwrap-stencils (remove ly:stencil-empty?
                              (interpret-markup-list layout props args))
@@ -909,15 +986,15 @@ equivalent to @code{\"fi\"}.
                          (ly:output-def-lookup layout 'line-width))
                      text-direction))
 
-(define-builtin-markup-command (justify layout props args)
+(define-markup-command (justify layout props args)
   (markup-list?)
-  align
-  ((baseline-skip)
-   wordwrap-internal-markup-list)
+  #:category align
+  #:properties ((baseline-skip)
+               wordwrap-internal-markup-list)
   "
 @cindex justifying text
 
-Like wordwrap, but with lines stretched to justify the margins.
+Like @code{\\wordwrap}, but with lines stretched to justify the margins.
 Use @code{\\override #'(line-width . @var{X})} to set the line width;
 @var{X}@tie{}is the number of staff spaces.
 
@@ -934,11 +1011,11 @@ Use @code{\\override #'(line-width . @var{X})} to set the line width;
   (stack-lines DOWN 0.0 baseline-skip
                (wordwrap-internal-markup-list layout props #t args)))
 
-(define-builtin-markup-command (wordwrap layout props args)
+(define-markup-command (wordwrap layout props args)
   (markup-list?)
-  align
-  ((baseline-skip)
-   wordwrap-internal-markup-list)
+  #:category align
+  #:properties ((baseline-skip)
+               wordwrap-internal-markup-list)
   "Simple wordwrap.  Use @code{\\override #'(line-width . @var{X})} to set
 the line width, where @var{X} is the number of staff spaces.
 
@@ -955,11 +1032,11 @@ the line width, where @var{X} is the number of staff spaces.
   (stack-lines DOWN 0.0 baseline-skip
               (wordwrap-internal-markup-list layout props #f args)))
 
-(define-builtin-markup-list-command (wordwrap-string-internal layout props justify arg)
+(define-markup-list-command (wordwrap-string-internal layout props justify arg)
   (boolean? string?)
-  ((line-width)
-   (word-space)
-   (text-direction RIGHT))
+  #:properties ((line-width)
+               (word-space)
+               (text-direction RIGHT))
   "Internal markup list command used to define @code{\\justify-string} and
 @code{\\wordwrap-string}."
   (let* ((para-strings (regexp-split
@@ -982,71 +1059,70 @@ the line width, where @var{X} is the number of staff spaces.
                           list-para-words)))
     (apply append para-lines)))
 
-(define-builtin-markup-command (wordwrap-string layout props arg)
+(define-markup-command (wordwrap-string layout props arg)
   (string?)
-  align
-  ((baseline-skip)
-   wordwrap-string-internal-markup-list)
+  #:category align
+  #:properties ((baseline-skip)
+               wordwrap-string-internal-markup-list)
   "Wordwrap a string.  Paragraphs may be separated with double newlines.
-  
+
 @lilypond[verbatim,quote]
 \\markup {
   \\override #'(line-width . 40)
   \\wordwrap-string #\"Lorem ipsum dolor sit amet, consectetur
-    adipisicing elit, sed do eiusmod tempor incididunt ut labore
-    et dolore magna aliqua.
-    
-    
-    Ut enim ad minim veniam, quis nostrud exercitation ullamco
-    laboris nisi ut aliquip ex ea commodo consequat.
-    
-    
-    Excepteur sint occaecat cupidatat non proident, sunt in culpa
-    qui officia deserunt mollit anim id est laborum\"
+      adipisicing elit, sed do eiusmod tempor incididunt ut labore
+      et dolore magna aliqua.
+
+
+      Ut enim ad minim veniam, quis nostrud exercitation ullamco
+      laboris nisi ut aliquip ex ea commodo consequat.
+
+
+      Excepteur sint occaecat cupidatat non proident, sunt in culpa
+      qui officia deserunt mollit anim id est laborum\"
 }
 @end lilypond"
   (stack-lines DOWN 0.0 baseline-skip
                (wordwrap-string-internal-markup-list layout props #f arg)))
 
-(define-builtin-markup-command (justify-string layout props arg)
+(define-markup-command (justify-string layout props arg)
   (string?)
-  align
-  ((baseline-skip)
-   wordwrap-string-internal-markup-list)
+  #:category align
+  #:properties ((baseline-skip)
+               wordwrap-string-internal-markup-list)
   "Justify a string.  Paragraphs may be separated with double newlines
-  
+
 @lilypond[verbatim,quote]
 \\markup {
   \\override #'(line-width . 40)
   \\justify-string #\"Lorem ipsum dolor sit amet, consectetur
-    adipisicing elit, sed do eiusmod tempor incididunt ut labore
-    et dolore magna aliqua.
-    
-    
-    Ut enim ad minim veniam, quis nostrud exercitation ullamco
-    laboris nisi ut aliquip ex ea commodo consequat.
-    
-    
-    Excepteur sint occaecat cupidatat non proident, sunt in culpa
-    qui officia deserunt mollit anim id est laborum\"
+      adipisicing elit, sed do eiusmod tempor incididunt ut labore
+      et dolore magna aliqua.
+
+
+      Ut enim ad minim veniam, quis nostrud exercitation ullamco
+      laboris nisi ut aliquip ex ea commodo consequat.
+
+
+      Excepteur sint occaecat cupidatat non proident, sunt in culpa
+      qui officia deserunt mollit anim id est laborum\"
 }
 @end lilypond"
   (stack-lines DOWN 0.0 baseline-skip
                (wordwrap-string-internal-markup-list layout props #t arg)))
 
-(define-builtin-markup-command (wordwrap-field layout props symbol)
+(define-markup-command (wordwrap-field layout props symbol)
   (symbol?)
-  align
-  ()
+  #:category align
   "Wordwrap the data which has been assigned to @var{symbol}.
-  
+
 @lilypond[verbatim,quote]
 \\header {
   title = \"My title\"
-  descr = \"Lorem ipsum dolor sit amet, consectetur adipisicing elit,
-  sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
-  Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
-  nisi ut aliquip ex ea commodo consequat.\"
+  myText = \"Lorem ipsum dolor sit amet, consectetur adipisicing
+    elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+    aliqua.  Ut enim ad minim veniam, quis nostrud exercitation ullamco
+    laboris nisi ut aliquip ex ea commodo consequat.\"
 }
 
 \\paper {
@@ -1054,7 +1130,7 @@ the line width, where @var{X} is the number of staff spaces.
     \\column {
       \\fill-line { \\fromproperty #'header:title }
       \\null
-      \\wordwrap-field #'header:descr
+      \\wordwrap-field #'header:myText
     }
   }
 }
@@ -1068,19 +1144,18 @@ the line width, where @var{X} is the number of staff spaces.
         (wordwrap-string-markup layout props m)
         empty-stencil)))
 
-(define-builtin-markup-command (justify-field layout props symbol)
+(define-markup-command (justify-field layout props symbol)
   (symbol?)
-  align
-  ()
+  #:category align
   "Justify the data which has been assigned to @var{symbol}.
-  
+
 @lilypond[verbatim,quote]
 \\header {
   title = \"My title\"
-  descr = \"Lorem ipsum dolor sit amet, consectetur adipisicing elit,
-  sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
-  Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
-  nisi ut aliquip ex ea commodo consequat.\"
+  myText = \"Lorem ipsum dolor sit amet, consectetur adipisicing
+    elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+    aliqua.  Ut enim ad minim veniam, quis nostrud exercitation ullamco
+    laboris nisi ut aliquip ex ea commodo consequat.\"
 }
 
 \\paper {
@@ -1088,7 +1163,7 @@ the line width, where @var{X} is the number of staff spaces.
     \\column {
       \\fill-line { \\fromproperty #'header:title }
       \\null
-      \\justify-field #'header:descr
+      \\justify-field #'header:myText
     }
   }
 }
@@ -1102,10 +1177,9 @@ the line width, where @var{X} is the number of staff spaces.
         (justify-string-markup layout props m)
         empty-stencil)))
 
-(define-builtin-markup-command (combine layout props m1 m2)
+(define-markup-command (combine layout props arg1 arg2)
   (markup? markup?)
-  align
-  ()
+  #:category align
   "
 @cindex merging text
 
@@ -1127,23 +1201,23 @@ curly braces as an argument; the follow example will not compile:
     \\arrow-head #Y #DOWN ##f
 }
 @end lilypond"
-  (let* ((s1 (interpret-markup layout props m1))
-        (s2 (interpret-markup layout props m2)))
+  (let* ((s1 (interpret-markup layout props arg1))
+        (s2 (interpret-markup layout props arg2)))
     (ly:stencil-add s1 s2)))
 
 ;;
 ;; TODO: should extract baseline-skip from each argument somehow..
-;; 
-(define-builtin-markup-command (column layout props args)
+;;
+(define-markup-command (column layout props args)
   (markup-list?)
-  align
-  ((baseline-skip))
+  #:category align
+  #:properties ((baseline-skip))
   "
 @cindex stacking text in a column
 
 Stack the markups in @var{args} vertically.  The property
-@code{baseline-skip} determines the space between each
-markup in @var{args}.
+@code{baseline-skip} determines the space between markups
+in @var{args}.
 
 @lilypond[verbatim,quote]
 \\markup {
@@ -1158,27 +1232,34 @@ markup in @var{args}.
     (stack-lines -1 0.0 baseline-skip
                  (remove ly:stencil-empty? arg-stencils))))
 
-(define-builtin-markup-command (dir-column layout props args)
+(define-markup-command (dir-column layout props args)
   (markup-list?)
-  align
-  ((direction)
-   (baseline-skip))
+  #:category align
+  #:properties ((direction)
+               (baseline-skip))
   "
 @cindex changing direction of text columns
 
-Make a column of args, going up or down, depending on the setting
-of the @code{#'direction} layout property.
+Make a column of @var{args}, going up or down, depending on the
+setting of the @code{direction} layout property.
 
 @lilypond[verbatim,quote]
 \\markup {
-  \\override #'(direction . 1) {
+  \\override #`(direction . ,UP) {
     \\dir-column {
       going up
     }
   }
+  \\hspace #1
   \\dir-column {
     going down
   }
+  \\hspace #1
+  \\override #'(direction . 1) {
+    \\dir-column {
+      going up
+    }
+  }
 }
 @end lilypond"
   (stack-lines (if (number? direction) direction -1)
@@ -1186,10 +1267,16 @@ of the @code{#'direction} layout property.
                baseline-skip
                (interpret-markup-list layout props args)))
 
-(define-builtin-markup-command (center-align layout props args)
+(define (general-column align-dir baseline mols)
+  "Stack @var{mols} vertically, aligned to  @var{align-dir} horizontally."
+
+  (let* ((aligned-mols (map (lambda (x) (ly:stencil-aligned-to x X align-dir)) mols)))
+    (stack-lines -1 0.0 baseline aligned-mols)))
+
+(define-markup-command (center-column layout props args)
   (markup-list?)
-  align
-  ((baseline-skip))
+  #:category align
+  #:properties ((baseline-skip))
   "
 @cindex centering a column of text
 
@@ -1197,21 +1284,58 @@ Put @code{args} in a centered column.
 
 @lilypond[verbatim,quote]
 \\markup {
-  \\center-align {
+  \\center-column {
+    one
+    two
+    three
+  }
+}
+@end lilypond"
+  (general-column CENTER baseline-skip (interpret-markup-list layout props args)))
+
+(define-markup-command (left-column layout props args)
+  (markup-list?)
+  #:category align
+  #:properties ((baseline-skip))
+ "
+@cindex text columns, left-aligned
+
+Put @code{args} in a left-aligned column.
+
+@lilypond[verbatim,quote]
+\\markup {
+  \\left-column {
     one
     two
     three
   }
 }
 @end lilypond"
-  (let* ((mols (interpret-markup-list layout props args))
-         (cmols (map (lambda (x) (ly:stencil-aligned-to x X CENTER)) mols)))
-    (stack-lines -1 0.0 baseline-skip cmols)))
+  (general-column LEFT baseline-skip (interpret-markup-list layout props args)))
 
-(define-builtin-markup-command (vcenter layout props arg)
+(define-markup-command (right-column layout props args)
+  (markup-list?)
+  #:category align
+  #:properties ((baseline-skip))
+ "
+@cindex text columns, right-aligned
+
+Put @code{args} in a right-aligned column.
+
+@lilypond[verbatim,quote]
+\\markup {
+  \\right-column {
+    one
+    two
+    three
+  }
+}
+@end lilypond"
+  (general-column RIGHT baseline-skip (interpret-markup-list layout props args)))
+
+(define-markup-command (vcenter layout props arg)
   (markup?)
-  align
-  ()
+  #:category align
   "
 @cindex vertically centering text
 
@@ -1219,19 +1343,18 @@ Align @code{arg} to its Y@tie{}center.
 
 @lilypond[verbatim,quote]
 \\markup {
-  \\arrow-head #X #RIGHT ##f
+  one
   \\vcenter
-  Centered
-  \\arrow-head #X #LEFT ##f
+  two
+  three
 }
 @end lilypond"
   (let* ((mol (interpret-markup layout props arg)))
     (ly:stencil-aligned-to mol Y CENTER)))
 
-(define-builtin-markup-command (hcenter layout props arg)
+(define-markup-command (center-align layout props arg)
   (markup?)
-  align
-  ()
+  #:category align
   "
 @cindex horizontally centering text
 
@@ -1240,19 +1363,19 @@ Align @code{arg} to its X@tie{}center.
 @lilypond[verbatim,quote]
 \\markup {
   \\column {
-    â†“
-    \\hcenter
-    centered
+    one
+    \\center-align
+    two
+    three
   }
 }
 @end lilypond"
   (let* ((mol (interpret-markup layout props arg)))
     (ly:stencil-aligned-to mol X CENTER)))
 
-(define-builtin-markup-command (right-align layout props arg)
+(define-markup-command (right-align layout props arg)
   (markup?)
-  align
-  ()
+  #:category align
   "
 @cindex right aligning text
 
@@ -1261,19 +1384,19 @@ Align @var{arg} on its right edge.
 @lilypond[verbatim,quote]
 \\markup {
   \\column {
-    â†“
+    one
     \\right-align
-    right-aligned
+    two
+    three
   }
 }
 @end lilypond"
   (let* ((m (interpret-markup layout props arg)))
     (ly:stencil-aligned-to m X RIGHT)))
 
-(define-builtin-markup-command (left-align layout props arg)
+(define-markup-command (left-align layout props arg)
   (markup?)
-  align
-  ()
+  #:category align
   "
 @cindex left aligning text
 
@@ -1282,19 +1405,19 @@ Align @var{arg} on its left edge.
 @lilypond[verbatim,quote]
 \\markup {
   \\column {
-    â†“
+    one
     \\left-align
-    left-aligned
+    two
+    three
   }
 }
 @end lilypond"
   (let* ((m (interpret-markup layout props arg)))
     (ly:stencil-aligned-to m X LEFT)))
 
-(define-builtin-markup-command (general-align layout props axis dir arg)
+(define-markup-command (general-align layout props axis dir arg)
   (integer? number? markup?)
-  align
-  ()
+  #:category align
   "
 @cindex controlling general text alignment
 
@@ -1303,26 +1426,28 @@ Align @var{arg} in @var{axis} direction to the @var{dir} side.
 @lilypond[verbatim,quote]
 \\markup {
   \\column {
-    â†“
+    one
     \\general-align #X #LEFT
-    \\line { X, Left }
-    â†“
+    two
+    three
+    \\null
+    one
     \\general-align #X #CENTER
-    \\line { X, Center }
+    two
+    three
     \\null
     \\line {
-      \\arrow-head #X #RIGHT ##f
-      \\general-align #Y #DOWN
-      \\line { Y, Down }
-      \\arrow-head #X #LEFT ##f
+      one
+      \\general-align #Y #UP
+      two
+      three
     }
+    \\null
     \\line {
-      \\arrow-head #X #RIGHT ##f
+      one
       \\general-align #Y #3.2
-      \\line {
-        \\line { Y, Arbitrary alignment }
-      }
-      \\arrow-head #X #LEFT ##f
+      two
+      three
     }
   }
 }
@@ -1330,10 +1455,9 @@ Align @var{arg} in @var{axis} direction to the @var{dir} side.
   (let* ((m (interpret-markup layout props arg)))
     (ly:stencil-aligned-to m axis dir)))
 
-(define-builtin-markup-command (halign layout props dir arg)
+(define-markup-command (halign layout props dir arg)
   (number? markup?)
-  align
-  ()
+  #:category align
   "
 @cindex setting horizontal text alignment
 
@@ -1344,42 +1468,59 @@ alignment accordingly.
 @lilypond[verbatim,quote]
 \\markup {
   \\column {
-    â†“
+    one
     \\halign #LEFT
-    Left
-    â†“
+    two
+    three
+    \\null
+    one
     \\halign #CENTER
-    Center
-    â†“
+    two
+    three
+    \\null
+    one
     \\halign #RIGHT
-    Right
-    â†“
-    \\halign #1.2
-    \\line {
-      Arbitrary alignment
-    }
+    two
+    three
+    \\null
+    one
+    \\halign #-5
+    two
+    three
   }
 }
 @end lilypond"
   (let* ((m (interpret-markup layout props arg)))
     (ly:stencil-aligned-to m X dir)))
 
-(define-builtin-markup-command (with-dimensions layout props x y arg)
+(define-markup-command (with-dimensions layout props x y arg)
   (number-pair? number-pair? markup?)
-  other
-  ()
+  #:category other
   "
 @cindex setting extent of text objects
 
-Set the dimensions of @var{arg} to @var{x} and@tie{}@var{y}."  
+Set the dimensions of @var{arg} to @var{x} and@tie{}@var{y}."
   (let* ((m (interpret-markup layout props arg)))
     (ly:make-stencil (ly:stencil-expr m) x y)))
 
-(define-builtin-markup-command (pad-around layout props amount arg)
+(define-markup-command (pad-around layout props amount arg)
   (number? markup?)
-  align
-  ()
-  "Add padding @var{amount} all around @var{arg}."  
+  #:category align
+  "Add padding @var{amount} all around @var{arg}.
+
+@lilypond[verbatim,quote]
+\\markup {
+  \\box {
+    default
+  }
+  \\hspace #2
+  \\box {
+    \\pad-around #0.5 {
+      padded
+    }
+  }
+}
+@end lilypond"
   (let* ((m (interpret-markup layout props arg))
          (x (ly:stencil-extent m X))
          (y (ly:stencil-extent m Y)))
@@ -1387,14 +1528,27 @@ Set the dimensions of @var{arg} to @var{x} and@tie{}@var{y}."
                      (interval-widen x amount)
                      (interval-widen y amount))))
 
-(define-builtin-markup-command (pad-x layout props amount arg)
+(define-markup-command (pad-x layout props amount arg)
   (number? markup?)
-  align
-  ()
+  #:category align
   "
 @cindex padding text horizontally
 
-Add padding @var{amount} around @var{arg} in the X@tie{}direction."
+Add padding @var{amount} around @var{arg} in the X@tie{}direction.
+
+@lilypond[verbatim,quote]
+\\markup {
+  \\box {
+    default
+  }
+  \\hspace #4
+  \\box {
+    \\pad-x #2 {
+      padded
+    }
+  }
+}
+@end lilypond"
   (let* ((m (interpret-markup layout props arg))
          (x (ly:stencil-extent m X))
          (y (ly:stencil-extent m Y)))
@@ -1402,21 +1556,19 @@ Add padding @var{amount} around @var{arg} in the X@tie{}direction."
                      (interval-widen x amount)
                      y)))
 
-(define-builtin-markup-command (put-adjacent layout props arg1 axis dir arg2)
-  (markup? integer? ly:dir? markup?)
-  align
-  ()
+(define-markup-command (put-adjacent layout props axis dir arg1 arg2)
+  (integer? ly:dir? markup? markup?)
+  #:category align
   "Put @var{arg2} next to @var{arg1}, without moving @var{arg1}."
   (let ((m1 (interpret-markup layout props arg1))
         (m2 (interpret-markup layout props arg2)))
     (ly:stencil-combine-at-edge m1 axis dir m2 0.0)))
 
-(define-builtin-markup-command (transparent layout props arg)
+(define-markup-command (transparent layout props arg)
   (markup?)
-  other
-  ()
-  "Make the argument transparent.
-  
+  #:category other
+  "Make @var{arg} transparent.
+
 @lilypond[verbatim,quote]
 \\markup {
   \\transparent {
@@ -1429,11 +1581,24 @@ Add padding @var{amount} around @var{arg} in the X@tie{}direction."
          (y (ly:stencil-extent m Y)))
     (ly:make-stencil "" x y)))
 
-(define-builtin-markup-command (pad-to-box layout props x-ext y-ext arg)
+(define-markup-command (pad-to-box layout props x-ext y-ext arg)
   (number-pair? number-pair? markup?)
-  align
-  ()
-  "Make @var{arg} take at least @var{x-ext}, @var{y-ext} space."
+  #:category align
+  "Make @var{arg} take at least @var{x-ext}, @var{y-ext} space.
+
+@lilypond[verbatim,quote]
+\\markup {
+  \\box {
+    default
+  }
+  \\hspace #4
+  \\box {
+    \\pad-to-box #'(0 . 10) #'(0 . 3) {
+      padded
+    }
+  }
+}
+@end lilypond"
   (let* ((m (interpret-markup layout props arg))
          (x (ly:stencil-extent m X))
          (y (ly:stencil-extent m Y)))
@@ -1441,26 +1606,44 @@ Add padding @var{amount} around @var{arg} in the X@tie{}direction."
                      (interval-union x-ext x)
                      (interval-union y-ext y))))
 
-(define-builtin-markup-command (hcenter-in layout props length arg)
+(define-markup-command (hcenter-in layout props length arg)
   (number? markup?)
-  align
-  ()
+  #:category align
   "Center @var{arg} horizontally within a box of extending
-@var{length}/2 to the left and right."
+@var{length}/2 to the left and right.
+
+@lilypond[quote,verbatim]
+\\new StaffGroup <<
+  \\new Staff {
+    \\set Staff.instrumentName = \\markup {
+      \\hcenter-in #12
+      Oboe
+    }
+    c''1
+  }
+  \\new Staff {
+    \\set Staff.instrumentName = \\markup {
+      \\hcenter-in #12
+      Bassoon
+    }
+    \\clef tenor
+    c'1
+  }
+>>
+@end lilypond"
   (interpret-markup layout props
                     (make-pad-to-box-markup
                      (cons (/ length -2) (/ length 2))
                      '(0 . 0)
-                     (make-hcenter-markup arg))))
+                     (make-center-align-markup arg))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; property
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(define-builtin-markup-command (fromproperty layout props symbol)
+(define-markup-command (fromproperty layout props symbol)
   (symbol?)
-  other
-  ()
+  #:category other
   "Read the @var{symbol} from property settings, and produce a stencil
 from the markup contained within.  If @var{symbol} is not defined, it
 returns an empty markup.
@@ -1483,10 +1666,9 @@ returns an empty markup.
         (interpret-markup layout props m)
         empty-stencil)))
 
-(define-builtin-markup-command (on-the-fly layout props procedure arg)
+(define-markup-command (on-the-fly layout props procedure arg)
   (symbol? markup?)
-  other
-  ()
+  #:category other
   "Apply the @var{procedure} markup command to @var{arg}.
 @var{procedure} should take a single argument."
   (let ((anonymous-with-signature (lambda (layout props arg) (procedure layout props arg))))
@@ -1495,20 +1677,16 @@ returns an empty markup.
                          (list markup?))
     (interpret-markup layout props (list anonymous-with-signature arg))))
 
-(define-builtin-markup-command (override layout props new-prop arg)
+(define-markup-command (override layout props new-prop arg)
   (pair? markup?)
-  other
-  ()
+  #:category other
   "
 @cindex overriding properties within text markup
 
-Add the first argument in to the property list.  Properties may be
-any sort of property supported by @rinternals{font-interface} and
-@rinternals{text-interface}, for example
-
-@example
-\\override #'(font-family . married) \"bla\"
-@end example
+Add the argument @var{new-prop} to the property list.  Properties
+may be any property supported by @rinternals{font-interface},
+@rinternals{text-interface} and
+@rinternals{instrument-specific-markup-interface}.
 
 @lilypond[verbatim,quote]
 \\markup {
@@ -1533,11 +1711,10 @@ any sort of property supported by @rinternals{font-interface} and
 ;; files
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(define-builtin-markup-command (verbatim-file layout props name)
+(define-markup-command (verbatim-file layout props name)
   (string?)
-  other
-  ()
-  "Read the contents of a file, and include it verbatim.
+  #:category other
+  "Read the contents of file @var{name}, and include it verbatim.
 
 @lilypond[verbatim,quote]
 \\markup {
@@ -1556,34 +1733,12 @@ any sort of property supported by @rinternals{font-interface} and
 ;; fonts.
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(define-builtin-markup-command (bigger layout props arg)
-  (markup?)
-  font
-  ()
-  "Increase the font size relative to current setting.
-
-@lilypond[verbatim,quote]
-\\markup {
-  \\huge {
-    huge
-    \\hspace #2
-    \\bigger {
-      bigger
-    }
-    \\hspace #2
-    huge
-  }
-}
-@end lilypond"
-  (interpret-markup layout props
-   `(,fontsize-markup 1 ,arg)))
 
-(define-builtin-markup-command (smaller layout props arg)
+(define-markup-command (smaller layout props arg)
   (markup?)
-  font
-  ()
-  "Decrease the font size relative to current setting.
-  
+  #:category font
+  "Decrease the font size relative to the current setting.
+
 @lilypond[verbatim,quote]
 \\markup {
   \\fontsize #3.5 {
@@ -1600,11 +1755,10 @@ any sort of property supported by @rinternals{font-interface} and
   (interpret-markup layout props
    `(,fontsize-markup -1 ,arg)))
 
-(define-builtin-markup-command (larger layout props arg)
+(define-markup-command (larger layout props arg)
   (markup?)
-  font
-  ()
-  "Copy of the @code{\\bigger} command.
+  #:category font
+  "Increase the font size relative to the current setting.
 
 @lilypond[verbatim,quote]
 \\markup {
@@ -1614,13 +1768,14 @@ any sort of property supported by @rinternals{font-interface} and
   larger
 }
 @end lilypond"
-  (interpret-markup layout props (make-bigger-markup arg)))
+  (interpret-markup layout props
+   `(,fontsize-markup 1 ,arg)))
 
-(define-builtin-markup-command (finger layout props arg)
+(define-markup-command (finger layout props arg)
   (markup?)
-  font
-  ()
-  "Set the argument as small numbers.
+  #:category font
+  "Set @var{arg} as small numbers.
+
 @lilypond[verbatim,quote]
 \\markup {
   \\finger {
@@ -1629,15 +1784,15 @@ any sort of property supported by @rinternals{font-interface} and
 }
 @end lilypond"
   (interpret-markup layout
-                    (cons '((font-size . -5) (font-encoding . fetaNumber)) props)
+                    (cons '((font-size . -5) (font-encoding . fetaText)) props)
                     arg))
 
-(define-builtin-markup-command (abs-fontsize layout props size arg)
+(define-markup-command (abs-fontsize layout props size arg)
   (number? markup?)
-  font
-  ()
+  #:category font
   "Use @var{size} as the absolute font size to display @var{arg}.
-Adjust baseline skip and word space accordingly.
+Adjusts @code{baseline-skip} and @code{word-space} accordingly.
+
 @lilypond[verbatim,quote]
 \\markup {
   default text font size
@@ -1659,13 +1814,15 @@ Adjust baseline skip and word space accordingly.
                            props)
                      arg)))
 
-(define-builtin-markup-command (fontsize layout props increment arg)
+(define-markup-command (fontsize layout props increment arg)
   (number? markup?)
-  font
-  ((font-size 0)
-   (word-space 1)
-   (baseline-skip 2))
-  "Add @var{increment} to the font-size.  Adjust baseline skip accordingly.
+  #:category font
+  #:properties ((font-size 0)
+               (word-space 1)
+               (baseline-skip 2))
+  "Add @var{increment} to the font-size.  Adjusts @code{baseline-skip}
+accordingly.
+
 @lilypond[verbatim,quote]
 \\markup {
   default
@@ -1680,10 +1837,9 @@ Adjust baseline skip and word space accordingly.
                   (cons 'font-size (+ font-size increment)))))
     (interpret-markup layout (cons entries props) arg)))
 
-(define-builtin-markup-command (magnify layout props sz arg)
+(define-markup-command (magnify layout props sz arg)
   (number? markup?)
-  font
-  ()
+  #:category font
   "
 @cindex magnifying text
 
@@ -1707,16 +1863,15 @@ Use @code{\\fontsize} otherwise.
 }
 @end lilypond"
   (interpret-markup
-   layout 
+   layout
    (prepend-alist-chain 'font-size (magnification->font-size sz) props)
    arg))
 
-(define-builtin-markup-command (bold layout props arg)
+(define-markup-command (bold layout props arg)
   (markup?)
-  font
-  ()
+  #:category font
   "Switch to bold font-series.
-  
+
 @lilypond[verbatim,quote]
 \\markup {
   default
@@ -1727,12 +1882,11 @@ Use @code{\\fontsize} otherwise.
 @end lilypond"
   (interpret-markup layout (prepend-alist-chain 'font-series 'bold props) arg))
 
-(define-builtin-markup-command (sans layout props arg)
+(define-markup-command (sans layout props arg)
   (markup?)
-  font
-  ()
-  "Switch to the sans serif family.
-  
+  #:category font
+  "Switch to the sans serif font family.
+
 @lilypond[verbatim,quote]
 \\markup {
   default
@@ -1744,13 +1898,12 @@ Use @code{\\fontsize} otherwise.
 @end lilypond"
   (interpret-markup layout (prepend-alist-chain 'font-family 'sans props) arg))
 
-(define-builtin-markup-command (number layout props arg)
+(define-markup-command (number layout props arg)
   (markup?)
-  font
-  ()
+  #:category font
   "Set font family to @code{number}, which yields the font used for
-time signatures and fingerings.  This font only contains numbers and
-some punctuation.  It doesn't have any letters.
+time signatures and fingerings.  This font contains numbers and
+some punctuation; it has no letters.
 
 @lilypond[verbatim,quote]
 \\markup {
@@ -1759,14 +1912,13 @@ some punctuation.  It doesn't have any letters.
   }
 }
 @end lilypond"
-  (interpret-markup layout (prepend-alist-chain 'font-encoding 'fetaNumber props) arg))
+  (interpret-markup layout (prepend-alist-chain 'font-encoding 'fetaText props) arg))
 
-(define-builtin-markup-command (roman layout props arg)
+(define-markup-command (roman layout props arg)
   (markup?)
-  font
-  ()
+  #:category font
   "Set font family to @code{roman}.
-  
+
 @lilypond[verbatim,quote]
 \\markup {
   \\sans \\bold {
@@ -1782,10 +1934,9 @@ some punctuation.  It doesn't have any letters.
 @end lilypond"
   (interpret-markup layout (prepend-alist-chain 'font-family 'roman props) arg))
 
-(define-builtin-markup-command (huge layout props arg)
+(define-markup-command (huge layout props arg)
   (markup?)
-  font
-  ()
+  #:category font
   "Set font size to +2.
 
 @lilypond[verbatim,quote]
@@ -1798,10 +1949,9 @@ some punctuation.  It doesn't have any letters.
 @end lilypond"
   (interpret-markup layout (prepend-alist-chain 'font-size 2 props) arg))
 
-(define-builtin-markup-command (large layout props arg)
+(define-markup-command (large layout props arg)
   (markup?)
-  font
-  ()
+  #:category font
   "Set font size to +1.
 
 @lilypond[verbatim,quote]
@@ -1814,12 +1964,11 @@ some punctuation.  It doesn't have any letters.
 @end lilypond"
   (interpret-markup layout (prepend-alist-chain 'font-size 1 props) arg))
 
-(define-builtin-markup-command (normalsize layout props arg)
+(define-markup-command (normalsize layout props arg)
   (markup?)
-  font
-  ()
+  #:category font
   "Set font size to default.
-  
+
 @lilypond[verbatim,quote]
 \\markup {
   \\teeny {
@@ -1835,12 +1984,11 @@ some punctuation.  It doesn't have any letters.
 @end lilypond"
   (interpret-markup layout (prepend-alist-chain 'font-size 0 props) arg))
 
-(define-builtin-markup-command (small layout props arg)
+(define-markup-command (small layout props arg)
   (markup?)
-  font
-  ()
+  #:category font
   "Set font size to -1.
-  
+
 @lilypond[verbatim,quote]
 \\markup {
   default
@@ -1851,12 +1999,11 @@ some punctuation.  It doesn't have any letters.
 @end lilypond"
   (interpret-markup layout (prepend-alist-chain 'font-size -1 props) arg))
 
-(define-builtin-markup-command (tiny layout props arg)
+(define-markup-command (tiny layout props arg)
   (markup?)
-  font
-  ()
+  #:category font
   "Set font size to -2.
-  
+
 @lilypond[verbatim,quote]
 \\markup {
   default
@@ -1867,12 +2014,11 @@ some punctuation.  It doesn't have any letters.
 @end lilypond"
   (interpret-markup layout (prepend-alist-chain 'font-size -2 props) arg))
 
-(define-builtin-markup-command (teeny layout props arg)
+(define-markup-command (teeny layout props arg)
   (markup?)
-  font
-  ()
+  #:category font
   "Set font size to -3.
-  
+
 @lilypond[verbatim,quote]
 \\markup {
   default
@@ -1883,21 +2029,19 @@ some punctuation.  It doesn't have any letters.
 @end lilypond"
   (interpret-markup layout (prepend-alist-chain 'font-size -3 props) arg))
 
-(define-builtin-markup-command (fontCaps layout props arg)
+(define-markup-command (fontCaps layout props arg)
   (markup?)
-  font
-  ()
+  #:category font
   "Set @code{font-shape} to @code{caps}
-  
+
 Note: @code{\\fontCaps} requires the installation and selection of
 fonts which support the @code{caps} font shape."
   (interpret-markup layout (prepend-alist-chain 'font-shape 'caps props) arg))
 
 ;; Poor man's caps
-(define-builtin-markup-command (smallCaps layout props text)
+(define-markup-command (smallCaps layout props arg)
   (markup?)
-  font
-  ()
+  #:category font
   "Emit @var{arg} as small caps.
 
 Note: @code{\\smallCaps} does not support accented characters.
@@ -1938,14 +2082,13 @@ Note: @code{\\smallCaps} does not support accented characters.
                                            currents current-is-lower)
                                         prev-result)))))))
   (interpret-markup layout props
-    (if (string? text)
-       (make-small-caps (string->list text) (list) #f (list))
-       text)))
+    (if (string? arg)
+       (make-small-caps (string->list arg) (list) #f (list))
+       arg)))
 
-(define-builtin-markup-command (caps layout props arg)
+(define-markup-command (caps layout props arg)
   (markup?)
-  font
-  ()
+  #:category font
   "Copy of the @code{\\smallCaps} command.
 
 @lilypond[verbatim,quote]
@@ -1959,10 +2102,9 @@ Note: @code{\\smallCaps} does not support accented characters.
 @end lilypond"
   (interpret-markup layout props (make-smallCaps-markup arg)))
 
-(define-builtin-markup-command (dynamic layout props arg)
+(define-markup-command (dynamic layout props arg)
   (markup?)
-  font
-  ()
+  #:category font
   "Use the dynamic font.  This font only contains @b{s}, @b{f}, @b{m},
 @b{z}, @b{p}, and @b{r}.  When producing phrases, like
 @q{pi@`{u}@tie{}@b{f}}, the normal words (like @q{pi@`{u}}) should be
@@ -1975,14 +2117,13 @@ done in a different font.  The recommended font for this is bold and italic.
 }
 @end lilypond"
   (interpret-markup
-   layout (prepend-alist-chain 'font-encoding 'fetaDynamic props) arg))
+   layout (prepend-alist-chain 'font-encoding 'fetaText props) arg))
 
-(define-builtin-markup-command (text layout props arg)
+(define-markup-command (text layout props arg)
   (markup?)
-  font
-  ()
+  #:category font
   "Use a text font instead of music symbol or music alphabet font.
-  
+
 @lilypond[verbatim,quote]
 \\markup {
   \\number {
@@ -1999,10 +2140,9 @@ done in a different font.  The recommended font for this is bold and italic.
   (interpret-markup layout (prepend-alist-chain 'font-encoding 'latin1 props)
                    arg))
 
-(define-builtin-markup-command (italic layout props arg)
+(define-markup-command (italic layout props arg)
   (markup?)
-  font
-  ()
+  #:category font
   "Use italic @code{font-shape} for @var{arg}.
 
 @lilypond[verbatim,quote]
@@ -2015,12 +2155,11 @@ done in a different font.  The recommended font for this is bold and italic.
 @end lilypond"
   (interpret-markup layout (prepend-alist-chain 'font-shape 'italic props) arg))
 
-(define-builtin-markup-command (typewriter layout props arg)
+(define-markup-command (typewriter layout props arg)
   (markup?)
-  font
-  ()
+  #:category font
   "Use @code{font-family} typewriter for @var{arg}.
-  
+
 @lilypond[verbatim,quote]
 \\markup {
   default
@@ -2032,11 +2171,11 @@ done in a different font.  The recommended font for this is bold and italic.
   (interpret-markup
    layout (prepend-alist-chain 'font-family 'typewriter props) arg))
 
-(define-builtin-markup-command (upright layout props arg)
+(define-markup-command (upright layout props arg)
   (markup?)
-  font
-  ()
-  "Set font shape to @code{upright}.  This is the opposite of @code{italic}.
+  #:category font
+  "Set @code{font-shape} to @code{upright}.  This is the opposite
+of @code{italic}.
 
 @lilypond[verbatim,quote]
 \\markup {
@@ -2054,11 +2193,10 @@ done in a different font.  The recommended font for this is bold and italic.
   (interpret-markup
    layout (prepend-alist-chain 'font-shape 'upright props) arg))
 
-(define-builtin-markup-command (medium layout props arg)
+(define-markup-command (medium layout props arg)
   (markup?)
-  font
-  ()
-  "Switch to medium font series (in contrast to bold).
+  #:category font
+  "Switch to medium font-series (in contrast to bold).
 
 @lilypond[verbatim,quote]
 \\markup {
@@ -2076,10 +2214,9 @@ done in a different font.  The recommended font for this is bold and italic.
   (interpret-markup layout (prepend-alist-chain 'font-series 'medium props)
                    arg))
 
-(define-builtin-markup-command (normal-text layout props arg)
+(define-markup-command (normal-text layout props arg)
   (markup?)
-  font
-  ()
+  #:category font
   "Set all font related properties (except the size) to get the default
 normal text font, no matter what font was used earlier.
 
@@ -2107,10 +2244,9 @@ normal text font, no matter what font was used earlier.
 ;; symbols.
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(define-builtin-markup-command (doublesharp layout props)
-  ()
-  music
+(define-markup-command (doublesharp layout props)
   ()
+  #:category music
   "Draw a double sharp symbol.
 
 @lilypond[verbatim,quote]
@@ -2120,10 +2256,9 @@ normal text font, no matter what font was used earlier.
 @end lilypond"
   (interpret-markup layout props (markup #:musicglyph (assoc-get 1 standard-alteration-glyph-name-alist ""))))
 
-(define-builtin-markup-command (sesquisharp layout props)
-  ()
-  music
+(define-markup-command (sesquisharp layout props)
   ()
+  #:category music
   "Draw a 3/2 sharp symbol.
 
 @lilypond[verbatim,quote]
@@ -2131,12 +2266,11 @@ normal text font, no matter what font was used earlier.
   \\sesquisharp
 }
 @end lilypond"
-  (interpret-markup layout props (markup #:musicglyph (assoc-get 3/4 standard-alteration-glyph-name-alist ""))))                                        
+  (interpret-markup layout props (markup #:musicglyph (assoc-get 3/4 standard-alteration-glyph-name-alist ""))))
 
-(define-builtin-markup-command (sharp layout props)
-  ()
-  music
+(define-markup-command (sharp layout props)
   ()
+  #:category music
   "Draw a sharp symbol.
 
 @lilypond[verbatim,quote]
@@ -2146,11 +2280,10 @@ normal text font, no matter what font was used earlier.
 @end lilypond"
   (interpret-markup layout props (markup #:musicglyph (assoc-get 1/2 standard-alteration-glyph-name-alist ""))))
 
-(define-builtin-markup-command (semisharp layout props)
+(define-markup-command (semisharp layout props)
   ()
-  music
-  ()
-  "Draw a semi sharp symbol.
+  #:category music
+  "Draw a semisharp symbol.
 
 @lilypond[verbatim,quote]
 \\markup {
@@ -2159,10 +2292,9 @@ normal text font, no matter what font was used earlier.
 @end lilypond"
   (interpret-markup layout props (markup #:musicglyph (assoc-get 1/4 standard-alteration-glyph-name-alist ""))))
 
-(define-builtin-markup-command (natural layout props)
-  ()
-  music
+(define-markup-command (natural layout props)
   ()
+  #:category music
   "Draw a natural symbol.
 
 @lilypond[verbatim,quote]
@@ -2172,10 +2304,9 @@ normal text font, no matter what font was used earlier.
 @end lilypond"
   (interpret-markup layout props (markup #:musicglyph (assoc-get 0 standard-alteration-glyph-name-alist ""))))
 
-(define-builtin-markup-command (semiflat layout props)
-  ()
-  music
+(define-markup-command (semiflat layout props)
   ()
+  #:category music
   "Draw a semiflat symbol.
 
 @lilypond[verbatim,quote]
@@ -2185,10 +2316,9 @@ normal text font, no matter what font was used earlier.
 @end lilypond"
   (interpret-markup layout props (markup #:musicglyph (assoc-get -1/4 standard-alteration-glyph-name-alist ""))))
 
-(define-builtin-markup-command (flat layout props)
-  ()
-  music
+(define-markup-command (flat layout props)
   ()
+  #:category music
   "Draw a flat symbol.
 
 @lilypond[verbatim,quote]
@@ -2198,10 +2328,9 @@ normal text font, no matter what font was used earlier.
 @end lilypond"
   (interpret-markup layout props (markup #:musicglyph (assoc-get -1/2 standard-alteration-glyph-name-alist ""))))
 
-(define-builtin-markup-command (sesquiflat layout props)
-  ()
-  music
+(define-markup-command (sesquiflat layout props)
   ()
+  #:category music
   "Draw a 3/2 flat symbol.
 
 @lilypond[verbatim,quote]
@@ -2211,10 +2340,9 @@ normal text font, no matter what font was used earlier.
 @end lilypond"
   (interpret-markup layout props (markup #:musicglyph (assoc-get -3/4 standard-alteration-glyph-name-alist ""))))
 
-(define-builtin-markup-command (doubleflat layout props)
-  ()
-  music
+(define-markup-command (doubleflat layout props)
   ()
+  #:category music
   "Draw a double flat symbol.
 
 @lilypond[verbatim,quote]
@@ -2224,10 +2352,9 @@ normal text font, no matter what font was used earlier.
 @end lilypond"
   (interpret-markup layout props (markup #:musicglyph (assoc-get -1 standard-alteration-glyph-name-alist ""))))
 
-(define-builtin-markup-command (with-color layout props color arg)
+(define-markup-command (with-color layout props color arg)
   (color? markup?)
-  other
-  ()
+  #:category other
   "
 @cindex coloring text
 
@@ -2249,15 +2376,14 @@ Draw @var{arg} in color specified by @var{color}.
     (ly:make-stencil (list 'color color (ly:stencil-expr stil))
                     (ly:stencil-extent stil X)
                     (ly:stencil-extent stil Y))))
-\f
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; glyphs
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(define-builtin-markup-command (arrow-head layout props axis direction filled)
+(define-markup-command (arrow-head layout props axis dir filled)
   (integer? ly:dir? boolean?)
-  graphic
-  ()
+  #:category graphic
   "Produce an arrow head in specified direction and axis.
 Use the filled head if @var{filled} is specified.
 @lilypond[verbatim,quote]
@@ -2279,16 +2405,15 @@ Use the filled head if @var{filled} is specified.
                         "close"
                         "open")
                     axis
-                    direction)))
+                    dir)))
     (ly:font-get-glyph
      (ly:paper-get-font layout (cons '((font-encoding . fetaMusic))
                                     props))
      name)))
 
-(define-builtin-markup-command (musicglyph layout props glyph-name)
+(define-markup-command (musicglyph layout props glyph-name)
   (string?)
-  music
-  ()
+  #:category music
   "@var{glyph-name} is converted to a musical symbol; for example,
 @code{\\musicglyph #\"accidentals.natural\"} selects the natural sign from
 the music font.  See @ruser{The Feta font} for a complete listing of
@@ -2304,7 +2429,7 @@ the possible glyphs.
   (let* ((font (ly:paper-get-font layout
                                  (cons '((font-encoding . fetaMusic)
                                          (font-name . #f))
-                                       
+
                                                 props)))
         (glyph (ly:font-get-glyph font glyph-name)))
     (if (null? (ly:stencil-expr glyph))
@@ -2313,12 +2438,11 @@ the possible glyphs.
     glyph))
 
 
-(define-builtin-markup-command (lookup layout props glyph-name)
+(define-markup-command (lookup layout props glyph-name)
   (string?)
-  other
-  ()
+  #:category other
   "Lookup a glyph by name.
-  
+
 @lilypond[verbatim,quote]
 \\markup {
   \\override #'(font-encoding . fetaBraces) {
@@ -2332,16 +2456,15 @@ the possible glyphs.
   (ly:font-get-glyph (ly:paper-get-font layout props)
                     glyph-name))
 
-(define-builtin-markup-command (char layout props num)
+(define-markup-command (char layout props num)
   (integer?)
-  other
-  ()
-  "Produce a single character.  For example, @code{\\char #65} produces the 
-letter @q{A}.
+  #:category other
+  "Produce a single character.  Characters encoded in hexadecimal
+format require the prefix @code{#x}.
 
 @lilypond[verbatim,quote]
 \\markup {
-  \\char #65
+  \\char #65 \\char ##x00a9
 }
 @end lilypond"
   (ly:text-interface::interpret-markup layout props (ly:wide-char->utf-8 num)))
@@ -2362,16 +2485,15 @@ letter @q{A}.
 (define (number->markletter-string vec n)
   "Double letters for big marks."
   (let* ((lst (vector-length vec)))
-    
+
     (if (>= n lst)
        (string-append (number->markletter-string vec (1- (quotient n lst)))
                       (number->markletter-string vec (remainder n lst)))
        (make-string 1 (vector-ref vec n)))))
 
-(define-builtin-markup-command (markletter layout props num)
+(define-markup-command (markletter layout props num)
   (integer?)
-  other
-  ()
+  #:category other
   "Make a markup letter for @var{num}.  The letters start with A to@tie{}Z
 (skipping letter@tie{}I), and continue with double letters.
 
@@ -2385,10 +2507,9 @@ letter @q{A}.
   (ly:text-interface::interpret-markup layout props
     (number->markletter-string number->mark-letter-vector num)))
 
-(define-builtin-markup-command (markalphabet layout props num)
+(define-markup-command (markalphabet layout props num)
   (integer?)
-  other
-  ()
+  #:category other
    "Make a markup letter for @var{num}.  The letters start with A to@tie{}Z
 and continue with double letters.
 
@@ -2403,7 +2524,6 @@ and continue with double letters.
      (number->markletter-string number->mark-alphabet-vector num)))
 
 (define-public (horizontal-slash-interval num forward number-interval mag)
-  (ly:message "Mag step: ~a" mag)
   (if forward
     (cond ;((= num 6) (interval-widen number-interval (* mag 0.5)))
           ;((= num 5) (interval-widen number-interval (* mag 0.5)))
@@ -2440,7 +2560,7 @@ and continue with double letters.
          ; backward slashes might use slope and point in the other direction!
          (dy (* mag (if forward 0.4 -0.4)))
          (number-stencil (interpret-markup layout
-                                           (prepend-alist-chain 'font-encoding 'fetaNumber props)
+                                           (prepend-alist-chain 'font-encoding 'fetaText props)
                                            (number->string num)))
          (num-x (horizontal-slash-interval num forward (ly:stencil-extent number-stencil X) mag))
          (center (interval-center (ly:stencil-extent number-stencil Y)))
@@ -2449,13 +2569,10 @@ and continue with double letters.
          (num-y (interval-widen (cons center center) (abs dy)))
          (is-sane (and (interval-sane? num-x) (interval-sane? num-y)))
          (slash-stencil (if is-sane
-                            (ly:make-stencil
-                             `(draw-line ,thickness
-                                         ,(car num-x) ,(- (interval-center num-y) dy)
-                                         ,(cdr num-x) ,(+ (interval-center num-y) dy))
-                             num-x num-y)
+                            (make-line-stencil thickness
+                                         (car num-x) (- (interval-center num-y) dy)
+                                         (cdr num-x) (+ (interval-center num-y) dy))
                             #f)))
-(ly:message "Num: ~a, X-interval: ~a" num num-x)
     (if (ly:stencil? slash-stencil)
       (begin
         ; for some numbers we need to shift the slash/backslash up or down to make
@@ -2467,11 +2584,11 @@ and continue with double letters.
     number-stencil))
 
 
-(define-builtin-markup-command (slashed-digit layout props num)
+(define-markup-command (slashed-digit layout props num)
   (integer?)
-  other
-  ((font-size 0)
-   (thickness 1.6))
+  #:category other
+  #:properties ((font-size 0)
+               (thickness 1.6))
   "
 @cindex slashed digits
 
@@ -2487,11 +2604,11 @@ figured bass notation.
 @end lilypond"
   (slashed-digit-internal layout props num #t font-size thickness))
 
-(define-builtin-markup-command (backslashed-digit layout props num)
+(define-markup-command (backslashed-digit layout props num)
   (integer?)
-  other
-  ((font-size 0)
-   (thickness 1.6))
+  #:category other
+  #:properties ((font-size 0)
+               (thickness 1.6))
   "
 @cindex backslashed digits
 
@@ -2507,22 +2624,110 @@ figured bass notation.
 @end lilypond"
   (slashed-digit-internal layout props num #f font-size thickness))
 
+;; eyeglasses
+(define eyeglassesps
+     "0.15 setlinewidth
+      -0.9 0 translate
+      1.1 1.1 scale
+      1.2 0.7 moveto
+      0.7 0.7 0.5 0 361 arc
+      stroke
+      2.20 0.70 0.50 0 361 arc
+      stroke
+      1.45 0.85 0.30 0 180 arc
+      stroke
+      0.20 0.70 moveto
+      0.80 2.00 lineto
+      0.92 2.26 1.30 2.40 1.15 1.70 curveto
+      stroke
+      2.70 0.70 moveto
+      3.30 2.00 lineto
+      3.42 2.26 3.80 2.40 3.65 1.70 curveto
+      stroke")
+
+(define-markup-command (eyeglasses layout props)
+  ()
+  #:category other
+  "Prints out eyeglasses, indicating strongly to look at the conductor.
+@lilypond[verbatim,quote]
+\\markup { \\eyeglasses }
+@end lilypond"
+  (interpret-markup layout props
+    (make-with-dimensions-markup '(-0.61 . 3.22) '(0.2 . 2.41)
+      (make-postscript-markup eyeglassesps))))
+
+(define-markup-command (left-brace layout props size)
+  (number?)
+  #:category other
+  "
+A feta brace in point size @var{size}.
+
+@lilypond[verbatim,quote]
+\\markup {
+  \\left-brace #35
+  \\hspace #2
+  \\left-brace #45
+}
+@end lilypond"
+  (let* ((font (ly:paper-get-font layout
+                                  (cons '((font-encoding . fetaBraces)
+                                          (font-name . #f))
+                                        props)))
+        (glyph-count (1- (ly:otf-glyph-count font)))
+         (scale (ly:output-def-lookup layout 'output-scale))
+         (scaled-size (/ (ly:pt size) scale))
+         (glyph (lambda (n)
+                  (ly:font-get-glyph font (string-append "brace"
+                                                        (number->string n)))))
+        (get-y-from-brace (lambda (brace)
+                            (interval-length
+                             (ly:stencil-extent (glyph brace) Y))))
+         (find-brace (binary-search 0 glyph-count get-y-from-brace scaled-size))
+         (glyph-found (glyph find-brace)))
+
+    (if (or (null? (ly:stencil-expr glyph-found))
+           (< scaled-size (interval-length (ly:stencil-extent (glyph 0) Y)))
+           (> scaled-size (interval-length
+                           (ly:stencil-extent (glyph glyph-count) Y))))
+        (begin
+          (ly:warning (_ "no brace found for point size ~S ") size)
+          (ly:warning (_ "defaulting to ~S pt")
+                     (/ (* scale (interval-length
+                                  (ly:stencil-extent glyph-found Y)))
+                        (ly:pt 1)))))
+    glyph-found))
+
+(define-markup-command (right-brace layout props size)
+  (number?)
+  #:category other
+  "
+A feta brace in point size @var{size}, rotated 180 degrees.
+
+@lilypond[verbatim,quote]
+\\markup {
+  \\right-brace #45
+  \\hspace #2
+  \\right-brace #35
+}
+@end lilypond"
+  (interpret-markup layout props (markup #:rotate 180 #:left-brace size)))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; the note command.
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 ;; TODO: better syntax.
 
-(define-builtin-markup-command (note-by-number layout props log dot-count dir)
+(define-markup-command (note-by-number layout props log dot-count dir)
   (number? number? number?)
-  music
-  ((font-size 0)
-   (style '()))
+  #:category music
+  #:properties ((font-size 0)
+               (style '()))
   "
 @cindex notes within text by log and dot-count
 
 Construct a note symbol, with stem.  By using fractional values for
-@var{dir}, you can obtain longer or shorter stems.
+@var{dir}, longer or shorter stems can be obtained.
 
 @lilypond[verbatim,quote]
 \\markup {
@@ -2533,25 +2738,36 @@ Construct a note symbol, with stem.  By using fractional values for
 @end lilypond"
   (define (get-glyph-name-candidates dir log style)
     (map (lambda (dir-name)
-     (format "noteheads.~a~a~a" dir-name (min log 2)
-            (if (and (symbol? style)
-                     (not (equal? 'default style)))
-                (symbol->string style)
-                "")))
+          (format "noteheads.~a~a" dir-name
+                  (if (and (symbol? style)
+                           (not (equal? 'default style)))
+                      (select-head-glyph style (min log 2))
+                      (min log 2))))
         (list (if (= dir UP) "u" "d")
               "s")))
-                  
+
   (define (get-glyph-name font cands)
     (if (null? cands)
-     ""
-     (if (ly:stencil-empty? (ly:font-get-glyph font (car cands)))
-        (get-glyph-name font (cdr cands))
-        (car cands))))
-    
-  (let* ((font (ly:paper-get-font layout (cons '((font-encoding . fetaMusic)) props)))
+       ""
+       (if (ly:stencil-empty? (ly:font-get-glyph font (car cands)))
+           (get-glyph-name font (cdr cands))
+           (car cands))))
+
+  (let* ((font (ly:paper-get-font layout (cons '((font-encoding . fetaMusic))
+                                              props)))
         (size-factor (magstep font-size))
-         (stem-length (*  size-factor (max 3 (- log 1))))
-         (head-glyph-name (get-glyph-name font (get-glyph-name-candidates (sign dir) log style)))
+         (stem-length (* size-factor (max 3 (- log 1))))
+         (head-glyph-name
+         (let ((result (get-glyph-name font (get-glyph-name-candidates
+                                             (sign dir) log style))))
+           (if (string-null? result)
+               ;; If no glyph name can be found, select default heads.  Though
+               ;; this usually means an unsupported style has been chosen, it
+               ;; also prevents unrelated 'style settings from other grobs
+               ;; (e.g., TextSpanner and TimeSignature) leaking into markup.
+               (get-glyph-name font (get-glyph-name-candidates
+                                     (sign dir) log 'default))
+               result)))
          (head-glyph (ly:font-get-glyph font head-glyph-name))
         (attach-indices (ly:note-head::stem-attachment font head-glyph-name))
          (stem-thickness (* size-factor 0.13))
@@ -2559,18 +2775,19 @@ Construct a note symbol, with stem.  By using fractional values for
          (attach-off (cons (interval-index
                            (ly:stencil-extent head-glyph X)
                            (* (sign dir) (car attach-indices)))
-                          (* (sign dir)        ; fixme, this is inconsistent between X & Y.
+                          (* (sign dir) ; fixme, this is inconsistent between X & Y.
                              (interval-index
                               (ly:stencil-extent head-glyph Y)
                               (cdr attach-indices)))))
          (stem-glyph (and (> log 0)
                          (ly:round-filled-box
                           (ordered-cons (car attach-off)
-                                        (+ (car attach-off)  (* (- (sign dir)) stem-thickness)))
+                                        (+ (car attach-off)
+                                           (* (- (sign dir)) stem-thickness)))
                           (cons (min stemy (cdr attach-off))
                                 (max stemy (cdr attach-off)))
                           (/ stem-thickness 3))))
-        
+
          (dot (ly:font-get-glyph font "dots.dot"))
          (dotwid (interval-length (ly:stencil-extent dot X)))
          (dots (and (> dot-count 0)
@@ -2585,11 +2802,15 @@ Construct a note symbol, with stem.  By using fractional values for
                                          (string-append "flags."
                                                         (if (> dir 0) "u" "d")
                                                         (number->string log)))
-                       (cons (+ (car attach-off) (if (< dir 0) stem-thickness 0)) stemy)))))
-
-    ; If there is a flag on an upstem and the stem is short, move the dots to avoid the flag.
-    ; 16th notes get a special case because their flags hang lower than any other flags.
-    (if (and dots (> dir 0) (> log 2) (or (< dir 1.15) (and (= log 4) (< dir 1.3))))
+                       (cons (+ (car attach-off) (if (< dir 0)
+                                                    stem-thickness 0))
+                            stemy)))))
+
+    ;; If there is a flag on an upstem and the stem is short, move the dots
+    ;; to avoid the flag.  16th notes get a special case because their flags
+    ;; hang lower than any other flags.
+    (if (and dots (> dir 0) (> log 2)
+            (or (< dir 1.15) (and (= log 4) (< dir 1.3))))
        (set! dots (ly:stencil-translate-axis dots 0.5 X)))
     (if flaggl
         (set! stem-glyph (ly:stencil-add flaggl stem-glyph)))
@@ -2606,15 +2827,17 @@ Construct a note symbol, with stem.  By using fractional values for
                stem-glyph)))
     stem-glyph))
 
-(define-public log2 
+(define-public log2
   (let ((divisor (log 2)))
     (lambda (z) (inexact->exact (/ (log z) divisor)))))
 
 (define (parse-simple-duration duration-string)
-  "Parse the `duration-string', e.g. ''4..'' or ''breve.'', and return a (log dots) list."
-  (let ((match (regexp-exec (make-regexp "(breve|longa|maxima|[0-9]+)(\\.*)") duration-string)))
+  "Parse the `duration-string', e.g. ''4..'' or ''breve.'',
+and return a (log dots) list."
+  (let ((match (regexp-exec (make-regexp "(breve|longa|maxima|[0-9]+)(\\.*)")
+                           duration-string)))
     (if (and match (string=? duration-string (match:substring match 0)))
-        (let ((len  (match:substring match 1))
+        (let ((len (match:substring match 1))
               (dots (match:substring match 2)))
           (list (cond ((string=? len "breve") -1)
                       ((string=? len "longa") -2)
@@ -2623,10 +2846,10 @@ Construct a note symbol, with stem.  By using fractional values for
                 (if dots (string-length dots) 0)))
         (ly:error (_ "not a valid duration string: ~a") duration-string))))
 
-(define-builtin-markup-command (note layout props duration dir)
+(define-markup-command (note layout props duration dir)
   (string? number?)
-  music
-  (note-by-number-markup)
+  #:category music
+  #:properties (note-by-number-markup)
   "
 @cindex notes within text by string
 
@@ -2651,10 +2874,9 @@ a shortened down stem.
 ;; translating.
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(define-builtin-markup-command (lower layout props amount arg)
+(define-markup-command (lower layout props amount arg)
   (number? markup?)
-  align
-  ()
+  #:category align
   "
 @cindex lowering text
 
@@ -2663,19 +2885,19 @@ A negative @var{amount} indicates raising; see also @code{\\raise}.
 
 @lilypond[verbatim,quote]
 \\markup {
-  default
-  \\lower #3 {
-    three spaces lower
-  }
+  one
+  \\lower #3
+  two
+  three
 }
 @end lilypond"
   (ly:stencil-translate-axis (interpret-markup layout props arg)
                             (- amount) Y))
 
-(define-builtin-markup-command (translate-scaled layout props offset arg)
+(define-markup-command (translate-scaled layout props offset arg)
   (number-pair? markup?)
-  align
-  ((font-size 0))
+  #:category align
+  #:properties ((font-size 0))
   "
 @cindex translating text
 @cindex scaling text
@@ -2698,13 +2920,12 @@ Translate @var{arg} by @var{offset}, scaling the offset by the
     (ly:stencil-translate (interpret-markup layout props arg)
                           scaled)))
 
-(define-builtin-markup-command (raise layout props amount arg)
+(define-markup-command (raise layout props amount arg)
   (number? markup?)
-  align
-  ()
+  #:category align
   "
 @cindex raising text
-  
+
 Raise @var{arg} by the distance @var{amount}.
 A negative @var{amount} indicates lowering, see also @code{\\lower}.
 
@@ -2729,10 +2950,10 @@ and/or @code{extra-offset} properties.
 @end lilypond"
   (ly:stencil-translate-axis (interpret-markup layout props arg) amount Y))
 
-(define-builtin-markup-command (fraction layout props arg1 arg2)
+(define-markup-command (fraction layout props arg1 arg2)
   (markup? markup?)
-  other
-  ((font-size 0))
+  #:category other
+  #:properties ((font-size 0))
   "
 @cindex creating text fractions
 
@@ -2765,10 +2986,10 @@ Make a fraction of two markups.
       ;; empirical anyway
       (ly:stencil-translate-axis stack offset Y))))
 
-(define-builtin-markup-command (normal-size-super layout props arg)
+(define-markup-command (normal-size-super layout props arg)
   (markup?)
-  font
-  ((baseline-skip))
+  #:category font
+  #:properties ((baseline-skip))
   "
 @cindex setting superscript in standard font size
 
@@ -2786,16 +3007,15 @@ Set @var{arg} in superscript with a normal font size.
    (interpret-markup layout props arg)
    (* 0.5 baseline-skip) Y))
 
-(define-builtin-markup-command (super layout props arg)
+(define-markup-command (super layout props arg)
   (markup?)
-  font
-  ((font-size 0)
-   (baseline-skip))
-  "  
+  #:category font
+  #:properties ((font-size 0)
+               (baseline-skip))
+  "
 @cindex superscript text
 
-Raising and lowering texts can be done with @code{\\super} and
-@code{\\sub}:
+Set @var{arg} in superscript.
 
 @lilypond[verbatim,quote]
 \\markup {
@@ -2815,23 +3035,14 @@ Raising and lowering texts can be done with @code{\\super} and
    (* 0.5 baseline-skip)
    Y))
 
-(define-builtin-markup-command (translate layout props offset arg)
+(define-markup-command (translate layout props offset arg)
   (number-pair? markup?)
-  align
-  ()
+  #:category align
   "
 @cindex translating text
-  
-This translates an object.  Its first argument is a cons of numbers.
-
-@example
-A \\translate #(cons 2 -3) @{ B C @} D
-@end example
 
-This moves @q{B C} 2@tie{}spaces to the right, and 3 down, relative to its
-surroundings.  This command cannot be used to move isolated scripts
-vertically, for the same reason that @code{\\raise} cannot be used for
-that.
+Translate @var{arg} relative to its surroundings.  @var{offset}
+is a pair of numbers representing the displacement in the X and Y axis.
 
 @lilypond[verbatim,quote]
 \\markup {
@@ -2843,11 +3054,11 @@ that.
   (ly:stencil-translate (interpret-markup layout props arg)
                        offset))
 
-(define-builtin-markup-command (sub layout props arg)
+(define-markup-command (sub layout props arg)
   (markup?)
-  font
-  ((font-size 0)
-   (baseline-skip))
+  #:category font
+  #:properties ((font-size 0)
+               (baseline-skip))
   "
 @cindex subscript text
 
@@ -2872,14 +3083,14 @@ Set @var{arg} in subscript.
    (* -0.5 baseline-skip)
    Y))
 
-(define-builtin-markup-command (normal-size-sub layout props arg)
+(define-markup-command (normal-size-sub layout props arg)
   (markup?)
-  font
-  ((baseline-skip))
+  #:category font
+  #:properties ((baseline-skip))
   "
 @cindex setting subscript in standard font size
 
-Set @var{arg} in subscript, in a normal font size.
+Set @var{arg} in subscript with a normal font size.
 
 @lilypond[verbatim,quote]
 \\markup {
@@ -2893,18 +3104,17 @@ Set @var{arg} in subscript, in a normal font size.
    (interpret-markup layout props arg)
    (* -0.5 baseline-skip)
    Y))
-\f
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; brackets.
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(define-builtin-markup-command (hbracket layout props arg)
+(define-markup-command (hbracket layout props arg)
   (markup?)
-  graphic
-  ()
+  #:category graphic
   "
 @cindex placing horizontal brackets around text
-  
+
 Draw horizontal brackets around @var{arg}.
 
 @lilypond[verbatim,quote]
@@ -2920,13 +3130,12 @@ Draw horizontal brackets around @var{arg}.
         (m (interpret-markup layout props arg)))
     (bracketify-stencil m X th (* 2.5 th) th)))
 
-(define-builtin-markup-command (bracket layout props arg)
+(define-markup-command (bracket layout props arg)
   (markup?)
-  graphic
-  ()
+  #:category graphic
   "
 @cindex placing vertical brackets around text
-  
+
 Draw vertical brackets around @var{arg}.
 
 @lilypond[verbatim,quote]
@@ -2939,15 +3148,61 @@ Draw vertical brackets around @var{arg}.
   (let ((th 0.1) ;; todo: take from GROB.
         (m (interpret-markup layout props arg)))
     (bracketify-stencil m Y th (* 2.5 th) th)))
+
+(define-markup-command (parenthesize layout props arg)
+  (markup?)
+  #:category graphic
+  #:properties ((angularity 0)
+               (padding)
+               (size 1)
+               (thickness 1)
+               (width 0.25))
+  "
+@cindex placing parentheses around text
+
+Draw parentheses around @var{arg}.  This is useful for parenthesizing
+a column containing several lines of text.
+
+@lilypond[verbatim,quote]
+\\markup {
+  \\line {
+    \\parenthesize {
+      \\column {
+        foo
+        bar
+      }
+    }
+    \\override #'(angularity . 2) {
+      \\parenthesize {
+        \\column {
+          bah
+          baz
+        }
+      }
+    }
+  }
+}
+@end lilypond"
+  (let* ((markup (interpret-markup layout props arg))
+        (scaled-width (* size width))
+        (scaled-thickness
+         (* (chain-assoc-get 'line-thickness props 0.1)
+            thickness))
+        (half-thickness
+         (min (* size 0.5 scaled-thickness)
+              (* (/ 4 3.0) scaled-width)))
+        (padding (chain-assoc-get 'padding props half-thickness)))
+    (parenthesize-stencil
+     markup half-thickness scaled-width angularity padding)))
+
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Delayed markup evaluation
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(define-builtin-markup-command (page-ref layout props label gauge default)
+(define-markup-command (page-ref layout props label gauge default)
   (symbol? markup? markup?)
-  other
-  ()
+  #:category other
   "
 @cindex referencing page numbers in text
 
@@ -2962,8 +3217,9 @@ when @var{label} is not found."
      `(delay-stencil-evaluation
        ,(delay (ly:stencil-expr
                (let* ((table (ly:output-def-lookup layout 'label-page-table))
-                      (label-page (and (list? table) (assoc label table)))
-                      (page-number (and label-page (cdr label-page)))
+                      (page-number (if (list? table)
+                                       (assoc-get label table)
+                                       #f))
                       (page-markup (if page-number (format "~a" page-number) default))
                       (page-stencil (interpret-markup layout props page-markup))
                       (gap (- (interval-length x-ext)
@@ -2972,7 +3228,7 @@ when @var{label} is not found."
                                    (markup #:concat (#:hspace gap page-markup)))))))
      x-ext
      y-ext)))
-\f
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Markup list commands
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -2998,10 +3254,10 @@ when @var{label} is not found."
                                   dy-top)))))
          (space-stil (cdr stils) (cons new-stil result))))))
 
-(define-builtin-markup-list-command (justified-lines layout props args)
+(define-markup-list-command (justified-lines layout props args)
   (markup-list?)
-  ((baseline-skip)
-   wordwrap-internal-markup-list)
+  #:properties ((baseline-skip)
+               wordwrap-internal-markup-list)
   "
 @cindex justifying lines of text
 
@@ -3012,10 +3268,10 @@ Use @code{\\override-lines #'(line-width . @var{X})} to set the line width;
                (interpret-markup-list layout props
                                       (make-wordwrap-internal-markup-list #t args))))
 
-(define-builtin-markup-list-command (wordwrap-lines layout props args)
+(define-markup-list-command (wordwrap-lines layout props args)
   (markup-list?)
-  ((baseline-skip)
-   wordwrap-internal-markup-list)
+  #:properties ((baseline-skip)
+               wordwrap-internal-markup-list)
   "Like @code{\\wordwrap}, but return a list of lines instead of a single markup.
 Use @code{\\override-lines #'(line-width . @var{X})} to set the line width,
 where @var{X} is the number of staff spaces."
@@ -3023,16 +3279,15 @@ where @var{X} is the number of staff spaces."
                (interpret-markup-list layout props
                                       (make-wordwrap-internal-markup-list #f args))))
 
-(define-builtin-markup-list-command (column-lines layout props args)
+(define-markup-list-command (column-lines layout props args)
   (markup-list?)
-  ((baseline-skip))
+  #:properties ((baseline-skip))
   "Like @code{\\column}, but return a list of lines instead of a single markup.
 @code{baseline-skip} determines the space between each markup in @var{args}."
-  (space-lines (chain-assoc-get 'baseline-skip props)
+  (space-lines baseline-skip
               (interpret-markup-list layout props args)))
 
-(define-builtin-markup-list-command (override-lines layout props new-prop args)
+(define-markup-list-command (override-lines layout props new-prop args)
   (pair? markup-list?)
-  ()
   "Like @code{\\override}, for markup lists."
   (interpret-markup-list layout (cons (list new-prop) props) args))