1 ;;; geiser-repl.el --- Geiser's REPL
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>.
12 (require 'geiser-company
)
13 (require 'geiser-autodoc
)
14 (require 'geiser-edit
)
15 (require 'geiser-impl
)
16 (require 'geiser-eval
)
17 (require 'geiser-connection
)
18 (require 'geiser-menu
)
19 (require 'geiser-custom
)
20 (require 'geiser-base
)
29 (defgroup geiser-repl nil
30 "Interacting with the Geiser REPL."
33 (geiser-custom--defcustom geiser-repl-use-other-window t
34 "Whether to Use a window other than the current buffer's when
35 switching to the Geiser REPL buffer."
39 (geiser-custom--defcustom geiser-repl-window-allow-split t
40 "Whether to allow window splitting when switching to the Geiser
45 (geiser-custom--defcustom geiser-repl-history-filename
(expand-file-name "~/.geiser_history")
46 "File where REPL input history is saved, so that it persists between sessions.
47 This is actually the base name: the concrete Scheme
48 implementation name gets appended to it."
52 (geiser-custom--defcustom geiser-repl-history-size comint-input-ring-size
53 "Maximum size of the saved REPL input history."
57 (geiser-custom--defcustom geiser-repl-history-no-dups-p t
58 "Whether to skip duplicates when recording history."
62 (geiser-custom--defcustom geiser-repl-autodoc-p t
63 "Whether to enable `geiser-autodoc-mode' in the REPL by default."
67 (geiser-custom--defcustom geiser-repl-company-p t
68 "Whether to use company-mode for completion, if available."
72 (geiser-custom--defcustom geiser-repl-read-only-prompt-p t
73 "Whether the REPL's prompt should be read-only."
77 (geiser-custom--defcustom geiser-repl-auto-indent-p t
78 "Whether newlines for incomplete sexps are autoindented."
82 (geiser-custom--defcustom geiser-repl-forget-old-errors-p t
83 "Whether to forget old errors upon entering a new expression.
85 When on (the default), every time a new expression is entered in
86 the REPL old error messages are flushed, and using \\[next-error]
87 afterwards will jump only to error locations produced by the new
93 ;;; Geiser REPL buffers and processes:
95 (defvar geiser-repl--repls nil
)
96 (defvar geiser-repl--closed-repls nil
)
98 (make-variable-buffer-local
99 (defvar geiser-repl--repl nil
))
101 (defsubst geiser-repl--set-this-buffer-repl
(r)
102 (setq geiser-repl--repl r
))
104 (defun geiser-repl--live-p ()
105 (and geiser-repl--repl
106 (get-buffer-process geiser-repl--repl
)))
108 (defun geiser-repl--repl/impl
(impl &optional repls
)
110 (dolist (repl (or repls geiser-repl--repls
))
111 (with-current-buffer repl
112 (when (eq geiser-impl--implementation impl
)
113 (throw 'repl repl
))))))
115 (defun geiser-repl--set-up-repl (impl)
116 (or (and (not impl
) geiser-repl--repl
)
117 (setq geiser-repl--repl
119 geiser-impl--implementation
120 (geiser-impl--guess))))
121 (when impl
(geiser-repl--repl/impl impl
))))))
123 (defun geiser-repl--active-impls ()
125 (dolist (repl geiser-repl--repls act
)
126 (with-current-buffer repl
127 (add-to-list 'act geiser-impl--implementation
)))))
129 (defsubst geiser-repl--repl-name
(impl)
130 (format "%s REPL" (geiser-impl--impl-str impl
)))
132 (defun geiser-repl--to-repl-buffer (impl)
133 (unless (and (eq major-mode
'geiser-repl-mode
)
134 (not (get-buffer-process (current-buffer))))
135 (let* ((old (geiser-repl--repl/impl impl geiser-repl--closed-repls
))
136 (old (and (buffer-live-p old
)
137 (not (get-buffer-process old
))
141 (generate-new-buffer (format "* %s *"
142 (geiser-repl--repl-name impl
)))))))
144 (geiser-impl--set-buffer-implementation impl
))
146 (geiser-impl--define-caller geiser-repl--binary binary
()
147 "A variable or function returning the path to the scheme binary
148 for this implementation.")
150 (geiser-impl--define-caller geiser-repl--arglist arglist
()
151 "A function taking no arguments and returning a list of
152 arguments to be used when invoking the scheme binary.")
154 (geiser-impl--define-caller geiser-repl--prompt-regexp prompt-regexp
()
155 "A variable (or thunk returning a value) giving the regular
156 expression for this implementation's scheme prompt.")
158 (geiser-impl--define-caller
159 geiser-repl--debugger-prompt-regexp debugger-prompt-regexp
()
160 "A variable (or thunk returning a value) giving the regular
161 expression for this implementation's debugging prompt.")
163 (geiser-impl--define-caller
164 geiser-repl--debugger-preamble-regexp debugger-preamble-regexp
()
165 "A variable (or thunk returning a value) used to determine whether
166 the REPL has entered debugging mode.")
168 (geiser-impl--define-caller geiser-repl--startup startup
()
169 "Function taking no parameters that is called after the REPL
170 has been initialised. All Geiser functionality is available to
173 (defun geiser-repl--start-repl (impl)
174 (message "Starting Geiser REPL for %s ..." impl
)
175 (geiser-repl--to-repl-buffer impl
)
176 (let ((binary (geiser-repl--binary impl
))
177 (args (geiser-repl--arglist impl
))
178 (prompt-rx (geiser-repl--prompt-regexp impl
))
179 (deb-prompt-rx (geiser-repl--debugger-prompt-regexp impl
))
180 (deb-preamble-rx (geiser-repl--debugger-preamble-regexp impl
))
181 (cname (geiser-repl--repl-name impl
)))
182 (unless (and binary prompt-rx
)
183 (error "Sorry, I don't know how to start a REPL for %s" impl
))
184 (set (make-local-variable 'comint-prompt-regexp
) prompt-rx
)
185 (apply 'make-comint-in-buffer
186 `(,cname
,(current-buffer) ,binary nil
,@args
))
187 (geiser-repl--wait-for-prompt 10000)
188 (geiser-repl--history-setup)
189 (geiser-con--setup-connection (current-buffer)
193 (add-to-list 'geiser-repl--repls
(current-buffer))
194 (geiser-repl--set-this-buffer-repl (current-buffer))
195 (geiser-repl--startup impl
)))
197 (defun geiser-repl--process ()
198 (let ((buffer (geiser-repl--set-up-repl geiser-impl--implementation
)))
199 (or (and (buffer-live-p buffer
) (get-buffer-process buffer
))
200 (error "No Geiser REPL for this buffer (try M-x run-geiser)"))))
202 (setq geiser-eval--default-proc-function
'geiser-repl--process
)
204 (defun geiser-repl--wait-for-prompt (timeout)
205 (let ((p (point)) (seen) (buffer (current-buffer)))
206 (while (and (not seen
)
208 (get-buffer-process buffer
))
210 (setq timeout
(- timeout
100))
212 (setq seen
(re-search-forward comint-prompt-regexp nil t
)))
213 (goto-char (point-max))
214 (unless seen
(error "No prompt found!"))))
217 ;;; Interface: starting and interacting with geiser REPL:
219 (defun geiser-repl--read-impl (prompt &optional active
)
220 (geiser-impl--read-impl prompt
(and active
(geiser-repl--active-impls))))
222 (defsubst geiser-repl--only-impl-p
()
223 (and (null (cdr geiser-active-implementations
))
224 (car geiser-active-implementations
)))
226 (defun run-geiser (impl)
227 "Start a new Geiser REPL."
229 (list (or (geiser-repl--only-impl-p)
230 (and (eq major-mode
'geiser-repl-mode
)
231 geiser-impl--implementation
)
232 (geiser-repl--read-impl
233 "Start Geiser for scheme implementation: "))))
234 (geiser-repl--start-repl impl
))
236 (make-variable-buffer-local
237 (defvar geiser-repl--last-scm-buffer nil
))
239 (defun switch-to-geiser (&optional ask impl buffer
)
240 "Switch to running Geiser REPL.
241 With prefix argument, ask for which one if more than one is running.
242 If no REPL is running, execute `run-geiser' to start a fresh one."
244 (let* ((impl (or impl geiser-impl--implementation
))
245 (repl (cond ((and (not ask
) (not impl
)
246 (or geiser-repl--repl
(car geiser-repl--repls
))))
247 ((and (not ask
) impl
(geiser-repl--repl/impl impl
)))))
248 (pop-up-windows geiser-repl-window-allow-split
))
249 (cond ((and (eq (current-buffer) repl
)
250 (not (eq repl buffer
))
251 (buffer-live-p geiser-repl--last-scm-buffer
))
252 (pop-to-buffer geiser-repl--last-scm-buffer
))
253 (repl (pop-to-buffer repl
))
254 (t (run-geiser (or impl
256 (geiser-repl--only-impl-p))
257 (geiser-repl--read-impl
258 "Switch to scheme REPL: ")))))
259 (when (and buffer
(eq major-mode
'geiser-repl-mode
))
260 (setq geiser-repl--last-scm-buffer buffer
))))
262 (defalias 'geiser
'switch-to-geiser
)
264 (defun geiser-repl--send (cmd)
265 (when (and cmd
(eq major-mode
'geiser-repl-mode
))
266 (goto-char (point-max))
269 (let ((comint-input-filter (lambda (x) nil
)))
270 (comint-send-input nil t
))))
272 (geiser-impl--define-caller geiser-repl--enter-cmd enter-command
(module)
273 "Function taking a module designator and returning a REPL enter
274 module command as a string")
276 (defun switch-to-geiser-module (&optional module buffer
)
277 "Switch to running Geiser REPL and try to enter a given module."
279 (let* ((module (or module
280 (geiser-completion--read-module "Switch to module: ")))
282 (geiser-repl--enter-cmd geiser-impl--implementation
284 (unless (eq major-mode
'geiser-repl-mode
)
285 (switch-to-geiser nil nil
(or buffer
(current-buffer))))
286 (geiser-repl--send cmd
)))
288 (geiser-impl--define-caller geiser-repl--import-cmd import-command
(module)
289 "Function taking a module designator and returning a REPL import
290 module command as a string")
292 (defun geiser-repl-import-module (&optional module
)
293 "Import a given module in the current namespace of the REPL."
295 (let* ((module (or module
296 (geiser-completion--read-module "Import module: ")))
298 (geiser-repl--import-cmd geiser-impl--implementation
300 (switch-to-geiser nil nil
(current-buffer))
301 (geiser-repl--send cmd
)))
303 (defun geiser-repl-nuke ()
304 "Try this command if the REPL becomes unresponsive."
306 (goto-char (point-max))
307 (comint-kill-region comint-last-input-start
(point))
308 (comint-redirect-cleanup)
309 (geiser-con--setup-connection (current-buffer)
311 geiser-con--debugging-prompt-regexp
312 geiser-con--debugging-preamble-regexp
))
315 ;;; REPL history and clean-up:
317 (defsubst geiser-repl--history-file
()
318 (format "%s.%s" geiser-repl-history-filename geiser-impl--implementation
))
320 (defun geiser-repl--on-quit ()
321 (comint-write-input-ring)
322 (let ((cb (current-buffer))
323 (impl geiser-impl--implementation
)
324 (comint-prompt-read-only nil
))
325 (setq geiser-repl--repls
(remove cb geiser-repl--repls
))
326 (dolist (buffer (buffer-list))
327 (when (buffer-live-p buffer
)
328 (with-current-buffer buffer
329 (when (and (eq geiser-impl--implementation impl
)
330 (equal cb geiser-repl--repl
))
331 (geiser-repl--set-up-repl geiser-impl--implementation
)))))))
333 (defun geiser-repl--sentinel (proc event
)
334 (let ((pb (process-buffer proc
)))
335 (when (buffer-live-p pb
)
336 (with-current-buffer pb
337 (let ((comint-prompt-read-only nil
)
338 (comint-input-ring-file-name (geiser-repl--history-file)))
339 (geiser-repl--on-quit)
340 (push pb geiser-repl--closed-repls
)
341 (when (buffer-name (current-buffer))
342 (comint-kill-region comint-last-input-start
(point))
343 (insert "\nIt's been nice interacting with you!\n")
344 (insert "Press C-c C-z to bring me back.\n" )))))))
346 (defun geiser-repl--on-kill ()
347 (geiser-repl--on-quit)
348 (setq geiser-repl--closed-repls
349 (remove (current-buffer) geiser-repl--closed-repls
)))
351 (defun geiser-repl--input-filter (str)
352 (not (or (geiser-con--is-debugging)
353 (string-match "^\\s *$" str
)
354 (string-match "^,quit *$" str
))))
356 (defun geiser-repl--old-input ()
360 (buffer-substring (point) end
))))
362 (defun geiser-repl--history-setup ()
363 (set (make-local-variable 'comint-input-ring-file-name
)
364 (geiser-repl--history-file))
365 (set (make-local-variable 'comint-input-ring-size
) geiser-repl-history-size
)
366 (set (make-local-variable 'comint-input-filter
) 'geiser-repl--input-filter
)
367 (set (make-local-variable 'comint-get-old-input
) 'geiser-repl--old-input
)
368 (add-hook 'kill-buffer-hook
'geiser-repl--on-kill nil t
)
369 (comint-read-input-ring t
)
370 (set-process-sentinel (get-buffer-process (current-buffer))
371 'geiser-repl--sentinel
))
374 ;;; geiser-repl mode:
376 (defun geiser-repl--bol ()
378 (when (= (point) (comint-bol)) (beginning-of-line)))
380 (defun geiser-repl--beginning-of-defun ()
382 (when comint-last-prompt-overlay
383 (narrow-to-region (overlay-end comint-last-prompt-overlay
) (point)))
384 (let ((beginning-of-defun-function nil
))
385 (beginning-of-defun))))
387 (defun geiser-repl--module-function (&optional ignore
) :f
)
389 (defun geiser-repl--doc-module ()
391 (let ((geiser-eval--get-module-function
392 (geiser-impl--method 'find-module geiser-impl--implementation
)))
393 (geiser-doc-module)))
395 (defun geiser-repl--newline-and-indent ()
398 (narrow-to-region comint-last-input-start
(point-max))
402 (defun geiser-repl--nesting-level ()
403 (let ((begin (if comint-last-prompt-overlay
404 (overlay-end comint-last-prompt-overlay
)
405 (save-excursion (geiser-repl--bol) (point)))))
407 (narrow-to-region begin
(point-max))
408 (geiser-syntax--nesting-level))))
410 (defun geiser-repl--send-input ()
411 (let* ((proc (get-buffer-process (current-buffer)))
412 (pmark (and proc
(process-mark proc
)))
413 (intxt (and pmark
(buffer-substring pmark
(point)))))
415 (when (and geiser-repl-forget-old-errors-p
416 (not (geiser-con--is-debugging)))
417 (compilation-forget-errors))
419 (when (string-match "^\\s-*$" intxt
)
420 (comint-send-string proc
421 (geiser-eval--scheme-str '((:ge no-values
))))
422 (comint-send-string proc
"\n")))))
424 (defun geiser-repl--maybe-send ()
428 (if (<= (geiser-repl--nesting-level) 0)
429 (geiser-repl--send-input)
431 (if geiser-repl-auto-indent-p
432 (geiser-repl--newline-and-indent)
435 (define-derived-mode geiser-repl-mode comint-mode
"REPL"
436 "Major mode for interacting with an inferior scheme repl process.
437 \\{geiser-repl-mode-map}"
438 (scheme-mode-variables)
439 (set (make-local-variable 'mode-line-process
) nil
)
440 (set (make-local-variable 'comint-use-prompt-regexp
) nil
)
441 (set (make-local-variable 'comint-prompt-read-only
)
442 geiser-repl-read-only-prompt-p
)
443 (set (make-local-variable 'beginning-of-defun-function
)
444 'geiser-repl--beginning-of-defun
)
445 (set (make-local-variable 'comint-input-ignoredups
)
446 geiser-repl-history-no-dups-p
)
447 (setq geiser-eval--get-module-function
'geiser-repl--module-function
)
448 (when geiser-repl-autodoc-p
(geiser-autodoc-mode 1))
449 (setq geiser-autodoc--inhibit-function
'geiser-con--is-debugging
)
450 (geiser-company--setup geiser-repl-company-p
)
451 (setq geiser-smart-tab-mode-string
"")
452 ;; enabling compilation-shell-minor-mode without the annoying highlighter
453 (compilation-setup t
))
455 (define-key geiser-repl-mode-map
"\C-d" 'delete-char
)
456 (define-key geiser-repl-mode-map
"\C-m" 'geiser-repl--maybe-send
)
457 (define-key geiser-repl-mode-map
[return] 'geiser-repl--maybe-send)
458 (define-key geiser-repl-mode-map "\C-j" 'geiser-repl--newline-and-indent)
460 (define-key geiser-repl-mode-map "\C-a" 'geiser-repl--bol)
461 (define-key geiser-repl-mode-map (kbd "<home>") 'geiser-repl--bol)
463 (geiser-menu--defmenu repl geiser-repl-mode-map
464 ("Complete symbol" ((kbd "TAB") (kbd "M-TAB"))
465 geiser-completion--complete-symbol :enable (symbol-at-point))
466 ("Complete module name" ((kbd "C-.") (kbd "M-`"))
467 geiser-completion--complete-module :enable (symbol-at-point))
468 ("Edit symbol" "\M-." geiser-edit-symbol-at-point
469 :enable (symbol-at-point))
471 ("Switch to module..." "\C-c\C-m" switch-to-geiser-module)
472 ("Import module..." "\C-c\C-i" geiser-repl-import-module)
474 ("Previous matching input" "\M-p" comint-previous-matching-input-from-input
475 "Previous input matching current")
476 ("Next matching input" "\M-n" comint-next-matching-input-from-input
477 "Next input matching current")
478 ("Previous input" "\C-c\M-p" comint-previous-input)
479 ("Next input" "\C-c\M-n" comint-next-input)
481 (mode "Autodoc mode" ("\C-c\C-da" "\C-c\C-d\C-a") geiser-autodoc-mode)
482 ("Symbol documentation" ("\C-c\C-dd" "\C-c\C-d\C-d")
483 geiser-doc-symbol-at-point
484 "Documentation for symbol at point" :enable (symbol-at-point))
485 ("Module documentation" ("\C-c\C-dm" "\C-c\C-d\C-m") geiser-repl--doc-module
486 "Documentation for module at point" :enable (symbol-at-point))
488 ("Kill Scheme interpreter" "\C-c\C-q" comint-kill-subjob
489 :enable (geiser-repl--live-p))
490 ("Restart" "\C-c\C-z" switch-to-geiser :enable (not (geiser-repl--live-p)))
491 ("Revive REPL" "\C-c\C-k" geiser-repl-nuke
492 "Use this command if the REPL becomes irresponsive"
493 :enable (geiser-repl--live-p))
495 (custom "REPL options" geiser-repl))
497 (define-key geiser-repl-mode-map [menu-bar completion] 'undefined)
502 (defun geiser-repl--repl-list ()
504 (dolist (repl geiser-repl--repls lst)
505 (when (buffer-live-p repl)
506 (with-current-buffer repl
507 (push geiser-impl--implementation lst))))))
509 (defun geiser-repl--restore (impls)
511 (when impl (run-geiser impl))))
513 (defun geiser-repl-unload-function ()
514 (dolist (repl geiser-repl--repls)
515 (when (buffer-live-p repl)
516 (kill-buffer repl))))
519 (provide 'geiser-repl)
520 ;;; geiser-repl.el ends here