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