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