(pages-copy-header-and-position): Call end-of-line, not forward-line.
[bpt/emacs.git] / lisp / shell.el
CommitLineData
5336e829 1;;; shell.el --- specialized comint.el for running the shell.
24fdffaa 2;;; Copyright (C) 1988, 1993 Free Software Foundation, Inc.
6d74b528 3
630cc463 4;; Author: Olin Shivers <shivers@cs.cmu.edu>
d76b71af 5;; Adapted-by: Simon Marshall <s.marshall@dcs.hull.ac.uk>
d7b4d18f 6;; Keywords: processes
630cc463 7
c88ab9ce
ER
8;;; This file is part of GNU Emacs.
9
10;;; GNU Emacs is free software; you can redistribute it and/or modify
11;;; it under the terms of the GNU General Public License as published by
e5167999 12;;; the Free Software Foundation; either version 2, or (at your option)
c88ab9ce
ER
13;;; any later version.
14
15;;; GNU Emacs is distributed in the hope that it will be useful,
16;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;;; GNU General Public License for more details.
19
20;;; You should have received a copy of the GNU General Public License
21;;; along with GNU Emacs; see the file COPYING. If not, write to
22;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
be9b65ac 23
630cc463
ER
24;;; Commentary:
25
a9ec2adb
JB
26;;; Please send me bug reports, bug fixes, and extensions, so that I can
27;;; merge them into the master source.
28;;; - Olin Shivers (shivers@cs.cmu.edu)
d76b71af 29;;; - Simon Marshall (s.marshall@dcs.hull.ac.uk)
be9b65ac 30
a9ec2adb 31;;; This file defines a a shell-in-a-buffer package (shell mode) built
c88ab9ce
ER
32;;; on top of comint mode. This is actually cmushell with things
33;;; renamed to replace its counterpart in Emacs 18. cmushell is more
34;;; featureful, robust, and uniform than the Emacs 18 version.
be9b65ac
DL
35
36;;; Since this mode is built on top of the general command-interpreter-in-
37;;; a-buffer mode (comint mode), it shares a common base functionality,
38;;; and a common set of bindings, with all modes derived from comint mode.
a9ec2adb 39;;; This makes these modes easier to use.
be9b65ac
DL
40
41;;; For documentation on the functionality provided by comint mode, and
42;;; the hooks available for customising it, see the file comint.el.
a9ec2adb 43;;; For further information on shell mode, see the comments below.
be9b65ac
DL
44
45;;; Needs fixin:
46;;; When sending text from a source file to a subprocess, the process-mark can
47;;; move off the window, so you can lose sight of the process interactions.
48;;; Maybe I should ensure the process mark is in the window when I send
49;;; text to the process? Switch selectable?
50
a9ec2adb
JB
51;; YOUR .EMACS FILE
52;;=============================================================================
53;; Some suggestions for your .emacs file.
54;;
3bede93e 55;; ;; Define C-c t to run my favorite command in shell mode:
d76b71af 56;; (setq shell-mode-hook
a9ec2adb 57;; '((lambda ()
fa8f1b25 58;; (define-key shell-mode-map "\C-ct" 'favorite-cmd))))
a9ec2adb
JB
59
60\f
61;;; Brief Command Documentation:
62;;;============================================================================
63;;; Comint Mode Commands: (common to shell and all comint-derived modes)
64;;;
65;;; m-p comint-previous-input Cycle backwards in input history
66;;; m-n comint-next-input Cycle forwards
d76b71af
RS
67;;; m-r comint-previous-matching-input Previous input matching a regexp
68;;; m-R comint-previous-matching-input-from-input -"- matching input
69;;; m-s comint-next-matching-input Next input that matches
70;;; m-S comint-next-matching-input-from-input -"- matching input
f5a131d8 71;;; m-c-l comint-show-output Show last batch of process output
a9ec2adb 72;;; return comint-send-input
d76b71af 73;;; c-a comint-bol Beginning of line; skip prompt
a9ec2adb
JB
74;;; c-d comint-delchar-or-maybe-eof Delete char unless at end of buff.
75;;; c-c c-u comint-kill-input ^u
76;;; c-c c-w backward-kill-word ^w
77;;; c-c c-c comint-interrupt-subjob ^c
78;;; c-c c-z comint-stop-subjob ^z
79;;; c-c c-\ comint-quit-subjob ^\
80;;; c-c c-o comint-kill-output Delete last batch of process output
81;;; c-c c-r comint-show-output Show last batch of process output
d76b71af 82;;; c-c c-h comint-dynamic-list-input-ring List input history
a9ec2adb
JB
83;;; send-invisible Read line w/o echo & send to proc
84;;; comint-continue-subjob Useful if you accidentally suspend
d76b71af 85;;; top-level job
a9ec2adb
JB
86;;; comint-mode-hook is the comint mode hook.
87
88;;; Shell Mode Commands:
d76b71af
RS
89;;; shell Fires up the shell process
90;;; tab comint-dynamic-complete Complete filename/command/history
91;;; m-? comint-dynamic-list-filename-completions List completions in help buffer
92;;; m-c-f shell-forward-command Forward a shell command
93;;; m-c-b shell-backward-command Backward a shell command
94;;; dirs Resync the buffer's dir stack
95;;; dirtrack-toggle Turn dir tracking on/off
a9ec2adb
JB
96;;;
97;;; The shell mode hook is shell-mode-hook
a9ec2adb
JB
98;;; comint-prompt-regexp is initialised to shell-prompt-pattern, for backwards
99;;; compatibility.
100
101;;; Read the rest of this file for more information.
102\f
c88ab9ce
ER
103;;; SHELL.EL COMPATIBILITY
104;;; Notes from when this was called cmushell, and was not the standard emacs
105;;; shell package.
a9ec2adb
JB
106;;;============================================================================
107;;; In brief: this package should have no trouble coexisting with shell.el.
108;;;
109;;; Most customising variables -- e.g., explicit-shell-file-name -- are the
110;;; same, so the users shouldn't have much trouble. Hooks have different
c88ab9ce 111;;; names, however, so you can customise shell mode differently from cmushell
a9ec2adb
JB
112;;; mode. You basically just have to remember to type M-x cmushell instead of
113;;; M-x shell.
114;;;
115;;; It would be nice if this file was completely plug-compatible with the old
116;;; shell package -- if you could just name this file shell.el, and have it
117;;; transparently replace the old one. But you can't. Several other packages
118;;; (tex-mode, background, dbx, gdb, kermit, monkey, prolog, telnet) are also
119;;; clients of shell mode. These packages assume detailed knowledge of shell
120;;; mode internals in ways that are incompatible with cmushell mode (mostly
121;;; because of cmushell mode's greater functionality). So, unless we are
122;;; willing to port all of these packages, we can't have this file be a
123;;; complete replacement for shell.el -- that is, we can't name this file
124;;; shell.el, and its main entry point (shell), because dbx.el will break
125;;; when it loads it in and tries to use it.
126;;;
127;;; There are two ways to fix this. One: rewrite these other modes to use the
128;;; new package. This is a win, but can't be assumed. The other, backwards
129;;; compatible route, is to make this package non-conflict with shell.el, so
130;;; both files can be loaded in at the same time. And *that* is why some
131;;; functions and variables have different names: (cmushell),
132;;; cmushell-mode-map, that sort of thing. All the names have been carefully
133;;; chosen so that shell.el and cmushell.el won't tromp on each other.
134\f
8f95f0ce 135;;; Customization and Buffer Variables
a9ec2adb
JB
136;;; ===========================================================================
137;;;
138
630cc463
ER
139;;; Code:
140
141(require 'comint)
142
c88ab9ce 143;;;###autoload
ac75ef20 144(defvar shell-prompt-pattern "^[^#$%>\n]*[#$%>] *"
a9ec2adb 145 "Regexp to match prompts in the inferior shell.
ac75ef20 146Defaults to \"^[^#$%>\\n]*[#$%>] *\", which works pretty well.
24fdffaa 147This variable is used to initialise `comint-prompt-regexp' in the
a9ec2adb
JB
148shell buffer.
149
ac75ef20
JB
150The pattern should probably not match more than one line. If it does,
151shell-mode may become confused trying to distinguish prompt from input
152on lines which don't start with a prompt.
153
24fdffaa 154This is a fine thing to set in your `.emacs' file.")
a9ec2adb 155
d76b71af
RS
156(defvar shell-delimiter-argument-list '("|" "&" "<" ">" "(" ")" ";")
157 "List of characters to recognise as separate arguments.
158Defaults to \(\"|\" \"&\" \"\(\" \")\" \";\"), which works pretty well.
159This variable is used to initialise `comint-delimiter-argument-list' in the
160shell buffer.
161
162This is a fine thing to set in your `.emacs' file.")
163
164(defvar shell-command-regexp "\\((.*)\\|[^;&|]\\)+"
165 "*Regexp to match shell commands.
166Elements of pipes are considered as separate commands, forks and redirections
167as part of one command.")
168
169(defvar shell-completion-execonly t
170 "*If non-nil, use executable files only for completion candidates.
5394cb44 171This mirrors the optional behavior of tcsh.
d76b71af
RS
172
173Detecting executability of files may slow command completion considerably.")
174
be9b65ac
DL
175(defvar shell-popd-regexp "popd"
176 "*Regexp to match subshell commands equivalent to popd.")
177
178(defvar shell-pushd-regexp "pushd"
179 "*Regexp to match subshell commands equivalent to pushd.")
180
d76b71af
RS
181(defvar shell-pushd-tohome nil
182 "*If non-nil, make pushd with no arg behave as \"pushd ~\" (like cd).
5394cb44 183This mirrors the optional behavior of tcsh.")
d76b71af
RS
184
185(defvar shell-pushd-dextract nil
186 "*If non-nil, make \"pushd +n\" pop the nth dir to the stack top.
5394cb44 187This mirrors the optional behavior of tcsh.")
d76b71af
RS
188
189(defvar shell-pushd-dunique nil
190 "*If non-nil, make pushd only add unique directories to the stack.
5394cb44 191This mirrors the optional behavior of tcsh.")
d76b71af 192
be9b65ac
DL
193(defvar shell-cd-regexp "cd"
194 "*Regexp to match subshell commands equivalent to cd.")
195
196(defvar explicit-shell-file-name nil
197 "*If non-nil, is file name to use for explicitly requested inferior shell.")
198
199(defvar explicit-csh-args
200 (if (eq system-type 'hpux)
201 ;; -T persuades HP's csh not to think it is smarter
202 ;; than us about what terminal modes to use.
203 '("-i" "-T")
204 '("-i"))
205 "*Args passed to inferior shell by M-x shell, if the shell is csh.
206Value is a list of strings, which may be nil.")
207
c88ab9ce 208;;; All the above vars aren't prefixed "cmushell-" to make them
a9ec2adb
JB
209;;; backwards compatible w/shell.el and old .emacs files.
210
be9b65ac 211(defvar shell-dirstack nil
c88ab9ce
ER
212 "List of directories saved by pushd in this buffer's shell.
213Thus, this does not include the shell's current directory.")
be9b65ac 214
fa8f1b25
ER
215(defvar shell-last-dir nil
216 "Keep track of last directory for ksh `cd -' command.")
217
be9b65ac 218(defvar shell-dirstack-query "dirs"
24fdffaa 219 "Command used by `shell-resync-dir' to query the shell.")
be9b65ac 220
a9ec2adb 221(defvar shell-mode-map '())
be9b65ac 222(cond ((not shell-mode-map)
a9ec2adb 223 (setq shell-mode-map (full-copy-sparse-keymap comint-mode-map))
d76b71af
RS
224 (define-key shell-mode-map "\C-c\C-f" 'shell-forward-command)
225 (define-key shell-mode-map "\C-c\C-b" 'shell-backward-command)
be9b65ac 226 (define-key shell-mode-map "\t" 'comint-dynamic-complete)
d76b71af
RS
227 (define-key shell-mode-map "\M-?"
228 'comint-dynamic-list-filename-completions)))
be9b65ac
DL
229
230(defvar shell-mode-hook '()
24fdffaa 231 "*Hook for customising Shell mode.")
be9b65ac
DL
232
233\f
234;;; Basic Procedures
235;;; ===========================================================================
236;;;
237
238(defun shell-mode ()
239 "Major mode for interacting with an inferior shell.
240Return after the end of the process' output sends the text from the
241 end of process to the end of the current line.
c88ab9ce
ER
242Return before end of process output copies the current line (except
243 for the prompt) to the end of the buffer and sends it.
be9b65ac 244M-x send-invisible reads a line of text without echoing it, and sends it to
c88ab9ce 245 the shell. This is useful for entering passwords.
be9b65ac
DL
246
247If you accidentally suspend your process, use \\[comint-continue-subjob]
248to continue it.
249
250cd, pushd and popd commands given to the shell are watched by Emacs to keep
251this buffer's default directory the same as the shell's working directory.
252M-x dirs queries the shell and resyncs Emacs' idea of what the current
253 directory stack is.
254M-x dirtrack-toggle turns directory tracking on and off.
255
256\\{shell-mode-map}
24fdffaa 257Customization: Entry to this mode runs the hooks on `comint-mode-hook' and
d76b71af 258`shell-mode-hook' (in that order). After each shell output, the hooks on
5394cb44 259`comint-output-filter-functions' are run.
be9b65ac 260
24fdffaa 261Variables `shell-cd-regexp', `shell-pushd-regexp' and `shell-popd-regexp'
d76b71af 262are used to match their respective commands, while `shell-pushd-tohome',
5394cb44 263`shell-pushd-dextract' and `shell-pushd-dunique' control the behavior of the
d76b71af
RS
264relevant command.
265
266Variables `comint-completion-autolist', `comint-completion-addsuffix' and
5394cb44 267`comint-completion-recexact' control the behavior of file name, command name
d76b71af 268and variable name completion. Variable `shell-completion-execonly' controls
5394cb44 269the behavior of command name completion.
d76b71af
RS
270
271Variables `comint-input-ring-file-name' and `comint-input-autoexpand' control
272the initialisation of the input ring history, and history expansion.
273
5394cb44
RS
274Variables `comint-output-filter-functions', `comint-scroll-to-bottom-on-input',
275and `comint-scroll-to-bottom-on-output' control whether input and output
276cause the window to scroll to the end of the buffer."
be9b65ac
DL
277 (interactive)
278 (comint-mode)
a9ec2adb 279 (setq major-mode 'shell-mode)
bd5201e3 280 (setq mode-name "Shell")
be9b65ac 281 (use-local-map shell-mode-map)
d76b71af
RS
282 (setq comint-prompt-regexp shell-prompt-pattern)
283 (setq comint-delimiter-argument-list shell-delimiter-argument-list)
284 (setq comint-after-partial-filename-command 'shell-after-partial-filename)
285 (setq comint-get-current-command 'shell-get-current-command)
286 (setq comint-dynamic-complete-command-command 'shell-dynamic-complete-command)
287 (make-local-variable 'paragraph-start)
288 (setq paragraph-start comint-prompt-regexp)
be9b65ac 289 (make-local-variable 'shell-dirstack)
a9ec2adb 290 (setq shell-dirstack nil)
fa8f1b25 291 (setq shell-last-dir nil)
a9ec2adb
JB
292 (make-local-variable 'shell-dirtrackp)
293 (setq shell-dirtrackp t)
294 (setq comint-input-sentinel 'shell-directory-tracker)
d76b71af
RS
295 ;; shell-dependent assignments.
296 (let ((shell (car (process-command (get-buffer-process (current-buffer))))))
297 (setq comint-input-ring-file-name
298 (or (getenv "HISTFILE")
299 (cond ((string-match "csh$" shell) "~/.history")
300 ((string-match "bash$" shell) "~/.bash_history")
301 ((string-match "ksh$" shell) "~/.sh_history")
302 (t "~/.history")))))
303 (run-hooks 'shell-mode-hook)
f5a131d8 304 (comint-read-input-ring t)
d76b71af 305 (shell-dirstack-message))
be9b65ac 306\f
c88ab9ce 307;;;###autoload
be9b65ac
DL
308(defun shell ()
309 "Run an inferior shell, with I/O through buffer *shell*.
310If buffer exists but shell process is not running, make new shell.
d76b71af 311If buffer exists and shell process is running, just switch to buffer `*shell*'.
24fdffaa 312Program used comes from variable `explicit-shell-file-name',
a9ec2adb
JB
313 or (if that is nil) from the ESHELL environment variable,
314 or else from SHELL if there is no ESHELL.
fbc270e7 315If a file `~/.emacs_SHELLNAME' exists, it is given as initial input
a9ec2adb
JB
316 (Note that this may lose due to a timing error if the shell
317 discards input when it starts up.)
fbc270e7
RS
318The buffer is put in Shell mode, giving commands for sending input
319and controlling the subjobs of the shell. See `shell-mode'.
320See also the variable `shell-prompt-pattern'.
be9b65ac 321
a9ec2adb 322The shell file name (sans directories) is used to make a symbol name
62c9fad7 323such as `explicit-csh-args'. If that symbol is a variable,
be9b65ac
DL
324its value is used as a list of arguments when invoking the shell.
325Otherwise, one argument `-i' is passed to the shell.
326
327\(Type \\[describe-mode] in the shell buffer for a list of commands.)"
328 (interactive)
d76b71af
RS
329 (if (not (comint-check-proc "*shell*"))
330 (let* ((prog (or explicit-shell-file-name
331 (getenv "ESHELL")
332 (getenv "SHELL")
333 "/bin/sh"))
334 (name (file-name-nondirectory prog))
335 (startfile (concat "~/.emacs_" name))
336 (xargs-name (intern-soft (concat "explicit-" name "-args"))))
337 (set-buffer (apply 'make-comint "shell" prog
338 (if (file-exists-p startfile) startfile)
339 (if (and xargs-name (boundp xargs-name))
340 (symbol-value xargs-name)
341 '("-i"))))
342 (shell-mode)))
be9b65ac 343 (switch-to-buffer "*shell*"))
be9b65ac
DL
344\f
345;;; Directory tracking
346;;; ===========================================================================
347;;; This code provides the shell mode input sentinel
348;;; SHELL-DIRECTORY-TRACKER
349;;; that tracks cd, pushd, and popd commands issued to the shell, and
350;;; changes the current directory of the shell buffer accordingly.
351;;;
352;;; This is basically a fragile hack, although it's more accurate than
b7fc702e 353;;; the version in Emacs 18's shell.el. It has the following failings:
be9b65ac 354;;; 1. It doesn't know about the cdpath shell variable.
d76b71af
RS
355;;; 2. It cannot infallibly deal with command sequences, though it does well
356;;; with these and with ignoring commands forked in another shell with ()s.
357;;; 3. More generally, any complex command is going to throw it. Otherwise,
358;;; you'd have to build an entire shell interpreter in emacs lisp. Failing
359;;; that, there's no way to catch shell commands where cd's are buried
360;;; inside conditional expressions, aliases, and so forth.
be9b65ac
DL
361;;;
362;;; The whole approach is a crock. Shell aliases mess it up. File sourcing
363;;; messes it up. You run other processes under the shell; these each have
364;;; separate working directories, and some have commands for manipulating
365;;; their w.d.'s (e.g., the lcd command in ftp). Some of these programs have
a9ec2adb 366;;; commands that do *not* affect the current w.d. at all, but look like they
be9b65ac
DL
367;;; do (e.g., the cd command in ftp). In shells that allow you job
368;;; control, you can switch between jobs, all having different w.d.'s. So
369;;; simply saying %3 can shift your w.d..
370;;;
371;;; The solution is to relax, not stress out about it, and settle for
372;;; a hack that works pretty well in typical circumstances. Remember
373;;; that a half-assed solution is more in keeping with the spirit of Unix,
374;;; anyway. Blech.
375;;;
376;;; One good hack not implemented here for users of programmable shells
377;;; is to program up the shell w.d. manipulation commands to output
378;;; a coded command sequence to the tty. Something like
379;;; ESC | <cwd> |
380;;; where <cwd> is the new current working directory. Then trash the
381;;; directory tracking machinery currently used in this package, and
382;;; replace it with a process filter that watches for and strips out
383;;; these messages.
384
be9b65ac
DL
385(defun shell-directory-tracker (str)
386 "Tracks cd, pushd and popd commands issued to the shell.
387This function is called on each input passed to the shell.
388It watches for cd, pushd and popd commands and sets the buffer's
389default directory to track these commands.
390
391You may toggle this tracking on and off with M-x dirtrack-toggle.
392If emacs gets confused, you can resync with the shell with M-x dirs.
393
d76b71af
RS
394See variables `shell-cd-regexp', `shell-pushd-regexp', and `shell-popd-regexp',
395while `shell-pushd-tohome', `shell-pushd-dextract' and `shell-pushd-dunique'
5394cb44 396control the behavior of the relevant command.
d76b71af 397
24fdffaa 398Environment variables are expanded, see function `substitute-in-file-name'."
d76b71af
RS
399 (if shell-dirtrackp
400 ;; We fail gracefully if we think the command will fail in the shell.
401 (condition-case chdir-failure
402 (let ((start (progn (string-match "^[;\\s ]*" str) ; skip whitespace
403 (match-end 0)))
404 end cmd arg1)
405 (while (string-match shell-command-regexp str start)
406 (setq end (match-end 0)
407 cmd (comint-arguments (substring str start end) 0 0)
408 arg1 (comint-arguments (substring str start end) 1 1))
409 (cond ((eq (string-match shell-popd-regexp cmd) 0)
410 (shell-process-popd (substitute-in-file-name arg1)))
411 ((eq (string-match shell-pushd-regexp cmd) 0)
412 (shell-process-pushd (substitute-in-file-name arg1)))
413 ((eq (string-match shell-cd-regexp cmd) 0)
414 (shell-process-cd (substitute-in-file-name arg1))))
415 (setq start (progn (string-match "[;\\s ]*" str end) ; skip again
416 (match-end 0)))))
417 (error (message "Couldn't cd")))))
418
419
420;; Like `cd', but prepends comint-file-name-prefix to absolute names.
9dac0433
RM
421(defsubst shell-cd (directory)
422 (if (file-name-absolute-p directory)
d76b71af 423 (cd-absolute (concat comint-file-name-prefix directory))
9dac0433
RM
424 (cd directory)))
425
be9b65ac
DL
426;;; popd [+n]
427(defun shell-process-popd (arg)
d76b71af
RS
428 (let ((num (or (shell-extract-num arg) 0)))
429 (cond ((and num (= num 0) shell-dirstack)
430 (shell-cd (car shell-dirstack))
431 (setq shell-dirstack (cdr shell-dirstack))
432 (shell-dirstack-message))
433 ((and num (> num 0) (<= num (length shell-dirstack)))
434 (let* ((ds (cons nil shell-dirstack))
435 (cell (nthcdr (1- num) ds)))
436 (rplacd cell (cdr (cdr cell)))
437 (setq shell-dirstack (cdr ds))
438 (shell-dirstack-message)))
439 (t
440 (error (message "Couldn't popd."))))))
be9b65ac
DL
441
442;;; cd [dir]
443(defun shell-process-cd (arg)
d76b71af
RS
444 (let ((new-dir (cond ((zerop (length arg)) (getenv "HOME"))
445 ((string-equal "-" arg) shell-last-dir)
446 (t arg))))
447 (setq shell-last-dir default-directory)
448 (shell-cd new-dir)
449 (shell-dirstack-message)))
be9b65ac
DL
450
451;;; pushd [+n | dir]
452(defun shell-process-pushd (arg)
d76b71af
RS
453 (let ((num (shell-extract-num arg)))
454 (cond ((zerop (length arg))
455 ;; no arg -- swap pwd and car of stack unless shell-pushd-tohome
456 (cond (shell-pushd-tohome
457 (shell-process-pushd "~"))
458 (shell-dirstack
459 (let ((old default-directory))
460 (shell-cd (car shell-dirstack))
461 (setq shell-dirstack
462 (cons old (cdr shell-dirstack)))
463 (shell-dirstack-message)))
464 (t
465 (message "Directory stack empty."))))
466 ((numberp num)
467 ;; pushd +n
468 (cond ((> num (length shell-dirstack))
469 (message "Directory stack not that deep."))
470 ((= num 0)
471 (error (message "Couldn't cd.")))
472 (shell-pushd-dextract
473 (let ((dir (nth (1- num) shell-dirstack)))
474 (shell-process-popd arg)
475 (shell-process-pushd default-directory)
476 (shell-cd dir)
477 (shell-dirstack-message)))
478 (t
479 (let* ((ds (cons default-directory shell-dirstack))
480 (dslen (length ds))
481 (front (nthcdr num ds))
482 (back (reverse (nthcdr (- dslen num) (reverse ds))))
483 (new-ds (append front back)))
484 (shell-cd (car new-ds))
485 (setq shell-dirstack (cdr new-ds))
486 (shell-dirstack-message)))))
487 (t
488 ;; pushd <dir>
489 (let ((old-wd default-directory))
490 (shell-cd arg)
491 (if (or (null shell-pushd-dunique)
492 (not (member old-wd shell-dirstack)))
493 (setq shell-dirstack (cons old-wd shell-dirstack)))
494 (shell-dirstack-message))))))
be9b65ac
DL
495
496;; If STR is of the form +n, for n>0, return n. Otherwise, nil.
497(defun shell-extract-num (str)
498 (and (string-match "^\\+[1-9][0-9]*$" str)
499 (string-to-int str)))
500
501
502(defun shell-dirtrack-toggle ()
503 "Turn directory tracking on and off in a shell buffer."
504 (interactive)
505 (setq shell-dirtrackp (not shell-dirtrackp))
d76b71af 506 (message "Directory tracking %s" (if shell-dirtrackp "ON" "OFF")))
be9b65ac
DL
507
508;;; For your typing convenience:
31e1d920 509(defalias 'dirtrack-toggle 'shell-dirtrack-toggle)
be9b65ac
DL
510
511
512(defun shell-resync-dirs ()
513 "Resync the buffer's idea of the current directory stack.
514This command queries the shell with the command bound to
24fdffaa 515`shell-dirstack-query' (default \"dirs\"), reads the next
be9b65ac
DL
516line output and parses it to form the new directory stack.
517DON'T issue this command unless the buffer is at a shell prompt.
518Also, note that if some other subprocess decides to do output
519immediately after the query, its output will be taken as the
520new directory stack -- you lose. If this happens, just do the
521command again."
522 (interactive)
523 (let* ((proc (get-buffer-process (current-buffer)))
524 (pmark (process-mark proc)))
525 (goto-char pmark)
526 (insert shell-dirstack-query) (insert "\n")
527 (sit-for 0) ; force redisplay
528 (comint-send-string proc shell-dirstack-query)
529 (comint-send-string proc "\n")
530 (set-marker pmark (point))
531 (let ((pt (point))) ; wait for 1 line
532 ;; This extra newline prevents the user's pending input from spoofing us.
533 (insert "\n") (backward-char 1)
534 (while (not (looking-at ".+\n"))
535 (accept-process-output proc)
536 (goto-char pt)))
537 (goto-char pmark) (delete-char 1) ; remove the extra newline
538 ;; That's the dirlist. grab it & parse it.
d76b71af 539 (let* ((dl (buffer-substring (match-beginning 0) (1- (match-end 0))))
be9b65ac
DL
540 (dl-len (length dl))
541 (ds '()) ; new dir stack
542 (i 0))
543 (while (< i dl-len)
544 ;; regexp = optional whitespace, (non-whitespace), optional whitespace
545 (string-match "\\s *\\(\\S +\\)\\s *" dl i) ; pick off next dir
546 (setq ds (cons (substring dl (match-beginning 1) (match-end 1))
547 ds))
548 (setq i (match-end 0)))
549 (let ((ds (reverse ds)))
550 (condition-case nil
d76b71af 551 (progn (cd (car ds))
be9b65ac
DL
552 (setq shell-dirstack (cdr ds))
553 (shell-dirstack-message))
554 (error (message "Couldn't cd.")))))))
555
556;;; For your typing convenience:
31e1d920 557(defalias 'dirs 'shell-resync-dirs)
be9b65ac
DL
558
559
560;;; Show the current dirstack on the message line.
561;;; Pretty up dirs a bit by changing "/usr/jqr/foo" to "~/foo".
562;;; (This isn't necessary if the dirlisting is generated with a simple "dirs".)
563;;; All the commands that mung the buffer's dirstack finish by calling
564;;; this guy.
565(defun shell-dirstack-message ()
94f9dcbe
RM
566 (let* ((msg "")
567 (ds (cons default-directory shell-dirstack))
d76b71af 568 (home (expand-file-name (concat comint-file-name-prefix "~/")))
94f9dcbe 569 (homelen (length home)))
be9b65ac
DL
570 (while ds
571 (let ((dir (car ds)))
94f9dcbe
RM
572 (and (>= (length dir) homelen) (string= home (substring dir 0 homelen))
573 (setq dir (concat "~/" (substring dir homelen))))
d76b71af
RS
574 ;; Strip off comint-file-name-prefix if present.
575 (and comint-file-name-prefix
576 (>= (length dir) (length comint-file-name-prefix))
577 (string= comint-file-name-prefix
578 (substring dir 0 (length comint-file-name-prefix)))
579 (setq dir (substring dir (length comint-file-name-prefix)))
94f9dcbe 580 (setcar ds dir))
d76b71af 581 (setq msg (concat msg (directory-file-name dir) " "))
be9b65ac
DL
582 (setq ds (cdr ds))))
583 (message msg)))
a9ec2adb 584\f
d76b71af
RS
585(defun shell-forward-command (&optional arg)
586 "Move forward across ARG shell command(s). Does not cross lines.
587See `shell-command-regexp'."
588 (interactive "p")
589 (let ((limit (save-excursion (end-of-line nil) (point))))
590 (if (re-search-forward (concat shell-command-regexp "\\([;&|][\\s ]*\\)+")
591 limit 'move arg)
592 (skip-syntax-backward "^\\s "))))
593
594
595(defun shell-backward-command (&optional arg)
596 "Move backward across ARG shell command(s). Does not cross lines.
597See `shell-command-regexp'."
598 (interactive "p")
599 (let ((limit (save-excursion (comint-bol nil) (point))))
600 (skip-syntax-backward "\\s " limit)
601 (if (re-search-backward
602 (format "[;&|]+[\\s ]*\\(%s\\)" shell-command-regexp) limit 'move arg)
603 (progn (goto-char (match-beginning 1))
604 (skip-syntax-backward "^\\s ")))))
605
606
607(defun shell-get-current-command ()
608 "Function that returns the current command including arguments."
609 (save-excursion
610 (if (looking-at "\\s *[^;&|]")
611 (goto-char (match-end 0)))
612 (buffer-substring
613 (progn (shell-backward-command 1) (point))
614 (progn (shell-forward-command 1) (if (eolp) (point) (match-end 1))))))
615
616
617(defun shell-after-partial-filename ()
618 "Returns t if point is after a file name.
619File names are assumed to contain `/'s or not be the first item in the command.
620
621See also `shell-backward-command'."
622 (let ((filename (comint-match-partial-filename)))
623 (or (save-match-data (string-match "/" filename))
624 (not (eq (match-beginning 0)
625 (save-excursion (shell-backward-command 1) (point)))))))
626
627
628(defun shell-dynamic-complete-command ()
629 "Dynamically complete the command at point.
630This function is similar to `comint-dynamic-complete-filename', except that it
631searches `exec-path' (minus the trailing emacs library path) for completion
632candidates. Note that this may not be the same as the shell's idea of the
633path.
634
635Completion is dependent on the value of `shell-completion-execonly', plus
636those that effect file completion. See `comint-dynamic-complete-filename'."
637 (interactive)
638 (let* ((completion-ignore-case nil)
639 (filename (comint-match-partial-filename))
640 (pathnondir (file-name-nondirectory filename))
641 (paths (cdr (reverse exec-path)))
642 (cwd (file-name-as-directory (expand-file-name default-directory)))
643 (ignored-extensions
644 (mapconcat (function (lambda (x) (concat (regexp-quote x) "$")))
645 completion-ignored-extensions "\\|"))
646 (path "") (comps-in-path ()) (file "") (filepath "") (completions ()))
647 ;; Go thru each path in the search path, finding completions.
648 (while paths
649 (setq path (file-name-as-directory (comint-directory (or (car paths) ".")))
650 comps-in-path (and (file-accessible-directory-p path)
651 (file-name-all-completions pathnondir path)))
652 ;; Go thru each completion found, to see whether it should be used.
653 (while comps-in-path
654 (setq file (car comps-in-path)
655 filepath (concat path file))
656 (if (and (not (member file completions))
657 (not (string-match ignored-extensions file))
658 (or (string-equal path cwd)
659 (not (file-directory-p filepath)))
660 (or (null shell-completion-execonly)
661 (file-executable-p filepath)))
662 (setq completions (cons file completions)))
663 (setq comps-in-path (cdr comps-in-path)))
664 (setq paths (cdr paths)))
665 ;; OK, we've got a list of completions.
666 (cond ((null completions)
667 (message "No completions of %s" filename)
668 (ding))
669 ((= 1 (length completions)) ; Gotcha!
670 (let ((completion (car completions)))
671 (if (string-equal completion pathnondir)
672 (message "Sole completion")
673 (insert (substring (directory-file-name completion)
674 (length pathnondir)))
675 (message "Completed"))
676 (if comint-completion-addsuffix
677 (insert (if (file-directory-p completion) "/" " ")))))
678 (t ; There's no unique completion.
679 (let ((completion
680 (try-completion pathnondir (mapcar (function (lambda (x)
681 (list x)))
682 completions))))
683 ;; Insert the longest substring.
684 (insert (substring (directory-file-name completion)
685 (length pathnondir)))
686 (cond ((and comint-completion-recexact comint-completion-addsuffix
687 (string-equal pathnondir completion)
688 (member completion completions))
689 ;; It's not unique, but user wants shortest match.
690 (insert (if (file-directory-p completion) "/" " "))
691 (message "Completed shortest"))
692 ((or comint-completion-autolist
693 (string-equal pathnondir completion))
694 ;; It's not unique, list possible completions.
695 (comint-dynamic-list-completions completions))
696 (t
697 (message "Partially completed"))))))))
698\f
8f95f0ce 699;;; Do the user's customization...
d76b71af
RS
700;;;
701;;; Isn't this what eval-after-load is for?
702;;;(defvar shell-load-hook nil
703;;; "This hook is run when shell is loaded in.
704;;;This is a good place to put keybindings.")
705;;;
706;;;(run-hooks 'shell-load-hook)
a9ec2adb 707
c88ab9ce
ER
708(provide 'shell)
709
710;;; shell.el ends here