Preserve the position of (point) after evaling
[geiser.git] / elisp / geiser-mode.el
blob0d00662584a607d64752b66bc072efef34cf5c89
1 ;; geiser-mode.el -- minor mode for scheme buffers
3 ;; Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 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: Sun Feb 08, 2009 15:13
14 (require 'geiser-repl)
15 (require 'geiser-menu)
16 (require 'geiser-doc)
17 (require 'geiser-compile)
18 (require 'geiser-completion)
19 (require 'geiser-company)
20 (require 'geiser-xref)
21 (require 'geiser-edit)
22 (require 'geiser-autodoc)
23 (require 'geiser-debug)
24 (require 'geiser-syntax)
25 (require 'geiser-impl)
26 (require 'geiser-eval)
27 (require 'geiser-popup)
28 (require 'geiser-custom)
29 (require 'geiser-base)
32 ;;; Customization:
34 (defgroup geiser-mode nil
35 "Mode enabling Geiser abilities in Scheme buffers &co.."
36 :group 'geiser)
38 (geiser-custom--defcustom geiser-mode-auto-p t
39 "Whether `geiser-mode' should be active by default in all scheme buffers."
40 :group 'geiser-mode
41 :type 'boolean)
43 (geiser-custom--defcustom geiser-mode-start-repl-p nil
44 "Whether a REPL should be automatically started if one is not
45 active when `geiser-mode' is activated in a buffer."
46 :group 'geiser-mode
47 :type 'boolean)
49 (geiser-custom--defcustom geiser-mode-autodoc-p t
50 "Whether `geiser-autodoc-mode' gets enabled by default in Scheme buffers."
51 :group 'geiser-mode
52 :group 'geiser-autodoc
53 :type 'boolean)
55 (geiser-custom--defcustom geiser-mode-company-p t
56 "Whether to use company-mode for completion, if available."
57 :group 'geiser-mode
58 :type 'boolean)
60 (geiser-custom--defcustom geiser-mode-smart-tab-p nil
61 "Whether `geiser-smart-tab-mode' gets enabled by default in Scheme buffers."
62 :group 'geiser-mode
63 :type 'boolean)
65 (geiser-custom--defcustom geiser-mode-eval-last-sexp-to-buffer nil
66 "Whether `eval-last-sexp' prints results to buffer"
67 :group 'geiser-mode
68 :type 'boolean)
70 (geiser-custom--defcustom geiser-mode-eval-to-buffer-prefix " "
71 "When `geiser-mode-eval-last-sexp-to-buffer', the prefix string which will prepend to results"
72 :group 'geiser-mode
73 :type 'string)
77 ;;; Evaluation commands:
79 (defun geiser--go-to-repl ()
80 (switch-to-geiser nil nil (current-buffer))
81 (push-mark)
82 (goto-char (point-max)))
84 (defun geiser-eval-region (start end &optional and-go raw nomsg)
85 "Eval the current region in the Geiser REPL.
87 With prefix, goes to the REPL buffer afterwards (as
88 `geiser-eval-region-and-go')"
89 (interactive "rP")
90 (save-restriction
91 (narrow-to-region start end)
92 (check-parens))
93 (geiser-debug--send-region nil
94 start
95 end
96 (and and-go 'geiser--go-to-repl)
97 (not raw)
98 nomsg))
100 (defun geiser-eval-region-and-go (start end)
101 "Eval the current region in the Geiser REPL and visit it afterwads."
102 (interactive "r")
103 (geiser-eval-region start end t))
105 (geiser-impl--define-caller geiser-eval--bounds eval-bounds ()
106 "A pair with the bounds of a buffer to be evaluated, defaulting
107 to (cons (point-min) . (point-max)).")
109 (defun geiser-eval-buffer (&optional and-go raw nomsg)
110 "Eval the current buffer in the Geiser REPL.
112 With prefix, goes to the REPL buffer afterwards (as
113 `geiser-eval-buffer-and-go')"
114 (interactive "P")
115 (let* ((bounds (geiser-eval--bounds geiser-impl--implementation))
116 (from (or (car bounds) (point-min)))
117 (to (or (cdr bounds) (point-max))))
118 (geiser-eval-region from to and-go raw nomsg)))
120 (defun geiser-eval-buffer-and-go ()
121 "Eval the current buffer in the Geiser REPL and visit it afterwads."
122 (interactive)
123 (geiser-eval-buffer t))
125 (defun geiser-eval-definition (&optional and-go)
126 "Eval the current definition in the Geiser REPL.
128 With prefix, goes to the REPL buffer afterwards (as
129 `geiser-eval-definition-and-go')"
130 (interactive "P")
131 (save-excursion
132 (end-of-defun)
133 (let ((end (point)))
134 (beginning-of-defun)
135 (geiser-eval-region (point) end and-go t))))
137 (defun geiser-eval-definition-and-go ()
138 "Eval the current definition in the Geiser REPL and visit it afterwads."
139 (interactive)
140 (geiser-eval-definition t))
142 (defun geiser-eval-last-sexp (print-to-buffer-p)
143 "Eval the previous sexp in the Geiser REPL.
145 With a prefix, revert the effect of `geiser-mode-eval-last-sexp-to-buffer' "
146 (interactive "P")
147 (let* (bosexp
148 (eosexp (save-excursion (backward-sexp)
149 (setq bosexp (point))
150 (forward-sexp)
151 (point)))
152 (ret (save-excursion
153 (geiser-eval-region bosexp ;beginning of sexp
154 eosexp ;end of sexp
157 print-to-buffer-p)))
158 (err (geiser-eval--retort-error ret))
159 (will-eval-to-buffer (if print-to-buffer-p
160 (not geiser-mode-eval-last-sexp-to-buffer)
161 geiser-mode-eval-last-sexp-to-buffer))
162 (str (geiser-eval--retort-result-str ret (when will-eval-to-buffer ""))))
163 (cond ((not will-eval-to-buffer) str)
164 (err (insert (format "%sERROR:%s"
165 geiser-mode-eval-to-buffer-prefix
166 (geiser-eval--error-str err))))
167 ((string= "" str))
168 (t (push-mark)
169 (insert (format "%s%s" geiser-mode-eval-to-buffer-prefix str))))))
171 (defun geiser-compile-definition (&optional and-go)
172 "Compile the current definition in the Geiser REPL.
174 With prefix, goes to the REPL buffer afterwards (as
175 `geiser-eval-definition-and-go')"
176 (interactive "P")
177 (save-excursion
178 (end-of-defun)
179 (let ((end (point)))
180 (beginning-of-defun)
181 (geiser-debug--send-region t
182 (point)
184 (and and-go 'geiser--go-to-repl)
185 t))))
187 (defun geiser-compile-definition-and-go ()
188 "Compile the current definition in the Geiser REPL and visit it afterwads."
189 (interactive)
190 (geiser-compile-definition t))
192 (defun geiser-expand-region (start end &optional all raw)
193 "Macro-expand the current region and display it in a buffer.
194 With prefix, recursively macro-expand the resulting expression."
195 (interactive "rP")
196 (geiser-debug--expand-region start end all (not raw)))
198 (defun geiser-expand-definition (&optional all)
199 "Macro-expand the current definition.
201 With prefix, recursively macro-expand the resulting expression."
202 (interactive "P")
203 (save-excursion
204 (end-of-defun)
205 (let ((end (point)))
206 (beginning-of-defun)
207 (geiser-expand-region (point) end all t))))
209 (defun geiser-expand-last-sexp (&optional all)
210 "Macro-expand the previous sexp.
212 With prefix, recursively macro-expand the resulting expression."
213 (interactive "P")
214 (geiser-expand-region (save-excursion (backward-sexp) (point))
215 (point)
219 (defun geiser-set-scheme ()
220 "Associates current buffer with a given Scheme implementation."
221 (interactive)
222 (geiser-syntax--remove-kws)
223 (let ((impl (geiser-impl--read-impl)))
224 (geiser-impl--set-buffer-implementation impl)
225 (geiser-repl--set-up-repl impl)
226 (geiser-syntax--add-kws)
227 (geiser-syntax--fontify)))
229 (defun geiser-mode-switch-to-repl (arg)
230 "Switches to Geiser REPL.
232 With prefix, try to enter the current buffer's module."
233 (interactive "P")
234 (if arg
235 (switch-to-geiser-module (geiser-eval--get-module) (current-buffer))
236 (switch-to-geiser nil nil (current-buffer))))
238 (defun geiser-mode-switch-to-repl-and-enter ()
239 "Switches to Geiser REPL and enters current buffer's module."
240 (interactive)
241 (geiser-mode-switch-to-repl t))
243 (defun geiser-restart-repl ()
244 "Restarts the REPL associated with the current buffer."
245 (interactive)
246 (let ((b (current-buffer)))
247 (geiser-mode-switch-to-repl nil)
248 (comint-kill-subjob)
249 (sit-for 0.1) ;; ugly hack; but i don't care enough to fix it
250 (call-interactively 'run-geiser)
251 (sit-for 0.2) ;; ditto
252 (goto-char (point-max))
253 (pop-to-buffer b)))
255 (defun geiser-squarify (n)
256 "Toggle between () and [] for current form.
258 With numeric prefix, perform that many toggles, forward for
259 positive values and backward for negative."
260 (interactive "p")
261 (let ((pared (and (boundp 'paredit-mode) paredit-mode))
262 (fwd (> n 0))
263 (steps (abs n)))
264 (when (and pared (fboundp 'paredit-mode)) (paredit-mode -1))
265 (unwind-protect
266 (save-excursion
267 (unless (looking-at-p "\\s(") (backward-up-list))
268 (while (> steps 0)
269 (let ((p (point))
270 (round (looking-at-p "(")))
271 (forward-sexp)
272 (backward-delete-char 1)
273 (insert (if round "]" ")"))
274 (goto-char p)
275 (delete-char 1)
276 (insert (if round "[" "("))
277 (setq steps (1- steps))
278 (backward-char)
279 (condition-case nil
280 (progn (when fwd (forward-sexp 2))
281 (backward-sexp))
282 (error (setq steps 0))))))
283 (when (and pared (fboundp 'paredit-mode)) (paredit-mode 1)))))
285 (defun geiser-insert-lambda (&optional full)
286 "Insert λ at point. With prefix, inserts (λ ())."
287 (interactive "P")
288 (if (not full)
289 (insert (make-char 'greek-iso8859-7 107))
290 (insert "(" (make-char 'greek-iso8859-7 107) " ())")
291 (backward-char 2)))
294 ;;; Geiser mode:
296 (make-variable-buffer-local
297 (defvar geiser-mode-string nil
298 "Modeline indicator for geiser-mode"))
300 (defun geiser-mode--lighter ()
301 (or geiser-mode-string
302 (format " %s" (or (geiser-impl--impl-str) "G"))))
304 (defvar geiser-mode-map (make-sparse-keymap))
306 (define-minor-mode geiser-mode
307 "Toggle Geiser's mode.
309 With no argument, this command toggles the mode.
310 Non-null prefix argument turns on the mode.
311 Null prefix argument turns off the mode.
313 When Geiser mode is enabled, a host of nice utilities for
314 interacting with the Geiser REPL is at your disposal.
315 \\{geiser-mode-map}"
316 :init-value nil
317 :lighter (:eval (geiser-mode--lighter))
318 :group 'geiser-mode
319 :keymap geiser-mode-map
320 (when geiser-mode (geiser-impl--set-buffer-implementation nil t))
321 (setq geiser-autodoc-mode-string "/A")
322 (setq geiser-smart-tab-mode-string "/T")
323 (geiser-company--setup (and geiser-mode geiser-mode-company-p))
324 (geiser-completion--setup geiser-mode)
325 (when geiser-mode-autodoc-p
326 (geiser-autodoc-mode (if geiser-mode 1 -1)))
327 (when geiser-mode-smart-tab-p
328 (geiser-smart-tab-mode (if geiser-mode 1 -1)))
329 (geiser-syntax--add-kws)
330 (when (and geiser-mode
331 geiser-mode-start-repl-p
332 (not (geiser-syntax--font-lock-buffer-p))
333 (not (geiser-repl--connection*)))
334 (save-window-excursion (run-geiser geiser-impl--implementation))))
336 (defun turn-on-geiser-mode ()
337 "Enable `geiser-mode' (in a Scheme buffer)."
338 (interactive)
339 (geiser-mode 1))
341 (defun turn-off-geiser-mode ()
342 "Disable `geiser-mode' (in a Scheme buffer)."
343 (interactive)
344 (geiser-mode -1))
346 (defun geiser-mode--maybe-activate ()
347 (when (and geiser-mode-auto-p (eq major-mode 'scheme-mode))
348 (turn-on-geiser-mode)))
351 ;;; Keys:
353 (geiser-menu--defmenu geiserm geiser-mode-map
354 ("Eval sexp before point" "\C-x\C-e" geiser-eval-last-sexp)
355 ("Eval definition" ("\M-\C-x" "\C-c\C-c") geiser-eval-definition)
356 ("Eval definition and go" ("\C-c\M-e" "\C-c\M-e")
357 geiser-eval-definition-and-go)
358 ("Eval region" "\C-c\C-r" geiser-eval-region :enable mark-active)
359 ("Eval region and go" "\C-c\M-r" geiser-eval-region-and-go
360 geiser-eval-region :enable mark-active)
361 ("Eval buffer" "\C-c\C-b" geiser-eval-buffer)
362 ("Eval buffer and go" "\C-c\M-b" geiser-eval-buffer-and-go)
363 ("Load scheme file..." "\C-c\C-l" geiser-load-file)
364 (menu "Macroexpand"
365 ("Sexp before point" ("\C-c\C-m\C-e" "\C-c\C-me")
366 geiser-expand-last-sexp)
367 ("Region" ("\C-c\C-m\C-r" "\C-c\C-mr") geiser-expand-region)
368 ("Definition" ("\C-c\C-m\C-x" "\C-c\C-mx") geiser-expand-definition))
370 ("Symbol documentation" ("\C-c\C-d\C-d" "\C-c\C-dd")
371 geiser-doc-symbol-at-point :enable (geiser--symbol-at-point))
372 ("Short symbol documentation" ("\C-c\C-d\C-s" "\C-c\C-ds")
373 geiser-autodoc-show :enable (geiser--symbol-at-point))
374 ("Module documentation" ("\C-c\C-d\C-m" "\C-c\C-dm") geiser-doc-module)
375 ("Symbol manual lookup" ("\C-c\C-d\C-i" "\C-c\C-di")
376 geiser-doc-look-up-manual :enable (geiser-doc--manual-available-p))
377 (mode "Autodoc mode" ("\C-c\C-d\C-a" "\C-c\C-da") geiser-autodoc-mode)
379 ("Compile buffer" "\C-c\C-k" geiser-compile-current-buffer)
380 ("Switch to REPL" "\C-c\C-z" geiser-mode-switch-to-repl)
381 ("Switch to REPL and enter module" "\C-c\C-a"
382 geiser-mode-switch-to-repl-and-enter)
383 ("Set Scheme..." "\C-c\C-s" geiser-set-scheme)
385 ("Edit symbol at point" "\M-." geiser-edit-symbol-at-point
386 :enable (geiser--symbol-at-point))
387 ("Go to previous definition" "\M-," geiser-pop-symbol-stack)
388 ("Complete symbol" ((kbd "M-TAB")) completion-at-point
389 :enable (geiser--symbol-at-point))
390 ("Complete module name" ((kbd "M-`") (kbd "C-."))
391 geiser-completion--complete-module)
392 ("Edit module" ("\C-c\C-e\C-m" "\C-c\C-em") geiser-edit-module)
393 ("Add to load path..." ("\C-c\C-e\C-l" "\C-c\C-el") geiser-add-to-load-path)
394 ("Toggle ()/[]" ("\C-c\C-e\C-[" "\C-c\C-e[") geiser-squarify)
395 ("Insert λ" ("\C-c\\" "\C-c\C-\\") geiser-insert-lambda)
397 ("Callers" ((kbd "C-c <")) geiser-xref-callers
398 :enable (and (geiser-eval--supported-p 'callers)
399 (geiser--symbol-at-point)))
400 ("Callees" ((kbd "C-c >")) geiser-xref-callees
401 :enable (and (geiser-eval--supported-p 'callees)
402 (geiser--symbol-at-point)))
404 (mode "Smart TAB mode" nil geiser-smart-tab-mode)
406 (custom "Customize Geiser mode" geiser-mode))
408 (define-key geiser-mode-map [menu-bar scheme] 'undefined)
410 ;; (geiser-mode--triple-chord ?x ?m 'geiser-xref-generic-methods)
413 ;;; Reload support:
415 (defun geiser-mode--buffers ()
416 (let ((buffers))
417 (dolist (buffer (buffer-list))
418 (when (buffer-live-p buffer)
419 (set-buffer buffer)
420 (when geiser-mode
421 (push (cons buffer geiser-impl--implementation) buffers))))
422 buffers))
424 (defun geiser-mode--restore (buffers)
425 (dolist (b buffers)
426 (when (buffer-live-p (car b))
427 (set-buffer (car b))
428 (when (cdr b)
429 (geiser-impl--set-buffer-implementation (cdr b)))
430 (geiser-mode 1))))
432 (defun geiser-mode-unload-function ()
433 (dolist (b (geiser-mode--buffers))
434 (with-current-buffer (car b) (geiser-mode nil))))
437 (provide 'geiser-mode)