*** empty log message ***
[bpt/emacs.git] / lisp / cmuscheme.el
CommitLineData
2f790b20 1;;; cmuscheme.el -- Scheme process in a buffer. Adapted from tea.el.
c0274f38 2
07168830 3;; Author: Olin Shivers <olin.shivers@cs.cmu.edu>
d1c7011d 4;; Last-Modified: 16 Mar 1992
fd7fa35a 5;; Keyword: processes, lisp
d1c7011d 6
2f790b20
JB
7;;; Copyright Olin Shivers (1988)
8;;; Please imagine a long, tedious, legalistic 5-page gnu-style copyright
9;;; notice appearing here to the effect that you may use this code any
10;;; way you like, as long as you don't charge money for it, remove this
11;;; notice, or hold me liable for its results.
d1c7011d
ER
12
13;;; Commentary:
14
2f790b20
JB
15;;; This is a customisation of comint-mode (see comint.el)
16;;;
17;;; Written by Olin Shivers (olin.shivers@cs.cmu.edu). With bits and pieces
18;;; lifted from scheme.el, shell.el, clisp.el, newclisp.el, cobol.el, et al..
19;;; 8/88
20;;;
21;;; Please send me bug reports, bug fixes, and extensions, so that I can
22;;; merge them into the master source.
23;;;
24;;; The changelog is at the end of this file.
25;;;
26;;; NOTE: MIT Cscheme, when invoked with the -emacs flag, has a special user
27;;; interface that communicates process state back to the superior emacs by
28;;; outputting special control sequences. The gnumacs package, xscheme.el, has
29;;; lots and lots of special purpose code to read these control sequences, and
30;;; so is very tightly integrated with the cscheme process. The cscheme
31;;; interrupt handler and debugger read single character commands in cbreak
32;;; mode; when this happens, xscheme.el switches to special keymaps that bind
33;;; the single letter command keys to emacs functions that directly send the
34;;; character to the scheme process. Cmuscheme mode does *not* provide this
35;;; functionality. If you are a cscheme user, you may prefer to use the
36;;; xscheme.el/cscheme -emacs interaction.
37;;;
38;;; Here's a summary of the pros and cons, as I see them.
39;;; xscheme: Tightly integrated with inferior cscheme process! A few commands
40;;; not in cmuscheme. But. Integration is a bit of a hack. Input
41;;; history only keeps the immediately prior input. Bizarre
42;;; keybindings.
43;;;
44;;; cmuscheme: Not tightly integrated with inferior cscheme process. But.
45;;; Carefully integrated functionality with the entire suite of
46;;; comint-derived CMU process modes. Keybindings reminiscent of
47;;; Zwei and Hemlock. Good input history. A few commands not in
48;;; xscheme.
49;;;
50;;; It's a tradeoff. Pay your money; take your choice. If you use a Scheme
51;;; that isn't Cscheme, of course, there isn't a choice. Xscheme.el is *very*
52;;; Cscheme-specific; you must use cmuscheme.el. Interested parties are
53;;; invited to port xscheme functionality on top of comint mode...
54
55;; YOUR .EMACS FILE
56;;=============================================================================
57;; Some suggestions for your .emacs file.
58;;
59;; ; If cmuscheme lives in some non-standard directory, you must tell emacs
60;; ; where to get it. This may or may not be necessary.
61;; (setq load-path (cons (expand-file-name "~jones/lib/emacs") load-path))
62;;
63;; ; Autoload run-scheme from file cmuscheme.el
64;; (autoload 'run-scheme "cmuscheme"
65;; "Run an inferior Scheme process."
66;; t)
67;;
68;; ; Files ending in ".scm" are Scheme source,
69;; ; so put their buffers in scheme-mode.
70;; (setq auto-mode-alist
71;; (cons '("\\.scm$" . scheme-mode)
72;; auto-mode-alist))
73;;
74;; ; Define C-c t to run my favorite command in inferior scheme mode:
75;; (setq cmuscheme-load-hook
76;; '((lambda () (define-key inferior-scheme-mode-map "\C-ct"
77;; 'favorite-cmd))))
78;;;
79;;; Unfortunately, scheme.el defines run-scheme to autoload from xscheme.el.
80;;; This will womp your declaration to autoload run-scheme from cmuscheme.el
81;;; if you haven't loaded cmuscheme in before scheme. Three fixes:
82;;; - Put the autoload on your scheme mode hook and in your .emacs toplevel:
83;;; (setq scheme-mode-hook
84;;; '((lambda () (autoload 'run-scheme "cmuscheme"
85;;; "Run an inferior Scheme" t))))
86;;; (autoload 'run-scheme "cmuscheme" "Run an inferior Scheme" t)
87;;; Now when scheme.el autoloads, it will restore the run-scheme autoload.
88;;; - Load cmuscheme.el in your .emacs: (load-library 'cmuscheme)
89;;; - Change autoload declaration in scheme.el to point to cmuscheme.el:
90;;; (autoload 'run-scheme "cmuscheme" "Run an inferior Scheme" t)
91;;; *or* just delete the autoload declaration from scheme.el altogether,
92;;; which will allow the autoload in your .emacs to have its say.
93
d1c7011d
ER
94;;; Code:
95
2f790b20
JB
96(require 'scheme)
97(require 'comint)
98
99;;; INFERIOR SCHEME MODE STUFF
100;;;============================================================================
101
102(defvar inferior-scheme-mode-hook nil
103 "*Hook for customising inferior-scheme mode.")
104(defvar inferior-scheme-mode-map nil)
105
106(cond ((not inferior-scheme-mode-map)
107 (setq inferior-scheme-mode-map
108 (full-copy-sparse-keymap comint-mode-map))
109 (define-key inferior-scheme-mode-map "\M-\C-x" ;gnu convention
110 'scheme-send-definition)
111 (define-key inferior-scheme-mode-map "\C-x\C-e" 'scheme-send-last-sexp)
112 (define-key inferior-scheme-mode-map "\C-c\C-l" 'scheme-load-file)
113 (define-key inferior-scheme-mode-map "\C-c\C-k" 'scheme-compile-file)
114 (scheme-mode-commands inferior-scheme-mode-map)))
115
116;; Install the process communication commands in the scheme-mode keymap.
117(define-key scheme-mode-map "\M-\C-x" 'scheme-send-definition);gnu convention
118(define-key scheme-mode-map "\C-x\C-e" 'scheme-send-last-sexp);gnu convention
119(define-key scheme-mode-map "\C-c\C-e" 'scheme-send-definition)
120(define-key scheme-mode-map "\C-c\M-e" 'scheme-send-definition-and-go)
121(define-key scheme-mode-map "\C-c\C-r" 'scheme-send-region)
122(define-key scheme-mode-map "\C-c\M-r" 'scheme-send-region-and-go)
123(define-key scheme-mode-map "\C-c\M-c" 'scheme-compile-definition)
124(define-key scheme-mode-map "\C-c\C-c" 'scheme-compile-definition-and-go)
125(define-key scheme-mode-map "\C-c\C-z" 'switch-to-scheme)
126(define-key scheme-mode-map "\C-c\C-l" 'scheme-load-file)
127(define-key scheme-mode-map "\C-c\C-k" 'scheme-compile-file) ;k for "kompile"
128
129(defun inferior-scheme-mode ()
130 "Major mode for interacting with an inferior Scheme process.
131
132The following commands are available:
133\\{inferior-scheme-mode-map}
134
135A Scheme process can be fired up with M-x run-scheme.
136
137Customisation: Entry to this mode runs the hooks on comint-mode-hook and
138inferior-scheme-mode-hook (in that order).
139
140You can send text to the inferior Scheme process from other buffers containing
141Scheme source.
142 switch-to-scheme switches the current buffer to the Scheme process buffer.
143 scheme-send-definition sends the current definition to the Scheme process.
144 scheme-compile-definition compiles the current definition.
145 scheme-send-region sends the current region to the Scheme process.
146 scheme-compile-region compiles the current region.
147
148 scheme-send-definition-and-go, scheme-compile-definition-and-go,
149 scheme-send-region-and-go, and scheme-compile-region-and-go
150 switch to the Scheme process buffer after sending their text.
151For information on running multiple processes in multiple buffers, see
152documentation for variable scheme-buffer.
153
154Commands:
155Return after the end of the process' output sends the text from the
156 end of process to point.
157Return before the end of the process' output copies the sexp ending at point
158 to the end of the process' output, and sends it.
159Delete converts tabs to spaces as it moves back.
160Tab indents for Scheme; with argument, shifts rest
161 of expression rigidly with the current line.
162C-M-q does Tab on each line starting within following expression.
163Paragraphs are separated only by blank lines. Semicolons start comments.
164If you accidentally suspend your process, use \\[comint-continue-subjob]
165to continue it."
166 (interactive)
167 (comint-mode)
168 ;; Customise in inferior-scheme-mode-hook
169 (setq comint-prompt-regexp "^[^>]*>+ *") ; OK for cscheme, oaklisp, T,...
170 (scheme-mode-variables)
171 (setq major-mode 'inferior-scheme-mode)
172 (setq mode-name "Inferior Scheme")
173 (setq mode-line-process '(": %s"))
174 (use-local-map inferior-scheme-mode-map)
175 (setq comint-input-filter (function scheme-input-filter))
176 (setq comint-input-sentinel (function ignore))
177 (setq comint-get-old-input (function scheme-get-old-input))
178 (run-hooks 'inferior-scheme-mode-hook))
179
180(defun scheme-input-filter (str)
181 "Don't save anything matching inferior-scheme-filter-regexp"
182 (not (string-match inferior-scheme-filter-regexp str)))
183
184(defvar inferior-scheme-filter-regexp "\\`\\s *\\S ?\\S ?\\s *\\'"
185 "*Input matching this regexp are not saved on the history list.
186Defaults to a regexp ignoring all inputs of 0, 1, or 2 letters.")
187
188(defun scheme-get-old-input ()
189 "Snarf the sexp ending at point"
190 (save-excursion
191 (let ((end (point)))
192 (backward-sexp)
193 (buffer-substring (point) end))))
194
195(defun scheme-args-to-list (string)
196 (let ((where (string-match "[ \t]" string)))
197 (cond ((null where) (list string))
198 ((not (= where 0))
199 (cons (substring string 0 where)
200 (scheme-args-to-list (substring string (+ 1 where)
201 (length string)))))
202 (t (let ((pos (string-match "[^ \t]" string)))
203 (if (null pos)
204 nil
205 (scheme-args-to-list (substring string pos
206 (length string)))))))))
207
208(defvar scheme-program-name "scheme"
209 "*Program invoked by the run-scheme command")
210
211;;; Obsolete
212(defun scheme (&rest foo)
213 "Use run-scheme"
214 (interactive)
215 (message "Use run-scheme")
216 (ding))
217
218(defun run-scheme (cmd)
219 "Run an inferior Scheme process, input and output via buffer *scheme*.
220If there is a process already running in *scheme*, just switch to that buffer.
221With argument, allows you to edit the command line (default is value
222of scheme-program-name). Runs the hooks from inferior-scheme-mode-hook
223\(after the comint-mode-hook is run).
224\(Type \\[describe-mode] in the process buffer for a list of commands.)"
225
226 (interactive (list (if current-prefix-arg
227 (read-string "Run Scheme: " scheme-program-name)
228 scheme-program-name)))
229 (if (not (comint-check-proc "*scheme*"))
230 (let ((cmdlist (scheme-args-to-list cmd)))
231 (set-buffer (apply 'make-comint "scheme" (car cmdlist)
232 nil (cdr cmdlist)))
233 (inferior-scheme-mode)))
234 (setq scheme-buffer "*scheme*")
235 (switch-to-buffer "*scheme*"))
236
237
238(defun scheme-send-region (start end)
239 "Send the current region to the inferior Scheme process."
240 (interactive "r")
241 (comint-send-region (scheme-proc) start end)
242 (comint-send-string (scheme-proc) "\n"))
243
244(defun scheme-send-definition ()
245 "Send the current definition to the inferior Scheme process."
246 (interactive)
247 (save-excursion
248 (end-of-defun)
249 (let ((end (point)))
250 (beginning-of-defun)
251 (scheme-send-region (point) end))))
252
253(defun scheme-send-last-sexp ()
254 "Send the previous sexp to the inferior Scheme process."
255 (interactive)
256 (scheme-send-region (save-excursion (backward-sexp) (point)) (point)))
257
258(defvar scheme-compile-exp-command "(compile '%s)"
259 "*Template for issuing commands to compile arbitrary Scheme expressions.")
260
261(defun scheme-compile-region (start end)
262 "Compile the current region in the inferior Scheme process
263\(A BEGIN is wrapped around the region: (BEGIN <region>))"
264 (interactive "r")
265 (comint-send-string (scheme-proc) (format scheme-compile-exp-command
266 (format "(begin %s)"
267 (buffer-substring start end))))
268 (comint-send-string (scheme-proc) "\n"))
269
270(defun scheme-compile-definition ()
271 "Compile the current definition in the inferior Scheme process."
272 (interactive)
273 (save-excursion
274 (end-of-defun)
275 (let ((end (point)))
276 (beginning-of-defun)
277 (scheme-compile-region (point) end))))
278
279(defun switch-to-scheme (eob-p)
280 "Switch to the scheme process buffer.
281With argument, positions cursor at end of buffer."
282 (interactive "P")
283 (if (get-buffer scheme-buffer)
284 (pop-to-buffer scheme-buffer)
285 (error "No current process buffer. See variable scheme-buffer."))
286 (cond (eob-p
287 (push-mark)
288 (goto-char (point-max)))))
289
290(defun scheme-send-region-and-go (start end)
291 "Send the current region to the inferior Scheme process,
292and switch to the process buffer."
293 (interactive "r")
294 (scheme-send-region start end)
295 (switch-to-scheme t))
296
297(defun scheme-send-definition-and-go ()
298 "Send the current definition to the inferior Scheme,
299and switch to the process buffer."
300 (interactive)
301 (scheme-send-definition)
302 (switch-to-scheme t))
303
304(defun scheme-compile-definition-and-go ()
305 "Compile the current definition in the inferior Scheme,
306and switch to the process buffer."
307 (interactive)
308 (scheme-compile-definition)
309 (switch-to-scheme t))
310
311(defun scheme-compile-region-and-go (start end)
312 "Compile the current region in the inferior Scheme,
313and switch to the process buffer."
314 (interactive "r")
315 (scheme-compile-region start end)
316 (switch-to-scheme t))
317
318(defvar scheme-source-modes '(scheme-mode)
319 "*Used to determine if a buffer contains Scheme source code.
320If it's loaded into a buffer that is in one of these major modes, it's
321considered a scheme source file by scheme-load-file and scheme-compile-file.
322Used by these commands to determine defaults.")
323
324(defvar scheme-prev-l/c-dir/file nil
325 "Caches the (directory . file) pair used in the last scheme-load-file or
326scheme-compile-file command. Used for determining the default in the
327next one.")
328
329(defun scheme-load-file (file-name)
330 "Load a Scheme file into the inferior Scheme process."
331 (interactive (comint-get-source "Load Scheme file: " scheme-prev-l/c-dir/file
332 scheme-source-modes t)) ; T because LOAD
333 ; needs an exact name
334 (comint-check-source file-name) ; Check to see if buffer needs saved.
335 (setq scheme-prev-l/c-dir/file (cons (file-name-directory file-name)
336 (file-name-nondirectory file-name)))
337 (comint-send-string (scheme-proc) (concat "(load \""
338 file-name
339 "\"\)\n")))
340
341(defun scheme-compile-file (file-name)
342 "Compile a Scheme file in the inferior Scheme process."
343 (interactive (comint-get-source "Compile Scheme file: "
344 scheme-prev-l/c-dir/file
345 scheme-source-modes
346 nil)) ; NIL because COMPILE doesn't
347 ; need an exact name.
348 (comint-check-source file-name) ; Check to see if buffer needs saved.
349 (setq scheme-prev-l/c-dir/file (cons (file-name-directory file-name)
350 (file-name-nondirectory file-name)))
351 (comint-send-string (scheme-proc) (concat "(compile-file \""
352 file-name
353 "\"\)\n")))
354
355\f
356(defvar scheme-buffer nil "*The current scheme process buffer.
357
358MULTIPLE PROCESS SUPPORT
359===========================================================================
360Cmuscheme.el supports, in a fairly simple fashion, running multiple Scheme
361processes. To run multiple Scheme processes, you start the first up with
362\\[run-scheme]. It will be in a buffer named *scheme*. Rename this buffer
363with \\[rename-buffer]. You may now start up a new process with another
364\\[run-scheme]. It will be in a new buffer, named *scheme*. You can
365switch between the different process buffers with \\[switch-to-buffer].
366
367Commands that send text from source buffers to Scheme processes --
368like scheme-send-definition or scheme-compile-region -- have to choose a
369process to send to, when you have more than one Scheme process around. This
370is determined by the global variable scheme-buffer. Suppose you
371have three inferior Schemes running:
372 Buffer Process
373 foo scheme
374 bar scheme<2>
375 *scheme* scheme<3>
376If you do a \\[scheme-send-definition-and-go] command on some Scheme source
377code, what process do you send it to?
378
379- If you're in a process buffer (foo, bar, or *scheme*),
380 you send it to that process.
381- If you're in some other buffer (e.g., a source file), you
382 send it to the process attached to buffer scheme-buffer.
383This process selection is performed by function scheme-proc.
384
385Whenever \\[run-scheme] fires up a new process, it resets scheme-buffer
386to be the new process's buffer. If you only run one process, this will
387do the right thing. If you run multiple processes, you can change
388scheme-buffer to another process buffer with \\[set-variable].
389
390More sophisticated approaches are, of course, possible. If you find youself
391needing to switch back and forth between multiple processes frequently,
392you may wish to consider ilisp.el, a larger, more sophisticated package
393for running inferior Lisp and Scheme processes. The approach taken here is
394for a minimal, simple implementation. Feel free to extend it.")
395
396(defun scheme-proc ()
397 "Returns the current scheme process. See variable scheme-buffer."
398 (let ((proc (get-buffer-process (if (eq major-mode 'inferior-scheme-mode)
399 (current-buffer)
400 scheme-buffer))))
401 (or proc
402 (error "No current process. See variable scheme-buffer"))))
403
404
405;;; Do the user's customisation...
406
407(defvar cmuscheme-load-hook nil
408 "This hook is run when cmuscheme is loaded in.
409This is a good place to put keybindings.")
410
411(run-hooks 'cmuscheme-load-hook)
412
413
414;;; CHANGE LOG
415;;; ===========================================================================
416;;; 8/88 Olin
417;;; Created.
418;;;
419;;; 2/15/89 Olin
420;;; Removed -emacs flag from process invocation. It's only useful for
421;;; cscheme, and makes cscheme assume it's running under xscheme.el,
422;;; which messes things up royally. A bug.
423;;;
424;;; 5/22/90 Olin
425;;; - Upgraded to use comint-send-string and comint-send-region.
426;;; - run-scheme now offers to let you edit the command line if
427;;; you invoke it with a prefix-arg. M-x scheme is redundant, and
428;;; has been removed.
429;;; - Explicit references to process "scheme" have been replaced with
430;;; (scheme-proc). This allows better handling of multiple process bufs.
431;;; - Added scheme-send-last-sexp, bound to C-x C-e. A gnu convention.
432;;; - Have not added process query facility a la cmulisp.el's lisp-show-arglist
433;;; and friends, but interested hackers might find a useful application
434;;; of this facility.
435;;;
436;;; 3/12/90 Olin
437;;; - scheme-load-file and scheme-compile-file no longer switch-to-scheme.
438;;; Tale suggested this.
49116ac0
JB
439
440(provide 'cmuscheme)
c0274f38
ER
441
442;;; cmuscheme.el ends here