#lang scheme/base (require scribble/eval scribble/core scribble/scheme scheme/class scheme/file scheme/runtime-path scheme/serialize "private/gui-eval-exn.ss" scheme/system) (define-syntax define-mr (syntax-rules () [(_ mr orig) (begin (provide mr) (define-syntax mr (syntax-rules () [(_ x (... ...)) (parameterize ([scribble-eval-handler gui-eval-handler]) (orig #:eval gui-eval x (... ...)))])))])) (define gui-eval (make-base-eval)) (define-mr gui-interaction interaction) (define-mr gui-interaction-eval interaction-eval) (define-mr gui-interaction-eval-show interaction-eval-show) (define-mr gui-def+int def+int) (define-mr gui-defs+int defs+int) (define-mr gui-schememod+eval schememod+eval) (define-mr gui-schemeblock+eval schemeblock+eval) (define mred? (getenv "MREVAL")) (when mred? (gui-eval '(require scheme/gui/base)) (gui-eval '(require slideshow))) ;; This one needs to be relative, because it ends up in the ;; exprs.dat file: (define img-dir "images") ; relative to src dir ;; This one can be absolute: (define exprs-dat-file (build-path "images" "exprs.dat")) (define gui-eval-handler (if mred? (let ([eh (scribble-eval-handler)] [log-file (open-output-file exprs-dat-file #:exists 'truncate/replace)]) (lambda (ev catching-exns? expr) (write (serialize (if (syntax? expr) (syntax->datum expr) expr)) log-file) (newline log-file) (flush-output log-file) (let ([result (with-handlers ([exn:fail? (lambda (exn) (make-gui-exn (exn-message exn)))]) (eh ev catching-exns? expr))]) (let ([result (fixup-picts result)]) (write (serialize result) log-file) (newline log-file) (flush-output log-file) (if (gui-exn? result) (raise (make-exn:fail (gui-exn-message result) (current-continuation-marks))) result))))) (let ([log-file (with-handlers ([exn:fail:filesystem? (lambda (exn) (open-input-string ""))]) (open-input-file exprs-dat-file))]) (lambda (ev catching-exns? expr) (with-handlers ([exn:fail? (lambda (exn) (if catching-exns? (raise exn) (void)))]) (let ([v (read log-file)]) (if (eof-object? v) (error "expression not in log file") (let ([v (deserialize v)]) (if (equal? v (if (syntax? expr) (syntax->datum expr) expr)) (let ([v (read log-file)]) (if (eof-object? v) (error "expression result missing in log file") (let ([v (deserialize v)]) (if (gui-exn? v) (raise (make-exn:fail (gui-exn-message v) (current-continuation-marks))) v)))) (error 'mreval "expression does not match log file: ~e versus: ~e" expr v)))))))))) (define image-counter 0) ;; This path will be marshaled for use on multiple platforms (define (build-string-path a b) (string-append a "/" b)) (define (fixup-picts v) (cond [((gui-eval 'pict?) v) (let ([fn (build-string-path img-dir (format "img~a.png" image-counter))]) (set! image-counter (add1 image-counter)) (let ([dc (let ([pss (make-object (gui-eval 'ps-setup%))]) (send pss set-mode 'file) (send pss set-file (path-replace-suffix fn #".ps")) (parameterize ([(gui-eval 'current-ps-setup) pss]) (make-object (gui-eval 'post-script-dc%) #f)))]) (send dc start-doc "Image") (send dc start-page) (((gui-eval 'make-pict-drawer) v) dc 0 0) (send dc end-page) (send dc end-doc) (system (format "epstopdf ~a" (path-replace-suffix fn #".ps")))) (let* ([bm (make-object (gui-eval 'bitmap%) (inexact->exact (ceiling ((gui-eval 'pict-width) v))) (inexact->exact (ceiling ((gui-eval 'pict-height) v))))] [dc (make-object (gui-eval 'bitmap-dc%) bm)]) (send dc set-smoothing 'aligned) (send dc clear) (((gui-eval 'make-pict-drawer) v) dc 0 0) (send bm save-file fn 'png) (make-image-element #f (list "[image]") ;; Be sure to use a string rather than a path, because ;; it gets recorded in "exprs.dat". (path->string (path-replace-suffix fn #"")) '(".pdf" ".png") 1.0)))] [(pair? v) (cons (fixup-picts (car v)) (fixup-picts (cdr v)))] [(serializable? v) v] [else (make-element #f (list (format "~s" v)))]))