aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorDavid Lawrence1990-11-05 10:06:02 +0000
committerDavid Lawrence1990-11-05 10:06:02 +0000
commitbe9b65ac336e5ff60f39b55beb8f63e6fd7c65f7 (patch)
treefd63ccd9e8f24deb0975dc6e0c6265416b74ad13 /lisp
parent0b7da9adc9ade93d30f616acdb9d8596baf28da9 (diff)
downloademacs-be9b65ac336e5ff60f39b55beb8f63e6fd7c65f7.tar.gz
emacs-be9b65ac336e5ff60f39b55beb8f63e6fd7c65f7.zip
Initial revision
Diffstat (limited to 'lisp')
-rw-r--r--lisp/comint.el866
-rw-r--r--lisp/shell.el392
-rw-r--r--lisp/subr.el316
3 files changed, 1574 insertions, 0 deletions
diff --git a/lisp/comint.el b/lisp/comint.el
new file mode 100644
index 00000000000..0a81e2f5f1a
--- /dev/null
+++ b/lisp/comint.el
@@ -0,0 +1,866 @@
1;;; -*-Emacs-Lisp-*- General command interpreter in a window stuff
2;;; Copyright (C) 1989 Free Software Foundation, Inc.
3;;; Original author: Olin Shivers <olin.shivers@cs.cmu.edu> Aug 1988
4
5;;; This file is part of GNU Emacs.
6
7;;; GNU Emacs is free software; you can redistribute it and/or modify
8;;; it under the terms of the GNU General Public License as published by
9;;; the Free Software Foundation; either version 1, or (at your option)
10;;; any later version.
11
12;;; GNU Emacs is distributed in the hope that it will be useful,
13;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;;; GNU General Public License for more details.
16
17;;; You should have received a copy of the GNU General Public License
18;;; along with GNU Emacs; see the file COPYING. If not, write to
19;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
20
21;;; This file defines a general command-interpreter-in-a-buffer package
22;;; (comint mode). The idea is that you can build specific process-in-a-buffer
23;;; modes on top of comint mode -- e.g., lisp, shell, scheme, T, soar, ....
24;;; This way, all these specific packages share a common base functionality,
25;;; and a common set of bindings, which makes them easier to use (and
26;;; saves code, implementation time, etc., etc.).
27
28;;; For documentation on the functionality provided by comint mode, and
29;;; the hooks available for customising it, see the comments below.
30;;; For further information on the standard derived modes (shell,
31;;; inferior-lisp, inferior-scheme, ...), see the relevant source files.
32
33;;; For hints on converting existing process modes to use comint-mode
34;;; instead of shell-mode, see the notes at the end of this file.
35
36(require 'history)
37(provide 'comint)
38(defconst comint-version "2.01")
39
40
41;;; Not bound by default in comint-mode
42;;; send-invisible Read a line w/o echo, and send to proc
43;;; (These are bound in shell-mode)
44;;; comint-dynamic-complete Complete filename at point.
45;;; comint-dynamic-list-completions List completions in help buffer.
46;;; comint-replace-by-expanded-filename Expand and complete filename at point;
47;;; replace with expanded/completed name.
48(defvar comint-mode-map nil)
49
50(if comint-mode-map
51 nil
52 (setq comint-mode-map (make-sparse-keymap))
53 (define-key comint-mode-map "\C-a" 'comint-bol)
54 (define-key comint-mode-map "\C-d" 'comint-delchar-or-maybe-eof)
55 (define-key comint-mode-map "\C-m" 'comint-send-input)
56 (define-key comint-mode-map "\M-p" 'comint-previous-input)
57 (define-key comint-mode-map "\M-n" 'comint-next-input)
58 (define-key comint-mode-map "\M-s" 'comint-previous-similar-input)
59 (define-key comint-mode-map "\C-c\C-c" 'comint-interrupt-subjob) ; tty ^C
60 (define-key comint-mode-map "\C-c\C-f" 'comint-continue-subjob) ; shell "fg"
61 (define-key comint-mode-map "\C-c\C-l" 'comint-show-output)
62 (define-key comint-mode-map "\C-c\C-o" 'comint-flush-output) ; tty ^O
63 (define-key comint-mode-map "\C-c\C-r" 'comint-history-search-backward)
64 (define-key comint-mode-map "\C-c\C-s" 'comint-history-search-forward)
65 (define-key comint-mode-map "\C-c\C-u" 'comint-kill-input) ; tty ^U
66 (define-key comint-mode-map "\C-c\C-w" 'backward-kill-word) ; tty ^W
67 (define-key comint-mode-map "\C-c\C-z" 'comint-stop-subjob) ; tty ^Z
68 (define-key comint-mode-map "\C-c\C-\\" 'comint-quit-subjob)) ; tty ^\
69
70;;; Buffer Local Variables:
71;;;============================================================================
72;;; Comint mode buffer local variables:
73;;; comint-prompt-regexp - string comint-bol uses to match prompt.
74;;; comint-last-input-end - marker For comint-flush-output command
75;;; input-ring-size - integer For the input history
76;;; input-ring - ring mechanism
77;;; input-ring-index - marker ...
78;;; comint-last-input-match - string ...
79;;; comint-get-old-input - function Hooks for specific
80;;; comint-input-sentinel - function process-in-a-buffer
81;;; comint-input-filter - function modes.
82;;; comint-input-send - function
83;;; comint-eol-on-send - boolean
84
85(make-variable-buffer-local
86 (defvar comint-prompt-regexp "^"
87 "*Regexp to recognise prompts in the inferior process. Defaults to \"^\".
88
89Good choices:
90 Canonical Lisp: \"^[^> \n]*>+:? *\" (Lucid, Franz, KCL, T, cscheme, oaklisp)
91 Lucid Common Lisp: \"^\\(>\\|\\(->\\)+\\) *\"
92 Franz: \"^\\(->\\|<[0-9]*>:\\) *\"
93 KCL and T: \"^>+ *\"
94 shell: \"^[^#$%>\n]*[#$%>] *\"
95
96This is a good thing to set in mode hooks."))
97
98(make-variable-buffer-local
99 (defvar input-ring-size 30 "Size of input history ring."))
100
101;;; Here are the per-interpreter hooks.
102(make-variable-buffer-local
103 (defvar comint-get-old-input (function comint-get-old-input-default)
104 "Function that submits old text in comint mode.
105This function is called when return is typed while the point is in old text.
106It returns the text to be submitted as process input. The default is
107comint-get-old-input-default, which grabs the current line, and strips off
108leading text matching comint-prompt-regexp."))
109
110(make-variable-buffer-local
111 (defvar comint-input-sentinel (function ignore)
112 "Called on each input submitted to comint mode process by comint-send-input.
113Thus it can, for instance, track cd/pushd/popd commands issued to the csh."))
114
115(make-variable-buffer-local
116 (defvar comint-input-filter
117 (function (lambda (str) (not (string-match "\\`\\s *\\'" str))))
118 "Predicate for filtering additions to input history.
119Only inputs answering true to this function are saved on the input
120history list. Default is to save anything that isn't all whitespace"))
121
122(defvar comint-mode-hook '()
123 "Called upon entry into comint-mode")
124
125(defun comint-mode ()
126 "Major mode for interacting with an inferior interpreter.
127Interpreter name is same as buffer name, sans the asterisks.
128Return at end of buffer sends line as input.
129Return not at end copies rest of line to end and sends it.
130
131This mode is typically customised to create inferior-lisp-mode,
132shell-mode, et cetera. This can be done by setting the hooks
133comint-input-sentinel, comint-input-filter, and comint-get-old-input
134to appropriate functions, and the variable comint-prompt-regexp
135to the appropriate regular expression.
136
137An input history is maintained of size input-ring-size, and
138can be accessed with the commands comint-next-input [\\[comint-next-input]] and
139comint-previous-input [\\[comint-previous-input]]. Commands not keybound by
140default are send-invisible, comint-dynamic-complete, and
141comint-list-dynamic-completions.
142
143If you accidentally suspend your process, use \\[comint-continue-subjob]
144to continue it.
145
146\\{comint-mode-map}
147
148Entry to this mode runs the hooks on comint-mode-hook."
149 (interactive)
150 (make-local-variable 'input-ring)
151 (put 'input-ring 'preserved t)
152 (kill-all-local-variables)
153 (setq major-mode 'comint-mode
154 mode-name "Comint"
155 mode-line-process '(": %s"))
156 (use-local-map comint-mode-map)
157 (set (make-local-variable 'comint-last-input-match) "")
158 (set (make-local-variable 'comint-last-similar--string) "")
159 (set (make-local-variable 'input-ring-index) 0)
160 (set (make-local-variable 'comint-last-input-end) (make-marker))
161 (set-marker comint-last-input-end (point-max))
162 (run-hooks 'comint-mode-hook))
163
164(defun comint-check-proc (buffer-name)
165 "True if there is a running or stopped process associated with BUFFER."
166 (let ((proc (get-buffer-process buffer-name)))
167 (and proc (memq (process-status proc) '(run stop)))))
168
169(defun comint-mark ()
170 ;; Returns the process-mark of the current-buffer
171 (process-mark (get-buffer-process (current-buffer))))
172
173;;; Note that this guy, unlike shell.el's make-shell, barfs if you pass it ()
174;;; for the second argument (program).
175(defun make-comint (name program &optional startfile &rest switches)
176 (let* ((buffer (get-buffer-create (concat "*" name "*")))
177 (proc (get-buffer-process buffer)))
178 ;; If no process, or nuked process, crank up a new one and put buffer in
179 ;; comint mode. Otherwise, leave buffer and existing process alone.
180 (cond ((not (comint-check-proc))
181 (save-excursion
182 (set-buffer buffer)
183 (comint-mode)) ; Install local vars, mode, keymap, ...
184 (comint-exec buffer name program startfile switches)))
185 buffer))
186
187(defun comint-exec (buffer name command startfile switches)
188 "Fires up a process in buffer for comint modes.
189Blasts any old process running in the buffer. Doesn't set the buffer mode.
190You can use this to cheaply run a series of processes in the same buffer."
191 (or command (error "No program for comint process"))
192 (save-excursion
193 (set-buffer buffer)
194 (let ((proc (get-buffer-process buffer))) ; Blast any old process.
195 (if proc (delete-process proc)))
196 ;; Crank up a new process
197 (let ((proc (comint-exec-1 name buffer command switches)))
198 ;; Jump to the end, and set the process mark.
199 (set-marker (comint-mark) (goto-char (point-max)))
200 ;; Feed it the startfile.
201 (cond (startfile
202 ;;This is guaranteed to wait long enough
203 ;;but has bad results if the comint does not prompt at all
204 ;; (while (= size (buffer-size))
205 ;; (sleep-for 1))
206 ;;I hope 1 second is enough!
207 (sleep-for 1)
208 (goto-char (point-max))
209 (insert-file-contents startfile)
210 (setq startfile (buffer-substring (point) (point-max)))
211 (delete-region (point) (point-max))
212 (comint-send-string proc startfile)))
213 buffer))
214
215;;; This auxiliary function cranks up the process for comint-exec in
216;;; the appropriate environment. It is twice as long as it should be
217;;; because emacs has two distinct mechanisms for manipulating the
218;;; process environment, selected at compile time with the
219;;; MAINTAIN-ENVIRONMENT #define. In one case, process-environment
220;;; is bound; in the other it isn't.
221
222(defun comint-exec-1 (name buffer command switches)
223 (if (boundp 'process-environment) ; Not a completely reliable test.
224 (let ((process-environment
225 (comint-update-env process-environment
226 (list (format "TERMCAP=emacs:co#%d:tc=unknown"
227 (screen-width))
228 "TERM=emacs"
229 "EMACS=t"))))
230 (apply 'start-process name buffer command switches))
231 (let ((tcapv (getenv "TERMCAP"))
232 (termv (getenv "TERM"))
233 (emv (getenv "EMACS")))
234 (unwind-protect
235 (progn (setenv "TERMCAP" (format "emacs:co#%d:tc=unknown"
236 (screen-width)))
237 (setenv "TERM" "emacs")
238 (setenv "EMACS" "t")
239 (apply 'start-process name buffer command switches))
240 (setenv "TERMCAP" tcapv)
241 (setenv "TERM" termv)
242 (setenv "EMACS" emv)))))
243
244;; This is just (append new old-env) that compresses out shadowed entries.
245;; It's also pretty ugly, mostly due to elisp's horrible iteration structures.
246(defun comint-update-env (old-env new)
247 (let ((ans (reverse new))
248 (vars (mapcar (function (lambda (vv)
249 (and (string-match "^[^=]*=" vv)
250 (substring vv 0 (match-end 0)))))
251 new)))
252 (while old-env
253 (let* ((vv (car old-env)) ; vv is var=value
254 (var (and (string-match "^[^=]*=" vv)
255 (substring vv 0 (match-end 0)))))
256 (setq old-env (cdr old-env))
257 (cond ((not (and var (member var vars)))
258 (if var (setq var (cons var vars)))
259 (setq ans (cons vv ans))))))
260 (nreverse ans)))
261
262;;; Input history retrieval commands
263;;; M-p -- previous input M-n -- next input
264;;; C-c r -- previous input matching
265;;; ===========================================================================
266
267(defun comint-previous-input (arg)
268 "Cycle backwards through input history."
269 (interactive "*p")
270 (let ((len (ring-length input-ring)))
271 (if (<= len 0) (error "Empty input ring"))
272 (if (< (point) (comint-mark))
273 (delete-region (comint-mark) (goto-char (point-max))))
274 (cond ((eq last-command 'comint-previous-input)
275 (delete-region (mark) (point)))
276 ((eq last-command 'comint-previous-similar-input)
277 (delete-region (comint-mark) (point)))
278 (t
279 (setq input-ring-index
280 (if (> arg 0) -1
281 (if (< arg 0) 1 0)))
282 (push-mark (point))))
283 (setq input-ring-index (comint-mod (+ input-ring-index arg) len))
284 (message "%d" (1+ input-ring-index))
285 (insert (ring-ref input-ring input-ring-index))
286 (setq this-command 'comint-previous-input)))
287
288(defun comint-next-input (arg)
289 "Cycle forwards through input history."
290 (interactive "*p")
291 (comint-previous-input (- arg)))
292
293(defun comint-previous-input-matching (str)
294 "Searches backwards through input history for substring match."
295 (interactive (let* ((last-command last-command) ; preserve around r-f-m
296 (s (read-from-minibuffer
297 (format "Command substring (default %s): "
298 comint-last-input-match))))
299 (list (if (string= s "") comint-last-input-match s))))
300; (interactive "sCommand substring: ")
301 (setq comint-last-input-match str) ; update default
302 (if (not (eq last-command 'comint-previous-input))
303 (setq input-ring-index -1))
304 (let ((str (regexp-quote str))
305 (len (ring-length input-ring))
306 (n (+ input-ring-index 1)))
307 (while (and (< n len) (not (string-match str (ring-ref input-ring n))))
308 (setq n (+ n 1)))
309 (cond ((< n len)
310 (comint-previous-input (- n input-ring-index)))
311 (t (if (eq last-command 'comint-previous-input)
312 (setq this-command 'comint-previous-input))
313 (error "Not found")))))
314
315;;;
316;;; Similar input -- contributed by ccm and highly winning.
317;;;
318;;; Reenter input, removing back to the last insert point if it exists.
319;;;
320(defun comint-previous-similar-input (arg)
321 "Reenters the last input that matches the string typed so far. If repeated
322successively older inputs are reentered. If arg is 1, it will go back
323in the history, if -1 it will go forward."
324 (interactive "p")
325 (if (< (point) (comint-mark))
326 (error "Not after process mark"))
327 (if (not (eq last-command 'comint-previous-similar-input))
328 (setq input-ring-index -1
329 comint-last-similar-string
330 (buffer-substring (comint-mark) (point))))
331 (let* ((size (length comint-last-similar-string))
332 (len (ring-length input-ring))
333 (n (+ input-ring-index arg))
334 entry)
335 (while (and (< n len)
336 (or (< (length (setq entry (ring-ref input-ring n))) size)
337 (not (equal comint-last-similar-string
338 (substring entry 0 size)))))
339 (setq n (+ n arg)))
340 (cond ((< n len)
341 (setq input-ring-index n)
342 (if (eq last-command 'comint-previous-similar-input)
343 (delete-region (comint-mark) (point)))
344 (insert (substring entry size)))
345 (t (error "Not found")))))
346
347(defun comint-send-input (&optional terminator delete)
348 "Send input to process, followed by a linefeed or optional TERMINATOR.
349After the process output mark, sends all text from the process mark to
350end of buffer as input to the process. Before the process output mark, calls
351value of variable comint-get-old-input to retrieve old input, replaces it in
352the input region (from the end of process output to the end of the buffer) and
353then sends it. In either case, the value of variable comint-input-sentinel is
354called on the input before sending it. The input is entered into the input
355history ring, if value of variable comint-input-filter returns non-nil when
356called on the input.
357
358If optional second argument DELETE is non-nil, then the input is deleted from
359the end of the buffer. This is useful if the process unconditionally echoes
360input. Processes which use TERMINATOR or DELETE should have a command wrapper
361which provides them bound to RET; see telnet.el for an example.
362
363comint-get-old-input, comint-input-sentinel, and comint-input-filter are chosen
364according to the command interpreter running in the buffer. For example,
365
366If the interpreter is the csh,
367 comint-get-old-input defaults: takes the current line, discard any
368 initial string matching regexp comint-prompt-regexp.
369 comint-input-sentinel: monitors input for \"cd\", \"pushd\", and \"popd\"
370 commands. When it sees one, it changes the default directory of the buffer.
371 comint-input-filter defaults: returns t if the input isn't all whitespace.
372
373If the comint is Lucid Common Lisp,
374 comint-get-old-input: snarfs the sexp ending at point.
375 comint-input-sentinel: does nothing.
376 comint-input-filter: returns nil if the input matches input-filter-regexp,
377 which matches (1) all whitespace (2) :a, :c, etc.
378
379Similar functions are used for other process modes."
380 (interactive)
381 ;; Note that the input string does not include its terminal newline.
382 (if (not (get-buffer-process (current-buffer)))
383 (error "Current buffer has no process")
384 (let* ((pmark (comint-mark))
385 (input (if (>= (point) pmark)
386 (buffer-substring pmark (goto-char (point-max)))
387 (let ((copy (funcall comint-get-old-input)))
388 (delete-region pmark (goto-char (point-max)))
389 (insert copy)
390 copy))))
391 (set-marker comint-last-input-end (point))
392 (setq input-ring-index 0)
393 (if (funcall comint-input-filter input) (ring-insert input-ring input))
394 (funcall comint-input-sentinel input)
395 (comint-send-string nil (concat input (or terminator "\n")))
396 (if delete (delete-region mark (point))
397 (insert "\n"))
398 (set-marker (comint-mark) (point)))))
399
400(defun comint-get-old-input-default ()
401 "Default for comint-get-old-input: use the current line sans prompt."
402 (save-excursion
403 (comint-bol)
404 (buffer-substring (point) (progn (end-of-line) (point)))))
405
406(defun comint-bol (arg)
407 "Goes to the beginning of line, then skips past the prompt, if any.
408With a prefix argument, (\\[universal-argument]), then doesn't skip prompt.
409
410The prompt skip is done by passing over text matching the regular expression
411comint-prompt-regexp, a buffer local variable."
412 (interactive "P")
413 (beginning-of-line)
414 (or arg (if (looking-at comint-prompt-regexp) (goto-char (match-end 0)))))
415
416;;; These two functions are for entering text you don't want echoed or
417;;; saved -- typically passwords to ftp, telnet, or somesuch.
418;;; Just enter M-x send-invisible and type in your line.
419(defun comint-read-noecho (prompt)
420 "Prompting with PROMPT, read a single line of text without echoing.
421The text can still be recovered (temporarily) with \\[view-lossage]. This
422may be a security bug for some applications."
423 (let ((echo-keystrokes 0)
424 (answ "")
425 tem)
426 (if (and (stringp prompt) (not (string= (message prompt) "")))
427 (message prompt))
428 (while (not (or (= (setq tem (read-char)) ?\^m)
429 (= tem ?\n)))
430 (setq answ (concat answ (char-to-string tem))))
431 (message "")
432 answ))
433
434(defun send-invisible (str)
435 "Read a string without echoing, and send it to the current buffer's process.
436A newline is also sent. String is not saved on comint input history list.
437Security bug: your string can still be temporarily recovered with \\[view-lossage]."
438; (interactive (list (comint-read-noecho "Enter non-echoed text")))
439 (interactive "P") ; Defeat snooping via C-x esc
440 (let ((proc (get-buffer-process (current-buffer))))
441 (if (not proc) (error "Current buffer has no process")
442 (comint-send-string proc
443 (if (stringp str) str
444 (comint-read-noecho "Enter non-echoed text")))
445 (comint-send-string proc "\n"))))
446
447
448;;; Low-level process communication
449
450(defvar comint-input-chunk-size 512
451 "*Long inputs send to comint processes are broken up into chunks of this size.
452If your process is choking on big inputs, try lowering the value.")
453
454(defun comint-send-string (proc str)
455 "Send PROCESS the contents of STRING as input.
456This is equivalent to process-send-string, except that long input strings
457are broken up into chunks of size comint-input-chunk-size. Processes
458are given a chance to output between chunks. This can help prevent processes
459from hanging when you send them long inputs on some OS's."
460 (let* ((len (length str))
461 (i (min len comint-input-chunk-size)))
462 (process-send-string proc (substring str 0 i))
463 (while (< i len)
464 (let ((next-i (+ i comint-input-chunk-size)))
465 (accept-process-output)
466 (process-send-string proc (substring str i (min len next-i)))
467 (setq i next-i)))))
468
469(defun comint-send-region (proc start end)
470 "Sends to PROC the region delimited by START and END.
471This is a replacement for process-send-region that tries to keep
472your process from hanging on long inputs. See comint-send-string."
473 (comint-send-string proc (buffer-substring start end)))
474
475
476;;; Random input hackage
477
478(defun comint-flush-output ()
479 "Kill all output from interpreter since last input."
480 (interactive)
481 (save-excursion
482 (goto-char (comint-mark))
483 (beginning-of-line)
484 (delete-region (1+ comint-last-input-end) (point))
485 (insert "*** output flushed ***\n")))
486
487(defun comint-show-output ()
488 "Start display of the current window at line preceding start of last output.
489\"Last output\" is considered to start at the line following the last command
490entered to the process."
491 (interactive)
492 (goto-char comint-last-input-end)
493 (beginning-of-line)
494 (set-window-start (selected-window) (point))
495 (comint-bol))
496
497(defun comint-interrupt-subjob ()
498 "Sent an interrupt signal to the current subprocess.
499If the process-connection-type is via ptys, the signal is sent to the current
500process group of the pseudoterminal which Emacs is using to communicate with
501the subprocess. If the process is a job-control shell, this means the
502shell's current subjob. If the process connection is via pipes, the signal is
503sent to the immediate subprocess."
504 (interactive)
505 (interrupt-process nil t))
506
507(defun comint-kill-subjob ()
508 "Send a kill signal to the current subprocess.
509See comint-interrupt-subjob for a description of \"current subprocess\"."
510 (interactive)
511 (kill-process nil t))
512
513(defun comint-quit-subjob ()
514 "Send a quit signal to the current subprocess.
515See comint-interrupt-subjob for a description of \"current subprocess\"."
516 (interactive)
517 (quit-process nil t))
518
519(defun comint-stop-subjob ()
520 "Stop the current subprocess.
521See comint-interrupt-subjob for a description of \"current subprocess\".
522
523WARNING: if there is no current subjob, you can end up suspending
524the top-level process running in the buffer. If you accidentally do
525this, use \\[comint-continue-subjob] to resume the process. (This is not a
526problem with most shells, since they ignore this signal.)"
527 (interactive)
528 (stop-process nil t))
529
530(defun comint-continue-subjob ()
531 "Send a continue signal to current subprocess.
532See comint-interrupt-subjob for a description of \"current subprocess\".
533Useful if you accidentally suspend the top-level process."
534 (interactive)
535 (continue-process nil t))
536
537(defun comint-kill-input ()
538 "Kill from current command through point."
539 (interactive)
540 (let ((pmark (comint-mark)))
541 (if (> (point) pmark)
542 (kill-region pmark (point))
543 (error "Nothing to kill"))))
544
545(defun comint-delchar-or-maybe-eof (arg)
546 "Delete ARG characters forward, or send an EOF to process if at end of buffer."
547 (interactive "p")
548 (if (eobp)
549 (process-send-eof)
550 (delete-char arg)))
551
552;;; Support for source-file processing commands.
553;;;============================================================================
554;;; Many command-interpreters (e.g., Lisp, Scheme, Soar) have
555;;; commands that process files of source text (e.g. loading or compiling
556;;; files). So the corresponding process-in-a-buffer modes have commands
557;;; for doing this (e.g., lisp-load-file). The functions below are useful
558;;; for defining these commands.
559;;;
560;;; Alas, these guys don't do exactly the right thing for Lisp, Scheme
561;;; and Soar, in that they don't know anything about file extensions.
562;;; So the compile/load interface gets the wrong default occasionally.
563;;; The load-file/compile-file default mechanism could be smarter -- it
564;;; doesn't know about the relationship between filename extensions and
565;;; whether the file is source or executable. If you compile foo.lisp
566;;; with compile-file, then the next load-file should use foo.bin for
567;;; the default, not foo.lisp. This is tricky to do right, particularly
568;;; because the extension for executable files varies so much (.o, .bin,
569;;; .lbin, .mo, .vo, .ao, ...).
570
571
572;;; COMINT-SOURCE-DEFAULT -- determines defaults for source-file processing
573;;; commands.
574;;;
575;;; COMINT-CHECK-SOURCE -- if FNAME is in a modified buffer, asks you if you
576;;; want to save the buffer before issuing any process requests to the command
577;;; interpreter.
578;;;
579;;; COMINT-GET-SOURCE -- used by the source-file processing commands to prompt
580;;; for the file to process.
581
582;;; (COMINT-SOURCE-DEFAULT previous-dir/file source-modes)
583;;;============================================================================
584;;; This function computes the defaults for the load-file and compile-file
585;;; commands for tea, soar, lisp, and scheme modes.
586;;;
587;;; - PREVIOUS-DIR/FILE is a pair (directory . filename) from the last
588;;; source-file processing command. NIL if there hasn't been one yet.
589;;; - SOURCE-MODES is a list used to determine what buffers contain source
590;;; files: if the major mode of the buffer is in SOURCE-MODES, it's source.
591;;; Typically, (lisp-mode) or (scheme-mode).
592;;;
593;;; If the command is given while the cursor is inside a string, *and*
594;;; the string is an existing filename, *and* the filename is not a directory,
595;;; then the string is taken as default. This allows you to just position
596;;; your cursor over a string that's a filename and have it taken as default.
597;;;
598;;; If the command is given in a file buffer whose major mode is in
599;;; SOURCE-MODES, then the the filename is the default file, and the
600;;; file's directory is the default directory.
601;;;
602;;; If the buffer isn't a source file buffer (e.g., it's the process buffer),
603;;; then the default directory & file are what was used in the last source-file
604;;; processing command (i.e., PREVIOUS-DIR/FILE). If this is the first time
605;;; the command has been run (PREVIOUS-DIR/FILE is nil), the default directory
606;;; is the cwd, with no default file. (\"no default file\" = nil)
607;;;
608;;; SOURCE-REGEXP is typically going to be something like (tea-mode)
609;;; for T programs, (lisp-mode) for Lisp programs, (soar-mode lisp-mode)
610;;; for Soar programs, etc.
611;;;
612;;; The function returns a pair: (default-directory . default-file).
613
614(defun comint-source-default (previous-dir/file source-modes)
615 (cond ((and buffer-file-name (memq major-mode source-modes))
616 (cons (file-name-directory buffer-file-name)
617 (file-name-nondirectory buffer-file-name)))
618 (previous-dir/file)
619 (t
620 (cons default-directory nil))))
621
622;;; (COMINT-CHECK-SOURCE fname)
623;;;============================================================================
624;;; Prior to loading or compiling (or otherwise processing) a file (in the
625;;; process-in-a-buffer modes), this function can be called on the filename.
626;;; If the file is loaded into a buffer, and the buffer is modified, the user
627;;; is queried to see if he wants to save the buffer before proceeding with
628;;; the load or compile.
629
630(defun comint-check-source (fname)
631 (let ((buff (get-file-buffer fname)))
632 (if (and buff
633 (buffer-modified-p buff)
634 (y-or-n-p (format "Save buffer %s first? "
635 (buffer-name buff))))
636 ;; save BUFF.
637 (let ((old-buffer (current-buffer)))
638 (set-buffer buff)
639 (save-buffer)
640 (set-buffer old-buffer)))))
641
642;;; (COMINT-GET-SOURCE prompt prev-dir/file source-modes mustmatch-p)
643;;;============================================================================
644;;; COMINT-GET-SOURCE is used to prompt for filenames in command-interpreter
645;;; commands that process source files (like loading or compiling a file).
646;;; It prompts for the filename, provides a default, if there is one,
647;;; and returns the result filename.
648;;;
649;;; See COMINT-SOURCE-DEFAULT for more on determining defaults.
650;;;
651;;; PROMPT is the prompt string. PREV-DIR/FILE is the (directory . file) pair
652;;; from the last source processing command. SOURCE-MODES is a list of major
653;;; modes used to determine what file buffers contain source files. (These
654;;; two arguments are used for determining defaults). If MUSTMATCH-P is true,
655;;; then the filename reader will only accept a file that exists.
656;;;
657;;; A typical use:
658;;; (interactive (comint-get-source "Compile file: " prev-lisp-dir/file
659;;; '(lisp-mode) t))
660
661;;; This is pretty stupid about strings. It decides we're in a string
662;;; if there's a quote on both sides of point on the current line.
663(defun comint-extract-string ()
664 "Returns string around point that starts the current line or nil."
665 (save-excursion
666 (let* ((point (point))
667 (bol (progn (beginning-of-line) (point)))
668 (eol (progn (end-of-line) (point)))
669 (start (progn (goto-char point)
670 (and (search-backward "\"" bol t)
671 (1+ (point)))))
672 (end (progn (goto-char point)
673 (and (search-forward "\"" eol t)
674 (1- (point))))))
675 (and start end
676 (buffer-substring start end)))))
677
678(defun comint-get-source (prompt prev-dir/file source-modes mustmatch-p)
679 (let* ((def (comint-source-default prev-dir/file source-modes))
680 (stringfile (comint-extract-string))
681 (sfile-p (and stringfile
682 (file-exists-p stringfile)
683 (not (file-directory-p stringfile))))
684 (defdir (if sfile-p (file-name-directory stringfile)
685 (car def)))
686 (deffile (if sfile-p (file-name-nondirectory stringfile)
687 (cdr def)))
688 (ans (read-file-name (if deffile (format "%s(default %s) "
689 prompt deffile)
690 prompt)
691 defdir
692 (concat defdir deffile)
693 mustmatch-p)))
694 (list (expand-file-name (substitute-in-file-name ans)))))
695
696
697;;; Simple process query facility.
698;;; ===========================================================================
699;;; This function is for commands that want to send a query to the process
700;;; and show the response to the user. For example, a command to get the
701;;; arglist for a Common Lisp function might send a "(arglist 'foo)" query
702;;; to an inferior Common Lisp process.
703;;;
704;;; This simple facility just sends strings to the inferior process and pops
705;;; up a window for the process buffer so you can see what the process
706;;; responds with. We don't do anything fancy like try to intercept what the
707;;; process responds with and put it in a pop-up window or on the message
708;;; line. We just display the buffer. Low tech. Simple. Works good.
709
710;;; Send to the inferior process PROC the string STR. Pop-up but do not select
711;;; a window for the inferior process so that its response can be seen.
712(defun comint-proc-query (proc str)
713 (let* ((proc-buf (process-buffer proc))
714 (proc-mark (process-mark proc)))
715 (display-buffer proc-buf)
716 (set-buffer proc-buf) ; but it's not the selected *window*
717 (let ((proc-win (get-buffer-window proc-buf))
718 (proc-pt (marker-position proc-mark)))
719 (comint-send-string proc str) ; send the query
720 (accept-process-output proc) ; wait for some output
721 ;; Try to position the proc window so you can see the answer.
722 ;; This is bogus code. If you delete the (sit-for 0), it breaks.
723 ;; I don't know why. Wizards invited to improve it.
724 (if (not (pos-visible-in-window-p proc-pt proc-win))
725 (let ((opoint (window-point proc-win)))
726 (set-window-point proc-win proc-mark) (sit-for 0)
727 (if (not (pos-visible-in-window-p opoint proc-win))
728 (push-mark opoint)
729 (set-window-point proc-win opoint)))))))
730
731
732;;; Filename completion in a buffer
733;;; ===========================================================================
734;;; Useful completion functions, courtesy of the Ergo group.
735;;; M-<Tab> will complete the filename at the cursor as much as possible
736;;; M-? will display a list of completions in the help buffer.
737
738;;; Three commands:
739;;; comint-dynamic-complete Complete filename at point.
740;;; comint-dynamic-list-completions List completions in help buffer.
741;;; comint-replace-by-expanded-filename Expand and complete filename at point;
742;;; replace with expanded/completed name.
743
744;;; These are not installed in the comint-mode keymap. But they are
745;;; available for people who want them. Shell-mode-map uses them, though.
746
747(defun comint-match-partial-pathname ()
748 "Returns the string of an existing filename or causes an error."
749 (if (save-excursion (backward-char 1) (looking-at "\\s ")) ""
750 (save-excursion
751 (re-search-backward "[^~/A-Za-z0-9---_.$#,]+")
752 (re-search-forward "[~/A-Za-z0-9---_.$#,]+")
753 (substitute-in-file-name
754 (buffer-substring (match-beginning 0) (match-end 0))))))
755
756(defun comint-replace-by-expanded-filename ()
757 "Replace the filename at point with its expanded, canonicalised completion.
758\"Expanded\" means environment variables (e.g., $HOME) and ~'s are
759replaced with the corresponding directories. \"Canonicalised\" means ..
760and . are removed, and the filename is made absolute instead of relative.
761See functions expand-file-name and substitute-in-file-name. See also
762comint-dynamic-complete."
763 (interactive)
764 (let* ((pathname (comint-match-partial-pathname))
765 (pathdir (file-name-directory pathname))
766 (pathnondir (file-name-nondirectory pathname))
767 (completion (file-name-completion pathnondir
768 (or pathdir default-directory))))
769 (cond ((null completion)
770 (error "No completions"))
771 ((eql completion t)
772 (message "Sole completion"))
773 (t ; this means a string was returned.
774 (delete-region (match-beginning 0) (match-end 0))
775 (insert (expand-file-name (concat pathdir completion)))))))
776
777(defun comint-dynamic-complete ()
778 "Complete the filename at point.
779This function is similar to comint-replace-by-expanded-filename, except
780that it won't change parts of the filename already entered in the buffer;
781it just adds completion characters to the end of the filename."
782 (interactive)
783 (let* ((pathname (comint-match-partial-pathname))
784 (pathdir (file-name-directory pathname))
785 (pathnondir (file-name-nondirectory pathname))
786 (completion (file-name-completion pathnondir
787 (or pathdir default-directory))))
788 (cond ((null completion)
789 (error "No completions"))
790 ((eql completion t)
791 (error "Sole completion"))
792 (t ; this means a string was returned.
793 (goto-char (match-end 0))
794 (insert (substring completion (length pathnondir)))))))
795
796(defun comint-dynamic-list-completions ()
797 "List all possible completions of the filename at point."
798 (interactive)
799 (let* ((pathname (comint-match-partial-pathname))
800 (pathdir (file-name-directory pathname))
801 (pathnondir (file-name-nondirectory pathname))
802 (completions
803 (file-name-all-completions pathnondir
804 (or pathdir default-directory))))
805 (cond ((null completions)
806 (error "No completions"))
807 (t
808 (let ((conf (current-window-configuration)))
809 (with-output-to-temp-buffer " *Completions*"
810 (display-completion-list completions))
811 (sit-for 0)
812 (message "Hit space to flush.")
813 (let ((ch (read-char)))
814 (if (= ch ?\ )
815 (set-window-configuration conf)
816 (setq unread-command-char ch))))))))
817
818
819;;; Converting process modes to use comint mode
820;;; ===========================================================================
821;;; Renaming variables
822;;; Most of the work is renaming variables and functions.
823;;; These are the common ones.
824
825;;; Local variables --
826;;; last-input-end comint-last-input-end
827;;; last-input-start <unnecessary>
828;;; shell-prompt-pattern comint-prompt-regexp
829;;; shell-set-directory-error-hook <no equivalent>
830;;; Miscellaneous --
831;;; shell-set-directory <unnecessary>
832;;; shell-mode-map comint-mode-map
833;;; Commands --
834;;; shell-send-input comint-send-input
835;;; shell-send-eof comint-delchar-or-maybe-eof
836;;; kill-shell-input comint-kill-input
837;;; interrupt-shell-subjob comint-interrupt-subjob
838;;; stop-shell-subjob comint-stop-subjob
839;;; quit-shell-subjob comint-quit-subjob
840;;; kill-shell-subjob comint-kill-subjob
841;;; kill-output-from-shell comint-kill-output
842;;; show-output-from-shell comint-show-output
843;;; copy-last-shell-input Use comint-previous-input/comint-next-input
844;;;
845;;; LAST-INPUT-START is no longer necessary because inputs are stored on the
846;;; input history ring. SHELL-SET-DIRECTORY is gone, its functionality taken
847;;; over by SHELL-DIRECTORY-TRACKER, the shell mode's comint-input-sentinel.
848;;; Comint mode does not provide functionality equivalent to
849;;; shell-set-directory-error-hook; it is gone.
850;;;
851;;; If you are implementing some process-in-a-buffer mode, called foo-mode, do
852;;; *not* create the comint-mode local variables in your foo-mode function.
853;;; This is not modular. Instead, call comint-mode, and let *it* create the
854;;; necessary comint-specific local variables. Then create the
855;;; foo-mode-specific local variables in foo-mode. Set the buffer's keymap to
856;;; be foo-mode-map, and its mode to be foo-mode. Set the comint-mode hooks
857;;; (comint-prompt-regexp, comint-input-filter, comint-input-sentinel,
858;;; comint-get-old-input) that need to be different from the defaults. Call
859;;; foo-mode-hook, and you're done. Don't run the comint-mode hook yourself;
860;;; comint-mode will take care of it.
861;;;
862;;; Note that make-comint is different from make-shell in that it
863;;; doesn't have a default program argument. If you give make-shell
864;;; a program name of NIL, it cleverly chooses one of explicit-shell-name,
865;;; $ESHELL, $SHELL, or /bin/sh. If you give make-comint a program argument
866;;; of NIL, it barfs. Adjust your code accordingly...
diff --git a/lisp/shell.el b/lisp/shell.el
new file mode 100644
index 00000000000..64c069bf05d
--- /dev/null
+++ b/lisp/shell.el
@@ -0,0 +1,392 @@
1;; -*-Emacs-Lisp-*- run a shell in an Emacs window
2;; Copyright (C) 1985, 1986, 1987, 1990 Free Software Foundation, Inc.
3
4;; This file is part of GNU Emacs.
5
6;; GNU Emacs is free software; you can redistribute it and/or modify
7;; it under the terms of the GNU General Public License as published by
8;; the Free Software Foundation; either version 1, or (at your option)
9;; any later version.
10
11;; GNU Emacs is distributed in the hope that it will be useful,
12;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;; GNU General Public License for more details.
15
16;; You should have received a copy of the GNU General Public License
17;; along with GNU Emacs; see the file COPYING. If not, write to
18;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20;;; Hacked from tea.el and shell.el by Olin Shivers (shivers@cs.cmu.edu). 8/88
21
22;;; Since this mode is built on top of the general command-interpreter-in-
23;;; a-buffer mode (comint mode), it shares a common base functionality,
24;;; and a common set of bindings, with all modes derived from comint mode.
25
26;;; For documentation on the functionality provided by comint mode, and
27;;; the hooks available for customising it, see the file comint.el.
28
29;;; Needs fixin:
30;;; When sending text from a source file to a subprocess, the process-mark can
31;;; move off the window, so you can lose sight of the process interactions.
32;;; Maybe I should ensure the process mark is in the window when I send
33;;; text to the process? Switch selectable?
34
35(require 'comint)
36(provide 'shell)
37
38(defvar shell-popd-regexp "popd"
39 "*Regexp to match subshell commands equivalent to popd.")
40
41(defvar shell-pushd-regexp "pushd"
42 "*Regexp to match subshell commands equivalent to pushd.")
43
44(defvar shell-cd-regexp "cd"
45 "*Regexp to match subshell commands equivalent to cd.")
46
47(defvar explicit-shell-file-name nil
48 "*If non-nil, is file name to use for explicitly requested inferior shell.")
49
50(defvar explicit-csh-args
51 (if (eq system-type 'hpux)
52 ;; -T persuades HP's csh not to think it is smarter
53 ;; than us about what terminal modes to use.
54 '("-i" "-T")
55 '("-i"))
56 "*Args passed to inferior shell by M-x shell, if the shell is csh.
57Value is a list of strings, which may be nil.")
58
59(defvar shell-dirstack nil
60 "List of directories saved by pushd in this buffer's shell.")
61
62(defvar shell-dirstack-query "dirs"
63 "Command used by shell-resync-dirlist to query shell.")
64
65(defvar shell-mode-map ())
66(cond ((not shell-mode-map)
67 (setq shell-mode-map (copy-keymap comint-mode-map))
68 (define-key shell-mode-map "\t" 'comint-dynamic-complete)
69 (define-key shell-mode-map "\M-?" 'comint-dynamic-list-completions)))
70
71(defvar shell-mode-hook '()
72 "*Hook for customising shell mode")
73
74
75;;; Basic Procedures
76;;; ===========================================================================
77;;;
78
79(defun shell-mode ()
80 "Major mode for interacting with an inferior shell.
81Return after the end of the process' output sends the text from the
82 end of process to the end of the current line.
83Return before end of process output copies rest of line to end (skipping
84 the prompt) and sends it.
85M-x send-invisible reads a line of text without echoing it, and sends it to
86 the shell.
87
88If you accidentally suspend your process, use \\[comint-continue-subjob]
89to continue it.
90
91cd, pushd and popd commands given to the shell are watched by Emacs to keep
92this buffer's default directory the same as the shell's working directory.
93M-x dirs queries the shell and resyncs Emacs' idea of what the current
94 directory stack is.
95M-x dirtrack-toggle turns directory tracking on and off.
96
97\\{shell-mode-map}
98Customisation: Entry to this mode runs the hooks on comint-mode-hook and
99shell-mode-hook (in that order).
100
101Variables shell-cd-regexp, shell-pushd-regexp and shell-popd-regexp are used
102to match their respective commands."
103 (interactive)
104 (comint-mode)
105 (setq major-mode 'shell-mode
106 mode-name "Shell"
107 comint-prompt-regexp shell-prompt-pattern
108 comint-input-sentinel 'shell-directory-tracker)
109 (use-local-map shell-mode-map)
110 (make-local-variable 'shell-dirstack)
111 (set (make-local-variable 'shell-dirtrackp) t)
112 (run-hooks 'shell-mode-hook))
113
114
115(defun shell ()
116 "Run an inferior shell, with I/O through buffer *shell*.
117If buffer exists but shell process is not running, make new shell.
118If buffer exists and shell process is running, just switch to buffer *shell*.
119
120The shell to use comes from the first non-nil variable found from these:
121explicit-shell-file-name in Emacs, ESHELL in the environment or SHELL in the
122environment. If none is found, /bin/sh is used.
123
124If a file ~/.emacs_SHELLNAME exists, it is given as initial input, simulating
125a start-up file for the shell like .profile or .cshrc. Note that this may
126lose due to a timing error if the shell discards input when it starts up.
127
128The buffer is put in shell-mode, giving commands for sending input
129and controlling the subjobs of the shell.
130
131The shell file name, sans directories, is used to make a symbol name
132such as `explicit-csh-arguments'. If that symbol is a variable,
133its value is used as a list of arguments when invoking the shell.
134Otherwise, one argument `-i' is passed to the shell.
135
136\(Type \\[describe-mode] in the shell buffer for a list of commands.)"
137 (interactive)
138 (cond ((not (comint-check-proc "*shell*"))
139 (let* ((prog (or explicit-shell-file-name
140 (getenv "ESHELL")
141 (getenv "SHELL")
142 "/bin/sh"))
143 (name (file-name-nondirectory prog))
144 (startfile (concat "~/.emacs_" name))
145 (xargs-name (intern-soft (concat "explicit-" name "-args"))))
146 (set-buffer (apply 'make-comint "shell" prog
147 (if (file-exists-p startfile) startfile)
148 (if (and xargs-name (boundp xargs-name))
149 (symbol-value xargs-name)
150 '("-i"))))
151 (shell-mode))))
152 (switch-to-buffer "*shell*"))
153
154
155;;; Directory tracking
156;;; ===========================================================================
157;;; This code provides the shell mode input sentinel
158;;; SHELL-DIRECTORY-TRACKER
159;;; that tracks cd, pushd, and popd commands issued to the shell, and
160;;; changes the current directory of the shell buffer accordingly.
161;;;
162;;; This is basically a fragile hack, although it's more accurate than
163;;; the original version in shell.el. It has the following failings:
164;;; 1. It doesn't know about the cdpath shell variable.
165;;; 2. It only spots the first command in a command sequence. E.g., it will
166;;; miss the cd in "ls; cd foo"
167;;; 3. More generally, any complex command (like ";" sequencing) is going to
168;;; throw it. Otherwise, you'd have to build an entire shell interpreter in
169;;; emacs lisp. Failing that, there's no way to catch shell commands where
170;;; cd's are buried inside conditional expressions, aliases, and so forth.
171;;;
172;;; The whole approach is a crock. Shell aliases mess it up. File sourcing
173;;; messes it up. You run other processes under the shell; these each have
174;;; separate working directories, and some have commands for manipulating
175;;; their w.d.'s (e.g., the lcd command in ftp). Some of these programs have
176;;; commands that do *not* effect the current w.d. at all, but look like they
177;;; do (e.g., the cd command in ftp). In shells that allow you job
178;;; control, you can switch between jobs, all having different w.d.'s. So
179;;; simply saying %3 can shift your w.d..
180;;;
181;;; The solution is to relax, not stress out about it, and settle for
182;;; a hack that works pretty well in typical circumstances. Remember
183;;; that a half-assed solution is more in keeping with the spirit of Unix,
184;;; anyway. Blech.
185;;;
186;;; One good hack not implemented here for users of programmable shells
187;;; is to program up the shell w.d. manipulation commands to output
188;;; a coded command sequence to the tty. Something like
189;;; ESC | <cwd> |
190;;; where <cwd> is the new current working directory. Then trash the
191;;; directory tracking machinery currently used in this package, and
192;;; replace it with a process filter that watches for and strips out
193;;; these messages.
194
195;;; REGEXP is a regular expression. STR is a string. START is a fixnum.
196;;; Returns T if REGEXP matches STR where the match is anchored to start
197;;; at position START in STR. Sort of like LOOKING-AT for strings.
198(defun shell-front-match (regexp str start)
199 (eq start (string-match regexp str start)))
200
201(defun shell-directory-tracker (str)
202 "Tracks cd, pushd and popd commands issued to the shell.
203This function is called on each input passed to the shell.
204It watches for cd, pushd and popd commands and sets the buffer's
205default directory to track these commands.
206
207You may toggle this tracking on and off with M-x dirtrack-toggle.
208If emacs gets confused, you can resync with the shell with M-x dirs.
209
210See variables shell-cd-regexp, shell-pushd-regexp, and shell-popd-regexp.
211Environment variables are expanded, see function substitute-in-file-name."
212 (condition-case err
213 (cond (shell-dirtrackp
214 (string-match "^\\s *" str) ; skip whitespace
215 (let ((bos (match-end 0))
216 (x nil))
217 (cond ((setq x (shell-match-cmd-w/optional-arg shell-popd-regexp
218 str bos))
219 (shell-process-popd (substitute-in-file-name x)))
220 ((setq x (shell-match-cmd-w/optional-arg shell-pushd-regexp
221 str bos))
222 (shell-process-pushd (substitute-in-file-name x)))
223 ((setq x (shell-match-cmd-w/optional-arg shell-cd-regexp
224 str bos))
225 (shell-process-cd (substitute-in-file-name x)))))))
226 (error (message (car (cdr err))))))
227
228
229;;; Try to match regexp CMD to string, anchored at position START.
230;;; CMD may be followed by a single argument. If a match, then return
231;;; the argument, if there is one, or the empty string if not. If
232;;; no match, return nil.
233
234(defun shell-match-cmd-w/optional-arg (cmd str start)
235 (and (shell-front-match cmd str start)
236 (let ((eoc (match-end 0))) ; end of command
237 (cond ((shell-front-match "\\s *\\(\;\\|$\\)" str eoc)
238 "") ; no arg
239 ((shell-front-match "\\s +\\([^ \t\;]+\\)\\s *\\(\;\\|$\\)"
240 str eoc)
241 (substring str (match-beginning 1) (match-end 1))) ; arg
242 (t nil))))) ; something else.
243;;; The first regexp is [optional whitespace, (";" or the end of string)].
244;;; The second regexp is [whitespace, (an arg), optional whitespace,
245;;; (";" or end of string)].
246
247
248;;; popd [+n]
249(defun shell-process-popd (arg)
250 (let ((num (if (zerop (length arg)) 0 ; no arg means +0
251 (shell-extract-num arg))))
252 (if (and num (< num (length shell-dirstack)))
253 (if (= num 0) ; condition-case because the CD could lose.
254 (condition-case nil (progn (cd (car shell-dirstack))
255 (setq shell-dirstack
256 (cdr shell-dirstack))
257 (shell-dirstack-message))
258 (error (message "Couldn't cd.")))
259 (let* ((ds (cons nil shell-dirstack))
260 (cell (nthcdr (- num 1) ds)))
261 (rplacd cell (cdr (cdr cell)))
262 (setq shell-dirstack (cdr ds))
263 (shell-dirstack-message)))
264 (message "Bad popd."))))
265
266
267;;; cd [dir]
268(defun shell-process-cd (arg)
269 (condition-case nil (progn (cd (if (zerop (length arg)) (getenv "HOME")
270 arg))
271 (shell-dirstack-message))
272 (error (message "Couldn't cd."))))
273
274
275;;; pushd [+n | dir]
276(defun shell-process-pushd (arg)
277 (if (zerop (length arg))
278 ;; no arg -- swap pwd and car of shell stack
279 (condition-case nil (if shell-dirstack
280 (let ((old default-directory))
281 (cd (car shell-dirstack))
282 (setq shell-dirstack
283 (cons old (cdr shell-dirstack)))
284 (shell-dirstack-message))
285 (message "Directory stack empty."))
286 (message "Couldn't cd."))
287
288 (let ((num (shell-extract-num arg)))
289 (if num ; pushd +n
290 (if (> num (length shell-dirstack))
291 (message "Directory stack not that deep.")
292 (let* ((ds (cons default-directory shell-dirstack))
293 (dslen (length ds))
294 (front (nthcdr num ds))
295 (back (reverse (nthcdr (- dslen num) (reverse ds))))
296 (new-ds (append front back)))
297 (condition-case nil
298 (progn (cd (car new-ds))
299 (setq shell-dirstack (cdr new-ds))
300 (shell-dirstack-message))
301 (error (message "Couldn't cd.")))))
302
303 ;; pushd <dir>
304 (let ((old-wd default-directory))
305 (condition-case nil
306 (progn (cd arg)
307 (setq shell-dirstack
308 (cons old-wd shell-dirstack))
309 (shell-dirstack-message))
310 (error (message "Couldn't cd."))))))))
311
312;; If STR is of the form +n, for n>0, return n. Otherwise, nil.
313(defun shell-extract-num (str)
314 (and (string-match "^\\+[1-9][0-9]*$" str)
315 (string-to-int str)))
316
317
318(defun shell-dirtrack-toggle ()
319 "Turn directory tracking on and off in a shell buffer."
320 (interactive)
321 (setq shell-dirtrackp (not shell-dirtrackp))
322 (message "directory tracking %s."
323 (if shell-dirtrackp "ON" "OFF")))
324
325;;; For your typing convenience:
326(fset 'dirtrack-toggle 'shell-dirtrack-toggle)
327
328
329(defun shell-resync-dirs ()
330 "Resync the buffer's idea of the current directory stack.
331This command queries the shell with the command bound to
332shell-dirstack-query (default \"dirs\"), reads the next
333line output and parses it to form the new directory stack.
334DON'T issue this command unless the buffer is at a shell prompt.
335Also, note that if some other subprocess decides to do output
336immediately after the query, its output will be taken as the
337new directory stack -- you lose. If this happens, just do the
338command again."
339 (interactive)
340 (let* ((proc (get-buffer-process (current-buffer)))
341 (pmark (process-mark proc)))
342 (goto-char pmark)
343 (insert shell-dirstack-query) (insert "\n")
344 (sit-for 0) ; force redisplay
345 (comint-send-string proc shell-dirstack-query)
346 (comint-send-string proc "\n")
347 (set-marker pmark (point))
348 (let ((pt (point))) ; wait for 1 line
349 ;; This extra newline prevents the user's pending input from spoofing us.
350 (insert "\n") (backward-char 1)
351 (while (not (looking-at ".+\n"))
352 (accept-process-output proc)
353 (goto-char pt)))
354 (goto-char pmark) (delete-char 1) ; remove the extra newline
355 ;; That's the dirlist. grab it & parse it.
356 (let* ((dl (buffer-substring (match-beginning 0) (- (match-end 0) 1)))
357 (dl-len (length dl))
358 (ds '()) ; new dir stack
359 (i 0))
360 (while (< i dl-len)
361 ;; regexp = optional whitespace, (non-whitespace), optional whitespace
362 (string-match "\\s *\\(\\S +\\)\\s *" dl i) ; pick off next dir
363 (setq ds (cons (substring dl (match-beginning 1) (match-end 1))
364 ds))
365 (setq i (match-end 0)))
366 (let ((ds (reverse ds)))
367 (condition-case nil
368 (progn (cd (car ds))
369 (setq shell-dirstack (cdr ds))
370 (shell-dirstack-message))
371 (error (message "Couldn't cd.")))))))
372
373;;; For your typing convenience:
374(fset 'dirs 'shell-resync-dirs)
375
376
377;;; Show the current dirstack on the message line.
378;;; Pretty up dirs a bit by changing "/usr/jqr/foo" to "~/foo".
379;;; (This isn't necessary if the dirlisting is generated with a simple "dirs".)
380;;; All the commands that mung the buffer's dirstack finish by calling
381;;; this guy.
382(defun shell-dirstack-message ()
383 (let ((msg "")
384 (ds (cons default-directory shell-dirstack)))
385 (while ds
386 (let ((dir (car ds)))
387 (if (string-match (format "^%s\\(/\\|$\\)" (getenv "HOME")) dir)
388 (setq dir (concat "~/" (substring dir (match-end 0)))))
389 (if (string-equal dir "~/") (setq dir "~"))
390 (setq msg (concat msg dir " "))
391 (setq ds (cdr ds))))
392 (message msg)))
diff --git a/lisp/subr.el b/lisp/subr.el
new file mode 100644
index 00000000000..512867ee3c0
--- /dev/null
+++ b/lisp/subr.el
@@ -0,0 +1,316 @@
1;; Basic lisp subroutines for Emacs
2;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
3
4;; This file is part of GNU Emacs.
5
6;; GNU Emacs is free software; you can redistribute it and/or modify
7;; it under the terms of the GNU General Public License as published by
8;; the Free Software Foundation; either version 1, or (at your option)
9;; any later version.
10
11;; GNU Emacs is distributed in the hope that it will be useful,
12;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;; GNU General Public License for more details.
15
16;; You should have received a copy of the GNU General Public License
17;; along with GNU Emacs; see the file COPYING. If not, write to
18;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20
21(defun one-window-p (&optional arg)
22 "Returns non-nil if there is only one window.
23Optional arg NOMINI non-nil means don't count the minibuffer
24even if it is active."
25 (eq (selected-window)
26 (next-window (selected-window) (if arg 'arg))))
27
28(defun walk-windows (proc &optional minibuf all-screens)
29 "Cycle through all visible windows, calling PROC for each one.
30PROC is called with a window as argument.
31Optional second arg MINIBUF t means count the minibuffer window
32even if not active. If MINIBUF is neither t nor nil it means
33not to count the minibuffer even if it is active.
34Optional third arg ALL-SCREENS t means include all windows in all screens;
35otherwise cycle within the selected screen."
36 (let* ((walk-windows-start (selected-window))
37 (walk-windows-current walk-windows-start))
38 (while (progn
39 (setq walk-windows-current
40 (next-window walk-windows-current minibuf all-screens))
41 (funcall proc walk-windows-current)
42 (not (eq walk-windows-current walk-windows-start))))))
43
44(defun read-quoted-char (&optional prompt)
45 "Like `read-char', except that if the first character read is an octal
46digit, we read up to two more octal digits and return the character
47represented by the octal number consisting of those digits.
48Optional argument PROMPT specifies a string to use to prompt the user."
49 (let ((count 0) (code 0) char)
50 (while (< count 3)
51 (let ((inhibit-quit (zerop count))
52 (help-form nil))
53 (and prompt (message "%s-" prompt))
54 (setq char (read-char))
55 (if inhibit-quit (setq quit-flag nil)))
56 (cond ((null char))
57 ((and (<= ?0 char) (<= char ?7))
58 (setq code (+ (* code 8) (- char ?0))
59 count (1+ count))
60 (and prompt (message (setq prompt
61 (format "%s %c" prompt char)))))
62 ((> count 0)
63 (setq unread-command-char char count 259))
64 (t (setq code char count 259))))
65 (logand 255 code)))
66
67(defun error (&rest args)
68 "Signal an error, making error message by passing all args to `format'."
69 (while t
70 (signal 'error (list (apply 'format args)))))
71
72(defun undefined ()
73 (interactive)
74 (ding))
75
76;Prevent the \{...} documentation construct
77;from mentioning keys that run this command.
78(put 'undefined 'suppress-keymap t)
79
80(defun suppress-keymap (map &optional nodigits)
81 "Make MAP override all normally self-inserting keys to be undefined.
82Normally, as an exception, digits and minus-sign are set to make prefix args,
83but optional second arg NODIGITS non-nil treats them like other chars."
84 (let ((i 0))
85 (while (<= i 127)
86 (if (eql (lookup-key global-map (char-to-string i)) 'self-insert-command)
87 (define-key map (char-to-string i) 'undefined))
88 (setq i (1+ i))))
89 (or nodigits
90 (let (loop)
91 (define-key map "-" 'negative-argument)
92 ;; Make plain numbers do numeric args.
93 (setq loop ?0)
94 (while (<= loop ?9)
95 (define-key map (char-to-string loop) 'digit-argument)
96 (setq loop (1+ loop))))))
97
98;; now in fns.c
99;(defun nth (n list)
100; "Returns the Nth element of LIST.
101;N counts from zero. If LIST is not that long, nil is returned."
102; (car (nthcdr n list)))
103;
104;(defun copy-alist (alist)
105; "Return a copy of ALIST.
106;This is a new alist which represents the same mapping
107;from objects to objects, but does not share the alist structure with ALIST.
108;The objects mapped (cars and cdrs of elements of the alist)
109;are shared, however."
110; (setq alist (copy-sequence alist))
111; (let ((tail alist))
112; (while tail
113; (if (consp (car tail))
114; (setcar tail (cons (car (car tail)) (cdr (car tail)))))
115; (setq tail (cdr tail))))
116; alist)
117
118;Moved to keymap.c
119;(defun copy-keymap (keymap)
120; "Return a copy of KEYMAP"
121; (while (not (keymapp keymap))
122; (setq keymap (signal 'wrong-type-argument (list 'keymapp keymap))))
123; (if (vectorp keymap)
124; (copy-sequence keymap)
125; (copy-alist keymap)))
126
127(defun substitute-key-definition (olddef newdef keymap)
128 "Replace OLDDEF with NEWDEF for any keys in KEYMAP now defined as OLDDEF.
129In other words, OLDDEF is replaced with NEWDEF where ever it appears.
130Prefix keymaps reached from KEYMAP are not checked recursively;
131perhaps they ought to be."
132 (if (arrayp keymap)
133 (let ((len (length keymap))
134 (i 0))
135 (while (< i len)
136 (if (eq (aref keymap i) olddef)
137 (aset keymap i newdef))
138 (setq i (1+ i))))
139 (while keymap
140 (if (eq (cdr-safe (car-safe keymap)) olddef)
141 (setcdr (car keymap) newdef))
142 (setq keymap (cdr keymap)))))
143
144;; Avoids useless byte-compilation.
145;; In the future, would be better to fix byte compiler
146;; not to really compile in cases like this,
147;; and use defun here.
148(fset 'ignore '(lambda (&rest ignore) nil))
149
150
151; old names
152(fset 'make-syntax-table 'copy-syntax-table)
153(fset 'dot 'point)
154(fset 'dot-marker 'point-marker)
155(fset 'dot-min 'point-min)
156(fset 'dot-max 'point-max)
157(fset 'window-dot 'window-point)
158(fset 'set-window-dot 'set-window-point)
159(fset 'read-input 'read-string)
160(fset 'send-string 'process-send-string)
161(fset 'send-region 'process-send-region)
162(fset 'show-buffer 'set-window-buffer)
163(fset 'buffer-flush-undo 'buffer-disable-undo)
164
165; alternate names
166(fset 'string= 'string-equal)
167(fset 'string< 'string-lessp)
168(fset 'move-marker 'set-marker)
169(fset 'eql 'eq)
170(fset 'not 'null)
171(fset 'numberp 'integerp)
172(fset 'rplaca 'setcar)
173(fset 'rplacd 'setcdr)
174(fset 'beep 'ding) ;preserve lingual purtity
175(fset 'indent-to-column 'indent-to)
176(fset 'backward-delete-char 'delete-backward-char)
177
178(defvar global-map nil
179 "Default global keymap mapping Emacs keyboard input into commands.
180The value is a keymap which is usually (but not necessarily) Emacs's
181global map.")
182
183(defvar ctl-x-map nil
184 "Default keymap for C-x commands.
185The normal global definition of the character C-x indirects to this keymap.")
186
187(defvar esc-map nil
188 "Default keymap for ESC (meta) commands.
189The normal global definition of the character ESC indirects to this keymap.")
190
191(defvar mouse-map nil
192 "Keymap for mouse commands from the X window system.")
193
194(defun run-hooks (&rest hooklist)
195 "Takes hook names and runs each one in turn. Major mode functions use this.
196Each argument should be a symbol, a hook variable.
197These symbols are processed in the order specified.
198If a hook symbol has a non-nil value, that value may be a function
199or a list of functions to be called to run the hook.
200If the value is a function, it is called with no arguments.
201If it is a list, the elements are called, in order, with no arguments."
202 (while hooklist
203 (let ((sym (car hooklist)))
204 (and (boundp sym)
205 (symbol-value sym)
206 (let ((value (symbol-value sym)))
207 (if (and (listp value) (not (eq (car value) 'lambda)))
208 (mapcar 'funcall value)
209 (funcall value)))))
210 (setq hooklist (cdr hooklist))))
211
212;; Tell C code how to call this function.
213(defconst run-hooks 'run-hooks
214 "Variable by which C primitives find the function `run-hooks'.
215Don't change it.")
216
217(defun add-hook (hook function)
218 "Add to the value of HOOK the function FUNCTION unless already present.
219HOOK should be a symbol, and FUNCTION may be any valid function.
220HOOK's value should be a list of functions, not a single function.
221If HOOK is void, it is first set to nil."
222 (or (boundp hook) (set hook nil))
223 (or (if (consp function)
224 ;; Clever way to tell whether a given lambda-expression
225 ;; is equal to anything in the hook.
226 (let ((tail (assoc (cdr function) (symbol-value hook))))
227 (equal function tail))
228 (memq function (symbol-value hook)))
229 (set hook (cons function hook))))
230
231(defun momentary-string-display (string pos &optional exit-char message)
232 "Momentarily display STRING in the buffer at POS.
233Display remains until next character is typed.
234If the char is EXIT-CHAR (optional third arg, default is SPC) it is swallowed;
235otherwise it is then available as input (as a command if nothing else).
236Display MESSAGE (optional fourth arg) in the echo area.
237If MESSAGE is nil, instructions to type EXIT-CHAR are displayed there."
238 (or exit-char (setq exit-char ?\ ))
239 (let ((buffer-read-only nil)
240 (modified (buffer-modified-p))
241 (name buffer-file-name)
242 insert-end)
243 (unwind-protect
244 (progn
245 (save-excursion
246 (goto-char pos)
247 ;; defeat file locking... don't try this at home, kids!
248 (setq buffer-file-name nil)
249 (insert-before-markers string)
250 (setq insert-end (point)))
251 (message (or message "Type %s to continue editing.")
252 (single-key-description exit-char))
253 (let ((char (read-char)))
254 (or (eq char exit-char)
255 (setq unread-command-char char))))
256 (if insert-end
257 (save-excursion
258 (delete-region pos insert-end)))
259 (setq buffer-file-name name)
260 (set-buffer-modified-p modified))))
261
262(defun start-process-shell-command (name buffer &rest args)
263 "Start a program in a subprocess. Return the process object for it.
264Args are NAME BUFFER COMMAND &rest COMMAND-ARGS.
265NAME is name for process. It is modified if necessary to make it unique.
266BUFFER is the buffer or (buffer-name) to associate with the process.
267 Process output goes at end of that buffer, unless you specify
268 an output stream or filter function to handle the output.
269 BUFFER may be also nil, meaning that this process is not associated
270 with any buffer
271Third arg is command name, the name of a shell command.
272Remaining arguments are the arguments for the command.
273Wildcards and redirection are handle as usual in the shell."
274 (if (eq system-type 'vax-vms)
275 (apply 'start-process name buffer args)
276 (start-process name buffer shell-file-name "-c"
277 (concat "exec " (mapconcat 'identity args " ")))))
278
279(defun eval-after-load (file form)
280 "Arrange that, if FILE is ever loaded, FORM will be run at that time.
281This makes or adds to an entry on `after-load-alist'.
282FILE should be the name of a library, with no directory name."
283 (or (assoc file after-load-alist)
284 (setq after-load-alist (cons (list file) after-load-alist)))
285 (nconc (assoc file after-load-alist) (list form))
286 form)
287
288(defun eval-next-after-load (file)
289 "Read the following input sexp, and run it whenever FILE is loaded.
290This makes or adds to an entry on `after-load-alist'.
291FILE should be the name of a library, with no directory name."
292 (eval-after-load file (read)))
293
294(defun user-original-login-name ()
295 "Return user's login name from original login.
296This tries to remain unaffected by `su', by looking in environment variables."
297 (or (getenv "LOGNAME") (getenv "USER") (user-login-name)))
298
299(defun force-mode-line-update (&optional all)
300 "Force the mode-line of the current buffer to be redisplayed.
301With optional non-nil ALL then force then force redisplay of all mode-lines."
302 (if all (save-excursion (set-buffer (other-buffer))))
303 (set-buffer-modified-p (buffer-modified-p)))
304
305(defun keyboard-translate (from to)
306 "Translate character FROM to TO at a low level.
307This function creates a `keyboard-translate-table' if necessary
308and then modifies one entry in it."
309 (or (boundp 'keyboard-translate-table)
310 (let ((table (make-string 256))
311 (i 0))
312 (while (< i 256)
313 (aset table i i)
314 (setq i (1+ i)))
315 (setq keyboard-translate-table table)))
316 (aset keyboard-translate-table from to))