3 Internally markup is stored as lists, whose head is a function.
5 (FUNCTION ARG1 ARG2 ... )
7 When the markup is formatted, then FUNCTION is called as follows
9 (FUNCTION GROB PROPS ARG1 ARG2 ... )
11 GROB is the current grob, PROPS is a list of alists, and ARG1.. are
12 the rest of the arguments.
14 The function should return a molecule (i.e. a formatted, ready to
21 1. It should be named COMMAND-markup
23 2. It should have an object property set that describes it's
24 signature. This is to allow the parser to figure out how many
27 (set-object-property! COMMAND-markup scm0-markup1)
29 (insert in the list below).
31 3. The command is now available in markup mode, e.g.
34 \markup { .... \COMMAND #1 argument ... }
39 At present, markup functions must be defined in this
40 file. Implementing user-access for markup functions is an excercise
50 (define (mydisplay x) (display x) (newline) x)
52 (define-public (simple-markup grob props . rest)
53 (Text_item::text_to_molecule grob props (car rest))
56 (define-public (stack-molecule-line space molecules)
58 (if (pair? (cdr molecules))
60 (tail (stack-molecule-line space (cdr molecules)))
61 (head (car molecules))
62 (xoff (+ space (cdr (ly:get-molecule-extent head X))))
67 (ly:molecule-translate-axis tail xoff X))
73 (define-public (line-markup grob props . rest)
75 (cdr (chain-assoc 'word-space props))
76 (map (lambda (x) (interpret-markup grob props x)) (car rest)))
79 (define (combine-molecule-list lst)
80 (if (null? (cdr lst)) (car lst)
81 (ly:add-molecule (car lst) (combine-molecule-list (cdr lst)))
84 (define-public (combine-markup grob props . rest)
86 (interpret-markup grob props (car rest))
87 (interpret-markup grob props (cadr rest))))
89 ; (combine-molecule-list (map (lambda (x) (interpret-markup grob props x)) (car rest))))
91 (define (font-markup qualifier value)
92 (lambda (grob props . rest)
93 (interpret-markup grob (cons (cons `(,qualifier . ,value) (car props)) (cdr props)) (car rest))
98 (define-public (set-property-markup qualifier)
99 (lambda (grob props . rest )
100 (interpret-markup grob
101 (cons (cons `(,qualifier . ,(car rest))
102 (car props)) (cdr props))
107 (define-public fontsize-markup (set-property-markup 'font-relative-size))
108 (define-public magnify-markup (set-property-markup 'font-magnification))
110 (define-public bold-markup
111 (font-markup 'font-series 'bold))
112 (define-public number-markup
113 (font-markup 'font-family 'number))
116 (define-public huge-markup
117 (font-markup 'font-relative-size 2))
118 (define-public large-markup
119 (font-markup 'font-relative-size 1))
120 (define-public small-markup
121 (font-markup 'font-relative-size -1))
122 (define-public tiny-markup
123 (font-markup 'font-relative-size -2))
124 (define-public teeny-markup
125 (font-markup 'font-relative-size -3))
126 (define-public dynamic-markup
127 (font-markup 'font-family 'dynamic))
128 (define-public italic-markup
129 (font-markup 'font-shape 'italic))
132 ;; TODO: baseline-skip should come from the font.
133 (define-public (column-markup grob props . rest)
135 -1 0.0 (cdr (chain-assoc 'baseline-skip props))
136 (map (lambda (x) (interpret-markup grob props x)) (car rest)))
139 (define-public (musicglyph-markup grob props . rest)
140 (ly:find-glyph-by-name
141 (ly:get-font grob (cons '((font-family . music)) props))
145 (define-public (lookup-markup grob props . rest)
146 "Lookup a glyph by name."
147 (ly:find-glyph-by-name
148 (ly:get-font grob props)
152 (define-public (char-markup grob props . rest)
153 "Syntax: \\char NUMBER. "
154 (ly:get-glyph (ly:get-font grob props) (car rest))
157 (define-public (raise-markup grob props . rest)
158 "Syntax: \\raise AMOUNT MARKUP. "
159 (ly:molecule-translate-axis (interpret-markup
166 (define-public (normal-size-super-markup grob props . rest)
167 (ly:molecule-translate-axis (interpret-markup
170 (* 0.5 (cdr (chain-assoc 'baseline-skip props)))
174 (define-public (super-markup grob props . rest)
175 "Syntax: \\super MARKUP. "
176 (ly:molecule-translate-axis (interpret-markup
178 (cons '((font-relative-size . -2)) props) (car rest))
179 (* 0.5 (cdr (chain-assoc 'baseline-skip props)))
183 (define-public (translate-markup grob props . rest)
184 "Syntax: \\translate OFFSET MARKUP. "
185 (ly:molecule-translate (interpret-markup grob props (cadr rest))
190 (define-public (sub-markup grob props . rest)
191 "Syntax: \\sub MARKUP."
192 (ly:molecule-translate-axis (interpret-markup
194 (cons '((font-relative-size . -2)) props)
196 (* -0.5 (cdr (chain-assoc 'baseline-skip props)))
200 (define-public (normal-size-sub-markup grob props . rest)
201 (ly:molecule-translate-axis (interpret-markup
204 (* -0.5 (cdr (chain-assoc 'baseline-skip props)))
209 ;; todo: fix negative space
210 (define (hspace-markup grob props . rest)
211 "Syntax: \\hspace NUMBER."
213 ((amount (car rest)))
215 (ly:make-molecule "" (cons 0 amount) '(-1 . 1) )
216 (ly:make-molecule "" (cons amount amount) '(-1 . 1)))
219 (define-public (override-markup grob props . rest)
220 "Tack the 1st arg in REST onto PROPS, e.g.
222 \override #'(font-family . married) \"bla\"
226 (interpret-markup grob (cons (list (car rest)) props)
229 (define-public (smaller-markup grob props . rest)
230 "Syntax: \\smaller MARKUP"
233 (fs (cdr (chain-assoc 'font-relative-size props)))
234 (entry (cons 'font-relative-size (- fs 1)))
237 grob (cons (list entry) props)
242 (define-public (bigger-markup grob props . rest)
243 "Syntax: \\bigger MARKUP"
246 (fs (cdr (chain-assoc 'font-relative-size props)))
247 (entry (cons 'font-relative-size (+ fs 1)))
250 grob (cons (list entry) props)
254 (define (markup-signature-to-keyword sig)
255 " (A B C) -> a0-b1-c2 "
258 (string->symbol (string-join
262 (set! count (+ count 1))
265 ;; for reasons I don't get,
266 ;; (case func ((markup?) .. )
269 ((eq? func markup?) "markup")
270 ((eq? func markup-list?) "markup-list")
273 (number->string (- count 1))
282 (define (markup-function? x)
283 (object-property x 'markup-signature)
286 (define (markup-list? arg)
287 (define (markup-list-inner? l)
290 (and (markup? (car l)) (markup-list-inner? (cdr l)))
293 (and (list? arg) (markup-list-inner? arg)))
295 (define (markup-argument-list? signature arguments)
296 "Typecheck argument list."
297 (if (and (pair? signature) (pair? arguments))
298 (and ((car signature) (car arguments))
299 (markup-argument-list? (cdr signature) (cdr arguments)))
300 (and (null? signature) (null? arguments)))
304 (define (markup-argument-list-error signature arguments number)
305 "return (ARG-NR TYPE-EXPECTED ARG-FOUND) if an error is detected, or
306 #f is no error found.
308 (if (and (pair? signature) (pair? arguments))
309 (if (not ((car signature) (car arguments)))
310 (list number (type-name (car signature)) (car arguments))
311 (markup-argument-list-error (cdr signature) (cdr arguments) (+ 1 number)))
316 ;; full recursive typecheck.
318 (define (markup-typecheck? arg)
321 (markup-function? (car arg))
322 (markup-argument-list?
323 (object-property (car arg) 'markup-signature)
329 ;; typecheck, and throw an error when something amiss.
331 (define (markup-thrower-typecheck arg)
335 (throw 'markup-format "Not a pair" arg)
337 ((not (markup-function? (car arg)))
338 (throw 'markup-format "Not a markup function " (car arg)))
341 ((not (markup-argument-list?
342 (object-property (car arg) 'markup-signature)
344 (throw 'markup-format "Arguments failed typecheck for " arg)))
349 ;; good enough if you only use make-XXX-markup functions.
351 (define (cheap-markup? x)
354 (markup-function? (car x))))
358 ;; replace by markup-thrower-typecheck for more detailed diagnostics.
360 (define markup? cheap-markup?)
363 (define markup-function-list
367 (cons teeny-markup (list markup?))
368 (cons tiny-markup (list markup?))
369 (cons small-markup (list markup?))
370 (cons dynamic-markup (list markup?))
371 (cons large-markup (list markup?))
373 (cons huge-markup (list markup?))
376 (cons smaller-markup (list markup?))
377 (cons bigger-markup (list markup?))
380 (cons sub-markup (list markup?))
381 (cons normal-size-sub-markup (list markup?))
383 (cons super-markup (list markup?))
384 (cons normal-size-super-markup (list markup?))
386 (cons bold-markup (list markup?))
387 (cons italic-markup (list markup?))
389 (cons number-markup (list markup?))
391 (cons column-markup (list markup-list?))
392 (cons line-markup (list markup-list?))
394 (cons combine-markup (list markup? markup?))
395 (cons simple-markup (list string?))
396 (cons musicglyph-markup (list scheme?))
398 (cons translate-markup (list number-pair? markup?))
399 (cons override-markup (list pair? markup?))
400 (cons char-markup (list integer?))
401 (cons lookup-markup (list string?))
403 (cons hspace-markup (list number?))
405 (cons raise-markup (list number? markup?))
406 (cons magnify-markup (list number? markup?))
407 (cons fontsize-markup (list number? markup?))
412 (define markup-module (current-module))
415 (set-object-property! (car x) 'markup-signature (cdr x))
416 (set-object-property! (car x) 'markup-keyword (markup-signature-to-keyword (cdr x)))
418 markup-function-list)
423 ;; make-FOO-markup function that typechecks its arguments.
425 ;; TODO: should construct a message says
426 ;; Invalid argument 4 : expecting a BLADIBLA, found: (list-ref 4 args)
428 ;; right now, you get the entire argument list.
431 (define (make-markup-maker entry)
433 ((foo-markup (car entry))
434 (signature (cons 'list (cdr entry)))
435 (name (symbol->string (procedure-name foo-markup)))
436 (make-name (string-append "make-" name))
439 `(define (,(string->symbol make-name) . args)
442 (arglen (length args))
443 (siglen (length ,signature))
445 (if (and (> 0 siglen) (> 0 arglen))
446 (markup-argument-list-error ,signature args 1)))
450 (if (or (not (= arglen siglen)) (< siglen 0) (< 0 arglen))
451 (scm-error 'markup-format ,make-name "Expect ~A arguments for ~A. Found ~A: ~S"
452 (list (length ,signature)
457 (scm-error 'markup-format ,make-name "Invalid argument in position ~A\n Expect: ~A\nFound: ~S." error-msg #f)
459 (cons ,foo-markup args)
466 (define (make-markup markup-function make-name signature args)
468 " Construct a markup object from MARKUP-FUNCTION and ARGS. Typecheck
469 against SIGNATURE, reporting MAKE-NAME as the user-invoked function.
474 (arglen (length args))
475 (siglen (length signature))
477 (if (and (> siglen 0) (> arglen 0))
478 (markup-argument-list-error signature args 1)))
482 (if (or (not (= arglen siglen)) (< siglen 0) (< arglen 0))
483 (scm-error 'markup-format make-name "Expect ~A arguments for ~A. Found ~A: ~S"
490 (scm-error 'markup-format make-name "Invalid argument in position ~A\nExpect: ~A\nFound: ~S." error-msg #f)
492 (cons markup-function args)
495 (define (make-markup-maker entry)
497 (name (symbol->string (procedure-name (car entry))))
498 (make-name (string-append "make-" name))
499 (signature (object-property (car entry) 'markup-signature))
502 `(define (,(string->symbol make-name) . args)
503 (make-markup ,(car entry) ,make-name ,(cons 'list signature) args)
508 (cons 'begin (map make-markup-maker markup-function-list))
512 (define-public (lookup-markup-command code)
514 ( (sym (string->symbol (string-append code "-markup")))
515 (var (module-local-variable markup-module sym))
519 (cons (variable-ref var) (object-property (variable-ref var) 'markup-keyword))
524 (define-public (brew-new-markup-molecule grob)
525 (interpret-markup grob
526 (Font_interface::get_property_alist_chain grob)
527 (ly:get-grob-property grob 'text)
531 (define-public empty-markup `(,simple-markup ""))
533 (define (interpret-markup grob props markup)
535 (simple-markup grob props markup)
542 (apply func (cons grob (cons props args)) )
546 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
549 (define (typecheck-with-error x)
552 (lambda () (markup? x))
553 (lambda (key message arg)
554 (display "\nERROR: markup format error: \n")
557 (write arg (current-output-port))
561 ;; test make-foo-markup functions
566 (display (make-line-markup (list (make-simple-markup "FOO"))))
568 (make-line-markup (make-simple-markup "FOO"))
569 (make-line-markup (make-simple-markup "FOO") (make-simple-markup "foo"))
570 (make-raise-markup "foo" (make-simple-markup "foo"))
576 ;; test typecheckers. Not wholly useful, because errors are detected
577 ;; in other places than they're made.
582 ;; To get error messages, see above to install the alternate
583 ;; typecheck routine for markup?.
587 (display (typecheck-with-error `(,simple-markup "foobar")))
588 (display (typecheck-with-error `(,simple-markup "foobar")))
589 (display (typecheck-with-error `(,simple-markup 1)))
591 (typecheck-with-error `(,line-markup ((,simple-markup "foobar"))
592 (,simple-markup 1))))
594 (typecheck-with-error `(,line-markup (,simple-markup "foobar")
595 (,simple-markup "bla"))))