X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/70360d0cab4f5e9fa351cd131e45fa86401896c0..838d78d411955dbe3ef5d75ff404ced8ca832c5a:/lisp/shell.el diff --git a/lisp/shell.el b/lisp/shell.el index 7171fbbe0f..e067fea4df 100644 --- a/lisp/shell.el +++ b/lisp/shell.el @@ -1,7 +1,7 @@ ;;; 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 Free Software Foundation, Inc. ;; Author: Olin Shivers ;; Simon Marshall @@ -10,10 +10,10 @@ ;; 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 @@ -21,9 +21,7 @@ ;; 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 . ;;; Commentary: @@ -88,7 +86,7 @@ ;; 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 @@ -186,6 +184,7 @@ This is a fine thing to set in your `.emacs' file.") 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 @@ -258,7 +257,9 @@ This mirrors the optional behavior of tcsh." (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) @@ -393,7 +394,9 @@ 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-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 @@ -511,6 +514,9 @@ Sentinels will always get the two parameters PROCESS and EVENT." (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', @@ -539,8 +545,16 @@ Otherwise, one argument `-i' is passed to the shell. (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)))))))) (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). @@ -610,8 +624,10 @@ 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 \\[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', @@ -767,17 +783,17 @@ Environment variables are expanded, see function `substitute-in-file-name'." (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'." @@ -797,51 +813,54 @@ new directory stack -- you lose. If this happens, just do the 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) @@ -945,7 +964,8 @@ Returns t if successful." (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))))) @@ -989,6 +1009,19 @@ See `shell-dynamic-complete-filename'. Returns t if successful." (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." @@ -1002,7 +1035,6 @@ See `shell-dynamic-complete-filename'. Returns t if successful." (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 \"$\". @@ -1020,7 +1052,8 @@ Returns non-nil if successful." (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)))))