X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=scm%2Fmarkup.scm;h=2b9bd32b1b344812623794b6ce6c3e0e38ae7f30;hb=e62c1e205cd619afcc43fd8c8a9a2c5a093b508e;hp=89eba1a42bf93a3beee192e80398b6ac94011aa8;hpb=38d7d319eabc906e82fb42002678c6d42a23b6f7;p=lilypond.git diff --git a/scm/markup.scm b/scm/markup.scm index 89eba1a42b..2b9bd32b1b 100644 --- a/scm/markup.scm +++ b/scm/markup.scm @@ -1,8 +1,19 @@ -;;;; markup.scm -- Implement a user extensible markup scheme. +;;;; This file is part of LilyPond, the GNU music typesetter. ;;;; -;;;; source file of the GNU LilyPond music typesetter -;;;; -;;;; (c) 2003--2009 Han-Wen Nienhuys +;;;; Copyright (C) 2003--2009 Han-Wen Nienhuys +;;;; +;;;; LilyPond is free software: you can redistribute it and/or modify +;;;; it under the terms of the GNU General Public License as published by +;;;; the Free Software Foundation, either version 3 of the License, or +;;;; (at your option) any later version. +;;;; +;;;; LilyPond is distributed in the hope that it will be useful, +;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;;; GNU General Public License for more details. +;;;; +;;;; You should have received a copy of the GNU General Public License +;;;; along with LilyPond. If not, see . " Internally markup is stored as lists, whose head is a function. @@ -20,9 +31,7 @@ The function should return a stencil (i.e. a formatted, ready to print object). -To add a builtin markup command, use the define-builtin-markup-command -utility. In a user file, the define-markup-command macro shall be used -(see ly/markup-init.ly). +To add a markup command, use the define-markup-command utility. (define-markup-command (mycommand layout prop arg1 ...) (arg1-type? ...) \"my command usage and description\" @@ -41,12 +50,16 @@ The command is now available in markup mode, e.g. ;; category -> markup functions (define-public markup-functions-by-category (make-hash-table 150)) ;; markup function -> used properties -(define-public markup-functions-properties (make-hash-table 150)) +(define-public markup-functions-properties (make-weak-key-hash-table 151)) ;; List of markup list functions -(define-public markup-list-function-list (list)) +(define-public markup-list-functions (make-weak-key-hash-table 151)) + +(use-modules (ice-9 optargs)) -(define-macro (define-builtin-markup-command command-and-args signature - category properties-or-copied-function . body) +(defmacro*-public define-markup-command + (command-and-args signature + #:key (category '()) (properties '()) + #:rest body) " * Define a COMMAND-markup function after command-and-args and body, register COMMAND-markup and its signature, @@ -58,16 +71,16 @@ register COMMAND-markup and its signature, * define a make-COMMAND-markup function. Syntax: - (define-builtin-markup-command (COMMAND layout props . arguments) + (define-markup-command (COMMAND layout props . arguments) argument-types - category - properties + [ #:category category ] + [ #:properties properties ] \"documentation string\" ...command body...) or: - (define-builtin-markup-command COMMAND + (define-markup-command COMMAND argument-types - category + [ #:category category ] function) where: @@ -76,19 +89,27 @@ where: properties a list of (property default-value) lists or COMMANDx-markup elements (when a COMMANDx-markup is found, the properties of the said commandx are added instead). No check is performed against cyclical references! + + The specified properties are available as let-bound variables in the + command body. " (let* ((command (if (pair? command-and-args) (car command-and-args) command-and-args)) (args (if (pair? command-and-args) (cdr command-and-args) '())) (command-name (string->symbol (format #f "~a-markup" command))) (make-markup-name (string->symbol (format #f "make-~a-markup" command)))) + (while (and (pair? body) (keyword? (car body))) + (set! body (cddr body))) `(begin ;; define the COMMAND-markup function ,(if (pair? args) - (let ((documentation (car body)) - (real-body (cdr body)) - (properties properties-or-copied-function)) + (let* ((documentation (if (string? (car body)) + (list (car body)) + '())) + (real-body (if (or (null? documentation) + (null? (cdr body))) + body (cdr body)))) `(define-public (,command-name ,@args) - ,documentation + ,@documentation (let ,(filter identity (map (lambda (prop-spec) (if (pair? prop-spec) @@ -102,18 +123,21 @@ where: properties)) ,@real-body))) (let ((args (gensym "args")) - (markup-command properties-or-copied-function)) + (markup-command (car body))) `(define-public (,command-name . ,args) ,(format #f "Copy of the ~a command." markup-command) (apply ,markup-command ,args)))) (set! (markup-command-signature ,command-name) (list ,@signature)) ;; Register the new function, for markup documentation ,@(map (lambda (category) - `(hashq-set! markup-functions-by-category ',category - (cons ,command-name - (or (hashq-ref markup-functions-by-category ',category) - (list))))) - (if (list? category) category (list category))) + `(hashq-set! + (or (hashq-ref markup-functions-by-category ',category) + (let ((hash (make-weak-key-hash-table 151))) + (hashq-set! markup-functions-by-category ',category + hash) + hash)) + ,command-name #t)) + (if (list? category) category (list category))) ;; Used properties, for markup documentation (hashq-set! markup-functions-properties ,command-name @@ -125,28 +149,34 @@ where: (else `(list ',(car prop-spec))))) (if (pair? args) - properties-or-copied-function + properties (list))))) ;; define the make-COMMAND-markup function (define-public (,make-markup-name . args) (let ((sig (list ,@signature))) (make-markup ,command-name ,(symbol->string make-markup-name) sig args)))))) -(define-macro (define-builtin-markup-list-command command-and-args signature - properties . body) - "Same as `define-builtin-markup-command, but defines a command that, when +(defmacro*-public define-markup-list-command + (command-and-args signature #:key (properties '()) #:rest body) + "Same as `define-markup-command, but defines a command that, when interpreted, returns a list of stencils instead os a single one" (let* ((command (if (pair? command-and-args) (car command-and-args) command-and-args)) (args (if (pair? command-and-args) (cdr command-and-args) '())) (command-name (string->symbol (format #f "~a-markup-list" command))) (make-markup-name (string->symbol (format #f "make-~a-markup-list" command)))) + (while (and (pair? body) (keyword? (car body))) + (set! body (cddr body))) `(begin ;; define the COMMAND-markup-list function ,(if (pair? args) - (let ((documentation (car body)) - (real-body (cdr body))) + (let* ((documentation (if (string? (car body)) + (list (car body)) + '())) + (real-body (if (or (null? documentation) + (null? (cdr body))) + body (cdr body)))) `(define-public (,command-name ,@args) - ,documentation + ,@documentation (let ,(filter identity (map (lambda (prop-spec) (if (pair? prop-spec) @@ -158,7 +188,7 @@ interpreted, returns a list of stencils instead os a single one" `(,prop (chain-assoc-get ',prop ,props ,default-value))) #f)) properties)) - ,@body))) + ,@real-body))) (let ((args (gensym "args")) (markup-command (car body))) `(define-public (,command-name . ,args) @@ -166,9 +196,7 @@ interpreted, returns a list of stencils instead os a single one" (apply ,markup-command ,args)))) (set! (markup-command-signature ,command-name) (list ,@signature)) ;; add the command to markup-list-function-list, for markup documentation - (if (not (member ,command-name markup-list-function-list)) - (set! markup-list-function-list (cons ,command-name - markup-list-function-list))) + (hashq-set! markup-list-functions ,command-name #t) ;; Used properties, for markup documentation (hashq-set! markup-functions-properties ,command-name @@ -207,16 +235,15 @@ against SIGNATURE, reporting MAKE-NAME as the user-invoked function. (ly:error (string-append make-name ": " - (_ "Invalid argument in position ~A. Expect: ~A, found: ~S.") - error-msg)) + (_ "Invalid argument in position ~A. Expect: ~A, found: ~S.")) + (car error-msg) (cadr error-msg)(caddr error-msg)) (cons markup-function args)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; markup constructors ;;; lilypond-like syntax for markup construction in scheme. -(use-modules (ice-9 optargs) - (ice-9 receive)) +(use-modules (ice-9 receive)) (defmacro*-public markup (#:rest body) "The `markup' macro provides a lilypond-like syntax for building markups.