--- /dev/null
+\header {
+ texidoc = "The graphviz feature draws dependency graphs for grob properties."
+
+ }
+
+\version "2.11.21"
+\include "graphviz-init.ly"
+
+#(whitelist-grob 'NoteHead)
+#(whitelist-grob 'Stem)
+#(whitelist-grob "NoteHead")
+#(whitelist-grob "Stem")
+
+#(map whitelist-symbol '(stencil style duration-log
+ stem-attachment end-position staff-position
+ glyph-name direction))
+
+
+\book { \score {
+ c'4
+} }
+
+
+#(graph-write graph (current-error-port))
+#(ly:set-grob-modification-callback #f)
+#(ly:set-property-cache-callback #f)
+
static SCM modification_callback = SCM_EOL;
static SCM cache_callback = SCM_EOL;
+
+/*
+
+FIXME: this should use ly:set-option interface instead.
+
+*/
+
LY_DEFINE (ly_set_grob_modification_callback, "ly:set-grob-modification-callback",
1, 0, 0, (SCM cb),
"Specify a procedure that will be called every time lilypond modifies "
"the property to be changed and "
"the new value for the property.")
{
- LY_ASSERT_TYPE (ly_is_procedure, cb, 1);
-
- modification_callback = cb;
+ modification_callback = (ly_is_procedure (cb)) ? cb : SCM_BOOL_F;
return SCM_UNSPECIFIED;
}
"the name of the callback that calculated the property and "
"the new (cached) value of the property.")
{
- LY_ASSERT_TYPE (ly_is_procedure, cb, 1);
-
- cache_callback = cb;
+ cache_callback = (ly_is_procedure (cb)) ? cb : SCM_BOOL_F;
return SCM_UNSPECIFIED;
}
#endif
+
void
Grob::instrumented_set_property (SCM sym, SCM v,
char const *file,
--- /dev/null
+\version "2.11.15"
+
+#(use-modules (scm graphviz))
+
+#(define last-grob-action '())
+
+#(define sym-blacklist '())
+#(define sym-whitelist '())
+
+#(define file-line-blacklist '())
+#(define file-line-whitelist '())
+
+#(define grob-blacklist '())
+#(define grob-whitelist '())
+
+#(define (blacklist-symbol sym)
+ (set! sym-blacklist (cons sym sym-blacklist)))
+
+#(define (whitelist-symbol sym)
+ (set! sym-whitelist (cons sym sym-whitelist)))
+
+#(define (whitelist-grob str)
+ (set! grob-whitelist (cons str grob-whitelist)))
+
+#(define graph (make-graph (format "~a.dot" (ly:parser-output-name parser))))
+
+#(define (grob-name g)
+ (let* ((meta (ly:grob-property g 'meta))
+ (name-pair (assq 'name meta)))
+ (if (pair? name-pair)
+ (cdr name-pair)
+ #f)))
+
+% an event is relevant if
+% (it is on some whitelist or all whitelists are empty)
+% and
+% (it isn't on any blacklist)
+
+#(define (relevant? grob file line prop)
+ (let ((file-line `(,file . ,line)))
+ (and
+ (or
+ (= 0 (length file-line-whitelist) (length sym-whitelist) (length grob-whitelist))
+ (memq prop sym-whitelist)
+ (memq (grob-name grob) grob-whitelist)
+ (member file-line file-line-whitelist))
+ (and
+ (not (memq prop sym-blacklist))
+ (not (memq (grob-name grob) grob-blacklist))
+ (not (member file-line file-line-blacklist))))))
+
+#(define (grob-event-node grob label cluster)
+ (let ((node-id (add-node graph label cluster))
+ (prev (assv grob last-grob-action)))
+ (if (pair? prev)
+ (add-edge graph (cdr prev) node-id))
+ (set! last-grob-action (assv-set! last-grob-action grob node-id))))
+
+#(define (truncate-value val)
+ (let ((val-str (format "~a" val)))
+ (string-take val-str (min 50 (string-length val-str)))))
+
+#(define (grob-mod grob file line func prop val)
+ (let* ((val-str (truncate-value val))
+ (label (format "~a\\n~a:~a\\n~a <- ~a" (grob-name grob) file line prop val-str)))
+ (if (relevant? grob file line prop)
+ (grob-event-node grob label file))))
+
+#(define (grob-cache grob prop callback value)
+ (let* ((val-str (truncate-value value))
+ (label (format "caching ~a.~a\\n~a -> ~a" (grob-name grob) prop callback value)))
+ (if (relevant? grob #f #f prop)
+ (grob-event-node grob label #f))))
+
+#(define (grob-create grob file line func)
+ (let ((label (format "~a\\n~a:~a" (grob-name grob) file line)))
+ (grob-event-node grob label file)))
+
+#(ly:set-grob-modification-callback grob-mod)
+#(ly:set-property-cache-callback grob-cache)
+%#(ly:set-grob-creation-callback grob-create)
+++ /dev/null
-\version "2.11.15"
-
-#(use-modules (scm graphviz))
-
-#(define last-grob-action '())
-
-#(define sym-blacklist '())
-#(define sym-whitelist '())
-
-#(define file-line-blacklist '())
-#(define file-line-whitelist '())
-
-#(define grob-blacklist '())
-#(define grob-whitelist '())
-
-#(define (blacklist-symbol sym)
- (set! sym-blacklist (cons sym sym-blacklist)))
-
-#(define (whitelist-symbol sym)
- (set! sym-whitelist (cons sym sym-whitelist)))
-
-#(define (whitelist-grob str)
- (set! grob-whitelist (cons str grob-whitelist)))
-
-#(define graph (make-graph "graph.dot"))
-
-#(define (grob-name g)
- (let* ((meta (ly:grob-property g 'meta))
- (name-pair (assq 'name meta)))
- (if (pair? name-pair)
- (cdr name-pair)
- #f)))
-
-% an event is relevant if
-% (it is on some whitelist or all whitelists are empty)
-% and
-% (it isn't on any blacklist)
-
-#(define (relevant? grob file line prop)
- (let ((file-line `(,file . ,line)))
- (and
- (or
- (= 0 (length file-line-whitelist) (length sym-whitelist) (length grob-whitelist))
- (memq prop sym-whitelist)
- (memq (grob-name grob) grob-whitelist)
- (member file-line file-line-whitelist))
- (and
- (not (memq prop sym-blacklist))
- (not (memq (grob-name grob) grob-blacklist))
- (not (member file-line file-line-blacklist))))))
-
-#(define (grob-event-node grob label cluster)
- (let ((node-id (add-node graph label cluster))
- (prev (assv grob last-grob-action)))
- (if (pair? prev)
- (add-edge graph (cdr prev) node-id))
- (set! last-grob-action (assv-set! last-grob-action grob node-id))))
-
-#(define (truncate-value val)
- (let ((val-str (format "~a" val)))
- (string-take val-str (min 50 (string-length val-str)))))
-
-#(define (grob-mod grob file line func prop val)
- (let* ((val-str (truncate-value val))
- (label (format "~a\\n~a:~a\\n~a <- ~a" (grob-name grob) file line prop val-str)))
- (if (relevant? grob file line prop)
- (grob-event-node grob label file))))
-
-#(define (grob-cache grob prop callback value)
- (let* ((val-str (truncate-value value))
- (label (format "caching ~a.~a\\n~a -> ~a" (grob-name grob) prop callback value)))
- (if (relevant? grob #f #f prop)
- (grob-event-node grob label #f))))
-
-#(define (grob-create grob file line func)
- (let ((label (format "~a\\n~a:~a" (grob-name grob) file line)))
- (grob-event-node grob label file)))
-
-#(ly:set-grob-modification-callback grob-mod)
-#(ly:set-property-cache-callback grob-cache)
-%#(ly:set-grob-creation-callback grob-create)
(define-module (scm graphviz)
#:use-module (lily)
- #:export (make-graph add-node add-edge add-cluster))
+ #:export
+ (make-graph add-node add-edge add-cluster
+ graph-write
+ ))
(define (make-graph filename)
- (let ((empty-graph (list->vector (list filename '() '() '()))))
- (ly:atexit write-graph (list empty-graph))
- empty-graph))
+ #(() () () ()))
-(define (filename g) (vector-ref g 0))
+
+;; fixme: use structs/records.
+;; fixme add & use setters.
(define (nodes g) (vector-ref g 1))
(define (edges g) (vector-ref g 2))
(define (clusters g) (vector-ref g 3))
(define (add-edge graph node1 node2)
(vector-set! graph 2 (cons `(,node1 . ,node2) (edges graph))))
-(define (write-graph graph)
- (let ((out (open-file (filename graph) "w"))
- (ns (nodes graph))
+(define (graph-write graph out)
+ (let ((ns (nodes graph))
(es (edges graph))
(cs (clusters graph)))
- (ly:message (format "writing graph ~s..." (filename graph)))
+ (ly:message (format (_ "Writing graph `~a'...") (port-filename out)))
(display "digraph G {\nrankdir=\"LR\"\nnode [shape=rectangle]\n" out)
(map (lambda (n) (display (format "~a [label=\"~a\"]\n" (car n) (cdr n)) out))
ns)