Racket: show images with print, write and display
[geiser.git] / scheme / racket / geiser / user.rkt
blobc566309135ff32b353c991c2afa938f05a698cac
1 ;;; user.rkt -- global bindings visible to geiser users
3 ;; Copyright (C) 2010, 2011, 2012, 2013, 2014 Jose Antonio Ortega Ruiz
5 ;; This program is free software; you can redistribute it and/or
6 ;; modify it under the terms of the Modified BSD License. You should
7 ;; have received a copy of the license along with this program. If
8 ;; not, see <http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5>.
10 ;; Start date: Wed Mar 31, 2010 22:24
12 #lang racket
14 (provide init-geiser-repl run-geiser-server start-geiser)
16 (require (for-syntax racket/base)
17          mzlib/thread
18          racket/tcp
19          racket/help
20          geiser
21          geiser/autodoc
22          geiser/images
23          geiser/enter
24          geiser/eval
25          geiser/modules)
27 (define top-namespace (current-namespace))
28 (define last-entered (make-parameter ""))
30 (define (do-enter mod name)
31   (visit-module mod)
32   (last-entered name)
33   (current-namespace (module->namespace mod)))
35 (define (file-mod? mod)
36   (and (list? mod)
37        (= 2 (length mod))
38        (eq? 'file (car mod))
39        (path-string? (cadr mod))))
41 (define (submod-path mod)
42   (and (list? mod)
43        (eq? 'submod (car mod))
44        (> (length mod) 1)
45        (let ([parent (cadr mod)])
46          (cond [(path-string? parent) `(submod (file ,parent) ,@(cddr mod))]
47                [(file-mod? parent) mod]
48                [(symbol? parent) mod]
49                [else #f]))))
51 (define (module-error stx mod)
52   (raise-syntax-error #f "Invalid module path" stx mod))
54 (define (enter! mod stx)
55   (cond [(not mod)
56          (current-namespace top-namespace)
57          (last-entered "")]
58         [(symbol? mod) (do-enter mod (symbol->string mod))]
59         [(path-string? mod) (do-enter `(file ,mod) mod)]
60         [(file-mod? mod) (do-enter mod (cadr mod))]
61         [(submod-path mod) => (lambda (m) (do-enter m m))]
62         [else (module-error stx mod)]))
64 (define (geiser-eval)
65   (define geiser-main (module->namespace 'geiser))
66   (define (eval-here form) (eval form geiser-main))
67   (let* ([mod (read)]
68          [lang (read)]
69          [form (read)]
70          [res (cond [(equal? form '(unquote apply))
71                      (let* ([proc (eval-here (read))]
72                             [args (map eval-here (read))]
73                             [ev (lambda () (apply proc args))])
74                        (eval-in `(,ev) mod lang #t))]
75                     [else ((geiser:eval lang) form mod)])])
76     (datum->syntax #f (list 'quote res))))
78 (define (geiser-load stx)
79   (let* ([mod (read)]
80          [res (call-with-result
81                (lambda ()
82                  (visit-module (cond [(file-mod? mod) mod]
83                                      [(path-string? mod) `(file ,mod)]
84                                      [(submod-path mod)]
85                                      [else (module-error stx mod)]))
86                  (void)))])
87     (datum->syntax stx (list 'quote res))))
89 (define ((geiser-read prompt))
90   (prompt)
91   (flush-output (current-error-port))
92   (flush-output (current-output-port))
93   (let* ([in ((current-get-interaction-input-port))]
94          [form ((current-read-interaction) (object-name in) in)])
95     (syntax-case form ()
96       [(uq cmd) (eq? 'unquote (syntax-e #'uq))
97        (case (syntax-e #'cmd)
98          [(start-geiser) (datum->syntax #f `(list 'port ,(start-geiser)))]
99          [(enter) (enter! (read) #'cmd)]
100          [(geiser-eval) (geiser-eval)]
101          [(geiser-load) (geiser-load #'cmd)]
102          [(geiser-no-values) (datum->syntax #f (void))]
103          [(add-to-load-path) (add-to-load-path (read))]
104          [(set-image-cache) (image-cache (read))]
105          [(help) (get-help (read) (read))]
106          [(image-cache) (image-cache)]
107          [(pwd) (~a (current-directory))]
108          [(cd) (current-directory (~a (read)))]
109          [else form])]
110       [_ form])))
112 (define geiser-prompt
113   (lambda ()
114     (let ([m (namespace->module-name (current-namespace) (last-entered))])
115       (printf "racket@~a> " (regexp-replace* " " m "_")))))
117 (define (geiser-prompt-read prompt)
118   (make-repl-reader (geiser-read prompt)))
120 (define (geiser-loader) (module-loader (current-load/use-compiled)))
122 (define (install-print-handler handler)
123   (let ([p (current-output-port)])
124     (handler p (make-port-print-handler (handler p)))))
126 (define (install-print-handlers)
127   (for-each install-print-handler (list port-print-handler
128                                         port-write-handler
129                                         port-display-handler)))
131 (define (init-geiser-repl)
132   (compile-enforce-module-constants #f)
133   (current-load/use-compiled (geiser-loader))
134   (preload-help)
135   (current-prompt-read (geiser-prompt-read geiser-prompt))
136   (current-print maybe-print-image)
137   (install-print-handlers))
139 (define (run-geiser-repl in out enforce-module-constants)
140   (parameterize [(compile-enforce-module-constants enforce-module-constants)
141                  (current-input-port in)
142                  (current-output-port out)
143                  (current-error-port out)
144                  (current-load/use-compiled (geiser-loader))
145                  (current-prompt-read (geiser-prompt-read geiser-prompt))
146                  (current-print maybe-print-image)]
147     (install-print-handlers)
148     (preload-help)
149     (read-eval-print-loop)))
151 (define server-channel (make-channel))
153 (define (run-geiser-server port enforce-module-constants (hostname #f))
154   (run-server port
155               (lambda (in out)
156                 (run-geiser-repl in out enforce-module-constants))
157               #f
158               void
159               (lambda (p _ __)
160                 (let ([lsner (tcp-listen p 4 #f hostname)])
161                   (let-values ([(_ p __ ___) (tcp-addresses lsner #t)])
162                     (channel-put server-channel p)
163                     lsner)))))
165 (define (start-geiser (port 0) (hostname #f) (enforce-module-constants #f))
166   (thread (lambda ()
167             (run-geiser-server port enforce-module-constants hostname)))
168   (channel-get server-channel))