1 ;; geiser-racket.el -- geiser support for Racket scheme
3 ;; Copyright (C) 2009, 2010 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: Sat Apr 25, 2009 21:13
14 (require 'geiser-edit
)
16 (require 'geiser-eval
)
17 (require 'geiser-syntax
)
18 (require 'geiser-custom
)
19 (require 'geiser-base
)
24 (defgroup geiser-racket nil
25 "Customization for Geiser's Racket flavour."
28 (geiser-custom--defcustom geiser-racket-binary
29 (cond ((eq system-type
'windows-nt
) "Racket.exe")
31 "Name to use to call the racket executable when starting a REPL."
32 :type
'(choice string
(repeat string
))
33 :group
'geiser-racket
)
35 (geiser-custom--defcustom geiser-racket-gracket-binary
36 (cond ((eq system-type
'windows-nt
) "GRacket-text.exe")
38 "Name to use to call the gracket executable when starting a REPL.
39 This executable is used by `run-gracket', and, if
40 `geiser-racket-use-gracket-p' is set to t, by `run-racket'."
41 :type
'(choice string
(repeat string
))
42 :group
'geiser-racket
)
44 (geiser-custom--defcustom geiser-racket-collects nil
45 "A list of paths to be added to racket's collection directories."
47 :group
'geiser-racket
)
49 (geiser-custom--defcustom geiser-racket-init-file
"~/.racket-geiser"
50 "Initialization file with user code for the racket REPL."
52 :group
'geiser-racket
)
54 (geiser-custom--defcustom geiser-racket-use-gracket-p nil
55 "Whether to use the gracket binary to start Racket REPLs."
57 :group
'geiser-racket
)
59 (geiser-custom--defcustom geiser-racket-extra-keywords
60 '("define-syntax-rule" "unless" "when" "with-handlers")
61 "Extra keywords highlighted in Racket buffers."
62 :type
'(repeat string
)
63 :group
'geiser-racket
)
68 (defsubst geiser-racket--real-binary
()
69 (if geiser-racket-use-gracket-p
70 geiser-racket-gracket-binary
71 geiser-racket-binary
))
73 (defun geiser-racket--binary ()
74 (let ((binary (geiser-racket--real-binary)))
75 (if (listp binary
) (car binary
) binary
)))
77 (defun geiser-racket--parameters ()
78 "Return a list with all parameters needed to start racket.
79 This function uses `geiser-racket-init-file' if it exists."
80 (let ((init-file (and (stringp geiser-racket-init-file
)
81 (expand-file-name geiser-racket-init-file
)))
82 (binary (geiser-racket--real-binary))
83 (rackdir (expand-file-name "racket/" geiser-scheme-dir
)))
86 ,@(apply 'append
(mapcar (lambda (p) (list "-S" p
)) geiser-racket-collects
))
87 ,@(and (listp binary
) (cdr binary
))
88 ,@(and init-file
(file-readable-p init-file
) (list "-f" init-file
))
89 "-f" ,(expand-file-name "geiser/startup.rkt" rackdir
))))
91 (defconst geiser-racket--prompt-regexp
"\\(mzscheme\\|racket\\)@[^ ]*?> ")
94 ;;; Evaluation support:
96 (defun geiser-racket--language ()
98 (goto-char (point-min))
99 (if (re-search-forward
100 "^\\(?:#lang\\|(module +[^ ]+?\\) +\\([^ ]+?\\|([^)]+)\\) *$" nil t
)
101 (car (geiser-syntax--read-from-string (match-string-no-properties 1)))
104 (defun geiser-racket--enter-command (module)
105 (when (stringp module
)
106 (cond ((zerop (length module
)) ",enter #f")
107 ((file-name-absolute-p module
) (format ",enter (file %S)" module
))
108 (t (format ",enter %s" module
)))))
110 (defun geiser-racket--geiser-procedure (proc &rest args
)
113 (format ",geiser-eval %s %s %s"
115 (geiser-racket--language)
116 (mapconcat 'identity
(cdr args
) " ")))
117 ((load-file compile-file
)
118 (format ",geiser-eval geiser/main racket (geiser:%s %s)"
120 ((no-values) ",geiser-no-values")
121 (t (format ",apply geiser:%s (%s)" proc
(mapconcat 'identity args
" ")))))
123 (defconst geiser-racket--module-re
124 "^(module +\\([^ ]+\\)")
126 (defun geiser-racket--explicit-module ()
128 (goto-char (point-min))
129 (and (re-search-forward geiser-racket--module-re nil t
)
131 (car (geiser-syntax--read-from-string
132 (match-string-no-properties 1)))))))
134 (defsubst geiser-racket--implicit-module
()
136 (goto-char (point-min))
137 (if (re-search-forward "^#lang " nil t
)
141 (defun geiser-racket--get-module (&optional module
)
142 (cond ((and (null module
) (buffer-file-name)))
143 ;; (geiser-racket--explicit-module)
144 ((null module
) (geiser-racket--implicit-module))
145 ((symbolp module
) module
)
146 ((and (stringp module
) (file-name-absolute-p module
)) module
)
147 ((stringp module
) (intern module
))
150 (defun geiser-racket--symbol-begin (module)
151 (save-excursion (skip-syntax-backward "^-()>") (point)))
153 (defun geiser-racket--import-command (module)
154 (and (stringp module
)
155 (not (zerop (length module
)))
156 (format "(require %s)" module
)))
158 (defun geiser-racket--exit-command ()
160 (get-buffer-process (current-buffer)))
162 (defconst geiser-racket--binding-forms
163 '(for for
/list for
/hash for
/hasheq for
/and for
/or
164 for
/lists for
/first for
/last for
/fold
165 for
: for
/list
: for
/hash
: for
/hasheq
: for
/and
: for
/or
:
166 for
/lists
: for
/first
: for
/last
: for
/fold
:))
168 (defconst geiser-racket--binding-forms
*
169 '(for* for
*/list for
*/lists for
*/hash for
*/hasheq for
*/and
170 for
*/or for
*/first for
*/last for
*/fold
171 for
*: for
*/list
: for
*/lists
: for
*/hash
: for
*/hasheq
: for
*/and
:
172 for
*/or
: for
*/first
: for
*/last
: for
*/fold
:))
176 (defsubst geiser-racket--get-help
(symbol module
)
177 (geiser-eval--send/wait
178 `(:eval
(get-help ',symbol
'(:module
,module
)) geiser
/autodoc
)))
180 (defun geiser-racket--external-help (id module
)
181 (message "Requesting help for '%s'..." id
)
182 (let ((out (geiser-eval--retort-output
183 (geiser-racket--get-help id module
))))
184 (when (and out
(string-match " but provided by:\n +\\(.+\\)\n" out
))
185 (geiser-racket--get-help id
(match-string 1 out
))))
186 (minibuffer-message "%s done" (current-message))
192 (defconst geiser-racket--file-rxs
194 "path:\"?\\([^>\"\n]+\\)\"?>"
195 "module: \"\\([^>\"\n]+\\)\""))
197 (defconst geiser-racket--geiser-file-rx
198 (format "^%s/?racket/geiser" (regexp-quote geiser-scheme-dir
)))
200 (defun geiser-racket--purge-trace ()
202 (while (re-search-forward geiser-racket--geiser-file-rx nil t
)
205 (defun geiser-racket--display-error (module key msg
)
208 (geiser-doc--insert-button key nil
'racket
)
216 (geiser-racket--purge-trace)
217 (mapc 'geiser-edit--buttonize-files geiser-racket--file-rxs
)
220 (or key
(not (zerop (length msg
)))))
223 ;;; Trying to ascertain whether a buffer is mzscheme scheme:
225 (defun geiser-racket--guess ()
227 (goto-char (point-min))
228 (re-search-forward "#lang " nil t
))
229 (geiser-racket--explicit-module)))
233 (defun geiser-racket--keywords ()
234 (when geiser-racket-extra-keywords
235 `((,(format "[[(]%s\\>" (regexp-opt geiser-racket-extra-keywords
1))
241 (defun connect-to-racket ()
242 "Start a Racket REPL connected to a remote process.
244 The remote process needs to be running a REPL server started
245 using start-geiser, a procedure in the geiser/server module."
247 (geiser-connect 'racket
))
251 ;;; Implementation definition:
253 (define-geiser-implementation racket
254 (unsupported-procedures '(callers callees generic-methods
))
255 (binary geiser-racket--binary
)
256 (arglist geiser-racket--parameters
)
257 (prompt-regexp geiser-racket--prompt-regexp
)
258 (marshall-procedure geiser-racket--geiser-procedure
)
259 (find-module geiser-racket--get-module
)
260 (enter-command geiser-racket--enter-command
)
261 (import-command geiser-racket--import-command
)
262 (exit-command geiser-racket--exit-command
)
263 (find-symbol-begin geiser-racket--symbol-begin
)
264 (display-error geiser-racket--display-error
)
265 (external-help geiser-racket--external-help
)
266 (check-buffer geiser-racket--guess
)
267 (keywords geiser-racket--keywords
)
268 (binding-forms geiser-racket--binding-forms
)
269 (binding-forms* geiser-racket--binding-forms
*))
271 (geiser-impl--add-to-alist 'regexp
"\\.ss$" 'racket t
)
272 (geiser-impl--add-to-alist 'regexp
"\\.rkt$" 'racket t
)
274 (defun run-gracket ()
275 "Start the Racket REPL using gracket instead of plain racket."
277 (let ((geiser-racket-use-gracket-p t
))
281 (provide 'geiser-racket
)