180 lines
5.0 KiB
Racket
180 lines
5.0 KiB
Racket
#lang typed/racket
|
|
|
|
;; Racket Esquire: a mini DrRacket
|
|
|
|
(require typed/racket/gui)
|
|
|
|
;; The REPL editor class
|
|
(define esq-text%
|
|
(class text%
|
|
;; lexical access to inherited methods
|
|
(inherit insert last-position get-text erase)
|
|
;; private fields
|
|
(define prompt-pos 0)
|
|
(define locked? #t)
|
|
;; augment can-insert? to block pre-prompt inserts
|
|
(define/augment (can-insert? start len)
|
|
(and (>= start prompt-pos)
|
|
(not locked?)))
|
|
;; augment can-delete? to block pre-prompt deletes
|
|
(define/augment (can-delete? start end)
|
|
(and (>= start prompt-pos)
|
|
(not locked?)))
|
|
;; override on-char to detect Enter/Return
|
|
(define/override (on-char c)
|
|
(super on-char c)
|
|
(when (and (eq? (send c get-key-code)
|
|
#\return)
|
|
(not locked?))
|
|
(set! locked? #t)
|
|
(evaluate
|
|
(get-text prompt-pos
|
|
(last-position)))))
|
|
;; method to insert a new prompt
|
|
(: new-prompt (-> Void))
|
|
(define/public (new-prompt)
|
|
(queue-output
|
|
(lambda ()
|
|
(set! locked? #f)
|
|
(insert "> ")
|
|
(set! prompt-pos (last-position)))))
|
|
;; method to display output
|
|
(: output (-> String Void))
|
|
(define/public (output str)
|
|
(queue-output
|
|
(lambda ()
|
|
(let ((was-locked? locked?))
|
|
(set! locked? #f)
|
|
(insert str)
|
|
(set! locked? was-locked?)))))
|
|
;; method to reset the REPL
|
|
(: reset (-> Void))
|
|
(define/public (reset)
|
|
(set! locked? #f)
|
|
(set! prompt-pos 0)
|
|
(erase)
|
|
(new-prompt))
|
|
|
|
;; initialize superclass-defined state
|
|
(super-new)
|
|
;; create the initial prompt
|
|
(new-prompt)))
|
|
|
|
;; Queueing REPL output as an event
|
|
|
|
(define esq-eventspace (current-eventspace))
|
|
|
|
(: queue-output (-> (-> Any) Void))
|
|
(define (queue-output proc)
|
|
(parameterize ((current-eventspace
|
|
esq-eventspace))
|
|
(queue-callback proc #f)))
|
|
|
|
;; GUI creation
|
|
|
|
(define frame
|
|
(make-object frame% "RacketEsq" #f 425 175))
|
|
(define reset-button
|
|
(make-object button% "Reset" frame
|
|
(lambda (b e)
|
|
(reset-program))))
|
|
(define repl-editor (make-object esq-text%))
|
|
|
|
(let ([s (send (send repl-editor get-style-list) find-named-style "Standard")])
|
|
(when s
|
|
(let ([d (make-object style-delta% 'change-size 24)])
|
|
(send s set-delta d))))
|
|
|
|
(define repl-display-canvas
|
|
(make-object editor-canvas% frame))
|
|
(send repl-display-canvas set-editor repl-editor)
|
|
|
|
;; Disable showing the frame for the TR tests
|
|
;(send frame show #t)
|
|
|
|
;; User space initialization
|
|
|
|
(define user-custodian (make-custodian))
|
|
|
|
(define user-output-port
|
|
(make-output-port
|
|
'stdout
|
|
;; always ready
|
|
always-evt
|
|
;; string printer
|
|
(lambda ([s : Bytes] [start : Integer] [end : Integer] nonblock? w/break?)
|
|
(send repl-editor output (bytes->string/utf-8 (subbytes s start end)))
|
|
(- end start))
|
|
;; closer
|
|
(lambda () 'nothing-to-close)))
|
|
|
|
(define user-eventspace
|
|
(parameterize ((current-custodian user-custodian))
|
|
(make-eventspace)))
|
|
|
|
(define user-namespace
|
|
(make-gui-namespace))
|
|
|
|
(define esq-inspector (current-inspector))
|
|
(define user-inspector (make-inspector))
|
|
|
|
;; Evaluation and resetting
|
|
|
|
(: evaluate (-> String Void))
|
|
(define (evaluate expr-str)
|
|
(parameterize ((current-eventspace user-eventspace))
|
|
(queue-callback
|
|
(lambda ()
|
|
(current-command-line-arguments #())
|
|
(current-output-port user-output-port)
|
|
(current-namespace user-namespace)
|
|
(current-inspector user-inspector)
|
|
(exit-handler (lambda (v) (reset-program)))
|
|
(with-handlers ((exn?
|
|
(lambda ([e : exn])
|
|
(display
|
|
(exn-message e))
|
|
(show-where
|
|
(exn-continuation-marks e)))))
|
|
(call-with-values
|
|
(lambda ()
|
|
(eval (instrument
|
|
(cast (read (open-input-string
|
|
expr-str))
|
|
Sexp))))
|
|
(lambda args
|
|
(parameterize ((current-inspector user-inspector))
|
|
(write (car args))))))
|
|
(newline)
|
|
(send repl-editor new-prompt)))))
|
|
|
|
(: reset-program (-> Void))
|
|
(define (reset-program)
|
|
(custodian-shutdown-all user-custodian)
|
|
(set! user-custodian (make-custodian))
|
|
(parameterize ((current-custodian user-custodian))
|
|
(set! user-eventspace (make-eventspace)))
|
|
(set! user-namespace (make-gui-namespace))
|
|
(send repl-editor reset))
|
|
|
|
;; Definition source instrumentation
|
|
|
|
(define where-key (gensym))
|
|
|
|
(: instrument (-> Sexp Sexp))
|
|
(define (instrument expr)
|
|
(if (and (pair? expr)
|
|
(eq? 'define (car expr))
|
|
(pair? (cdr expr))
|
|
(pair? (cadr expr)))
|
|
`(define ,(cadr expr)
|
|
(with-continuation-mark ',where-key ',(caadr expr)
|
|
,@(cddr expr)))
|
|
expr))
|
|
|
|
(: show-where (-> Continuation-Mark-Set Void))
|
|
(define (show-where cm)
|
|
(let ([l (continuation-mark-set->list cm where-key)])
|
|
(unless (null? l)
|
|
(printf " in ~a" (car l)))))
|