]> git.donarmstrong.com Git - lilypond.git/blob - scm/define-markup-commands.scm
Merge branch 'master' into lilypond/translation
[lilypond.git] / scm / define-markup-commands.scm
1 ;;;; This file is part of LilyPond, the GNU music typesetter.
2 ;;;;
3 ;;;; Copyright (C) 2000--2011  Han-Wen Nienhuys <hanwen@xs4all.nl>
4 ;;;;                  Jan Nieuwenhuizen <janneke@gnu.org>
5 ;;;;
6 ;;;; LilyPond is free software: you can redistribute it and/or modify
7 ;;;; it under the terms of the GNU General Public License as published by
8 ;;;; the Free Software Foundation, either version 3 of the License, or
9 ;;;; (at your option) any later version.
10 ;;;;
11 ;;;; LilyPond is distributed in the hope that it will be useful,
12 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 ;;;; GNU General Public License for more details.
15 ;;;;
16 ;;;; You should have received a copy of the GNU General Public License
17 ;;;; along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18
19 ;;;
20 ;;; Markup commands and markup-list commands definitions.
21 ;;;
22 ;;; Markup commands which are part of LilyPond, are defined
23 ;;; in the (lily) module, which is the current module in this file,
24 ;;; using the `define-markup-command' macro.
25 ;;;
26 ;;; Usage:
27 ;;;
28 ;;; (define-markup-command (command-name layout props args...)
29 ;;;   args-signature
30 ;;;   [ #:category category ]
31 ;;;   [ #:properties property-bindings ]
32 ;;;   documentation-string
33 ;;;   ..body..)
34 ;;;
35 ;;; with:
36 ;;;   command-name
37 ;;;     the name of the markup command
38 ;;;
39 ;;;   layout and props
40 ;;;     arguments that are automatically passed to the command when it
41 ;;;     is interpreted.
42 ;;;     `layout' is an output def, which properties can be accessed
43 ;;;     using `ly:output-def-lookup'.
44 ;;;     `props' is a list of property settings which can be accessed
45 ;;;     using `chain-assoc-get' (more on that below)
46 ;;;
47 ;;;   args...
48 ;;;     the command arguments.
49 ;;;     There is no limitation on the order of command arguments.
50 ;;;     However, markup functions taking a markup as their last
51 ;;;     argument are somewhat special as you can apply them to a
52 ;;;     markup list, and the result is a markup list where the
53 ;;;     markup function (with the specified leading arguments) has
54 ;;;     been applied to every element of the original markup list.
55 ;;;
56 ;;;     Since replicating the leading arguments for applying a
57 ;;;     markup function to a markup list is cheap mostly for
58 ;;;     Scheme arguments, you avoid performance pitfalls by just
59 ;;;     using Scheme arguments for the leading arguments of markup
60 ;;;     functions that take a markup as their last argument.
61 ;;;
62 ;;;   args-signature
63 ;;;     the arguments signature, i.e. a list of type predicates which
64 ;;;     are used to type check the arguments, and also to define the general
65 ;;;     argument types (markup, markup-list, scheme) that the command is
66 ;;;     expecting.
67 ;;;     For instance, if a command expects a number, then a markup, the
68 ;;;     signature would be: (number? markup?)
69 ;;;
70 ;;;   category
71 ;;;     for documentation purpose, builtin markup commands are grouped by
72 ;;;     category. This can be any symbol. When documentation is generated,
73 ;;;     the symbol is converted to a capitalized string, where hyphens are
74 ;;;     replaced by spaces.
75 ;;;
76 ;;;   property-bindings
77 ;;;     this is used both for documentation generation, and to ease
78 ;;;     programming the command itself. It is list of
79 ;;;        (property-name default-value)
80 ;;;     or (property-name)
81 ;;;     elements. Each property is looked-up in the `props' argument, and
82 ;;;     the symbol naming the property is bound to its value.
83 ;;;     When the property is not found in `props', then the symbol is bound
84 ;;;     to the given default value. When no default value is given, #f is
85 ;;;     used instead.
86 ;;;     Thus, using the following property bindings:
87 ;;;       ((thickness 0.1)
88 ;;;        (font-size 0))
89 ;;;     is equivalent to writing:
90 ;;;       (let ((thickness (chain-assoc-get 'thickness props 0.1))
91 ;;;             (font-size (chain-assoc-get 'font-size props 0)))
92 ;;;         ..body..)
93 ;;;     When a command `B' internally calls an other command `A', it may
94 ;;;     desirable to see in `B' documentation all the properties and
95 ;;;     default values used by `A'. In that case, add `A-markup' to the
96 ;;;     property-bindings of B. (This is used when generating
97 ;;;     documentation, but won't create bindings.)
98 ;;;
99 ;;;   documentation-string
100 ;;;     the command documentation string (used to generate manuals)
101 ;;;
102 ;;;   body
103 ;;;     the command body. The function is supposed to return a stencil.
104 ;;;
105 ;;; Each markup command definition shall have a documentation string
106 ;;; with description, syntax and example.
107
108 (use-modules (ice-9 regex))
109
110 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
111 ;; utility functions
112 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
113
114 (define-public empty-stencil (ly:make-stencil '() '(1 . -1) '(1 . -1)))
115 (define-public point-stencil (ly:make-stencil "" '(0 . 0) '(0 . 0)))
116
117 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
118 ;; geometric shapes
119 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
120
121 (define-markup-command (draw-line layout props dest)
122   (number-pair?)
123   #:category graphic
124   #:properties ((thickness 1))
125   "
126 @cindex drawing lines within text
127
128 A simple line.
129 @lilypond[verbatim,quote]
130 \\markup {
131   \\draw-line #'(4 . 4)
132   \\override #'(thickness . 5)
133   \\draw-line #'(-3 . 0)
134 }
135 @end lilypond"
136   (let ((th (* (ly:output-def-lookup layout 'line-thickness)
137                thickness))
138         (x (car dest))
139         (y (cdr dest)))
140     (make-line-stencil th 0 0 x y)))
141
142 (define-markup-command (draw-hline layout props)
143   ()
144   #:category graphic
145   #:properties ((draw-line-markup)
146                 (line-width))
147   "
148 @cindex drawing a line across a page
149
150 Draws a line across a page.
151 @lilypond[verbatim,quote]
152 \\markup {
153   \\draw-hline
154 }
155 @end lilypond"
156   (interpret-markup layout props (make-draw-line-markup (cons line-width 0))))
157
158 (define-markup-command (draw-circle layout props radius thickness filled)
159   (number? number? boolean?)
160   #:category graphic
161   "
162 @cindex drawing circles within text
163
164 A circle of radius @var{radius} and thickness @var{thickness},
165 optionally filled.
166
167 @lilypond[verbatim,quote]
168 \\markup {
169   \\draw-circle #2 #0.5 ##f
170   \\hspace #2
171   \\draw-circle #2 #0 ##t
172 }
173 @end lilypond"
174   (make-circle-stencil radius thickness filled))
175
176 (define-markup-command (triangle layout props filled)
177   (boolean?)
178   #:category graphic
179   #:properties ((thickness 0.1)
180                 (font-size 0)
181                 (baseline-skip 2))
182   "
183 @cindex drawing triangles within text
184
185 A triangle, either filled or empty.
186
187 @lilypond[verbatim,quote]
188 \\markup {
189   \\triangle ##t
190   \\hspace #2
191   \\triangle ##f
192 }
193 @end lilypond"
194   (let ((ex (* (magstep font-size) 0.8 baseline-skip)))
195     (ly:make-stencil
196      `(polygon '(0.0 0.0
197                      ,ex 0.0
198                      ,(* 0.5 ex)
199                      ,(* 0.86 ex))
200            ,thickness
201            ,filled)
202      (cons 0 ex)
203      (cons 0 (* .86 ex)))))
204
205 (define-markup-command (circle layout props arg)
206   (markup?)
207   #:category graphic
208   #:properties ((thickness 1)
209                 (font-size 0)
210                 (circle-padding 0.2))
211   "
212 @cindex circling text
213
214 Draw a circle around @var{arg}.  Use @code{thickness},
215 @code{circle-padding} and @code{font-size} properties to determine line
216 thickness and padding around the markup.
217
218 @lilypond[verbatim,quote]
219 \\markup {
220   \\circle {
221     Hi
222   }
223 }
224 @end lilypond"
225   (let ((th (* (ly:output-def-lookup layout 'line-thickness)
226                thickness))
227          (pad (* (magstep font-size) circle-padding))
228          (m (interpret-markup layout props arg)))
229     (circle-stencil m th pad)))
230
231 (define-markup-command (with-url layout props url arg)
232   (string? markup?)
233   #:category graphic
234   "
235 @cindex inserting URL links into text
236
237 Add a link to URL @var{url} around @var{arg}.  This only works in
238 the PDF backend.
239
240 @lilypond[verbatim,quote]
241 \\markup {
242   \\with-url #\"http://lilypond.org/web/\" {
243     LilyPond ... \\italic {
244       music notation for everyone
245     }
246   }
247 }
248 @end lilypond"
249   (let* ((stil (interpret-markup layout props arg))
250          (xextent (ly:stencil-extent stil X))
251          (yextent (ly:stencil-extent stil Y))
252          (old-expr (ly:stencil-expr stil))
253          (url-expr (list 'url-link url `(quote ,xextent) `(quote ,yextent))))
254
255     (ly:stencil-add (ly:make-stencil url-expr xextent yextent) stil)))
256
257 (define-markup-command (beam layout props width slope thickness)
258   (number? number? number?)
259   #:category graphic
260   "
261 @cindex drawing beams within text
262
263 Create a beam with the specified parameters.
264 @lilypond[verbatim,quote]
265 \\markup {
266   \\beam #5 #1 #2
267 }
268 @end lilypond"
269   (let* ((y (* slope width))
270          (yext (cons (min 0 y) (max 0 y)))
271          (half (/ thickness 2)))
272
273     (ly:make-stencil
274      `(polygon ',(list
275                   0 (/ thickness -2)
276                     width (+ (* width slope)  (/ thickness -2))
277                     width (+ (* width slope)  (/ thickness 2))
278                     0 (/ thickness 2))
279                ,(ly:output-def-lookup layout 'blot-diameter)
280                #t)
281      (cons 0 width)
282      (cons (+ (- half) (car yext))
283            (+ half (cdr yext))))))
284
285 (define-markup-command (underline layout props arg)
286   (markup?)
287   #:category font
288   #:properties ((thickness 1) (offset 2))
289   "
290 @cindex underlining text
291
292 Underline @var{arg}.  Looks at @code{thickness} to determine line
293 thickness, and @code{offset} to determine line y-offset.
294
295 @lilypond[verbatim,quote]
296 \\markup \\fill-line {
297   \\underline \"underlined\"
298   \\override #'(offset . 5)
299   \\override #'(thickness . 1)
300   \\underline \"underlined\"
301   \\override #'(offset . 1)
302   \\override #'(thickness . 5)
303   \\underline \"underlined\"
304 }
305 @end lilypond"
306   (let* ((thick (ly:output-def-lookup layout 'line-thickness))
307          (underline-thick (* thickness thick))
308          (markup (interpret-markup layout props arg))
309          (x1 (car (ly:stencil-extent markup X)))
310          (x2 (cdr (ly:stencil-extent markup X)))
311          (y (* thick (- offset)))
312          (line (make-line-stencil underline-thick x1 y x2 y)))
313     (ly:stencil-add markup line)))
314
315 (define-markup-command (box layout props arg)
316   (markup?)
317   #:category font
318   #:properties ((thickness 1)
319                 (font-size 0)
320                 (box-padding 0.2))
321   "
322 @cindex enclosing text within a box
323
324 Draw a box round @var{arg}.  Looks at @code{thickness},
325 @code{box-padding} and @code{font-size} properties to determine line
326 thickness and padding around the markup.
327
328 @lilypond[verbatim,quote]
329 \\markup {
330   \\override #'(box-padding . 0.5)
331   \\box
332   \\line { V. S. }
333 }
334 @end lilypond"
335   (let* ((th (* (ly:output-def-lookup layout 'line-thickness)
336                 thickness))
337          (pad (* (magstep font-size) box-padding))
338          (m (interpret-markup layout props arg)))
339     (box-stencil m th pad)))
340
341 (define-markup-command (filled-box layout props xext yext blot)
342   (number-pair? number-pair? number?)
343   #:category graphic
344   "
345 @cindex drawing solid boxes within text
346 @cindex drawing boxes with rounded corners
347
348 Draw a box with rounded corners of dimensions @var{xext} and
349 @var{yext}.  For example,
350 @verbatim
351 \\filled-box #'(-.3 . 1.8) #'(-.3 . 1.8) #0
352 @end verbatim
353 creates a box extending horizontally from -0.3 to 1.8 and
354 vertically from -0.3 up to 1.8, with corners formed from a
355 circle of diameter@tie{}0 (i.e., sharp corners).
356
357 @lilypond[verbatim,quote]
358 \\markup {
359   \\filled-box #'(0 . 4) #'(0 . 4) #0
360   \\filled-box #'(0 . 2) #'(-4 . 2) #0.4
361   \\filled-box #'(1 . 8) #'(0 . 7) #0.2
362   \\with-color #white
363   \\filled-box #'(-4.5 . -2.5) #'(3.5 . 5.5) #0.7
364 }
365 @end lilypond"
366   (ly:round-filled-box
367    xext yext blot))
368
369 (define-markup-command (rounded-box layout props arg)
370   (markup?)
371   #:category graphic
372   #:properties ((thickness 1)
373                 (corner-radius 1)
374                 (font-size 0)
375                 (box-padding 0.5))
376   "@cindex enclosing text in a box with rounded corners
377    @cindex drawing boxes with rounded corners around text
378 Draw a box with rounded corners around @var{arg}.  Looks at @code{thickness},
379 @code{box-padding} and @code{font-size} properties to determine line
380 thickness and padding around the markup; the @code{corner-radius} property
381 makes it possible to define another shape for the corners (default is 1).
382
383 @lilypond[quote,verbatim,relative=2]
384 c4^\\markup {
385   \\rounded-box {
386     Overtura
387   }
388 }
389 c,8. c16 c4 r
390 @end lilypond"
391   (let ((th (* (ly:output-def-lookup layout 'line-thickness)
392                thickness))
393         (pad (* (magstep font-size) box-padding))
394         (m (interpret-markup layout props arg)))
395     (ly:stencil-add (rounded-box-stencil m th pad corner-radius)
396                     m)))
397
398 (define-markup-command (rotate layout props ang arg)
399   (number? markup?)
400   #:category align
401   "
402 @cindex rotating text
403
404 Rotate object with @var{ang} degrees around its center.
405
406 @lilypond[verbatim,quote]
407 \\markup {
408   default
409   \\hspace #2
410   \\rotate #45
411   \\line {
412     rotated 45°
413   }
414 }
415 @end lilypond"
416   (let* ((stil (interpret-markup layout props arg)))
417     (ly:stencil-rotate stil ang 0 0)))
418
419 (define-markup-command (whiteout layout props arg)
420   (markup?)
421   #:category other
422   "
423 @cindex adding a white background to text
424
425 Provide a white background for @var{arg}.
426
427 @lilypond[verbatim,quote]
428 \\markup {
429   \\combine
430     \\filled-box #'(-1 . 10) #'(-3 . 4) #1
431     \\whiteout whiteout
432 }
433 @end lilypond"
434   (stencil-whiteout (interpret-markup layout props arg)))
435
436 (define-markup-command (pad-markup layout props amount arg)
437   (number? markup?)
438   #:category align
439   "
440 @cindex padding text
441 @cindex putting space around text
442
443 Add space around a markup object.
444
445 @lilypond[verbatim,quote]
446 \\markup {
447   \\box {
448     default
449   }
450   \\hspace #2
451   \\box {
452     \\pad-markup #1 {
453       padded
454     }
455   }
456 }
457 @end lilypond"
458   (let*
459       ((stil (interpret-markup layout props arg))
460        (xext (ly:stencil-extent stil X))
461        (yext (ly:stencil-extent stil Y)))
462
463     (ly:make-stencil
464      (ly:stencil-expr stil)
465      (interval-widen xext amount)
466      (interval-widen yext amount))))
467
468 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
469 ;; space
470 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
471
472 (define-markup-command (strut layout props)
473   ()
474   #:category other
475   "
476 @cindex creating vertical spaces in text
477
478 Create a box of the same height as the space in the current font."
479   (let ((m (ly:text-interface::interpret-markup layout props " ")))
480     (ly:make-stencil (ly:stencil-expr m)
481                      '(0 . 0)
482                      (ly:stencil-extent m X)
483                      )))
484
485 ;; todo: fix negative space
486 (define-markup-command (hspace layout props amount)
487   (number?)
488   #:category align
489   #:properties ((word-space))
490   "
491 @cindex creating horizontal spaces in text
492
493 Create an invisible object taking up horizontal space @var{amount}.
494
495 @lilypond[verbatim,quote]
496 \\markup {
497   one
498   \\hspace #2
499   two
500   \\hspace #8
501   three
502 }
503 @end lilypond"
504   (let ((corrected-space (- amount word-space)))
505     (if (> corrected-space 0)
506         (ly:make-stencil "" (cons 0 corrected-space) '(0 . 0))
507         (ly:make-stencil "" (cons corrected-space corrected-space) '(0 . 0)))))
508
509 ;; todo: fix negative space
510 (define-markup-command (vspace layout props amount)
511  (number?)
512  #:category align
513  "
514 @cindex creating vertical spaces in text
515
516 Create an invisible object taking up vertical space
517 of @var{amount} multiplied by 3.
518
519 @lilypond[verbatim,quote]
520 \\markup {
521     \\center-column {
522     one
523     \\vspace #2
524     two
525     \\vspace #5
526     three
527   }
528 }
529 @end lilypond"
530   (let ((amount (* amount 3.0)))
531     (if (> amount 0)
532         (ly:make-stencil "" (cons 0 0) (cons 0 amount))
533         (ly:make-stencil "" (cons 0 0) (cons amount amount)))))
534
535
536 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
537 ;; importing graphics.
538 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
539
540 (define-markup-command (stencil layout props stil)
541   (ly:stencil?)
542   #:category other
543   "
544 @cindex importing stencils into text
545
546 Use a stencil as markup.
547
548 @lilypond[verbatim,quote]
549 \\markup {
550   \\stencil #(make-circle-stencil 2 0 #t)
551 }
552 @end lilypond"
553   stil)
554
555 (define bbox-regexp
556   (make-regexp "%%BoundingBox:[ \t]+([0-9-]+)[ \t]+([0-9-]+)[ \t]+([0-9-]+)[ \t]+([0-9-]+)"))
557
558 (define (get-postscript-bbox string)
559   "Extract the bbox from STRING, or return #f if not present."
560   (let*
561       ((match (regexp-exec bbox-regexp string)))
562
563     (if match
564         (map (lambda (x)
565                (string->number (match:substring match x)))
566              (cdr (iota 5)))
567
568         #f)))
569
570 (define-markup-command (epsfile layout props axis size file-name)
571   (number? number? string?)
572   #:category graphic
573   "
574 @cindex inlining an Encapsulated PostScript image
575
576 Inline an EPS image.  The image is scaled along @var{axis} to
577 @var{size}.
578
579 @lilypond[verbatim,quote]
580 \\markup {
581   \\general-align #Y #DOWN {
582     \\epsfile #X #20 #\"context-example.eps\"
583     \\epsfile #Y #20 #\"context-example.eps\"
584   }
585 }
586 @end lilypond"
587   (if (ly:get-option 'safe)
588       (interpret-markup layout props "not allowed in safe")
589       (eps-file->stencil axis size file-name)
590       ))
591
592 (define-markup-command (postscript layout props str)
593   (string?)
594   #:category graphic
595   "
596 @cindex inserting PostScript directly into text
597 This inserts @var{str} directly into the output as a PostScript
598 command string.
599
600 @lilypond[verbatim,quote]
601 ringsps = #\"
602   0.15 setlinewidth
603   0.9 0.6 moveto
604   0.4 0.6 0.5 0 361 arc
605   stroke
606   1.0 0.6 0.5 0 361 arc
607   stroke
608   \"
609
610 rings = \\markup {
611   \\with-dimensions #'(-0.2 . 1.6) #'(0 . 1.2)
612   \\postscript #ringsps
613 }
614
615 \\relative c'' {
616   c2^\\rings
617   a2_\\rings
618 }
619 @end lilypond"
620   ;; FIXME
621   (ly:make-stencil
622    (list 'embedded-ps
623          (format "
624 gsave currentpoint translate
625 0.1 setlinewidth
626  ~a
627 grestore
628 "
629                  str))
630    '(0 . 0) '(0 . 0)))
631
632 (define-markup-command (path layout props thickness commands) (number? list?)
633   #:category graphic
634   #:properties ((line-cap-style 'round)
635                 (line-join-style 'round)
636                 (filled #f))
637   "
638 @cindex paths, drawing
639 @cindex drawing paths
640 Draws a path with line thickness @var{thickness} according to the
641 directions given in @var{commands}.  @var{commands} is a list of
642 lists where the @code{car} of each sublist is a drawing command and
643 the @code{cdr} comprises the associated arguments for each command.
644
645 Line-cap styles and line-join styles may be customized by
646 overriding the @code{line-cap-style} and @code{line-join-style}
647 properties, respectively.  Available line-cap styles are
648 @code{'butt}, @code{'round}, and @code{'square}.  Available
649 line-join styles are @code{'miter}, @code{'round}, and
650 @code{'bevel}.
651
652 The property @code{filled} specifies whether or not the path is
653 filled with color.
654
655 There are seven commands available to use in the list
656 @code{commands}: @code{moveto}, @code{rmoveto}, @code{lineto},
657 @code{rlineto}, @code{curveto}, @code{rcurveto}, and
658 @code{closepath}.  Note that the commands that begin with @emph{r}
659 are the relative variants of the other three commands.
660
661 The commands @code{moveto}, @code{rmoveto}, @code{lineto}, and
662 @code{rlineto} take 2 arguments; they are the X and Y coordinates
663 for the destination point.
664
665 The commands @code{curveto} and @code{rcurveto} create cubic
666 Bézier curves, and take 6 arguments; the first two are the X and Y
667 coordinates for the first control point, the second two are the X
668 and Y coordinates for the second control point, and the last two
669 are the X and Y coordinates for the destination point.
670
671 The @code{closepath} command takes zero arguments and closes the
672 current subpath in the active path.
673
674 Note that a sequence of commands @emph{must} begin with a
675 @code{moveto} or @code{rmoveto} to work with the SVG output.
676
677 @lilypond[verbatim,quote]
678 samplePath =
679   #'((moveto 0 0)
680      (lineto -1 1)
681      (lineto 1 1)
682      (lineto 1 -1)
683      (curveto -5 -5 -5 5 -1 0)
684      (closepath))
685
686 \\markup {
687   \\path #0.25 #samplePath
688 }
689 @end lilypond"
690   (let* ((half-thickness (/ thickness 2))
691          (current-point '(0 . 0))
692          (set-point (lambda (lst) (set! current-point lst)))
693          (relative? (lambda (x)
694                       (string-prefix? "r" (symbol->string (car x)))))
695          ;; For calculating extents, we want to modify the command
696          ;; list so that all coordinates are absolute.
697          (new-commands (map (lambda (x)
698                               (cond
699                                 ;; for rmoveto, rlineto
700                                 ((and (relative? x) (eq? 3 (length x)))
701                                  (let ((cp (cons
702                                              (+ (car current-point)
703                                                 (second x))
704                                              (+ (cdr current-point)
705                                                 (third x)))))
706                                    (set-point cp)
707                                    (list (car cp)
708                                          (cdr cp))))
709                                 ;; for rcurveto
710                                 ((and (relative? x) (eq? 7 (length x)))
711                                  (let* ((old-cp current-point)
712                                         (cp (cons
713                                               (+ (car old-cp)
714                                                  (sixth x))
715                                               (+ (cdr old-cp)
716                                                  (seventh x)))))
717                                    (set-point cp)
718                                    (list (+ (car old-cp) (second x))
719                                          (+ (cdr old-cp) (third x))
720                                          (+ (car old-cp) (fourth x))
721                                          (+ (cdr old-cp) (fifth x))
722                                          (car cp)
723                                          (cdr cp))))
724                                 ;; for moveto, lineto
725                                 ((eq? 3 (length x))
726                                  (set-point (cons (second x)
727                                                   (third x)))
728                                  (drop x 1))
729                                 ;; for curveto
730                                 ((eq? 7 (length x))
731                                  (set-point (cons (sixth x)
732                                                   (seventh x)))
733                                  (drop x 1))
734                                 ;; keep closepath for filtering;
735                                 ;; see `without-closepath'.
736                                 (else x)))
737                             commands))
738          ;; path-min-max does not accept 0-arg lists,
739          ;; and since closepath does not affect extents, filter
740          ;; out those commands here.
741          (without-closepath (filter (lambda (x)
742                                       (not (equal? 'closepath (car x))))
743                                     new-commands))
744          (extents (path-min-max
745                     ;; set the origin to the first moveto
746                     (list (list-ref (car without-closepath) 0)
747                           (list-ref (car without-closepath) 1))
748                     without-closepath))
749          (X-extent (cons (list-ref extents 0) (list-ref extents 1)))
750          (Y-extent (cons (list-ref extents 2) (list-ref extents 3)))
751          (command-list (fold-right append '() commands)))
752
753     ;; account for line thickness
754     (set! X-extent (interval-widen X-extent half-thickness))
755     (set! Y-extent (interval-widen Y-extent half-thickness))
756
757     (ly:make-stencil
758       `(path ,thickness `(,@',command-list)
759              ',line-cap-style ',line-join-style ,filled)
760       X-extent
761       Y-extent)))
762
763 (define-markup-command (score layout props score)
764   (ly:score?)
765   #:category music
766   #:properties ((baseline-skip))
767   "
768 @cindex inserting music into text
769
770 Inline an image of music.
771
772 @lilypond[verbatim,quote]
773 \\markup {
774   \\score {
775     \\new PianoStaff <<
776       \\new Staff \\relative c' {
777         \\key f \\major
778         \\time 3/4
779         \\mark \\markup { Allegro }
780         f2\\p( a4)
781         c2( a4)
782         bes2( g'4)
783         f8( e) e4 r
784       }
785       \\new Staff \\relative c {
786         \\clef bass
787         \\key f \\major
788         \\time 3/4
789         f8( a c a c a
790         f c' es c es c)
791         f,( bes d bes d bes)
792         f( g bes g bes g)
793       }
794     >>
795     \\layout {
796       indent = 0.0\\cm
797       \\context {
798         \\Score
799         \\override RehearsalMark #'break-align-symbols =
800           #'(time-signature key-signature)
801         \\override RehearsalMark #'self-alignment-X = #LEFT
802       }
803       \\context {
804         \\Staff
805         \\override TimeSignature #'break-align-anchor-alignment = #LEFT
806       }
807     }
808   }
809 }
810 @end lilypond"
811   (let ((output (ly:score-embedded-format score layout)))
812
813     (if (ly:music-output? output)
814         (stack-stencils Y DOWN baseline-skip
815                         (map paper-system-stencil
816                              (vector->list
817                               (ly:paper-score-paper-systems output))))
818         (begin
819           (ly:warning (_"no systems found in \\score markup, does it have a \\layout block?"))
820           empty-stencil))))
821
822 (define-markup-command (null layout props)
823   ()
824   #:category other
825   "
826 @cindex creating empty text objects
827
828 An empty markup with extents of a single point.
829
830 @lilypond[verbatim,quote]
831 \\markup {
832   \\null
833 }
834 @end lilypond"
835   point-stencil)
836
837 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
838 ;; basic formatting.
839 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
840
841 (define-markup-command (simple layout props str)
842   (string?)
843   #:category font
844   "
845 @cindex simple text strings
846
847 A simple text string; @code{\\markup @{ foo @}} is equivalent with
848 @code{\\markup @{ \\simple #\"foo\" @}}.
849
850 Note: for creating standard text markup or defining new markup commands,
851 the use of @code{\\simple} is unnecessary.
852
853 @lilypond[verbatim,quote]
854 \\markup {
855   \\simple #\"simple\"
856   \\simple #\"text\"
857   \\simple #\"strings\"
858 }
859 @end lilypond"
860   (interpret-markup layout props str))
861
862 (define-markup-command (tied-lyric layout props str)
863   (string?)
864   #:category music
865   "
866 @cindex simple text strings with tie characters
867
868 Like simple-markup, but use tie characters for @q{~} tilde symbols.
869
870 @lilypond[verbatim,quote]
871 \\markup {
872   \\tied-lyric #\"Lasciate~i monti\"
873 }
874 @end lilypond"
875   (if (string-contains str "~")
876       (let*
877           ((parts (string-split str #\~))
878            (tie-str (ly:wide-char->utf-8 #x203f))
879            (joined  (list-join parts tie-str))
880            (join-stencil (interpret-markup layout props tie-str))
881            )
882
883         (interpret-markup layout
884                           (prepend-alist-chain
885                            'word-space
886                            (/ (interval-length (ly:stencil-extent join-stencil X)) -3.5)
887                            props)
888                           (make-line-markup joined)))
889                            ;(map (lambda (s) (interpret-markup layout props s)) parts))
890       (interpret-markup layout props str)))
891
892 (define-public empty-markup
893   (make-simple-markup ""))
894
895 ;; helper for justifying lines.
896 (define (get-fill-space word-count line-width word-space text-widths)
897   "Calculate the necessary paddings between each two adjacent texts.
898   The lengths of all texts are stored in @var{text-widths}.
899   The normal formula for the padding between texts a and b is:
900   padding = line-width/(word-count - 1) - (length(a) + length(b))/2
901   The first and last padding have to be calculated specially using the
902   whole length of the first or last text.
903   All paddings are checked to be at least word-space, to ensure that
904   no texts collide.
905   Return a list of paddings."
906   (cond
907    ((null? text-widths) '())
908
909    ;; special case first padding
910    ((= (length text-widths) word-count)
911     (cons
912      (- (- (/ line-width (1- word-count)) (car text-widths))
913         (/ (car (cdr text-widths)) 2))
914      (get-fill-space word-count line-width word-space (cdr text-widths))))
915    ;; special case last padding
916    ((= (length text-widths) 2)
917     (list (- (/ line-width (1- word-count))
918              (+ (/ (car text-widths) 2) (car (cdr text-widths)))) 0))
919    (else
920     (let ((default-padding
921             (- (/ line-width (1- word-count))
922                (/ (+ (car text-widths) (car (cdr text-widths))) 2))))
923       (cons
924        (if (> word-space default-padding)
925            word-space
926            default-padding)
927        (get-fill-space word-count line-width word-space (cdr text-widths)))))))
928
929 (define-markup-command (fill-line layout props args)
930   (markup-list?)
931   #:category align
932   #:properties ((text-direction RIGHT)
933                 (word-space 0.6)
934                 (line-width #f))
935   "Put @var{markups} in a horizontal line of width @var{line-width}.
936 The markups are spaced or flushed to fill the entire line.
937 If there are no arguments, return an empty stencil.
938
939 @lilypond[verbatim,quote]
940 \\markup {
941   \\column {
942     \\fill-line {
943       Words evenly spaced across the page
944     }
945     \\null
946     \\fill-line {
947       \\line { Text markups }
948       \\line {
949         \\italic { evenly spaced }
950       }
951       \\line { across the page }
952     }
953   }
954 }
955 @end lilypond"
956   (let* ((orig-stencils (interpret-markup-list layout props args))
957          (stencils
958           (map (lambda (stc)
959                  (if (ly:stencil-empty? stc)
960                      point-stencil
961                      stc)) orig-stencils))
962          (text-widths
963           (map (lambda (stc)
964                  (if (ly:stencil-empty? stc)
965                      0.0
966                      (interval-length (ly:stencil-extent stc X))))
967                stencils))
968          (text-width (apply + text-widths))
969          (word-count (length stencils))
970          (line-width (or line-width (ly:output-def-lookup layout 'line-width)))
971          (fill-space
972           (cond
973            ((= word-count 1)
974             (list
975              (/ (- line-width text-width) 2)
976              (/ (- line-width text-width) 2)))
977            ((= word-count 2)
978             (list
979              (- line-width text-width)))
980            (else
981             (get-fill-space word-count line-width word-space text-widths))))
982
983          (line-contents (if (= word-count 1)
984                             (list
985                              point-stencil
986                              (car stencils)
987                              point-stencil)
988                             stencils)))
989
990     (if (null? (remove ly:stencil-empty? orig-stencils))
991         empty-stencil
992         (begin
993           (if (= text-direction LEFT)
994               (set! line-contents (reverse line-contents)))
995           (set! line-contents
996                 (stack-stencils-padding-list
997                  X RIGHT fill-space line-contents))
998           (if (> word-count 1)
999               ;; shift s.t. stencils align on the left edge, even if
1000               ;; first stencil had negative X-extent (e.g. center-column)
1001               ;; (if word-count = 1, X-extents are already normalized in
1002               ;; the definition of line-contents)
1003               (set! line-contents
1004                     (ly:stencil-translate-axis
1005                      line-contents
1006                      (- (car (ly:stencil-extent (car stencils) X)))
1007                      X)))
1008           line-contents))))
1009
1010 (define-markup-command (line layout props args)
1011   (markup-list?)
1012   #:category align
1013   #:properties ((word-space)
1014                 (text-direction RIGHT))
1015   "Put @var{args} in a horizontal line.  The property @code{word-space}
1016 determines the space between markups in @var{args}.
1017
1018 @lilypond[verbatim,quote]
1019 \\markup {
1020   \\line {
1021     one two three
1022   }
1023 }
1024 @end lilypond"
1025   (let ((stencils (interpret-markup-list layout props args)))
1026     (if (= text-direction LEFT)
1027         (set! stencils (reverse stencils)))
1028     (stack-stencil-line
1029      word-space
1030      (remove ly:stencil-empty? stencils))))
1031
1032 (define-markup-command (concat layout props args)
1033   (markup-list?)
1034   #:category align
1035   "
1036 @cindex concatenating text
1037 @cindex ligatures in text
1038
1039 Concatenate @var{args} in a horizontal line, without spaces in between.
1040 Strings and simple markups are concatenated on the input level, allowing
1041 ligatures.  For example, @code{\\concat @{ \"f\" \\simple #\"i\" @}} is
1042 equivalent to @code{\"fi\"}.
1043
1044 @lilypond[verbatim,quote]
1045 \\markup {
1046   \\concat {
1047     one
1048     two
1049     three
1050   }
1051 }
1052 @end lilypond"
1053   (define (concat-string-args arg-list)
1054     (fold-right (lambda (arg result-list)
1055                   (let ((result (if (pair? result-list)
1056                                     (car result-list)
1057                                   '())))
1058                     (if (and (pair? arg) (eqv? (car arg) simple-markup))
1059                       (set! arg (cadr arg)))
1060                     (if (and (string? result) (string? arg))
1061                         (cons (string-append arg result) (cdr result-list))
1062                       (cons arg result-list))))
1063                 '()
1064                 arg-list))
1065
1066   (interpret-markup layout
1067                     (prepend-alist-chain 'word-space 0 props)
1068                     (make-line-markup (if (markup-command-list? args)
1069                                           args
1070                                           (concat-string-args args)))))
1071
1072 (define (wordwrap-stencils stencils
1073                            justify base-space line-width text-dir)
1074   "Perform simple wordwrap, return stencil of each line."
1075   (define space (if justify
1076                     ;; justify only stretches lines.
1077                     (* 0.7 base-space)
1078                     base-space))
1079   (define (take-list width space stencils
1080                      accumulator accumulated-width)
1081     "Return (head-list . tail) pair, with head-list fitting into width"
1082     (if (null? stencils)
1083         (cons accumulator stencils)
1084         (let* ((first (car stencils))
1085                (first-wid (cdr (ly:stencil-extent (car stencils) X)))
1086                (newwid (+ space first-wid accumulated-width)))
1087           (if (or (null? accumulator)
1088                   (< newwid width))
1089               (take-list width space
1090                          (cdr stencils)
1091                          (cons first accumulator)
1092                          newwid)
1093               (cons accumulator stencils)))))
1094   (let loop ((lines '())
1095              (todo stencils))
1096     (let* ((line-break (take-list line-width space todo
1097                                   '() 0.0))
1098            (line-stencils (car line-break))
1099            (space-left (- line-width
1100                           (apply + (map (lambda (x) (cdr (ly:stencil-extent x X)))
1101                                         line-stencils))))
1102            (line-word-space (cond ((not justify) space)
1103                                   ;; don't stretch last line of paragraph.
1104                                   ;; hmmm . bug - will overstretch the last line in some case.
1105                                   ((null? (cdr line-break))
1106                                    base-space)
1107                                   ((null? line-stencils) 0.0)
1108                                   ((null? (cdr line-stencils)) 0.0)
1109                                   (else (/ space-left (1- (length line-stencils))))))
1110            (line (stack-stencil-line line-word-space
1111                                      (if (= text-dir RIGHT)
1112                                          (reverse line-stencils)
1113                                          line-stencils))))
1114       (if (pair? (cdr line-break))
1115           (loop (cons line lines)
1116                 (cdr line-break))
1117           (begin
1118             (if (= text-dir LEFT)
1119                 (set! line
1120                       (ly:stencil-translate-axis
1121                        line
1122                        (- line-width (interval-end (ly:stencil-extent line X)))
1123                        X)))
1124             (reverse (cons line lines)))))))
1125
1126 (define-markup-list-command (wordwrap-internal layout props justify args)
1127   (boolean? markup-list?)
1128   #:properties ((line-width #f)
1129                 (word-space)
1130                 (text-direction RIGHT))
1131   "Internal markup list command used to define @code{\\justify} and @code{\\wordwrap}."
1132   (wordwrap-stencils (remove ly:stencil-empty?
1133                              (interpret-markup-list layout props args))
1134                      justify
1135                      word-space
1136                      (or line-width
1137                          (ly:output-def-lookup layout 'line-width))
1138                      text-direction))
1139
1140 (define-markup-command (justify layout props args)
1141   (markup-list?)
1142   #:category align
1143   #:properties ((baseline-skip)
1144                 wordwrap-internal-markup-list)
1145   "
1146 @cindex justifying text
1147
1148 Like @code{\\wordwrap}, but with lines stretched to justify the margins.
1149 Use @code{\\override #'(line-width . @var{X})} to set the line width;
1150 @var{X}@tie{}is the number of staff spaces.
1151
1152 @lilypond[verbatim,quote]
1153 \\markup {
1154   \\justify {
1155     Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed
1156     do eiusmod tempor incididunt ut labore et dolore magna aliqua.
1157     Ut enim ad minim veniam, quis nostrud exercitation ullamco
1158     laboris nisi ut aliquip ex ea commodo consequat.
1159   }
1160 }
1161 @end lilypond"
1162   (stack-lines DOWN 0.0 baseline-skip
1163                (wordwrap-internal-markup-list layout props #t args)))
1164
1165 (define-markup-command (wordwrap layout props args)
1166   (markup-list?)
1167   #:category align
1168   #:properties ((baseline-skip)
1169                 wordwrap-internal-markup-list)
1170   "Simple wordwrap.  Use @code{\\override #'(line-width . @var{X})} to set
1171 the line width, where @var{X} is the number of staff spaces.
1172
1173 @lilypond[verbatim,quote]
1174 \\markup {
1175   \\wordwrap {
1176     Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed
1177     do eiusmod tempor incididunt ut labore et dolore magna aliqua.
1178     Ut enim ad minim veniam, quis nostrud exercitation ullamco
1179     laboris nisi ut aliquip ex ea commodo consequat.
1180   }
1181 }
1182 @end lilypond"
1183   (stack-lines DOWN 0.0 baseline-skip
1184                (wordwrap-internal-markup-list layout props #f args)))
1185
1186 (define-markup-list-command (wordwrap-string-internal layout props justify arg)
1187   (boolean? string?)
1188   #:properties ((line-width)
1189                 (word-space)
1190                 (text-direction RIGHT))
1191   "Internal markup list command used to define @code{\\justify-string} and
1192 @code{\\wordwrap-string}."
1193   (let* ((para-strings (regexp-split
1194                         (string-regexp-substitute
1195                          "\r" "\n"
1196                          (string-regexp-substitute "\r\n" "\n" arg))
1197                         "\n[ \t\n]*\n[ \t\n]*"))
1198          (list-para-words (map (lambda (str)
1199                                  (regexp-split str "[ \t\n]+"))
1200                                para-strings))
1201          (para-lines (map (lambda (words)
1202                             (let* ((stencils
1203                                     (remove ly:stencil-empty?
1204                                             (map (lambda (x)
1205                                                    (interpret-markup layout props x))
1206                                                  words))))
1207                               (wordwrap-stencils stencils
1208                                                  justify word-space
1209                                                  line-width text-direction)))
1210                           list-para-words)))
1211     (apply append para-lines)))
1212
1213 (define-markup-command (wordwrap-string layout props arg)
1214   (string?)
1215   #:category align
1216   #:properties ((baseline-skip)
1217                 wordwrap-string-internal-markup-list)
1218   "Wordwrap a string.  Paragraphs may be separated with double newlines.
1219
1220 @lilypond[verbatim,quote]
1221 \\markup {
1222   \\override #'(line-width . 40)
1223   \\wordwrap-string #\"Lorem ipsum dolor sit amet, consectetur
1224       adipisicing elit, sed do eiusmod tempor incididunt ut labore
1225       et dolore magna aliqua.
1226
1227
1228       Ut enim ad minim veniam, quis nostrud exercitation ullamco
1229       laboris nisi ut aliquip ex ea commodo consequat.
1230
1231
1232       Excepteur sint occaecat cupidatat non proident, sunt in culpa
1233       qui officia deserunt mollit anim id est laborum\"
1234 }
1235 @end lilypond"
1236   (stack-lines DOWN 0.0 baseline-skip
1237                (wordwrap-string-internal-markup-list layout props #f arg)))
1238
1239 (define-markup-command (justify-string layout props arg)
1240   (string?)
1241   #:category align
1242   #:properties ((baseline-skip)
1243                 wordwrap-string-internal-markup-list)
1244   "Justify a string.  Paragraphs may be separated with double newlines
1245
1246 @lilypond[verbatim,quote]
1247 \\markup {
1248   \\override #'(line-width . 40)
1249   \\justify-string #\"Lorem ipsum dolor sit amet, consectetur
1250       adipisicing elit, sed do eiusmod tempor incididunt ut labore
1251       et dolore magna aliqua.
1252
1253
1254       Ut enim ad minim veniam, quis nostrud exercitation ullamco
1255       laboris nisi ut aliquip ex ea commodo consequat.
1256
1257
1258       Excepteur sint occaecat cupidatat non proident, sunt in culpa
1259       qui officia deserunt mollit anim id est laborum\"
1260 }
1261 @end lilypond"
1262   (stack-lines DOWN 0.0 baseline-skip
1263                (wordwrap-string-internal-markup-list layout props #t arg)))
1264
1265 (define-markup-command (wordwrap-field layout props symbol)
1266   (symbol?)
1267   #:category align
1268   "Wordwrap the data which has been assigned to @var{symbol}.
1269
1270 @lilypond[verbatim,quote]
1271 \\header {
1272   title = \"My title\"
1273   myText = \"Lorem ipsum dolor sit amet, consectetur adipisicing
1274     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
1275     aliqua.  Ut enim ad minim veniam, quis nostrud exercitation ullamco
1276     laboris nisi ut aliquip ex ea commodo consequat.\"
1277 }
1278
1279 \\paper {
1280   bookTitleMarkup = \\markup {
1281     \\column {
1282       \\fill-line { \\fromproperty #'header:title }
1283       \\null
1284       \\wordwrap-field #'header:myText
1285     }
1286   }
1287 }
1288
1289 \\markup {
1290   \\null
1291 }
1292 @end lilypond"
1293   (let* ((m (chain-assoc-get symbol props)))
1294     (if (string? m)
1295         (wordwrap-string-markup layout props m)
1296         empty-stencil)))
1297
1298 (define-markup-command (justify-field layout props symbol)
1299   (symbol?)
1300   #:category align
1301   "Justify the data which has been assigned to @var{symbol}.
1302
1303 @lilypond[verbatim,quote]
1304 \\header {
1305   title = \"My title\"
1306   myText = \"Lorem ipsum dolor sit amet, consectetur adipisicing
1307     elit, sed do eiusmod tempor incididunt ut labore et dolore magna
1308     aliqua.  Ut enim ad minim veniam, quis nostrud exercitation ullamco
1309     laboris nisi ut aliquip ex ea commodo consequat.\"
1310 }
1311
1312 \\paper {
1313   bookTitleMarkup = \\markup {
1314     \\column {
1315       \\fill-line { \\fromproperty #'header:title }
1316       \\null
1317       \\justify-field #'header:myText
1318     }
1319   }
1320 }
1321
1322 \\markup {
1323   \\null
1324 }
1325 @end lilypond"
1326   (let* ((m (chain-assoc-get symbol props)))
1327     (if (string? m)
1328         (justify-string-markup layout props m)
1329         empty-stencil)))
1330
1331 (define-markup-command (combine layout props arg1 arg2)
1332   (markup? markup?)
1333   #:category align
1334   "
1335 @cindex merging text
1336
1337 Print two markups on top of each other.
1338
1339 Note: @code{\\combine} cannot take a list of markups enclosed in
1340 curly braces as an argument; the follow example will not compile:
1341
1342 @example
1343 \\combine @{ a list @}
1344 @end example
1345
1346 @lilypond[verbatim,quote]
1347 \\markup {
1348   \\fontsize #5
1349   \\override #'(thickness . 2)
1350   \\combine
1351     \\draw-line #'(0 . 4)
1352     \\arrow-head #Y #DOWN ##f
1353 }
1354 @end lilypond"
1355   (let* ((s1 (interpret-markup layout props arg1))
1356          (s2 (interpret-markup layout props arg2)))
1357     (ly:stencil-add s1 s2)))
1358
1359 ;;
1360 ;; TODO: should extract baseline-skip from each argument somehow..
1361 ;;
1362 (define-markup-command (column layout props args)
1363   (markup-list?)
1364   #:category align
1365   #:properties ((baseline-skip))
1366   "
1367 @cindex stacking text in a column
1368
1369 Stack the markups in @var{args} vertically.  The property
1370 @code{baseline-skip} determines the space between markups
1371 in @var{args}.
1372
1373 @lilypond[verbatim,quote]
1374 \\markup {
1375   \\column {
1376     one
1377     two
1378     three
1379   }
1380 }
1381 @end lilypond"
1382   (let ((arg-stencils (interpret-markup-list layout props args)))
1383     (stack-lines -1 0.0 baseline-skip
1384                  (remove ly:stencil-empty? arg-stencils))))
1385
1386 (define-markup-command (dir-column layout props args)
1387   (markup-list?)
1388   #:category align
1389   #:properties ((direction)
1390                 (baseline-skip))
1391   "
1392 @cindex changing direction of text columns
1393
1394 Make a column of @var{args}, going up or down, depending on the
1395 setting of the @code{direction} layout property.
1396
1397 @lilypond[verbatim,quote]
1398 \\markup {
1399   \\override #`(direction . ,UP) {
1400     \\dir-column {
1401       going up
1402     }
1403   }
1404   \\hspace #1
1405   \\dir-column {
1406     going down
1407   }
1408   \\hspace #1
1409   \\override #'(direction . 1) {
1410     \\dir-column {
1411       going up
1412     }
1413   }
1414 }
1415 @end lilypond"
1416   (stack-lines (if (number? direction) direction -1)
1417                0.0
1418                baseline-skip
1419                (interpret-markup-list layout props args)))
1420
1421 (define (general-column align-dir baseline mols)
1422   "Stack @var{mols} vertically, aligned to  @var{align-dir} horizontally."
1423
1424   (let* ((aligned-mols (map (lambda (x) (ly:stencil-aligned-to x X align-dir)) mols)))
1425     (stack-lines -1 0.0 baseline aligned-mols)))
1426
1427 (define-markup-command (center-column layout props args)
1428   (markup-list?)
1429   #:category align
1430   #:properties ((baseline-skip))
1431   "
1432 @cindex centering a column of text
1433
1434 Put @code{args} in a centered column.
1435
1436 @lilypond[verbatim,quote]
1437 \\markup {
1438   \\center-column {
1439     one
1440     two
1441     three
1442   }
1443 }
1444 @end lilypond"
1445   (general-column CENTER baseline-skip (interpret-markup-list layout props args)))
1446
1447 (define-markup-command (left-column layout props args)
1448   (markup-list?)
1449   #:category align
1450   #:properties ((baseline-skip))
1451  "
1452 @cindex text columns, left-aligned
1453
1454 Put @code{args} in a left-aligned column.
1455
1456 @lilypond[verbatim,quote]
1457 \\markup {
1458   \\left-column {
1459     one
1460     two
1461     three
1462   }
1463 }
1464 @end lilypond"
1465   (general-column LEFT baseline-skip (interpret-markup-list layout props args)))
1466
1467 (define-markup-command (right-column layout props args)
1468   (markup-list?)
1469   #:category align
1470   #:properties ((baseline-skip))
1471  "
1472 @cindex text columns, right-aligned
1473
1474 Put @code{args} in a right-aligned column.
1475
1476 @lilypond[verbatim,quote]
1477 \\markup {
1478   \\right-column {
1479     one
1480     two
1481     three
1482   }
1483 }
1484 @end lilypond"
1485   (general-column RIGHT baseline-skip (interpret-markup-list layout props args)))
1486
1487 (define-markup-command (vcenter layout props arg)
1488   (markup?)
1489   #:category align
1490   "
1491 @cindex vertically centering text
1492
1493 Align @code{arg} to its Y@tie{}center.
1494
1495 @lilypond[verbatim,quote]
1496 \\markup {
1497   one
1498   \\vcenter
1499   two
1500   three
1501 }
1502 @end lilypond"
1503   (let* ((mol (interpret-markup layout props arg)))
1504     (ly:stencil-aligned-to mol Y CENTER)))
1505
1506 (define-markup-command (center-align layout props arg)
1507   (markup?)
1508   #:category align
1509   "
1510 @cindex horizontally centering text
1511
1512 Align @code{arg} to its X@tie{}center.
1513
1514 @lilypond[verbatim,quote]
1515 \\markup {
1516   \\column {
1517     one
1518     \\center-align
1519     two
1520     three
1521   }
1522 }
1523 @end lilypond"
1524   (let* ((mol (interpret-markup layout props arg)))
1525     (ly:stencil-aligned-to mol X CENTER)))
1526
1527 (define-markup-command (right-align layout props arg)
1528   (markup?)
1529   #:category align
1530   "
1531 @cindex right aligning text
1532
1533 Align @var{arg} on its right edge.
1534
1535 @lilypond[verbatim,quote]
1536 \\markup {
1537   \\column {
1538     one
1539     \\right-align
1540     two
1541     three
1542   }
1543 }
1544 @end lilypond"
1545   (let* ((m (interpret-markup layout props arg)))
1546     (ly:stencil-aligned-to m X RIGHT)))
1547
1548 (define-markup-command (left-align layout props arg)
1549   (markup?)
1550   #:category align
1551   "
1552 @cindex left aligning text
1553
1554 Align @var{arg} on its left edge.
1555
1556 @lilypond[verbatim,quote]
1557 \\markup {
1558   \\column {
1559     one
1560     \\left-align
1561     two
1562     three
1563   }
1564 }
1565 @end lilypond"
1566   (let* ((m (interpret-markup layout props arg)))
1567     (ly:stencil-aligned-to m X LEFT)))
1568
1569 (define-markup-command (general-align layout props axis dir arg)
1570   (integer? number? markup?)
1571   #:category align
1572   "
1573 @cindex controlling general text alignment
1574
1575 Align @var{arg} in @var{axis} direction to the @var{dir} side.
1576
1577 @lilypond[verbatim,quote]
1578 \\markup {
1579   \\column {
1580     one
1581     \\general-align #X #LEFT
1582     two
1583     three
1584     \\null
1585     one
1586     \\general-align #X #CENTER
1587     two
1588     three
1589     \\null
1590     \\line {
1591       one
1592       \\general-align #Y #UP
1593       two
1594       three
1595     }
1596     \\null
1597     \\line {
1598       one
1599       \\general-align #Y #3.2
1600       two
1601       three
1602     }
1603   }
1604 }
1605 @end lilypond"
1606   (let* ((m (interpret-markup layout props arg)))
1607     (ly:stencil-aligned-to m axis dir)))
1608
1609 (define-markup-command (halign layout props dir arg)
1610   (number? markup?)
1611   #:category align
1612   "
1613 @cindex setting horizontal text alignment
1614
1615 Set horizontal alignment.  If @var{dir} is @code{-1}, then it is
1616 left-aligned, while @code{+1} is right.  Values in between interpolate
1617 alignment accordingly.
1618
1619 @lilypond[verbatim,quote]
1620 \\markup {
1621   \\column {
1622     one
1623     \\halign #LEFT
1624     two
1625     three
1626     \\null
1627     one
1628     \\halign #CENTER
1629     two
1630     three
1631     \\null
1632     one
1633     \\halign #RIGHT
1634     two
1635     three
1636     \\null
1637     one
1638     \\halign #-5
1639     two
1640     three
1641   }
1642 }
1643 @end lilypond"
1644   (let* ((m (interpret-markup layout props arg)))
1645     (ly:stencil-aligned-to m X dir)))
1646
1647 (define-markup-command (with-dimensions layout props x y arg)
1648   (number-pair? number-pair? markup?)
1649   #:category other
1650   "
1651 @cindex setting extent of text objects
1652
1653 Set the dimensions of @var{arg} to @var{x} and@tie{}@var{y}."
1654   (let* ((m (interpret-markup layout props arg)))
1655     (ly:make-stencil (ly:stencil-expr m) x y)))
1656
1657 (define-markup-command (pad-around layout props amount arg)
1658   (number? markup?)
1659   #:category align
1660   "Add padding @var{amount} all around @var{arg}.
1661
1662 @lilypond[verbatim,quote]
1663 \\markup {
1664   \\box {
1665     default
1666   }
1667   \\hspace #2
1668   \\box {
1669     \\pad-around #0.5 {
1670       padded
1671     }
1672   }
1673 }
1674 @end lilypond"
1675   (let* ((m (interpret-markup layout props arg))
1676          (x (ly:stencil-extent m X))
1677          (y (ly:stencil-extent m Y)))
1678     (ly:make-stencil (ly:stencil-expr m)
1679                      (interval-widen x amount)
1680                      (interval-widen y amount))))
1681
1682 (define-markup-command (pad-x layout props amount arg)
1683   (number? markup?)
1684   #:category align
1685   "
1686 @cindex padding text horizontally
1687
1688 Add padding @var{amount} around @var{arg} in the X@tie{}direction.
1689
1690 @lilypond[verbatim,quote]
1691 \\markup {
1692   \\box {
1693     default
1694   }
1695   \\hspace #4
1696   \\box {
1697     \\pad-x #2 {
1698       padded
1699     }
1700   }
1701 }
1702 @end lilypond"
1703   (let* ((m (interpret-markup layout props arg))
1704          (x (ly:stencil-extent m X))
1705          (y (ly:stencil-extent m Y)))
1706     (ly:make-stencil (ly:stencil-expr m)
1707                      (interval-widen x amount)
1708                      y)))
1709
1710 (define-markup-command (put-adjacent layout props axis dir arg1 arg2)
1711   (integer? ly:dir? markup? markup?)
1712   #:category align
1713   "Put @var{arg2} next to @var{arg1}, without moving @var{arg1}."
1714   (let ((m1 (interpret-markup layout props arg1))
1715         (m2 (interpret-markup layout props arg2)))
1716     (ly:stencil-combine-at-edge m1 axis dir m2 0.0)))
1717
1718 (define-markup-command (transparent layout props arg)
1719   (markup?)
1720   #:category other
1721   "Make @var{arg} transparent.
1722
1723 @lilypond[verbatim,quote]
1724 \\markup {
1725   \\transparent {
1726     invisible text
1727   }
1728 }
1729 @end lilypond"
1730   (let* ((m (interpret-markup layout props arg))
1731          (x (ly:stencil-extent m X))
1732          (y (ly:stencil-extent m Y)))
1733     (ly:make-stencil "" x y)))
1734
1735 (define-markup-command (pad-to-box layout props x-ext y-ext arg)
1736   (number-pair? number-pair? markup?)
1737   #:category align
1738   "Make @var{arg} take at least @var{x-ext}, @var{y-ext} space.
1739
1740 @lilypond[verbatim,quote]
1741 \\markup {
1742   \\box {
1743     default
1744   }
1745   \\hspace #4
1746   \\box {
1747     \\pad-to-box #'(0 . 10) #'(0 . 3) {
1748       padded
1749     }
1750   }
1751 }
1752 @end lilypond"
1753   (let* ((m (interpret-markup layout props arg))
1754          (x (ly:stencil-extent m X))
1755          (y (ly:stencil-extent m Y)))
1756     (ly:make-stencil (ly:stencil-expr m)
1757                      (interval-union x-ext x)
1758                      (interval-union y-ext y))))
1759
1760 (define-markup-command (hcenter-in layout props length arg)
1761   (number? markup?)
1762   #:category align
1763   "Center @var{arg} horizontally within a box of extending
1764 @var{length}/2 to the left and right.
1765
1766 @lilypond[quote,verbatim]
1767 \\new StaffGroup <<
1768   \\new Staff {
1769     \\set Staff.instrumentName = \\markup {
1770       \\hcenter-in #12
1771       Oboe
1772     }
1773     c''1
1774   }
1775   \\new Staff {
1776     \\set Staff.instrumentName = \\markup {
1777       \\hcenter-in #12
1778       Bassoon
1779     }
1780     \\clef tenor
1781     c'1
1782   }
1783 >>
1784 @end lilypond"
1785   (interpret-markup layout props
1786                     (make-pad-to-box-markup
1787                      (cons (/ length -2) (/ length 2))
1788                      '(0 . 0)
1789                      (make-center-align-markup arg))))
1790
1791 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1792 ;; property
1793 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1794
1795 (define-markup-command (fromproperty layout props symbol)
1796   (symbol?)
1797   #:category other
1798   "Read the @var{symbol} from property settings, and produce a stencil
1799 from the markup contained within.  If @var{symbol} is not defined, it
1800 returns an empty markup.
1801
1802 @lilypond[verbatim,quote]
1803 \\header {
1804   myTitle = \"myTitle\"
1805   title = \\markup {
1806     from
1807     \\italic
1808     \\fromproperty #'header:myTitle
1809   }
1810 }
1811 \\markup {
1812   \\null
1813 }
1814 @end lilypond"
1815   (let ((m (chain-assoc-get symbol props)))
1816     (if (markup? m)
1817         (interpret-markup layout props m)
1818         empty-stencil)))
1819
1820 (define-markup-command (on-the-fly layout props procedure arg)
1821   (symbol? markup?)
1822   #:category other
1823   "Apply the @var{procedure} markup command to @var{arg}.
1824 @var{procedure} should take a single argument."
1825   (let ((anonymous-with-signature (lambda (layout props arg) (procedure layout props arg))))
1826     (set-object-property! anonymous-with-signature
1827                           'markup-signature
1828                           (list markup?))
1829     (interpret-markup layout props (list anonymous-with-signature arg))))
1830
1831 (define-markup-command (footnote layout props mkup note)
1832   (markup? markup?)
1833   #:category other
1834   "Have footnote @var{note} act as an annotation to the markup @var{mkup}."
1835   (ly:stencil-combine-at-edge
1836     (interpret-markup layout props mkup)
1837     X
1838     RIGHT
1839     (ly:make-stencil
1840       `(footnote ,(interpret-markup layout props note))
1841       '(0 . 0)
1842       '(0 . 0))
1843     0.0))
1844
1845 (define-markup-command (override layout props new-prop arg)
1846   (pair? markup?)
1847   #:category other
1848   "
1849 @cindex overriding properties within text markup
1850
1851 Add the argument @var{new-prop} to the property list.  Properties
1852 may be any property supported by @rinternals{font-interface},
1853 @rinternals{text-interface} and
1854 @rinternals{instrument-specific-markup-interface}.
1855
1856 @lilypond[verbatim,quote]
1857 \\markup {
1858   \\line {
1859     \\column {
1860       default
1861       baseline-skip
1862     }
1863     \\hspace #2
1864     \\override #'(baseline-skip . 4) {
1865       \\column {
1866         increased
1867         baseline-skip
1868       }
1869     }
1870   }
1871 }
1872 @end lilypond"
1873   (interpret-markup layout (cons (list new-prop) props) arg))
1874
1875 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1876 ;; files
1877 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1878
1879 (define-markup-command (verbatim-file layout props name)
1880   (string?)
1881   #:category other
1882   "Read the contents of file @var{name}, and include it verbatim.
1883
1884 @lilypond[verbatim,quote]
1885 \\markup {
1886   \\verbatim-file #\"simple.ly\"
1887 }
1888 @end lilypond"
1889   (interpret-markup layout props
1890                     (if  (ly:get-option 'safe)
1891                          "verbatim-file disabled in safe mode"
1892                          (let* ((str (ly:gulp-file name))
1893                                 (lines (string-split str #\nl)))
1894                            (make-typewriter-markup
1895                             (make-column-markup lines))))))
1896
1897 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1898 ;; fonts.
1899 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1900
1901
1902 (define-markup-command (smaller layout props arg)
1903   (markup?)
1904   #:category font
1905   "Decrease the font size relative to the current setting.
1906
1907 @lilypond[verbatim,quote]
1908 \\markup {
1909   \\fontsize #3.5 {
1910     some large text
1911     \\hspace #2
1912     \\smaller {
1913       a bit smaller
1914     }
1915     \\hspace #2
1916     more large text
1917   }
1918 }
1919 @end lilypond"
1920   (interpret-markup layout props
1921    `(,fontsize-markup -1 ,arg)))
1922
1923 (define-markup-command (larger layout props arg)
1924   (markup?)
1925   #:category font
1926   "Increase the font size relative to the current setting.
1927
1928 @lilypond[verbatim,quote]
1929 \\markup {
1930   default
1931   \\hspace #2
1932   \\larger
1933   larger
1934 }
1935 @end lilypond"
1936   (interpret-markup layout props
1937    `(,fontsize-markup 1 ,arg)))
1938
1939 (define-markup-command (finger layout props arg)
1940   (markup?)
1941   #:category font
1942   "Set @var{arg} as small numbers.
1943
1944 @lilypond[verbatim,quote]
1945 \\markup {
1946   \\finger {
1947     1 2 3 4 5
1948   }
1949 }
1950 @end lilypond"
1951   (interpret-markup layout
1952                     (cons '((font-size . -5) (font-encoding . fetaText)) props)
1953                     arg))
1954
1955 (define-markup-command (abs-fontsize layout props size arg)
1956   (number? markup?)
1957   #:category font
1958   "Use @var{size} as the absolute font size to display @var{arg}.
1959 Adjusts @code{baseline-skip} and @code{word-space} accordingly.
1960
1961 @lilypond[verbatim,quote]
1962 \\markup {
1963   default text font size
1964   \\hspace #2
1965   \\abs-fontsize #16 { text font size 16 }
1966   \\hspace #2
1967   \\abs-fontsize #12 { text font size 12 }
1968 }
1969 @end lilypond"
1970   (let* ((ref-size (ly:output-def-lookup layout 'text-font-size 12))
1971          (text-props (list (ly:output-def-lookup layout 'text-font-defaults)))
1972          (ref-word-space (chain-assoc-get 'word-space text-props 0.6))
1973          (ref-baseline (chain-assoc-get 'baseline-skip text-props 3))
1974          (magnification (/ size ref-size)))
1975     (interpret-markup layout
1976                       (cons `((baseline-skip . ,(* magnification ref-baseline))
1977                               (word-space . ,(* magnification ref-word-space))
1978                               (font-size . ,(magnification->font-size magnification)))
1979                             props)
1980                       arg)))
1981
1982 (define-markup-command (fontsize layout props increment arg)
1983   (number? markup?)
1984   #:category font
1985   #:properties ((font-size 0)
1986                 (word-space 1)
1987                 (baseline-skip 2))
1988   "Add @var{increment} to the font-size.  Adjusts @code{baseline-skip}
1989 accordingly.
1990
1991 @lilypond[verbatim,quote]
1992 \\markup {
1993   default
1994   \\hspace #2
1995   \\fontsize #-1.5
1996   smaller
1997 }
1998 @end lilypond"
1999   (let ((entries (list
2000                   (cons 'baseline-skip (* baseline-skip (magstep increment)))
2001                   (cons 'word-space (* word-space (magstep increment)))
2002                   (cons 'font-size (+ font-size increment)))))
2003     (interpret-markup layout (cons entries props) arg)))
2004
2005 (define-markup-command (magnify layout props sz arg)
2006   (number? markup?)
2007   #:category font
2008   "
2009 @cindex magnifying text
2010
2011 Set the font magnification for its argument.  In the following
2012 example, the middle@tie{}A is 10% larger:
2013
2014 @example
2015 A \\magnify #1.1 @{ A @} A
2016 @end example
2017
2018 Note: Magnification only works if a font name is explicitly selected.
2019 Use @code{\\fontsize} otherwise.
2020
2021 @lilypond[verbatim,quote]
2022 \\markup {
2023   default
2024   \\hspace #2
2025   \\magnify #1.5 {
2026     50% larger
2027   }
2028 }
2029 @end lilypond"
2030   (interpret-markup
2031    layout
2032    (prepend-alist-chain 'font-size (magnification->font-size sz) props)
2033    arg))
2034
2035 (define-markup-command (bold layout props arg)
2036   (markup?)
2037   #:category font
2038   "Switch to bold font-series.
2039
2040 @lilypond[verbatim,quote]
2041 \\markup {
2042   default
2043   \\hspace #2
2044   \\bold
2045   bold
2046 }
2047 @end lilypond"
2048   (interpret-markup layout (prepend-alist-chain 'font-series 'bold props) arg))
2049
2050 (define-markup-command (sans layout props arg)
2051   (markup?)
2052   #:category font
2053   "Switch to the sans serif font family.
2054
2055 @lilypond[verbatim,quote]
2056 \\markup {
2057   default
2058   \\hspace #2
2059   \\sans {
2060     sans serif
2061   }
2062 }
2063 @end lilypond"
2064   (interpret-markup layout (prepend-alist-chain 'font-family 'sans props) arg))
2065
2066 (define-markup-command (number layout props arg)
2067   (markup?)
2068   #:category font
2069   "Set font family to @code{number}, which yields the font used for
2070 time signatures and fingerings.  This font contains numbers and
2071 some punctuation; it has no letters.
2072
2073 @lilypond[verbatim,quote]
2074 \\markup {
2075   \\number {
2076     0 1 2 3 4 5 6 7 8 9 . ,
2077   }
2078 }
2079 @end lilypond"
2080   (interpret-markup layout (prepend-alist-chain 'font-encoding 'fetaText props) arg))
2081
2082 (define-markup-command (roman layout props arg)
2083   (markup?)
2084   #:category font
2085   "Set font family to @code{roman}.
2086
2087 @lilypond[verbatim,quote]
2088 \\markup {
2089   \\sans \\bold {
2090     sans serif, bold
2091     \\hspace #2
2092     \\roman {
2093       text in roman font family
2094     }
2095     \\hspace #2
2096     return to sans
2097   }
2098 }
2099 @end lilypond"
2100   (interpret-markup layout (prepend-alist-chain 'font-family 'roman props) arg))
2101
2102 (define-markup-command (huge layout props arg)
2103   (markup?)
2104   #:category font
2105   "Set font size to +2.
2106
2107 @lilypond[verbatim,quote]
2108 \\markup {
2109   default
2110   \\hspace #2
2111   \\huge
2112   huge
2113 }
2114 @end lilypond"
2115   (interpret-markup layout (prepend-alist-chain 'font-size 2 props) arg))
2116
2117 (define-markup-command (large layout props arg)
2118   (markup?)
2119   #:category font
2120   "Set font size to +1.
2121
2122 @lilypond[verbatim,quote]
2123 \\markup {
2124   default
2125   \\hspace #2
2126   \\large
2127   large
2128 }
2129 @end lilypond"
2130   (interpret-markup layout (prepend-alist-chain 'font-size 1 props) arg))
2131
2132 (define-markup-command (normalsize layout props arg)
2133   (markup?)
2134   #:category font
2135   "Set font size to default.
2136
2137 @lilypond[verbatim,quote]
2138 \\markup {
2139   \\teeny {
2140     this is very small
2141     \\hspace #2
2142     \\normalsize {
2143       normal size
2144     }
2145     \\hspace #2
2146     teeny again
2147   }
2148 }
2149 @end lilypond"
2150   (interpret-markup layout (prepend-alist-chain 'font-size 0 props) arg))
2151
2152 (define-markup-command (small layout props arg)
2153   (markup?)
2154   #:category font
2155   "Set font size to -1.
2156
2157 @lilypond[verbatim,quote]
2158 \\markup {
2159   default
2160   \\hspace #2
2161   \\small
2162   small
2163 }
2164 @end lilypond"
2165   (interpret-markup layout (prepend-alist-chain 'font-size -1 props) arg))
2166
2167 (define-markup-command (tiny layout props arg)
2168   (markup?)
2169   #:category font
2170   "Set font size to -2.
2171
2172 @lilypond[verbatim,quote]
2173 \\markup {
2174   default
2175   \\hspace #2
2176   \\tiny
2177   tiny
2178 }
2179 @end lilypond"
2180   (interpret-markup layout (prepend-alist-chain 'font-size -2 props) arg))
2181
2182 (define-markup-command (teeny layout props arg)
2183   (markup?)
2184   #:category font
2185   "Set font size to -3.
2186
2187 @lilypond[verbatim,quote]
2188 \\markup {
2189   default
2190   \\hspace #2
2191   \\teeny
2192   teeny
2193 }
2194 @end lilypond"
2195   (interpret-markup layout (prepend-alist-chain 'font-size -3 props) arg))
2196
2197 (define-markup-command (fontCaps layout props arg)
2198   (markup?)
2199   #:category font
2200   "Set @code{font-shape} to @code{caps}
2201
2202 Note: @code{\\fontCaps} requires the installation and selection of
2203 fonts which support the @code{caps} font shape."
2204   (interpret-markup layout (prepend-alist-chain 'font-shape 'caps props) arg))
2205
2206 ;; Poor man's caps
2207 (define-markup-command (smallCaps layout props arg)
2208   (markup?)
2209   #:category font
2210   "Emit @var{arg} as small caps.
2211
2212 Note: @code{\\smallCaps} does not support accented characters.
2213
2214 @lilypond[verbatim,quote]
2215 \\markup {
2216   default
2217   \\hspace #2
2218   \\smallCaps {
2219     Text in small caps
2220   }
2221 }
2222 @end lilypond"
2223   (define (char-list->markup chars lower)
2224     (let ((final-string (string-upcase (reverse-list->string chars))))
2225       (if lower
2226           (markup #:fontsize -2 final-string)
2227           final-string)))
2228   (define (make-small-caps rest-chars currents current-is-lower prev-result)
2229     (if (null? rest-chars)
2230         (make-concat-markup
2231           (reverse! (cons (char-list->markup currents current-is-lower)
2232                           prev-result)))
2233         (let* ((ch (car rest-chars))
2234                (is-lower (char-lower-case? ch)))
2235           (if (or (and current-is-lower is-lower)
2236                   (and (not current-is-lower) (not is-lower)))
2237               (make-small-caps (cdr rest-chars)
2238                                (cons ch currents)
2239                                is-lower
2240                                prev-result)
2241               (make-small-caps (cdr rest-chars)
2242                                (list ch)
2243                                is-lower
2244                                (if (null? currents)
2245                                    prev-result
2246                                    (cons (char-list->markup
2247                                             currents current-is-lower)
2248                                          prev-result)))))))
2249   (interpret-markup layout props
2250     (if (string? arg)
2251         (make-small-caps (string->list arg) (list) #f (list))
2252         arg)))
2253
2254 (define-markup-command (caps layout props arg)
2255   (markup?)
2256   #:category font
2257   "Copy of the @code{\\smallCaps} command.
2258
2259 @lilypond[verbatim,quote]
2260 \\markup {
2261   default
2262   \\hspace #2
2263   \\caps {
2264     Text in small caps
2265   }
2266 }
2267 @end lilypond"
2268   (interpret-markup layout props (make-smallCaps-markup arg)))
2269
2270 (define-markup-command (dynamic layout props arg)
2271   (markup?)
2272   #:category font
2273   "Use the dynamic font.  This font only contains @b{s}, @b{f}, @b{m},
2274 @b{z}, @b{p}, and @b{r}.  When producing phrases, like
2275 @q{pi@`{u}@tie{}@b{f}}, the normal words (like @q{pi@`{u}}) should be
2276 done in a different font.  The recommended font for this is bold and italic.
2277 @lilypond[verbatim,quote]
2278 \\markup {
2279   \\dynamic {
2280     sfzp
2281   }
2282 }
2283 @end lilypond"
2284   (interpret-markup
2285    layout (prepend-alist-chain 'font-encoding 'fetaText props) arg))
2286
2287 (define-markup-command (text layout props arg)
2288   (markup?)
2289   #:category font
2290   "Use a text font instead of music symbol or music alphabet font.
2291
2292 @lilypond[verbatim,quote]
2293 \\markup {
2294   \\number {
2295     1, 2,
2296     \\text {
2297       three, four,
2298     }
2299     5
2300   }
2301 }
2302 @end lilypond"
2303
2304   ;; ugh - latin1
2305   (interpret-markup layout (prepend-alist-chain 'font-encoding 'latin1 props)
2306                     arg))
2307
2308 (define-markup-command (italic layout props arg)
2309   (markup?)
2310   #:category font
2311   "Use italic @code{font-shape} for @var{arg}.
2312
2313 @lilypond[verbatim,quote]
2314 \\markup {
2315   default
2316   \\hspace #2
2317   \\italic
2318   italic
2319 }
2320 @end lilypond"
2321   (interpret-markup layout (prepend-alist-chain 'font-shape 'italic props) arg))
2322
2323 (define-markup-command (typewriter layout props arg)
2324   (markup?)
2325   #:category font
2326   "Use @code{font-family} typewriter for @var{arg}.
2327
2328 @lilypond[verbatim,quote]
2329 \\markup {
2330   default
2331   \\hspace #2
2332   \\typewriter
2333   typewriter
2334 }
2335 @end lilypond"
2336   (interpret-markup
2337    layout (prepend-alist-chain 'font-family 'typewriter props) arg))
2338
2339 (define-markup-command (upright layout props arg)
2340   (markup?)
2341   #:category font
2342   "Set @code{font-shape} to @code{upright}.  This is the opposite
2343 of @code{italic}.
2344
2345 @lilypond[verbatim,quote]
2346 \\markup {
2347   \\italic {
2348     italic text
2349     \\hspace #2
2350     \\upright {
2351       upright text
2352     }
2353     \\hspace #2
2354     italic again
2355   }
2356 }
2357 @end lilypond"
2358   (interpret-markup
2359    layout (prepend-alist-chain 'font-shape 'upright props) arg))
2360
2361 (define-markup-command (medium layout props arg)
2362   (markup?)
2363   #:category font
2364   "Switch to medium font-series (in contrast to bold).
2365
2366 @lilypond[verbatim,quote]
2367 \\markup {
2368   \\bold {
2369     some bold text
2370     \\hspace #2
2371     \\medium {
2372       medium font series
2373     }
2374     \\hspace #2
2375     bold again
2376   }
2377 }
2378 @end lilypond"
2379   (interpret-markup layout (prepend-alist-chain 'font-series 'medium props)
2380                     arg))
2381
2382 (define-markup-command (normal-text layout props arg)
2383   (markup?)
2384   #:category font
2385   "Set all font related properties (except the size) to get the default
2386 normal text font, no matter what font was used earlier.
2387
2388 @lilypond[verbatim,quote]
2389 \\markup {
2390   \\huge \\bold \\sans \\caps {
2391     Some text with font overrides
2392     \\hspace #2
2393     \\normal-text {
2394       Default text, same font-size
2395     }
2396     \\hspace #2
2397     More text as before
2398   }
2399 }
2400 @end lilypond"
2401   ;; ugh - latin1
2402   (interpret-markup layout
2403                     (cons '((font-family . roman) (font-shape . upright)
2404                             (font-series . medium) (font-encoding . latin1))
2405                           props)
2406                     arg))
2407
2408 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2409 ;; symbols.
2410 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2411
2412 (define-markup-command (musicglyph layout props glyph-name)
2413   (string?)
2414   #:category music
2415   "@var{glyph-name} is converted to a musical symbol; for example,
2416 @code{\\musicglyph #\"accidentals.natural\"} selects the natural sign from
2417 the music font.  See @ruser{The Feta font} for a complete listing of
2418 the possible glyphs.
2419
2420 @lilypond[verbatim,quote]
2421 \\markup {
2422   \\musicglyph #\"f\"
2423   \\musicglyph #\"rests.2\"
2424   \\musicglyph #\"clefs.G_change\"
2425 }
2426 @end lilypond"
2427   (let* ((font (ly:paper-get-font layout
2428                                   (cons '((font-encoding . fetaMusic)
2429                                           (font-name . #f))
2430
2431                                                  props)))
2432          (glyph (ly:font-get-glyph font glyph-name)))
2433     (if (null? (ly:stencil-expr glyph))
2434         (ly:warning (_ "Cannot find glyph ~a") glyph-name))
2435
2436     glyph))
2437
2438 (define-markup-command (doublesharp layout props)
2439   ()
2440   #:category music
2441   "Draw a double sharp symbol.
2442
2443 @lilypond[verbatim,quote]
2444 \\markup {
2445   \\doublesharp
2446 }
2447 @end lilypond"
2448   (interpret-markup layout props (markup #:musicglyph (assoc-get 1 standard-alteration-glyph-name-alist ""))))
2449
2450 (define-markup-command (sesquisharp layout props)
2451   ()
2452   #:category music
2453   "Draw a 3/2 sharp symbol.
2454
2455 @lilypond[verbatim,quote]
2456 \\markup {
2457   \\sesquisharp
2458 }
2459 @end lilypond"
2460   (interpret-markup layout props (markup #:musicglyph (assoc-get 3/4 standard-alteration-glyph-name-alist ""))))
2461
2462 (define-markup-command (sharp layout props)
2463   ()
2464   #:category music
2465   "Draw a sharp symbol.
2466
2467 @lilypond[verbatim,quote]
2468 \\markup {
2469   \\sharp
2470 }
2471 @end lilypond"
2472   (interpret-markup layout props (markup #:musicglyph (assoc-get 1/2 standard-alteration-glyph-name-alist ""))))
2473
2474 (define-markup-command (semisharp layout props)
2475   ()
2476   #:category music
2477   "Draw a semisharp symbol.
2478
2479 @lilypond[verbatim,quote]
2480 \\markup {
2481   \\semisharp
2482 }
2483 @end lilypond"
2484   (interpret-markup layout props (markup #:musicglyph (assoc-get 1/4 standard-alteration-glyph-name-alist ""))))
2485
2486 (define-markup-command (natural layout props)
2487   ()
2488   #:category music
2489   "Draw a natural symbol.
2490
2491 @lilypond[verbatim,quote]
2492 \\markup {
2493   \\natural
2494 }
2495 @end lilypond"
2496   (interpret-markup layout props (markup #:musicglyph (assoc-get 0 standard-alteration-glyph-name-alist ""))))
2497
2498 (define-markup-command (semiflat layout props)
2499   ()
2500   #:category music
2501   "Draw a semiflat symbol.
2502
2503 @lilypond[verbatim,quote]
2504 \\markup {
2505   \\semiflat
2506 }
2507 @end lilypond"
2508   (interpret-markup layout props (markup #:musicglyph (assoc-get -1/4 standard-alteration-glyph-name-alist ""))))
2509
2510 (define-markup-command (flat layout props)
2511   ()
2512   #:category music
2513   "Draw a flat symbol.
2514
2515 @lilypond[verbatim,quote]
2516 \\markup {
2517   \\flat
2518 }
2519 @end lilypond"
2520   (interpret-markup layout props (markup #:musicglyph (assoc-get -1/2 standard-alteration-glyph-name-alist ""))))
2521
2522 (define-markup-command (sesquiflat layout props)
2523   ()
2524   #:category music
2525   "Draw a 3/2 flat symbol.
2526
2527 @lilypond[verbatim,quote]
2528 \\markup {
2529   \\sesquiflat
2530 }
2531 @end lilypond"
2532   (interpret-markup layout props (markup #:musicglyph (assoc-get -3/4 standard-alteration-glyph-name-alist ""))))
2533
2534 (define-markup-command (doubleflat layout props)
2535   ()
2536   #:category music
2537   "Draw a double flat symbol.
2538
2539 @lilypond[verbatim,quote]
2540 \\markup {
2541   \\doubleflat
2542 }
2543 @end lilypond"
2544   (interpret-markup layout props (markup #:musicglyph (assoc-get -1 standard-alteration-glyph-name-alist ""))))
2545
2546 (define-markup-command (with-color layout props color arg)
2547   (color? markup?)
2548   #:category other
2549   "
2550 @cindex coloring text
2551
2552 Draw @var{arg} in color specified by @var{color}.
2553
2554 @lilypond[verbatim,quote]
2555 \\markup {
2556   \\with-color #red
2557   red
2558   \\hspace #2
2559   \\with-color #green
2560   green
2561   \\hspace #2
2562   \\with-color #blue
2563   blue
2564 }
2565 @end lilypond"
2566   (let ((stil (interpret-markup layout props arg)))
2567     (ly:make-stencil (list 'color color (ly:stencil-expr stil))
2568                      (ly:stencil-extent stil X)
2569                      (ly:stencil-extent stil Y))))
2570
2571 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2572 ;; glyphs
2573 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2574
2575 (define-markup-command (arrow-head layout props axis dir filled)
2576   (integer? ly:dir? boolean?)
2577   #:category graphic
2578   "Produce an arrow head in specified direction and axis.
2579 Use the filled head if @var{filled} is specified.
2580 @lilypond[verbatim,quote]
2581 \\markup {
2582   \\fontsize #5 {
2583     \\general-align #Y #DOWN {
2584       \\arrow-head #Y #UP ##t
2585       \\arrow-head #Y #DOWN ##f
2586       \\hspace #2
2587       \\arrow-head #X #RIGHT ##f
2588       \\arrow-head #X #LEFT ##f
2589     }
2590   }
2591 }
2592 @end lilypond"
2593   (let*
2594       ((name (format "arrowheads.~a.~a~a"
2595                      (if filled
2596                          "close"
2597                          "open")
2598                      axis
2599                      dir)))
2600     (ly:font-get-glyph
2601      (ly:paper-get-font layout (cons '((font-encoding . fetaMusic))
2602                                      props))
2603      name)))
2604
2605 (define-markup-command (lookup layout props glyph-name)
2606   (string?)
2607   #:category other
2608   "Lookup a glyph by name.
2609
2610 @lilypond[verbatim,quote]
2611 \\markup {
2612   \\override #'(font-encoding . fetaBraces) {
2613     \\lookup #\"brace200\"
2614     \\hspace #2
2615     \\rotate #180
2616     \\lookup #\"brace180\"
2617   }
2618 }
2619 @end lilypond"
2620   (ly:font-get-glyph (ly:paper-get-font layout props)
2621                      glyph-name))
2622
2623 (define-markup-command (char layout props num)
2624   (integer?)
2625   #:category other
2626   "Produce a single character.  Characters encoded in hexadecimal
2627 format require the prefix @code{#x}.
2628
2629 @lilypond[verbatim,quote]
2630 \\markup {
2631   \\char #65 \\char ##x00a9
2632 }
2633 @end lilypond"
2634   (ly:text-interface::interpret-markup layout props (ly:wide-char->utf-8 num)))
2635
2636 (define number->mark-letter-vector (make-vector 25 #\A))
2637
2638 (do ((i 0 (1+ i))
2639      (j 0 (1+ j)))
2640     ((>= i 26))
2641   (if (= i (- (char->integer #\I) (char->integer #\A)))
2642       (set! i (1+ i)))
2643   (vector-set! number->mark-letter-vector j
2644                (integer->char (+ i (char->integer #\A)))))
2645
2646 (define number->mark-alphabet-vector (list->vector
2647   (map (lambda (i) (integer->char (+ i (char->integer #\A)))) (iota 26))))
2648
2649 (define (number->markletter-string vec n)
2650   "Double letters for big marks."
2651   (let* ((lst (vector-length vec)))
2652
2653     (if (>= n lst)
2654         (string-append (number->markletter-string vec (1- (quotient n lst)))
2655                        (number->markletter-string vec (remainder n lst)))
2656         (make-string 1 (vector-ref vec n)))))
2657
2658 (define-markup-command (markletter layout props num)
2659   (integer?)
2660   #:category other
2661   "Make a markup letter for @var{num}.  The letters start with A to@tie{}Z
2662 (skipping letter@tie{}I), and continue with double letters.
2663
2664 @lilypond[verbatim,quote]
2665 \\markup {
2666   \\markletter #8
2667   \\hspace #2
2668   \\markletter #26
2669 }
2670 @end lilypond"
2671   (ly:text-interface::interpret-markup layout props
2672     (number->markletter-string number->mark-letter-vector num)))
2673
2674 (define-markup-command (markalphabet layout props num)
2675   (integer?)
2676   #:category other
2677    "Make a markup letter for @var{num}.  The letters start with A to@tie{}Z
2678 and continue with double letters.
2679
2680 @lilypond[verbatim,quote]
2681 \\markup {
2682   \\markalphabet #8
2683   \\hspace #2
2684   \\markalphabet #26
2685 }
2686 @end lilypond"
2687    (ly:text-interface::interpret-markup layout props
2688      (number->markletter-string number->mark-alphabet-vector num)))
2689
2690 (define-public (horizontal-slash-interval num forward number-interval mag)
2691   (if forward
2692     (cond ;((= num 6) (interval-widen number-interval (* mag 0.5)))
2693           ;((= num 5) (interval-widen number-interval (* mag 0.5)))
2694           (else (interval-widen number-interval (* mag 0.25))))
2695     (cond ((= num 6) (interval-widen number-interval (* mag 0.5)))
2696           ;((= num 5) (interval-widen number-interval (* mag 0.5)))
2697           (else (interval-widen number-interval (* mag 0.25))))
2698   ))
2699
2700 (define-public (adjust-slash-stencil num forward stencil mag)
2701   (if forward
2702     (cond ((= num 2)
2703               (ly:stencil-translate stencil (cons (* mag -0.00) (* mag 0.2))))
2704           ((= num 3)
2705               (ly:stencil-translate stencil (cons (* mag -0.00) (* mag 0.2))))
2706           ;((= num 5)
2707               ;(ly:stencil-translate stencil (cons (* mag -0.00) (* mag -0.07))))
2708           ;((= num 7)
2709           ;    (ly:stencil-translate stencil (cons (* mag -0.00) (* mag -0.15))))
2710           (else stencil))
2711     (cond ((= num 6)
2712               (ly:stencil-translate stencil (cons (* mag -0.00) (* mag 0.15))))
2713           ;((= num 8)
2714           ;    (ly:stencil-translate stencil (cons (* mag -0.00) (* mag -0.15))))
2715           (else stencil))
2716   )
2717 )
2718
2719 (define (slashed-digit-internal layout props num forward font-size thickness)
2720   (let* ((mag (magstep font-size))
2721          (thickness (* mag
2722                        (ly:output-def-lookup layout 'line-thickness)
2723                        thickness))
2724          ; backward slashes might use slope and point in the other direction!
2725          (dy (* mag (if forward 0.4 -0.4)))
2726          (number-stencil (interpret-markup layout
2727                                            (prepend-alist-chain 'font-encoding 'fetaText props)
2728                                            (number->string num)))
2729          (num-x (horizontal-slash-interval num forward (ly:stencil-extent number-stencil X) mag))
2730          (center (interval-center (ly:stencil-extent number-stencil Y)))
2731          ; Use the real extents of the slash, not the whole number, because we
2732          ; might translate the slash later on!
2733          (num-y (interval-widen (cons center center) (abs dy)))
2734          (is-sane (and (interval-sane? num-x) (interval-sane? num-y)))
2735          (slash-stencil (if is-sane
2736                             (make-line-stencil thickness
2737                                          (car num-x) (- (interval-center num-y) dy)
2738                                          (cdr num-x) (+ (interval-center num-y) dy))
2739                             #f)))
2740     (if (ly:stencil? slash-stencil)
2741       (begin
2742         ; for some numbers we need to shift the slash/backslash up or down to make
2743         ; the slashed digit look better
2744         (set! slash-stencil (adjust-slash-stencil num forward slash-stencil mag))
2745         (set! number-stencil
2746           (ly:stencil-add number-stencil slash-stencil)))
2747       (ly:warning "Unable to create slashed digit ~a" num))
2748     number-stencil))
2749
2750
2751 (define-markup-command (slashed-digit layout props num)
2752   (integer?)
2753   #:category other
2754   #:properties ((font-size 0)
2755                 (thickness 1.6))
2756   "
2757 @cindex slashed digits
2758
2759 A feta number, with slash.  This is for use in the context of
2760 figured bass notation.
2761 @lilypond[verbatim,quote]
2762 \\markup {
2763   \\slashed-digit #5
2764   \\hspace #2
2765   \\override #'(thickness . 3)
2766   \\slashed-digit #7
2767 }
2768 @end lilypond"
2769   (slashed-digit-internal layout props num #t font-size thickness))
2770
2771 (define-markup-command (backslashed-digit layout props num)
2772   (integer?)
2773   #:category other
2774   #:properties ((font-size 0)
2775                 (thickness 1.6))
2776   "
2777 @cindex backslashed digits
2778
2779 A feta number, with backslash.  This is for use in the context of
2780 figured bass notation.
2781 @lilypond[verbatim,quote]
2782 \\markup {
2783   \\backslashed-digit #5
2784   \\hspace #2
2785   \\override #'(thickness . 3)
2786   \\backslashed-digit #7
2787 }
2788 @end lilypond"
2789   (slashed-digit-internal layout props num #f font-size thickness))
2790
2791 ;; eyeglasses
2792 (define eyeglassespath
2793   '((moveto 0.42 0.77)
2794     (rcurveto 0 0.304 -0.246 0.55 -0.55 0.55)
2795     (rcurveto -0.304 0 -0.55 -0.246 -0.55 -0.55)
2796     (rcurveto 0 -0.304 0.246 -0.55 0.55 -0.55)
2797     (rcurveto 0.304 0 0.55 0.246 0.55 0.55)
2798     (closepath)
2799     (moveto 2.07 0.77)
2800     (rcurveto 0 0.304 -0.246 0.55 -0.55 0.55)
2801     (rcurveto -0.304 0 -0.55 -0.246 -0.55 -0.55)
2802     (rcurveto 0 -0.304 0.246 -0.55 0.55 -0.55)
2803     (rcurveto 0.304 0 0.55 0.246 0.55 0.55)
2804     (closepath)
2805     (moveto 1.025 0.935)
2806     (rcurveto 0 0.182 -0.148 0.33 -0.33 0.33)
2807     (rcurveto -0.182 0 -0.33 -0.148 -0.33 -0.33)
2808     (moveto -0.68 0.77)
2809     (rlineto 0.66 1.43)
2810     (rcurveto 0.132 0.286 0.55 0.44 0.385 -0.33)
2811     (moveto 2.07 0.77)
2812     (rlineto 0.66 1.43)
2813     (rcurveto 0.132 0.286 0.55 0.44 0.385 -0.33)))
2814
2815 (define-markup-command (eyeglasses layout props)
2816   ()
2817   #:category other
2818   "Prints out eyeglasses, indicating strongly to look at the conductor.
2819 @lilypond[verbatim,quote]
2820 \\markup { \\eyeglasses }
2821 @end lilypond"
2822   (interpret-markup layout props
2823     (make-override-markup '(line-cap-style . butt)
2824       (make-path-markup 0.15 eyeglassespath))))
2825
2826 (define-markup-command (left-brace layout props size)
2827   (number?)
2828   #:category other
2829   "
2830 A feta brace in point size @var{size}.
2831
2832 @lilypond[verbatim,quote]
2833 \\markup {
2834   \\left-brace #35
2835   \\hspace #2
2836   \\left-brace #45
2837 }
2838 @end lilypond"
2839   (let* ((font (ly:paper-get-font layout
2840                                   (cons '((font-encoding . fetaBraces)
2841                                           (font-name . #f))
2842                                         props)))
2843          (glyph-count (1- (ly:otf-glyph-count font)))
2844          (scale (ly:output-def-lookup layout 'output-scale))
2845          (scaled-size (/ (ly:pt size) scale))
2846          (glyph (lambda (n)
2847                   (ly:font-get-glyph font (string-append "brace"
2848                                                          (number->string n)))))
2849          (get-y-from-brace (lambda (brace)
2850                              (interval-length
2851                               (ly:stencil-extent (glyph brace) Y))))
2852          (find-brace (binary-search 0 glyph-count get-y-from-brace scaled-size))
2853          (glyph-found (glyph find-brace)))
2854
2855     (if (or (null? (ly:stencil-expr glyph-found))
2856             (< scaled-size (interval-length (ly:stencil-extent (glyph 0) Y)))
2857             (> scaled-size (interval-length
2858                             (ly:stencil-extent (glyph glyph-count) Y))))
2859         (begin
2860           (ly:warning (_ "no brace found for point size ~S ") size)
2861           (ly:warning (_ "defaulting to ~S pt")
2862                       (/ (* scale (interval-length
2863                                    (ly:stencil-extent glyph-found Y)))
2864                          (ly:pt 1)))))
2865     glyph-found))
2866
2867 (define-markup-command (right-brace layout props size)
2868   (number?)
2869   #:category other
2870   "
2871 A feta brace in point size @var{size}, rotated 180 degrees.
2872
2873 @lilypond[verbatim,quote]
2874 \\markup {
2875   \\right-brace #45
2876   \\hspace #2
2877   \\right-brace #35
2878 }
2879 @end lilypond"
2880   (interpret-markup layout props (markup #:rotate 180 #:left-brace size)))
2881
2882 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2883 ;; the note command.
2884 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2885
2886 ;; TODO: better syntax.
2887
2888 (define-markup-command (note-by-number layout props log dot-count dir)
2889   (number? number? number?)
2890   #:category music
2891   #:properties ((font-size 0)
2892                 (style '()))
2893   "
2894 @cindex notes within text by log and dot-count
2895
2896 Construct a note symbol, with stem.  By using fractional values for
2897 @var{dir}, longer or shorter stems can be obtained.
2898
2899 @lilypond[verbatim,quote]
2900 \\markup {
2901   \\note-by-number #3 #0 #DOWN
2902   \\hspace #2
2903   \\note-by-number #1 #2 #0.8
2904 }
2905 @end lilypond"
2906   (define (get-glyph-name-candidates dir log style)
2907     (map (lambda (dir-name)
2908            (format "noteheads.~a~a" dir-name
2909                    (if (and (symbol? style)
2910                             (not (equal? 'default style)))
2911                        (select-head-glyph style (min log 2))
2912                        (min log 2))))
2913          (list (if (= dir UP) "u" "d")
2914                "s")))
2915
2916   (define (get-glyph-name font cands)
2917     (if (null? cands)
2918         ""
2919         (if (ly:stencil-empty? (ly:font-get-glyph font (car cands)))
2920             (get-glyph-name font (cdr cands))
2921             (car cands))))
2922
2923   (let* ((font (ly:paper-get-font layout (cons '((font-encoding . fetaMusic))
2924                                                props)))
2925          (size-factor (magstep font-size))
2926          (stem-length (* size-factor (max 3 (- log 1))))
2927          (head-glyph-name
2928           (let ((result (get-glyph-name font (get-glyph-name-candidates
2929                                               (sign dir) log style))))
2930             (if (string-null? result)
2931                 ;; If no glyph name can be found, select default heads.  Though
2932                 ;; this usually means an unsupported style has been chosen, it
2933                 ;; also prevents unrelated 'style settings from other grobs
2934                 ;; (e.g., TextSpanner and TimeSignature) leaking into markup.
2935                 (get-glyph-name font (get-glyph-name-candidates
2936                                       (sign dir) log 'default))
2937                 result)))
2938          (head-glyph (ly:font-get-glyph font head-glyph-name))
2939          (attach-indices (ly:note-head::stem-attachment font head-glyph-name))
2940          (stem-thickness (* size-factor 0.13))
2941          (stemy (* dir stem-length))
2942          (attach-off (cons (interval-index
2943                             (ly:stencil-extent head-glyph X)
2944                             (* (sign dir) (car attach-indices)))
2945                            (* (sign dir) ; fixme, this is inconsistent between X & Y.
2946                               (interval-index
2947                                (ly:stencil-extent head-glyph Y)
2948                                (cdr attach-indices)))))
2949          (stem-glyph (and (> log 0)
2950                           (ly:round-filled-box
2951                            (ordered-cons (car attach-off)
2952                                          (+ (car attach-off)
2953                                             (* (- (sign dir)) stem-thickness)))
2954                            (cons (min stemy (cdr attach-off))
2955                                  (max stemy (cdr attach-off)))
2956                            (/ stem-thickness 3))))
2957
2958          (dot (ly:font-get-glyph font "dots.dot"))
2959          (dotwid (interval-length (ly:stencil-extent dot X)))
2960          (dots (and (> dot-count 0)
2961                     (apply ly:stencil-add
2962                            (map (lambda (x)
2963                                   (ly:stencil-translate-axis
2964                                    dot (* 2 x dotwid) X))
2965                                 (iota dot-count)))))
2966          (flaggl (and (> log 2)
2967                       (ly:stencil-translate
2968                        (ly:font-get-glyph font
2969                                           (string-append "flags."
2970                                                          (if (> dir 0) "u" "d")
2971                                                          (number->string log)))
2972                        (cons (+ (car attach-off) (if (< dir 0)
2973                                                      stem-thickness 0))
2974                              stemy)))))
2975
2976     ;; If there is a flag on an upstem and the stem is short, move the dots
2977     ;; to avoid the flag.  16th notes get a special case because their flags
2978     ;; hang lower than any other flags.
2979     (if (and dots (> dir 0) (> log 2)
2980              (or (< dir 1.15) (and (= log 4) (< dir 1.3))))
2981         (set! dots (ly:stencil-translate-axis dots 0.5 X)))
2982     (if flaggl
2983         (set! stem-glyph (ly:stencil-add flaggl stem-glyph)))
2984     (if (ly:stencil? stem-glyph)
2985         (set! stem-glyph (ly:stencil-add stem-glyph head-glyph))
2986         (set! stem-glyph head-glyph))
2987     (if (ly:stencil? dots)
2988         (set! stem-glyph
2989               (ly:stencil-add
2990                (ly:stencil-translate-axis
2991                 dots
2992                 (+ (cdr (ly:stencil-extent head-glyph X)) dotwid)
2993                 X)
2994                stem-glyph)))
2995     stem-glyph))
2996
2997 (define-public log2
2998   (let ((divisor (log 2)))
2999     (lambda (z) (inexact->exact (/ (log z) divisor)))))
3000
3001 (define (parse-simple-duration duration-string)
3002   "Parse the `duration-string', e.g. ''4..'' or ''breve.'',
3003 and return a (log dots) list."
3004   (let ((match (regexp-exec (make-regexp "(breve|longa|maxima|[0-9]+)(\\.*)")
3005                             duration-string)))
3006     (if (and match (string=? duration-string (match:substring match 0)))
3007         (let ((len (match:substring match 1))
3008               (dots (match:substring match 2)))
3009           (list (cond ((string=? len "breve") -1)
3010                       ((string=? len "longa") -2)
3011                       ((string=? len "maxima") -3)
3012                       (else (log2 (string->number len))))
3013                 (if dots (string-length dots) 0)))
3014         (ly:error (_ "not a valid duration string: ~a") duration-string))))
3015
3016 (define-markup-command (note layout props duration dir)
3017   (string? number?)
3018   #:category music
3019   #:properties (note-by-number-markup)
3020   "
3021 @cindex notes within text by string
3022
3023 This produces a note with a stem pointing in @var{dir} direction, with
3024 the @var{duration} for the note head type and augmentation dots.  For
3025 example, @code{\\note #\"4.\" #-0.75} creates a dotted quarter note, with
3026 a shortened down stem.
3027
3028 @lilypond[verbatim,quote]
3029 \\markup {
3030   \\override #'(style . cross) {
3031     \\note #\"4..\" #UP
3032   }
3033   \\hspace #2
3034   \\note #\"breve\" #0
3035 }
3036 @end lilypond"
3037   (let ((parsed (parse-simple-duration duration)))
3038     (note-by-number-markup layout props (car parsed) (cadr parsed) dir)))
3039
3040 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3041 ;; translating.
3042 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3043
3044 (define-markup-command (lower layout props amount arg)
3045   (number? markup?)
3046   #:category align
3047   "
3048 @cindex lowering text
3049
3050 Lower @var{arg} by the distance @var{amount}.
3051 A negative @var{amount} indicates raising; see also @code{\\raise}.
3052
3053 @lilypond[verbatim,quote]
3054 \\markup {
3055   one
3056   \\lower #3
3057   two
3058   three
3059 }
3060 @end lilypond"
3061   (ly:stencil-translate-axis (interpret-markup layout props arg)
3062                              (- amount) Y))
3063
3064 (define-markup-command (translate-scaled layout props offset arg)
3065   (number-pair? markup?)
3066   #:category align
3067   #:properties ((font-size 0))
3068   "
3069 @cindex translating text
3070 @cindex scaling text
3071
3072 Translate @var{arg} by @var{offset}, scaling the offset by the
3073 @code{font-size}.
3074
3075 @lilypond[verbatim,quote]
3076 \\markup {
3077   \\fontsize #5 {
3078     * \\translate #'(2 . 3) translate
3079     \\hspace #2
3080     * \\translate-scaled #'(2 . 3) translate-scaled
3081   }
3082 }
3083 @end lilypond"
3084   (let* ((factor (magstep font-size))
3085          (scaled (cons (* factor (car offset))
3086                        (* factor (cdr offset)))))
3087     (ly:stencil-translate (interpret-markup layout props arg)
3088                           scaled)))
3089
3090 (define-markup-command (raise layout props amount arg)
3091   (number? markup?)
3092   #:category align
3093   "
3094 @cindex raising text
3095
3096 Raise @var{arg} by the distance @var{amount}.
3097 A negative @var{amount} indicates lowering, see also @code{\\lower}.
3098
3099 The argument to @code{\\raise} is the vertical displacement amount,
3100 measured in (global) staff spaces.  @code{\\raise} and @code{\\super}
3101 raise objects in relation to their surrounding markups.
3102
3103 If the text object itself is positioned above or below the staff, then
3104 @code{\\raise} cannot be used to move it, since the mechanism that
3105 positions it next to the staff cancels any shift made with
3106 @code{\\raise}.  For vertical positioning, use the @code{padding}
3107 and/or @code{extra-offset} properties.
3108
3109 @lilypond[verbatim,quote]
3110 \\markup {
3111   C
3112   \\small
3113   \\bold
3114   \\raise #1.0
3115   9/7+
3116 }
3117 @end lilypond"
3118   (ly:stencil-translate-axis (interpret-markup layout props arg) amount Y))
3119
3120 (define-markup-command (fraction layout props arg1 arg2)
3121   (markup? markup?)
3122   #:category other
3123   #:properties ((font-size 0))
3124   "
3125 @cindex creating text fractions
3126
3127 Make a fraction of two markups.
3128 @lilypond[verbatim,quote]
3129 \\markup {
3130   Ï€ â‰ˆ
3131   \\fraction 355 113
3132 }
3133 @end lilypond"
3134   (let* ((m1 (interpret-markup layout props arg1))
3135          (m2 (interpret-markup layout props arg2))
3136          (factor (magstep font-size))
3137          (boxdimen (cons (* factor -0.05) (* factor 0.05)))
3138          (padding (* factor 0.2))
3139          (baseline (* factor 0.6))
3140          (offset (* factor 0.75)))
3141     (set! m1 (ly:stencil-aligned-to m1 X CENTER))
3142     (set! m2 (ly:stencil-aligned-to m2 X CENTER))
3143     (let* ((x1 (ly:stencil-extent m1 X))
3144            (x2 (ly:stencil-extent m2 X))
3145            (line (ly:round-filled-box (interval-union x1 x2) boxdimen 0.0))
3146            ;; should stack mols separately, to maintain LINE on baseline
3147            (stack (stack-lines DOWN padding baseline (list m1 line m2))))
3148       (set! stack
3149             (ly:stencil-aligned-to stack Y CENTER))
3150       (set! stack
3151             (ly:stencil-aligned-to stack X LEFT))
3152       ;; should have EX dimension
3153       ;; empirical anyway
3154       (ly:stencil-translate-axis stack offset Y))))
3155
3156 (define-markup-command (normal-size-super layout props arg)
3157   (markup?)
3158   #:category font
3159   #:properties ((baseline-skip))
3160   "
3161 @cindex setting superscript in standard font size
3162
3163 Set @var{arg} in superscript with a normal font size.
3164
3165 @lilypond[verbatim,quote]
3166 \\markup {
3167   default
3168   \\normal-size-super {
3169     superscript in standard size
3170   }
3171 }
3172 @end lilypond"
3173   (ly:stencil-translate-axis
3174    (interpret-markup layout props arg)
3175    (* 0.5 baseline-skip) Y))
3176
3177 (define-markup-command (super layout props arg)
3178   (markup?)
3179   #:category font
3180   #:properties ((font-size 0)
3181                 (baseline-skip))
3182   "
3183 @cindex superscript text
3184
3185 Set @var{arg} in superscript.
3186
3187 @lilypond[verbatim,quote]
3188 \\markup {
3189   E =
3190   \\concat {
3191     mc
3192     \\super
3193     2
3194   }
3195 }
3196 @end lilypond"
3197   (ly:stencil-translate-axis
3198    (interpret-markup
3199     layout
3200     (cons `((font-size . ,(- font-size 3))) props)
3201     arg)
3202    (* 0.5 baseline-skip)
3203    Y))
3204
3205 (define-markup-command (translate layout props offset arg)
3206   (number-pair? markup?)
3207   #:category align
3208   "
3209 @cindex translating text
3210
3211 Translate @var{arg} relative to its surroundings.  @var{offset}
3212 is a pair of numbers representing the displacement in the X and Y axis.
3213
3214 @lilypond[verbatim,quote]
3215 \\markup {
3216   *
3217   \\translate #'(2 . 3)
3218   \\line { translated two spaces right, three up }
3219 }
3220 @end lilypond"
3221   (ly:stencil-translate (interpret-markup layout props arg)
3222                         offset))
3223
3224 (define-markup-command (sub layout props arg)
3225   (markup?)
3226   #:category font
3227   #:properties ((font-size 0)
3228                 (baseline-skip))
3229   "
3230 @cindex subscript text
3231
3232 Set @var{arg} in subscript.
3233
3234 @lilypond[verbatim,quote]
3235 \\markup {
3236   \\concat {
3237     H
3238     \\sub {
3239       2
3240     }
3241     O
3242   }
3243 }
3244 @end lilypond"
3245   (ly:stencil-translate-axis
3246    (interpret-markup
3247     layout
3248     (cons `((font-size . ,(- font-size 3))) props)
3249     arg)
3250    (* -0.5 baseline-skip)
3251    Y))
3252
3253 (define-markup-command (normal-size-sub layout props arg)
3254   (markup?)
3255   #:category font
3256   #:properties ((baseline-skip))
3257   "
3258 @cindex setting subscript in standard font size
3259
3260 Set @var{arg} in subscript with a normal font size.
3261
3262 @lilypond[verbatim,quote]
3263 \\markup {
3264   default
3265   \\normal-size-sub {
3266     subscript in standard size
3267   }
3268 }
3269 @end lilypond"
3270   (ly:stencil-translate-axis
3271    (interpret-markup layout props arg)
3272    (* -0.5 baseline-skip)
3273    Y))
3274
3275 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3276 ;; brackets.
3277 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3278
3279 (define-markup-command (hbracket layout props arg)
3280   (markup?)
3281   #:category graphic
3282   "
3283 @cindex placing horizontal brackets around text
3284
3285 Draw horizontal brackets around @var{arg}.
3286
3287 @lilypond[verbatim,quote]
3288 \\markup {
3289   \\hbracket {
3290     \\line {
3291       one two three
3292     }
3293   }
3294 }
3295 @end lilypond"
3296   (let ((th 0.1) ;; todo: take from GROB.
3297         (m (interpret-markup layout props arg)))
3298     (bracketify-stencil m X th (* 2.5 th) th)))
3299
3300 (define-markup-command (bracket layout props arg)
3301   (markup?)
3302   #:category graphic
3303   "
3304 @cindex placing vertical brackets around text
3305
3306 Draw vertical brackets around @var{arg}.
3307
3308 @lilypond[verbatim,quote]
3309 \\markup {
3310   \\bracket {
3311     \\note #\"2.\" #UP
3312   }
3313 }
3314 @end lilypond"
3315   (let ((th 0.1) ;; todo: take from GROB.
3316         (m (interpret-markup layout props arg)))
3317     (bracketify-stencil m Y th (* 2.5 th) th)))
3318
3319 (define-markup-command (parenthesize layout props arg)
3320   (markup?)
3321   #:category graphic
3322   #:properties ((angularity 0)
3323                 (padding)
3324                 (size 1)
3325                 (thickness 1)
3326                 (width 0.25))
3327   "
3328 @cindex placing parentheses around text
3329
3330 Draw parentheses around @var{arg}.  This is useful for parenthesizing
3331 a column containing several lines of text.
3332
3333 @lilypond[verbatim,quote]
3334 \\markup {
3335   \\line {
3336     \\parenthesize {
3337       \\column {
3338         foo
3339         bar
3340       }
3341     }
3342     \\override #'(angularity . 2) {
3343       \\parenthesize {
3344         \\column {
3345           bah
3346           baz
3347         }
3348       }
3349     }
3350   }
3351 }
3352 @end lilypond"
3353   (let* ((markup (interpret-markup layout props arg))
3354          (scaled-width (* size width))
3355          (scaled-thickness
3356           (* (chain-assoc-get 'line-thickness props 0.1)
3357              thickness))
3358          (half-thickness
3359           (min (* size 0.5 scaled-thickness)
3360                (* (/ 4 3.0) scaled-width)))
3361          (padding (chain-assoc-get 'padding props half-thickness)))
3362     (parenthesize-stencil
3363      markup half-thickness scaled-width angularity padding)))
3364
3365 \f
3366 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3367 ;; Delayed markup evaluation
3368 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3369
3370 (define-markup-command (page-ref layout props label gauge default)
3371   (symbol? markup? markup?)
3372   #:category other
3373   "
3374 @cindex referencing page numbers in text
3375
3376 Reference to a page number. @var{label} is the label set on the referenced
3377 page (using the @code{\\label} command), @var{gauge} a markup used to estimate
3378 the maximum width of the page number, and @var{default} the value to display
3379 when @var{label} is not found."
3380   (let* ((gauge-stencil (interpret-markup layout props gauge))
3381          (x-ext (ly:stencil-extent gauge-stencil X))
3382          (y-ext (ly:stencil-extent gauge-stencil Y)))
3383     (ly:make-stencil
3384      `(delay-stencil-evaluation
3385        ,(delay (ly:stencil-expr
3386                 (let* ((table (ly:output-def-lookup layout 'label-page-table))
3387                        (page-number (if (list? table)
3388                                         (assoc-get label table)
3389                                         #f))
3390                        (page-markup (if page-number (format "~a" page-number) default))
3391                        (page-stencil (interpret-markup layout props page-markup))
3392                        (gap (- (interval-length x-ext)
3393                                (interval-length (ly:stencil-extent page-stencil X)))))
3394                   (interpret-markup layout props
3395                                     (markup #:concat (#:hspace gap page-markup)))))))
3396      x-ext
3397      y-ext)))
3398
3399 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3400 ;; scaling
3401 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3402
3403 (define-markup-command (scale layout props factor-pair arg)
3404   (number-pair? markup?)
3405   #:category graphic
3406   "
3407 @cindex scaling markup
3408 @cindex mirroring markup
3409
3410 Scale @var{arg}.  @var{factor-pair} is a pair of numbers
3411 representing the scaling-factor in the X and Y axes.
3412 Negative values may be used to produce mirror images.
3413
3414 @lilypond[verbatim,quote]
3415 \\markup {
3416   \\line {
3417     \\scale #'(2 . 1)
3418     stretched
3419     \\scale #'(1 . -1)
3420     mirrored
3421   }
3422 }
3423 @end lilypond"
3424   (let ((stil (interpret-markup layout props arg))
3425         (sx (car factor-pair))
3426         (sy (cdr factor-pair)))
3427     (ly:stencil-scale stil sx sy)))
3428
3429 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3430 ;; Repeating
3431 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3432
3433 (define-markup-command (pattern layout props count axis space pattern)
3434   (integer? integer? number? markup?)
3435   #:category other
3436   "
3437 Prints @var{count} times a @var{pattern} markup.
3438 Patterns are spaced apart by @var{space}.
3439 Patterns are distributed on @var{axis}.
3440
3441 @lilypond[verbatim, quote]
3442 \\markup \\column {
3443   \"Horizontally repeated :\"
3444   \\pattern #7 #X #2 \\flat
3445   \\null
3446   \"Vertically repeated :\"
3447   \\pattern #3 #Y #0.5 \\flat
3448 }
3449 @end lilypond"
3450   (let ((pattern-width (interval-length
3451                          (ly:stencil-extent (interpret-markup layout props pattern) X)))
3452         (new-props (prepend-alist-chain 'word-space 0 (prepend-alist-chain 'baseline-skip 0 props))))
3453     (let loop ((i (1- count)) (patterns (markup)))
3454       (if (zero? i)
3455           (interpret-markup
3456             layout
3457             new-props
3458             (if (= axis X)
3459                 (markup patterns pattern)
3460                 (markup #:column (patterns pattern))))
3461           (loop (1- i)
3462             (if (= axis X)
3463                 (markup patterns pattern #:hspace space)
3464                 (markup #:column (patterns pattern #:vspace space))))))))
3465
3466 (define-markup-command (fill-with-pattern layout props space dir pattern left right)
3467   (number? ly:dir? markup? markup? markup?)
3468   #:category align
3469   #:properties ((word-space)
3470                 (line-width))
3471   "
3472 Put @var{left} and @var{right} in a horizontal line of width @code{line-width}
3473 with a line of markups @var{pattern} in between.
3474 Patterns are spaced apart by @var{space}.
3475 Patterns are aligned to the @var{dir} markup.
3476
3477 @lilypond[verbatim, quote]
3478 \\markup \\column {
3479   \"right-aligned :\"
3480   \\fill-with-pattern #1 #RIGHT . first right
3481   \\fill-with-pattern #1 #RIGHT . second right
3482   \\null
3483   \"center-aligned :\"
3484   \\fill-with-pattern #1.5 #CENTER - left right
3485   \\null
3486   \"left-aligned :\"
3487   \\override #'(line-width . 50) \\fill-with-pattern #2 #LEFT : left first
3488   \\override #'(line-width . 50) \\fill-with-pattern #2 #LEFT : left second
3489 }
3490 @end lilypond"
3491   (let* ((pattern-x-extent (ly:stencil-extent (interpret-markup layout props pattern) X))
3492          (pattern-width (interval-length pattern-x-extent))
3493          (left-width (interval-length (ly:stencil-extent (interpret-markup layout props left) X)))
3494          (right-width (interval-length (ly:stencil-extent (interpret-markup layout props right) X)))
3495          (middle-width (- line-width (+ (+ left-width right-width) (* word-space 2))))
3496          (period (+ space pattern-width))
3497          (count (truncate (/ (- middle-width pattern-width) period)))
3498          (x-offset (+ (* (- (- middle-width (* count period)) pattern-width) (/ (1+ dir) 2)) (abs (car pattern-x-extent)))))
3499     (interpret-markup layout props
3500                       (markup left
3501                               #:with-dimensions (cons 0 middle-width) '(0 . 0)
3502                               #:translate (cons x-offset 0)
3503                               #:pattern (1+ count) X space pattern
3504                               right))))
3505
3506 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3507 ;; Markup list commands
3508 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3509
3510 (define-public (space-lines baseline stils)
3511   (let space-stil ((stils stils)
3512                    (result (list)))
3513     (if (null? stils)
3514         (reverse! result)
3515         (let* ((stil (car stils))
3516                (dy-top (max (- (/ baseline 1.5)
3517                                (interval-bound (ly:stencil-extent stil Y) UP))
3518                             0.0))
3519                (dy-bottom (max (+ (/ baseline 3.0)
3520                                   (interval-bound (ly:stencil-extent stil Y) DOWN))
3521                                0.0))
3522                (new-stil (ly:make-stencil
3523                           (ly:stencil-expr stil)
3524                           (ly:stencil-extent stil X)
3525                           (cons (- (interval-bound (ly:stencil-extent stil Y) DOWN)
3526                                    dy-bottom)
3527                                 (+ (interval-bound (ly:stencil-extent stil Y) UP)
3528                                    dy-top)))))
3529           (space-stil (cdr stils) (cons new-stil result))))))
3530
3531 (define-markup-list-command (justified-lines layout props args)
3532   (markup-list?)
3533   #:properties ((baseline-skip)
3534                 wordwrap-internal-markup-list)
3535   "
3536 @cindex justifying lines of text
3537
3538 Like @code{\\justify}, but return a list of lines instead of a single markup.
3539 Use @code{\\override-lines #'(line-width . @var{X})} to set the line width;
3540 @var{X}@tie{}is the number of staff spaces."
3541   (space-lines baseline-skip
3542                (interpret-markup-list layout props
3543                                       (make-wordwrap-internal-markup-list #t args))))
3544
3545 (define-markup-list-command (wordwrap-lines layout props args)
3546   (markup-list?)
3547   #:properties ((baseline-skip)
3548                 wordwrap-internal-markup-list)
3549   "Like @code{\\wordwrap}, but return a list of lines instead of a single markup.
3550 Use @code{\\override-lines #'(line-width . @var{X})} to set the line width,
3551 where @var{X} is the number of staff spaces."
3552   (space-lines baseline-skip
3553                (interpret-markup-list layout props
3554                                       (make-wordwrap-internal-markup-list #f args))))
3555
3556 (define-markup-list-command (column-lines layout props args)
3557   (markup-list?)
3558   #:properties ((baseline-skip))
3559   "Like @code{\\column}, but return a list of lines instead of a single markup.
3560 @code{baseline-skip} determines the space between each markup in @var{args}."
3561   (space-lines baseline-skip
3562                (interpret-markup-list layout props args)))
3563
3564 (define-markup-list-command (override-lines layout props new-prop args)
3565   (pair? markup-list?)
3566   "Like @code{\\override}, for markup lists."
3567   (interpret-markup-list layout (cons (list new-prop) props) args))