* calendar/todo-mode.el: Fix two bugs.
[bpt/emacs.git] / lisp / shell.el
index b98efce..9dc9a01 100644 (file)
@@ -1,10 +1,11 @@
 ;;; shell.el --- specialized comint.el for running the shell -*- lexical-binding: t -*-
 
-;; Copyright (C) 1988, 1993-1997, 2000-2012 Free Software Foundation, Inc.
+;; Copyright (C) 1988, 1993-1997, 2000-2014 Free Software Foundation,
+;; Inc.
 
 ;; Author: Olin Shivers <shivers@cs.cmu.edu>
 ;;     Simon Marshall <simon@gnu.org>
-;; Maintainer: FSF <emacs-devel@gnu.org>
+;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: processes
 
 ;; This file is part of GNU Emacs.
@@ -46,7 +47,7 @@
 
 ;; YOUR .EMACS FILE
 ;;=============================================================================
-;; Some suggestions for your .emacs file.
+;; Some suggestions for your init file.
 ;;
 ;; ;; Define M-# to run some strange command:
 ;; (eval-after-load "shell"
   "Directory support in shell mode."
   :group 'shell)
 
-(defgroup shell-faces nil
-  "Faces in shell buffers."
-  :group 'shell)
+;; Unused.
+;;; (defgroup shell-faces nil
+;;;   "Faces in shell buffers."
+;;;   :group 'shell)
 
 ;;;###autoload
 (defcustom shell-dumb-shell-regexp (purecopy "cmd\\(proxy\\)?\\.exe")
@@ -136,9 +138,7 @@ how Shell mode treats paragraphs.
 
 The pattern should probably not match more than one line.  If it does,
 Shell mode may become confused trying to distinguish prompt from input
-on lines which don't start with a prompt.
-
-This is a fine thing to set in your `.emacs' file."
+on lines which don't start with a prompt."
   :type 'regexp
   :group 'shell)
 
@@ -146,9 +146,7 @@ This is a fine thing to set in your `.emacs' file."
   "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."
+Some people like (\"~\" \"#\" \"%\")."
   :type '(repeat (string :tag "Suffix"))
   :group 'shell)
 
@@ -158,31 +156,29 @@ This variable is used to initialize `comint-delimiter-argument-list' in the
 shell buffer.  The value may depend on the operating system or shell."
   :type '(choice (const nil)
                 (repeat :tag "List of characters" character))
-  ;; Reverted.
-;;  :version "24.1"                    ; changed to nil (bug#8027)
   :group 'shell)
 
-(defvar shell-file-name-chars
+(defcustom shell-file-name-chars
   (if (memq system-type '(ms-dos windows-nt cygwin))
       "~/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
-shell buffer.  The value may depend on the operating system or shell.
-
-This is a fine thing to set in your `.emacs' file.")
+shell buffer.  The value may depend on the operating system or shell."
+  :type 'string
+  :group 'shell)
 
-(defvar shell-file-name-quote-list
+(defcustom shell-file-name-quote-list
   (if (memq system-type '(ms-dos windows-nt))
       nil
     (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.
-
-This is a fine thing to set in your `.emacs' file.")
+shell buffer.  The value may depend on the operating system or shell."
+  :type '(repeat character)
+  :group 'shell)
 
-(defvar shell-dynamic-complete-functions
+(defcustom shell-dynamic-complete-functions
   '(comint-c-a-p-replace-by-expanded-history
     shell-environment-variable-completion
     shell-command-completion
@@ -192,9 +188,9 @@ This is a fine thing to set in your `.emacs' file.")
     comint-filename-completion)
   "List of functions called to perform completion.
 This variable is used to initialize `comint-dynamic-complete-functions' in the
-shell buffer.
-
-This is a fine thing to set in your `.emacs' file.")
+shell buffer."
+  :type '(repeat function)
+  :group 'shell)
 
 (defcustom shell-command-regexp "[^;&|\n]+"
   "Regexp to match a single command within a pipeline.
@@ -288,21 +284,9 @@ Value is a list of strings, which may be nil."
 ;; Note: There are no explicit references to the variable `explicit-bash-args'.
 ;; It is used implicitly by M-x shell when the interactive shell is `bash'.
 (defcustom explicit-bash-args
-  (let* ((prog (or (and (boundp 'explicit-shell-file-name) explicit-shell-file-name)
-                  (getenv "ESHELL") shell-file-name))
-        (name (file-name-nondirectory prog)))
-    ;; Tell bash not to use readline, except for bash 1.x which
-    ;; doesn't grok --noediting.  Bash 1.x has -nolineediting, but
-    ;; process-send-eof cannot terminate bash if we use it.
-    (if (and (not purify-flag)
-            (equal name "bash")
-            (file-executable-p prog)
-            (string-match "bad option"
-                          (shell-command-to-string
-                           (concat (shell-quote-argument prog)
-                                   " --noediting"))))
-       '("-i")
-      '("--noediting" "-i")))
+  ;; Tell bash not to use readline.  It's safe to assume --noediting now,
+  ;; as it was introduced in 1996 in Bash version 2.
+  '("--noediting" "-i")
   "Args passed to inferior shell by \\[shell], if the shell is bash.
 Value is a list of strings, which may be nil."
   :type '(repeat (string :tag "Argument"))
@@ -567,10 +551,8 @@ buffer."
   ;; very inefficient in Shell buffers (e.g. Bug#10835).  We use a
   ;; custom `ansi-color-apply-face-function' to convert color escape
   ;; sequences into `font-lock-face' properties.
-  (set (make-local-variable 'ansi-color-apply-face-function)
-       (lambda (beg end face)
-        (when face
-          (put-text-property beg end 'font-lock-face face))))
+  (setq-local ansi-color-apply-face-function #'shell-apply-ansi-color)
+  (shell-reapply-ansi-color)
 
   ;; 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.
@@ -609,6 +591,27 @@ buffer."
                   'shell-filter-ctrl-a-ctrl-b nil t)))
     (comint-read-input-ring t)))
 
+(defun shell-apply-ansi-color (beg end face)
+  "Apply FACE as the ansi-color face for the text between BEG and END."
+  (when face
+    (put-text-property beg end 'ansi-color-face face)
+    (put-text-property beg end 'font-lock-face face)))
+
+(defun shell-reapply-ansi-color ()
+  "Reapply ansi-color faces to the existing contents of the buffer."
+  (save-restriction
+    (widen)
+    (let* ((pos (point-min))
+          (end (or (next-single-property-change pos 'ansi-color-face)
+                   (point-max)))
+          face)
+      (while end
+       (if (setq face (get-text-property pos 'ansi-color-face))
+           (put-text-property pos (or end (point-max))
+                              'font-lock-face face))
+       (setq pos end
+             end (next-single-property-change pos 'ansi-color-face))))))
+
 (defun shell-filter-ctrl-a-ctrl-b (string)
   "Remove `^A' and `^B' characters from comint output.
 
@@ -677,7 +680,12 @@ Otherwise, one argument `-i' is passed to the shell.
     (and current-prefix-arg
         (prog1
             (read-buffer "Shell buffer: "
-                         (generate-new-buffer-name "*shell*"))
+                         ;; If the current buffer is an inactive
+                         ;; shell buffer, use it as the default.
+                         (if (and (eq major-mode 'shell-mode)
+                                  (null (get-buffer-process (current-buffer))))
+                             (buffer-name)
+                           (generate-new-buffer-name "*shell*")))
           (if (file-remote-p default-directory)
               ;; It must be possible to declare a local default-directory.
                ;; FIXME: This can't be right: it changes the default-directory
@@ -784,8 +792,11 @@ and `shell-pushd-dunique' control the behavior of the relevant command.
 Environment variables are expanded, see function `substitute-in-file-name'."
   (if shell-dirtrackp
       ;; We fail gracefully if we think the command will fail in the shell.
-      (condition-case nil
-         (let ((start (progn (string-match
+;;;      (with-demoted-errors "Directory tracker failure: %s"
+      ;; This fails so often that it seems better to just ignore errors (?).
+      ;; Eg even: foo=/tmp; cd $foo is beyond us (bug#17159).
+      (ignore-errors
+        (let ((start (progn (string-match
                               (concat "^" shell-command-separator-regexp)
                               str) ; skip whitespace
                              (match-end 0)))
@@ -817,8 +828,7 @@ Environment variables are expanded, see function `substitute-in-file-name'."
              (setq start (progn (string-match shell-command-separator-regexp
                                               str end)
                                 ;; skip again
-                                (match-end 0)))))
-       (error "Couldn't cd"))))
+                                (match-end 0))))))))
 
 (defun shell-unquote-argument (string)
   "Remove all kinds of shell quoting from STRING."
@@ -900,7 +910,7 @@ Environment variables are expanded, see function `substitute-in-file-name'."
           (cond ((> num (length shell-dirstack))
                  (message "Directory stack not that deep."))
                 ((= num 0)
-                 (error (message "Couldn't cd")))
+                 (error "Couldn't cd"))
                 (shell-pushd-dextract
                  (let ((dir (nth (1- num) shell-dirstack)))
                    (shell-process-popd arg)
@@ -1007,12 +1017,11 @@ command again."
                         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"))))))
+         (with-demoted-errors "Couldn't cd: %s"
+           (shell-cd (car ds))
+           (setq shell-dirstack (cdr ds)
+                 shell-last-dir (car shell-dirstack))
+           (shell-dirstack-message)))))
     (if started-at-pmark (goto-char (marker-position pmark)))))
 
 ;; For your typing convenience:
@@ -1103,18 +1112,19 @@ See `shell-command-regexp'."
 (defun shell-dynamic-complete-command ()
   "Dynamically complete the command at point.
 This function is similar to `comint-dynamic-complete-filename', except that it
-searches `exec-path' (minus the trailing Emacs library path) for completion
+searches `exec-path' (minus trailing `exec-directory') for completion
 candidates.  Note that this may not be the same as the shell's idea of the
 path.
 
-Completion is dependent on the value of `shell-completion-execonly', plus
-those that effect file completion.
+Completion is dependent on the value of `shell-completion-execonly',
+`shell-completion-fignore', plus those that affect file completion.  See Info
+node `Shell Options'.
 
 Returns t if successful."
   (interactive)
   (let ((data (shell-command-completion)))
     (if data
-       (prog2 (unless (window-minibuffer-p (selected-window))
+       (prog2 (unless (window-minibuffer-p)
                 (message "Completing command name..."))
            (apply #'completion-in-region data)))))
 
@@ -1133,7 +1143,9 @@ Returns t if successful."
          (start (if (zerop (length filename)) (point) (match-beginning 0)))
          (end (if (zerop (length filename)) (point) (match-end 0)))
         (filenondir (file-name-nondirectory filename))
-        (path-dirs (cdr (reverse exec-path))) ;FIXME: Why `cdr'?
+        ; why cdr? see `shell-dynamic-complete-command'
+        (path-dirs (append (cdr (reverse exec-path))
+          (if (memq system-type '(windows-nt ms-dos)) '("."))))
         (cwd (file-name-as-directory (expand-file-name default-directory)))
         (ignored-extensions
          (and comint-completion-fignore
@@ -1224,7 +1236,7 @@ Returns non-nil if successful."
   (interactive)
   (let ((data (shell-environment-variable-completion)))
     (if data
-       (prog2 (unless (window-minibuffer-p (selected-window))
+       (prog2 (unless (window-minibuffer-p)
                 (message "Completing variable name..."))
            (apply #'completion-in-region data)))))