#!/bin/sh #| -*- scheme -*- exec gracket -tm "$0" "$@" |# #lang racket/gui ;; =========================================================================== (define (insert-to-editor editor . xs) (for-each (lambda (x) (send editor insert (if (string? x) x (make-object editor-snip% x)))) xs)) ;; for number-snips etc (require framework mrlib/matrix-snip) ;; Hack support for "test-case-box%" (define test-sc (new (class snip-class% (define/override (read f) (let ([test (new test%)]) (send test read-from-file f) test)) (super-new)))) (define test% (class editor-snip% (inherit set-snipclass get-editor) (define to-test (new text%)) (define expected (new text%)) (define predicate (new text%)) (define should-raise (new text%)) (define error-message (new text%)) (define/public (read-from-file f) (unless (eq? 2 (send test-sc reading-version f)) (error "BOOM")) (send to-test read-from-file f) (send expected read-from-file f) (send predicate read-from-file f) (send should-raise read-from-file f) (send error-message read-from-file f) (send f get (box 0)) ; enabled? (send f get (box 0)) ; collapsed? (send f get (box 0))) ; error-box (super-new) (set-snipclass test-sc) (insert-to-editor (get-editor) "{{TEST:\n expression: " to-test "\n should be: " expected "\n}}"))) (send test-sc set-classname "test-case-box%") (send test-sc set-version 2) (send (get-the-snip-class-list) add test-sc) ;; Hack support for "text-box%" (define text-box-sc (new (class snip-class% (define/override (read f) (let ([text (new text-box%)]) (send text read-from-file f) text)) (super-new)))) (define text-box% (class editor-snip% (inherit set-snipclass get-editor) (define text (new text%)) (define/public (read-from-file f) (unless (eq? 1 (send text-box-sc reading-version f)) (error "BOOM")) (send text read-from-file f)) (super-new) (set-snipclass text-box-sc) (insert-to-editor (get-editor) "{{TEXT: " text "}}"))) (send text-box-sc set-classname "text-box%") (send text-box-sc set-version 2) (send (get-the-snip-class-list) add text-box-sc) ;; input-port->text-input-port : input-port (any -> any) -> input-port ;; the `filter' function is applied to special values; the filter result is ;; `display'ed into the stream in place of the special (define (input-port->text-input-port src . filter) ;; note that snip->text below already takes care of some snips (define (item->text x) (cond [(is-a? x snip%) (format "~a" (or (send x get-text 0 (send x get-count) #t) x))] [(special-comment? x) (format "#| ~a |#" (special-comment-value x))] [(syntax? x) (syntax->datum x)] [else x])) (let-values ([(filter) (if (pair? filter) (car filter) item->text)] [(in out) (make-pipe 4096)]) (thread (lambda () (let ([s (make-bytes 4096)]) (let loop () (let ([c (read-bytes-avail! s src)]) (cond [(number? c) (write-bytes s out 0 c) (loop)] [(procedure? c) (let ([v (let-values ([(l col p) (port-next-location src)]) (c (object-name src) l col p))]) (display (filter v) out)) (loop)] [else (close-output-port out)])))))) ; Must be EOF in)) (define (snip->text x) (let ([name (and (is-a? x snip%) (send (send x get-snipclass) get-classname))]) (cond [(equal? name "wximage") "{{IMAGE}}"] [(equal? name "(lib \"comment-snip.ss\" \"framework\")") ;; comments will have ";" prefix on every line, and "\n" suffix (format ";{{COMMENT:\n~a;}}\n" (send x get-text 0 (send x get-count)))] [else x]))) (define (unpack-submission str) (let* ([base (make-object editor-stream-in-bytes-base% str)] [stream (make-object editor-stream-in% base)] [text (make-object text%)]) (read-editor-version stream base #t) (read-editor-global-header stream) (send text read-from-file stream) (read-editor-global-footer stream) text)) (provide main) (define (main file) (define submission (file->bytes file)) (copy-port (input-port->text-input-port (open-input-text-editor (unpack-submission submission) 0 'end snip->text)) (current-output-port)))