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