X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=scm%2Flily.scm;h=cd7b92964bdcfa21ea590ca5349c092fb94c87ca;hb=6cb2c5ec23dea45f3cba3a03dc0d9128b630742b;hp=ab9e73dbf0b7e5500b025246db806d15d3e362f3;hpb=3bf590e96962fc6102267e4fcab9e4b55a75bca2;p=lilypond.git diff --git a/scm/lily.scm b/scm/lily.scm index ab9e73dbf0..cd7b92964b 100644 --- a/scm/lily.scm +++ b/scm/lily.scm @@ -43,6 +43,89 @@ (string-downcase (car (string-tokenize (utsname:sysname (uname))))))) +(define lilypond-declarations '()) + +(defmacro-public define-session (name value) + "This defines a variable @var{name} with the starting value +@var{value} that is reinitialized at the start of each session. +A@tie{}session basically corresponds to one LilyPond file on the +command line. The value is recorded at the start of the first session +after loading all initialization files and before loading the user +file and is reinstated for all of the following sessions. This +happens just by replacing the value, not by copying structures, so you +should not destructively modify them. For example, lists defined in +this manner should be changed within a session only be adding material +to their front or replacing them altogether, not by modifying parts of +them. It is an error to call @code{define-session} after the first +session has started." + (define (add-session-variable name value) + (if (ly:undead? lilypond-declarations) + (ly:error (_ "define-session used after session start"))) + (let ((var (make-variable value))) + (module-add! (current-module) name var) + (set! lilypond-declarations (cons var lilypond-declarations)))) + `(,add-session-variable ',name ,value)) + +(defmacro-public define-session-public (name value) + "Like @code{define-session}, but also exports @var{name}." + `(begin + (define-session ,name ,value) + (export ,name))) + +(define (session-terminate) + (if (ly:undead? lilypond-declarations) + (for-each + (lambda (p) (variable-set! (cadr p) (cddr p))) + (ly:get-undead lilypond-declarations)))) + +(define lilypond-interfaces #f) + +(define-public (session-initialize thunk) + "Initialize this session. The first session in a LilyPond run is +initialized by calling @var{thunk}, then recording the values of all +variables in the current module as well as those defined with +@code{define-session}. Subsequent calls of @code{session-initialize} +ignore @var{thunk} and instead just reinitialize all recorded +variables to their value after the initial call of @var{thunk}." + +;; We need to save the variables of the current module along with +;; their values: functions defined in the module might refer to the +;; variables. + +;; The entries in lilypond-declarations consist of a cons* consisting +;; of symbol, variable, and value. Variables defined with +;; define-session have the symbol set to #f. + + (if (ly:undead? lilypond-declarations) + (begin + (module-use-interfaces! (current-module) (reverse lilypond-interfaces)) + (for-each + (lambda (p) + (let ((var (cadr p)) + (val (cddr p))) + (variable-set! var val) + (if (car p) + (module-add! (current-module) (car p) var)))) + (ly:get-undead lilypond-declarations))) + (begin + (thunk) + (set! lilypond-interfaces + (filter (lambda (m) (eq? 'interface (module-kind m))) + (module-uses (current-module)))) + (let ((decl (map! (lambda (v) + (cons* #f v (variable-ref v))) + lilypond-declarations))) + (module-for-each + (lambda (s v) + (let ((val (variable-ref v))) + (if (not (ly:lily-parser? val)) + (set! decl + (cons + (cons* s v val) + decl))))) + (current-module)) + (set! lilypond-declarations (ly:make-undead decl)))))) + (define scheme-options-definitions `( ;; NAMING: either @@ -132,9 +215,6 @@ file to given string.") (music-strings-to-paths #f "Convert text strings to paths when glyphs belong to a music font.") - (old-relative #f -"Make \\relative mode for simultaneous music work -similar to chord syntax.") (point-and-click #t "Add point & click links to PDF output.") (paper-size "a4" @@ -289,7 +369,6 @@ messages into errors.") (if (memq (ly:get-option 'backend) music-string-to-path-backends) (ly:set-option 'music-strings-to-paths #t)) - (define-public (ly:load x) (let* ((file-name (%search-load-path x))) (ly:debug "[~A" file-name) @@ -382,6 +461,7 @@ messages into errors.") "define-note-names.scm" "c++.scm" "chord-entry.scm" + "skyline.scm" "stencil.scm" "define-markup-commands.scm" "markup.scm" @@ -408,6 +488,7 @@ messages into errors.") "font.scm" "encoding.scm" + "bar-line.scm" "flag-styles.scm" "fret-diagrams.scm" "tablature.scm" @@ -419,6 +500,7 @@ messages into errors.") "define-grobs.scm" "define-grob-interfaces.scm" "define-stencil-commands.scm" + "scheme-engravers.scm" "titling.scm" "text.scm" @@ -491,27 +573,32 @@ messages into errors.") (,fraction? . "fraction, as pair") (,grob-list? . "list of grobs") (,index? . "non-negative integer") - ;; this is built on cheap-list - (,list-or-symbol? . "list or symbol") (,markup? . "markup") (,markup-command-list? . "markup command list") (,markup-list? . "markup list") (,moment-pair? . "pair of moment objects") (,number-list? . "number list") (,number-or-grob? . "number or grob") + (,number-or-markup? . "number or markup") (,number-or-pair? . "number or pair") (,number-or-string? . "number or string") (,number-pair? . "pair of numbers") (,rhythmic-location? . "rhythmic location") (,scheme? . "any type") (,string-or-pair? . "string or pair") + (,string-or-music? . "string or music") (,string-or-symbol? . "string or symbol") + (,symbol-list? . "symbol list") + (,symbol-list-or-music? . "symbol list or music") + (,symbol-list-or-symbol? . "symbol list or symbol") (,void? . "void") )) (define-public lilypond-exported-predicates - `((,ly:box? . "box") + `((,ly:book? . "book") + (,ly:box? . "box") (,ly:context? . "context") + (,ly:context-def? . "context definition") (,ly:context-mod? . "context modification") (,ly:dimension? . "dimension, in staff space") (,ly:dir? . "direction") @@ -594,6 +681,10 @@ messages into errors.") (define gc-protect-stat-count 0) +;; Undead objects that should be ignored after the first time round +(define gc-zombies + (make-weak-key-hash-table 0)) + (define-public (dump-live-object-stats outfile) (for-each (lambda (x) (format outfile "~a: ~a\n" (car x) (cdr x))) @@ -640,6 +731,13 @@ messages into errors.") (ly:set-option 'debug-gc-assert-parsed-dead #t) (gc) (ly:set-option 'debug-gc-assert-parsed-dead #f) + (for-each + (lambda (x) + (if (not (hashq-ref gc-zombies x)) + (begin + (ly:programming-error "Parsed object should be dead: ~a" x) + (hashq-set! gc-zombies x #t)))) + (ly:parsed-undead-list!)) (set! stats (gc-live-object-stats)) (ly:progress "Dumping live object statistics.\n") (dump-live-object-stats outfile))) @@ -725,7 +823,7 @@ PIDs or the number of the process." (> (string-length s) 0)) (apply append (map (lambda (f) - (string-split (ly:gulp-file f) #\nl)) + (string-split (string-delete (ly:gulp-file f) #\cr) #\nl)) files))))) (if (and (number? (ly:get-option 'job-count)) (>= (length files) (ly:get-option 'job-count))) @@ -796,10 +894,11 @@ PIDs or the number of the process." (let* ((failed '()) (separate-logs (ly:get-option 'separate-log-files)) (ping-log - (if separate-logs - (open-file (if (string-or-symbol? (ly:get-option 'log-file)) - (format #f "~a.log" (ly:get-option 'log-file)) - "/dev/stderr") "a") #f)) + (and separate-logs + (if (string-or-symbol? (ly:get-option 'log-file)) + (open-file (format #f "~a.log" (ly:get-option 'log-file)) + "a") + (fdes->outport 2)))) (do-measurements (ly:get-option 'dump-profile)) (handler (lambda (key failed-file) (set! failed (append (list failed-file) failed))))) @@ -819,6 +918,7 @@ PIDs or the number of the process." (mtrace:start-trace (ly:get-option 'trace-memory-frequency))) (lilypond-file handler x) (ly:check-expected-warnings) + (session-terminate) (if start-measurements (dump-profile x start-measurements (profile-measurements))) (if (ly:get-option 'trace-memory-frequency) @@ -830,6 +930,13 @@ PIDs or the number of the process." (ly:set-option 'debug-gc-assert-parsed-dead #t) (gc) (ly:set-option 'debug-gc-assert-parsed-dead #f) + (for-each + (lambda (x) + (if (not (hashq-ref gc-zombies x)) + (begin + (ly:programming-error "Parsed object should be dead: ~a" x) + (hashq-set! gc-zombies x #t)))) + (ly:parsed-undead-list!)) (if (ly:get-option 'debug-gc) (dump-gc-protects) (ly:reset-all-fonts))