;;; shell.el --- specialized comint.el for running the shell
;; Copyright (C) 1988, 1993, 1994, 1995, 1996, 1997, 2000, 2001,
-;; 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+;; 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
;; Author: Olin Shivers <shivers@cs.cmu.edu>
;; Simon Marshall <simon@gnu.org>
;; This file is part of GNU Emacs.
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; 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-mode Turn dir tracking on/off
+;; shell-dirtrack-mode Turn dir tracking on/off
;; comint-strip-ctrl-m Remove trailing ^Ms from output
;;
;; The shell mode hook is shell-mode-hook
:group 'shell)
;;;###autoload
-(defcustom shell-dumb-shell-regexp "cmd\\(proxy\\)?\\.exe"
+(defcustom shell-dumb-shell-regexp (purecopy "cmd\\(proxy\\)?\\.exe")
"Regexp to match shells that don't save their command history, and
don't handle the backslash as a quote character. For shells that
match this regexp, Emacs will write out the command history when the
(defvar shell-file-name-quote-list
(if (memq system-type '(ms-dos windows-nt))
nil
- (append shell-delimiter-argument-list '(?\s ?\* ?\! ?\" ?\' ?\` ?\# ?\\)))
+ (append shell-delimiter-argument-list '(?\s ?$ ?\* ?\! ?\" ?\' ?\` ?\# ?\\)))
"List of characters to quote when in a file name.
This variable is used to initialize `comint-file-name-quote-list' in the
shell buffer. The value may depend on the operating system or shell.
shell-dynamic-complete-environment-variable
shell-dynamic-complete-command
shell-replace-by-expanded-directory
+ shell-dynamic-complete-filename
comint-dynamic-complete-filename)
"List of functions called to perform completion.
This variable is used to initialize `comint-dynamic-complete-functions' in the
(defcustom shell-dirtrack-verbose t
"If non-nil, show the directory stack following directory change.
-This is effective only if directory tracking is enabled."
+This is effective only if directory tracking is enabled.
+The `dirtrack' package provides an alternative implementation of this feature -
+see the function `dirtrack-mode'."
:type 'boolean
:group 'shell-directories)
'complete-expand)))
(defcustom shell-mode-hook '()
- "*Hook for customising Shell mode."
+ "Hook for customizing Shell mode."
:type 'hook
:group 'shell)
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-mode] turns directory tracking on and off.
+\\[shell-dirtrack-mode] turns directory tracking on and off.
+\(The `dirtrack' package provides an alternative implementation of this
+feature - see the function `dirtrack-mode'.)
\\{shell-mode-map}
Customization: Entry to this mode runs the hooks on `comint-mode-hook' and
(make-local-variable 'shell-last-dir)
(setq shell-last-dir nil)
(setq comint-input-autoexpand shell-input-autoexpand)
+ (shell-dirtrack-mode 1)
;; 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)
- (shell-dirtrack-mode 1)
(setq list-buffers-directory (expand-file-name default-directory))
;; shell-dependent assignments.
(when (ring-empty-p comint-input-ring)
(defun shell (&optional buffer)
"Run an inferior shell, with I/O through BUFFER (which defaults to `*shell*').
Interactively, a prefix arg means to prompt for BUFFER.
+If `default-directory' is a remote file name, it is also prompted
+to change if called with a prefix arg.
+
If BUFFER exists but shell process is not running, make new shell.
If BUFFER exists and shell process is running, just switch to BUFFER.
Program used comes from variable `explicit-shell-file-name',
(interactive
(list
(and current-prefix-arg
- (read-buffer "Shell buffer: "
- (generate-new-buffer-name "*shell*")))))
+ (prog1
+ (read-buffer "Shell buffer: "
+ (generate-new-buffer-name "*shell*"))
+ (if (file-remote-p default-directory)
+ ;; It must be possible to declare a local default-directory.
+ (setq default-directory
+ (expand-file-name
+ (read-file-name
+ "Default directory: " default-directory default-directory
+ t nil 'file-directory-p))))))))
+ (require 'ansi-color)
(setq buffer (get-buffer-create (or buffer "*shell*")))
;; Pop to buffer, so that the buffer's window will be correctly set
;; when we call comint (so that comint sets the COLUMNS env var properly).
buffer)
;; Don't do this when shell.el is loaded, only while dumping.
-;;;###autoload (add-hook 'same-window-buffer-names "*shell*")
+;;;###autoload (add-hook 'same-window-buffer-names (purecopy "*shell*"))
;;; Directory tracking
;;
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 \\[dirtrack-mode].
+You may toggle this tracking on and off with \\[shell-dirtrack-mode].
If Emacs gets confused, you can resync with the shell with \\[dirs].
+\(The `dirtrack' package provides an alternative implementation of this
+feature - see the function `dirtrack-mode'.)
See variables `shell-cd-regexp', `shell-chdrive-regexp', `shell-pushd-regexp',
and `shell-popd-regexp', while `shell-pushd-tohome', `shell-pushd-dextract',
(defvaralias 'shell-dirtrack-mode 'shell-dirtrackp)
(define-minor-mode shell-dirtrack-mode
- "Turn directory tracking on and off in a shell buffer."
+ "Turn directory tracking on and off in a shell buffer.
+The `dirtrack' package provides an alternative implementation of this
+feature - see the function `dirtrack-mode'."
nil nil nil
(setq list-buffers-directory (if shell-dirtrack-mode default-directory))
(if shell-dirtrack-mode
(add-hook 'comint-input-filter-functions 'shell-directory-tracker nil t)
(remove-hook 'comint-input-filter-functions 'shell-directory-tracker t)))
-;; For your typing convenience:
-(defalias 'shell-dirtrack-toggle 'shell-dirtrack-mode) ;??Convenience??
-(defalias 'dirtrack-toggle 'shell-dirtrack-mode)
-(defalias 'dirtrack-mode 'shell-dirtrack-mode)
+(define-obsolete-function-alias 'shell-dirtrack-toggle 'shell-dirtrack-mode
+ "23.1")
(defun shell-cd (dir)
"Do normal `cd' to DIR, and set `list-buffers-directory'."
command again."
(interactive)
(let* ((proc (get-buffer-process (current-buffer)))
- (pmark (process-mark proc)))
- (goto-char pmark)
- ;; If the process echoes commands, don't insert a fake command in
- ;; the buffer or it will appear twice.
- (unless comint-process-echoes
- (insert shell-dirstack-query) (insert "\n"))
- (sit-for 0) ; force redisplay
- (comint-send-string proc shell-dirstack-query)
- (comint-send-string proc "\n")
- (set-marker pmark (point))
- (let ((pt (point))
- (regexp
- (concat
- (if comint-process-echoes
- ;; Skip command echo if the process echoes
- (concat "\\(" (regexp-quote shell-dirstack-query) "\n\\)")
- "\\(\\)")
- "\\(.+\n\\)")))
- ;; This extra newline prevents the user's pending input from spoofing us.
- (insert "\n") (backward-char 1)
- ;; Wait for one line.
- (while (not (looking-at regexp))
- (accept-process-output proc)
- (goto-char pt)))
- (goto-char pmark) (delete-char 1) ; remove the extra newline
- ;; That's the dirlist. grab it & parse it.
- (let* ((dl (buffer-substring (match-beginning 2) (1- (match-end 2))))
- (dl-len (length dl))
- (ds '()) ; new dir stack
- (i 0))
- (while (< i dl-len)
- ;; regexp = optional whitespace, (non-whitespace), optional whitespace
- (string-match "\\s *\\(\\S +\\)\\s *" dl i) ; pick off next dir
- (setq ds (cons (concat comint-file-name-prefix
- (substring dl (match-beginning 1)
- (match-end 1)))
- ds))
- (setq i (match-end 0)))
- (let ((ds (nreverse ds)))
- (condition-case nil
- (progn (shell-cd (car ds))
- (setq shell-dirstack (cdr ds)
- shell-last-dir (car shell-dirstack))
- (shell-dirstack-message))
- (error (message "Couldn't cd")))))))
+ (pmark (process-mark proc))
+ (started-at-pmark (= (point) (marker-position pmark))))
+ (save-excursion
+ (goto-char pmark)
+ ;; If the process echoes commands, don't insert a fake command in
+ ;; the buffer or it will appear twice.
+ (unless comint-process-echoes
+ (insert shell-dirstack-query) (insert "\n"))
+ (sit-for 0) ; force redisplay
+ (comint-send-string proc shell-dirstack-query)
+ (comint-send-string proc "\n")
+ (set-marker pmark (point))
+ (let ((pt (point))
+ (regexp
+ (concat
+ (if comint-process-echoes
+ ;; Skip command echo if the process echoes
+ (concat "\\(" (regexp-quote shell-dirstack-query) "\n\\)")
+ "\\(\\)")
+ "\\(.+\n\\)")))
+ ;; This extra newline prevents the user's pending input from spoofing us.
+ (insert "\n") (backward-char 1)
+ ;; Wait for one line.
+ (while (not (looking-at regexp))
+ (accept-process-output proc)
+ (goto-char pt)))
+ (goto-char pmark) (delete-char 1) ; remove the extra newline
+ ;; That's the dirlist. grab it & parse it.
+ (let* ((dl (buffer-substring (match-beginning 2) (1- (match-end 2))))
+ (dl-len (length dl))
+ (ds '()) ; new dir stack
+ (i 0))
+ (while (< i dl-len)
+ ;; regexp = optional whitespace, (non-whitespace), optional whitespace
+ (string-match "\\s *\\(\\S +\\)\\s *" dl i) ; pick off next dir
+ (setq ds (cons (concat comint-file-name-prefix
+ (substring dl (match-beginning 1)
+ (match-end 1)))
+ ds))
+ (setq i (match-end 0)))
+ (let ((ds (nreverse ds)))
+ (condition-case nil
+ (progn (shell-cd (car ds))
+ (setq shell-dirstack (cdr ds)
+ shell-last-dir (car shell-dirstack))
+ (shell-dirstack-message))
+ (error (message "Couldn't cd"))))))
+ (if started-at-pmark (goto-char (marker-position pmark)))))
;; For your typing convenience:
(defalias 'dirs 'shell-resync-dirs)
(save-match-data (not (string-match "[~/]" filename)))
(eq (match-beginning 0)
(save-excursion (shell-backward-command 1) (point))))
- (prog2 (message "Completing command name...")
+ (prog2 (unless (window-minibuffer-p (selected-window))
+ (message "Completing command name..."))
(shell-dynamic-complete-as-command)))))
(insert " "))
success)))
+(defun shell-dynamic-complete-filename ()
+ "Dynamically complete the filename at point.
+This completes only if point is at a suitable position for a
+filename argument."
+ (interactive)
+ (let ((opoint (point))
+ (beg (comint-line-beginning-position)))
+ (when (save-excursion
+ (goto-char (if (re-search-backward "[;|&]" beg t)
+ (match-end 0)
+ beg))
+ (re-search-forward "[^ \t][ \t]" opoint t))
+ (comint-dynamic-complete-as-filename))))
(defun shell-match-partial-variable ()
"Return the shell variable at point, or nil if none is found."
(re-search-forward "\\$?{?[A-Za-z0-9_]*}?" limit)
(buffer-substring (match-beginning 0) (match-end 0))))))
-
(defun shell-dynamic-complete-environment-variable ()
"Dynamically complete the environment variable at point.
Completes if after a variable, i.e., if it starts with a \"$\".
(interactive)
(let ((variable (shell-match-partial-variable)))
(if (and variable (string-match "^\\$" variable))
- (prog2 (message "Completing variable name...")
+ (prog2 (unless (window-minibuffer-p (selected-window))
+ (message "Completing variable name..."))
(shell-dynamic-complete-as-environment-variable)))))