]> code.delx.au - gnu-emacs/blobdiff - lisp/shell.el
(smtpmail-send-it): Add autoload cookie.
[gnu-emacs] / lisp / shell.el
index 97e9589be27ec298b239dd13195557f985e6c1a9..03d06cae7e888b74b06f821ec72398d1acad0f05 100644 (file)
@@ -1,9 +1,10 @@
 ;;; shell.el --- specialized comint.el for running the shell.
 
-;; Copyright (C) 1988, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+;; Copyright (C) 1988, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
 
-;; Author: Olin Shivers <shivers@cs.cmu.edu>
-;; Maintainer: Simon Marshall <simon@gnu.ai.mit.edu>
+;; Author: Olin Shivers <shivers@cs.cmu.edu> then
+;;     Simon Marshall <simon@gnu.ai.mit.edu>
+;; Maintainer: FSF
 ;; Keywords: processes
 
 ;; This file is part of GNU Emacs.
 ;;============================================================================
 ;; Comint Mode Commands: (common to shell and all comint-derived modes)
 ;;
-;; m-p     comint-previous-input           Cycle backwards in input history
-;; m-n     comint-next-input               Cycle forwards
+;; m-p    comint-previous-input           Cycle backwards in input history
+;; m-n    comint-next-input               Cycle forwards
 ;; m-r     comint-previous-matching-input  Previous input matching a regexp
 ;; m-s     comint-next-matching-input      Next input that matches
-;; m-c-l   comint-show-output              Show last batch of process output
+;; m-c-l   comint-show-output             Show last batch of process output
 ;; return  comint-send-input
-;; c-d     comint-delchar-or-maybe-eof     Delete char unless at end of buff.
+;; c-d    comint-delchar-or-maybe-eof     Delete char unless at end of buff.
 ;; c-c c-a comint-bol                      Beginning of line; skip prompt
-;; c-c c-u comint-kill-input               ^u
-;; c-c c-w backward-kill-word              ^w
-;; c-c c-c comint-interrupt-subjob         ^c
-;; c-c c-z comint-stop-subjob              ^z
-;; c-c c-\ comint-quit-subjob              ^\
-;; c-c c-o comint-kill-output              Delete last batch of process output
-;; c-c c-r comint-show-output              Show last batch of process output
+;; c-c c-u comint-kill-input              ^u
+;; c-c c-w backward-kill-word             ^w
+;; c-c c-c comint-interrupt-subjob        ^c
+;; c-c c-z comint-stop-subjob             ^z
+;; c-c c-\ comint-quit-subjob             ^\
+;; c-c c-o comint-kill-output             Delete last batch of process output
+;; c-c c-r comint-show-output             Show last batch of process output
 ;; c-c c-h comint-dynamic-list-input-ring  List input history
 ;;         send-invisible                  Read line w/o echo & send to proc
-;;         comint-continue-subjob          Useful if you accidentally suspend
+;;         comint-continue-subjob         Useful if you accidentally suspend
 ;;                                             top-level job
 ;; comint-mode-hook is the comint mode hook.
 
@@ -90,8 +91,8 @@
 ;;                                     List completions in help buffer
 ;; m-c-f   shell-forward-command       Forward a shell command
 ;; m-c-b   shell-backward-command      Backward a shell command
-;;         dirs                        Resync the buffer's dir stack
-;;         dirtrack-toggle             Turn dir tracking on/off
+;;        dirs                         Resync the buffer's dir stack
+;;        dirtrack-mode                Turn dir tracking on/off
 ;;         comint-strip-ctrl-m         Remove trailing ^Ms from output
 ;;
 ;; The shell mode hook is shell-mode-hook
 
 ;;; Customization and Buffer Variables
 
+(defgroup shell nil
+  "Running shell from within Emacs buffers"
+  :group 'processes
+  :group 'unix)
+
+(defgroup shell-directories nil
+  "Directory support in shell mode"
+  :group 'shell)
+
+(defgroup shell-faces nil
+  "Faces in shell buffers"
+  :group 'shell)
+
 ;;;###autoload
 (defvar shell-prompt-pattern "^[^#$%>\n]*[#$%>] *"
   "Regexp to match prompts in the inferior shell.
@@ -119,13 +133,15 @@ on lines which don't start with a prompt.
 
 This is a fine thing to set in your `.emacs' file.")
 
-(defvar shell-completion-fignore nil
+(defcustom shell-completion-fignore nil
   "*List of suffixes to be disregarded during file/command completion.
 This variable is used to initialize `comint-completion-fignore' in the shell
 buffer.  The default is nil, for compatibility with most shells.
 Some people like (\"~\" \"#\" \"%\").
 
-This is a fine thing to set in your `.emacs' file.")  
+This is a fine thing to set in your `.emacs' file."
+  :type '(repeat (string :tag "Suffix"))
+  :group 'shell)
 
 (defvar shell-delimiter-argument-list '(?\| ?& ?< ?> ?\( ?\) ?\;)
   "List of characters to recognise as separate arguments.
@@ -136,7 +152,7 @@ This is a fine thing to set in your `.emacs' file.")
 
 (defvar shell-file-name-chars
   (if (memq system-type '(ms-dos windows-nt))
-      "~/A-Za-z0-9_^$!#%&{}@`'.()-"
+      "~/A-Za-z0-9_^$!#%&{}@`'.,:()-"
     "~/A-Za-z0-9+@:_.$#%,={}-")
   "String of characters valid in a file name.
 This variable is used to initialize `comint-file-name-chars' in the
@@ -166,57 +182,80 @@ shell buffer.
 
 This is a fine thing to set in your `.emacs' file.")
 
-(defvar shell-command-regexp "[^;&|\n]+"
+(defcustom shell-command-regexp "[^;&|\n]+"
   "*Regexp to match a single command within a pipeline.
-This is used for directory tracking and does not do a perfect job.")
+This is used for directory tracking and does not do a perfect job."
+  :type 'regexp
+  :group 'shell)
 
-(defvar shell-completion-execonly t
+(defcustom shell-completion-execonly t
   "*If non-nil, use executable files only for completion candidates.
 This mirrors the optional behavior of tcsh.
 
-Detecting executability of files may slow command completion considerably.")
+Detecting executability of files may slow command completion considerably."
+  :type 'boolean
+  :group 'shell)
 
-(defvar shell-popd-regexp "popd"
-  "*Regexp to match subshell commands equivalent to popd.")
+(defcustom shell-popd-regexp "popd"
+  "*Regexp to match subshell commands equivalent to popd."
+  :type 'regexp
+  :group 'shell-directories)
 
-(defvar shell-pushd-regexp "pushd"
-  "*Regexp to match subshell commands equivalent to pushd.")
+(defcustom shell-pushd-regexp "pushd"
+  "*Regexp to match subshell commands equivalent to pushd."
+  :type 'regexp
+  :group 'shell-directories)
 
-(defvar shell-pushd-tohome nil
+(defcustom shell-pushd-tohome nil
   "*If non-nil, make pushd with no arg behave as \"pushd ~\" (like cd).
-This mirrors the optional behavior of tcsh.")
+This mirrors the optional behavior of tcsh."
+  :type 'boolean
+  :group 'shell-directories)
 
-(defvar shell-pushd-dextract nil
+(defcustom shell-pushd-dextract nil
   "*If non-nil, make \"pushd +n\" pop the nth dir to the stack top.
-This mirrors the optional behavior of tcsh.")
+This mirrors the optional behavior of tcsh."
+  :type 'boolean
+  :group 'shell-directories)
 
-(defvar shell-pushd-dunique nil
+(defcustom shell-pushd-dunique nil
   "*If non-nil, make pushd only add unique directories to the stack.
-This mirrors the optional behavior of tcsh.")
+This mirrors the optional behavior of tcsh."
+  :type 'boolean
+  :group 'shell-directories)
 
-(defvar shell-cd-regexp "cd"
-  "*Regexp to match subshell commands equivalent to cd.")
+(defcustom shell-cd-regexp "cd"
+  "*Regexp to match subshell commands equivalent to cd."
+  :type 'regexp
+  :group 'shell-directories)
 
-(defvar shell-chdrive-regexp
+(defcustom shell-chdrive-regexp
   (if (memq system-type '(ms-dos windows-nt)) 
       ; NetWare allows the five chars between upper and lower alphabetics.
       "[]a-zA-Z^_`\\[\\\\]:"
     nil)
-  "*If non-nil, is regexp used to track drive changes.")
+  "*If non-nil, is regexp used to track drive changes."
+  :type '(choice regexp
+                (const nil))
+  :group 'shell-directories)
 
-(defvar explicit-shell-file-name nil
-  "*If non-nil, is file name to use for explicitly requested inferior shell.")
+(defcustom explicit-shell-file-name nil
+  "*If non-nil, is file name to use for explicitly requested inferior shell."
+  :type '(choice (const :tag "None" nil) file)
+  :group 'shell)
 
-(defvar explicit-csh-args
+(defcustom explicit-csh-args
   (if (eq system-type 'hpux)
       ;; -T persuades HP's csh not to think it is smarter
       ;; than us about what terminal modes to use.
       '("-i" "-T")
     '("-i"))
   "*Args passed to inferior shell by M-x shell, if the shell is csh.
-Value is a list of strings, which may be nil.")
+Value is a list of strings, which may be nil."
+  :type '(repeat (string :tag "Argument"))
+  :group 'shell)
 
-(defvar shell-input-autoexpand 'history
+(defcustom shell-input-autoexpand 'history
   "*If non-nil, expand input command history references on completion.
 This mirrors the optional behavior of tcsh (its autoexpand and histlit).
 
@@ -226,7 +265,9 @@ into the buffer's input ring.  See also `comint-magic-space' and
 `comint-dynamic-complete'.
 
 This variable supplies a default for `comint-input-autoexpand',
-for Shell mode only.")
+for Shell mode only."
+  :type '(choice (const nil) (const input) (const history))
+  :type 'shell)
 
 (defvar shell-dirstack nil
   "List of directories saved by pushd in this buffer's shell.
@@ -260,18 +301,22 @@ Thus, this does not include the shell's current directory.")
                              shell-replace-by-expanded-directory)
         'complete-expand)))
 
-(defvar shell-mode-hook '()
-  "*Hook for customising Shell mode.")
+(defcustom shell-mode-hook '()
+  "*Hook for customising Shell mode."
+  :type 'hook
+  :group 'shell)
 
 (defvar shell-font-lock-keywords
-  (list (cons shell-prompt-pattern 'font-lock-keyword-face)
-       '("[ \t]\\([+-][^ \t\n]+\\)" 1 font-lock-comment-face)
-       '("^[^ \t\n]+:.*" . font-lock-string-face)
-       '("^\\[[1-9][0-9]*\\]" . font-lock-string-face))
+  '((eval . (cons shell-prompt-pattern 'font-lock-warning-face))
+    ("[ \t]\\([+-][^ \t\n]+\\)" 1 font-lock-comment-face)
+    ("^[^ \t\n]+:.*" . font-lock-string-face)
+    ("^\\[[1-9][0-9]*\\]" . font-lock-string-face))
   "Additional expressions to highlight in Shell mode.")
 \f
 ;;; Basic Procedures
 
+(put 'shell-mode 'mode-class 'special)
+
 (defun shell-mode ()
   "Major mode for interacting with an inferior shell.
 \\[comint-send-input] after the end of the process' output sends the text from
@@ -297,7 +342,7 @@ While directory tracking is enabled, the shell's working directory is displayed
 by \\[list-buffers] or \\[mouse-buffer-menu] in the `File' field.
 \\[dirs] queries the shell and resyncs Emacs' idea of what the current 
     directory stack is.
-\\[dirtrack-toggle] turns directory tracking on and off.
+\\[dirtrack-mode] turns directory tracking on and off.
 
 \\{shell-mode-map}
 Customization: Entry to this mode runs the hooks on `comint-mode-hook' and
@@ -341,13 +386,16 @@ buffer."
   (setq font-lock-defaults '(shell-font-lock-keywords t))
   (make-local-variable 'shell-dirstack)
   (setq shell-dirstack nil)
+  (make-local-variable 'shell-last-dir)
   (setq shell-last-dir nil)
   (make-local-variable 'shell-dirtrackp)
   (setq shell-dirtrackp t)
   (add-hook 'comint-input-filter-functions 'shell-directory-tracker nil t)
   (setq comint-input-autoexpand shell-input-autoexpand)
-  ;; We used to set list-buffers-directory here, but that was wrong.
-  ;; A shell buffer is not a way of editing a directory.
+  ;; This is not really correct, since the shell buffer does not really
+  ;; edit this directory.  But it is useful in the buffer list and menus.
+  (make-local-variable 'list-buffers-directory)
+  (setq list-buffers-directory (expand-file-name default-directory))
   ;; shell-dependent assignments.
   (let ((shell (file-name-nondirectory (car
                 (process-command (get-buffer-process (current-buffer)))))))
@@ -382,6 +430,13 @@ The buffer is put in Shell mode, giving commands for sending input
 and controlling the subjobs of the shell.  See `shell-mode'.
 See also the variable `shell-prompt-pattern'.
 
+To specify a coding system for converting non-ASCII characters
+in the input and output to the shell, use \\[universal-coding-system-argument]
+before \\[shell].  You can also specify this with \\[set-buffer-process-coding-system]
+in the shell buffer, after you start the shell.
+The default comes from `process-coding-system-alist' and
+`default-process-coding-system'.
+
 The shell file name (sans directories) is used to make a symbol name
 such as `explicit-csh-args'.  If that symbol is a variable,
 its value is used as a list of arguments when invoking the shell.
@@ -458,7 +513,7 @@ This function is called on each input passed to the shell.
 It watches for cd, pushd and popd commands and sets the buffer's
 default directory to track these commands.
 
-You may toggle this tracking on and off with M-x dirtrack-toggle.
+You may toggle this tracking on and off with M-x dirtrack-mode.
 If emacs gets confused, you can resync with the shell with M-x dirs.
 
 See variables `shell-cd-regexp', `shell-chdrive-regexp', `shell-pushd-regexp',
@@ -583,7 +638,7 @@ Environment variables are expanded, see function `substitute-in-file-name'."
        (string-to-int str)))
 
 
-(defun shell-dirtrack-toggle ()
+(defun shell-dirtrack-mode ()
   "Turn directory tracking on and off in a shell buffer."
   (interactive)
   (if (setq shell-dirtrackp (not shell-dirtrackp))
@@ -592,7 +647,9 @@ Environment variables are expanded, see function `substitute-in-file-name'."
   (message "Directory tracking %s" (if shell-dirtrackp "ON" "OFF")))
 
 ;;; For your typing convenience:
-(defalias 'dirtrack-toggle 'shell-dirtrack-toggle)
+(defalias 'shell-dirtrack-toggle 'shell-dirtrack-mode)
+(defalias 'dirtrack-toggle 'shell-dirtrack-mode)
+(defalias 'dirtrack-mode 'shell-dirtrack-mode)
 
 (defun shell-cd (dir)
   "Do normal `cd' to DIR, and set `list-buffers-directory'."
@@ -677,6 +734,37 @@ command again."
        (setq ds (cdr ds))))
     (message "%s" msg)))
 \f
+;; This was mostly copied from shell-resync-dirs.
+(defun shell-snarf-envar (var)
+  "Return as a string the shell's value of environment variable VAR."
+  (let* ((cmd (format "printenv '%s'\n" var))
+        (proc (get-buffer-process (current-buffer)))
+        (pmark (process-mark proc)))
+    (goto-char pmark)
+    (insert cmd)
+    (sit-for 0)                                ; force redisplay
+    (comint-send-string proc cmd)
+    (set-marker pmark (point))
+    (let ((pt (point)))                        ; wait for 1 line
+      ;; This extra newline prevents the user's pending input from spoofing us.
+      (insert "\n") (backward-char 1)
+      (while (not (looking-at ".+\n"))
+       (accept-process-output proc)
+       (goto-char pt)))
+    (goto-char pmark) (delete-char 1)  ; remove the extra newline
+    (buffer-substring (match-beginning 0) (1- (match-end 0)))))
+
+(defun shell-copy-environment-variable (variable)
+  "Copy the environment variable VARIABLE from the subshell to Emacs.
+This command reads the value of the specified environment variable
+in the shell, and sets the same environment variable in Emacs
+\(what `getenv' in Emacs would return) to that value.
+That value will affect any new subprocesses that you subsequently start
+from Emacs."
+  (interactive (list (read-envvar-name "\
+Copy Shell environment variable to Emacs: ")))
+  (setenv variable (shell-snarf-envar variable)))
+\f
 (defun shell-forward-command (&optional arg)
   "Move forward across ARG shell command(s).  Does not cross lines.
 See `shell-command-regexp'."