]> code.delx.au - gnu-emacs/blobdiff - lisp/shell.el
(url-current-object, url-package-name, url-package-version): Add defvars.
[gnu-emacs] / lisp / shell.el
index f09e2c6b56e9ab3a14bd658383276cb4535c2722..0f71d8d820558e1de65fba8b50a605de5a25afc2 100644 (file)
@@ -1,6 +1,7 @@
 ;;; shell.el --- specialized comint.el for running the shell
 
 ;;; shell.el --- specialized comint.el for running the shell
 
-;; Copyright (C) 1988, 93, 94, 95, 96, 1997, 2000 Free Software Foundation, Inc.
+;; Copyright (C) 1988, 1993, 1994, 1995, 1996, 1997, 2000,
+;;   2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 ;; Author: Olin Shivers <shivers@cs.cmu.edu>
 ;;     Simon Marshall <simon@gnu.org>
 
 ;; Author: Olin Shivers <shivers@cs.cmu.edu>
 ;;     Simon Marshall <simon@gnu.org>
@@ -21,8 +22,8 @@
 
 ;; 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
 
 ;; 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., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
 
 ;;; Commentary:
 
@@ -31,9 +32,9 @@
 ;;     - Olin Shivers (shivers@cs.cmu.edu)
 ;;     - Simon Marshall (simon@gnu.org)
 
 ;;     - Olin Shivers (shivers@cs.cmu.edu)
 ;;     - Simon Marshall (simon@gnu.org)
 
-;; This file defines a a shell-in-a-buffer package (shell mode) built
-;; on top of comint mode.  This is actually cmushell with things
-;; renamed to replace its counterpart in Emacs 18.  cmushell is more
+;; This file defines a shell-in-a-buffer package (shell mode) built on
+;; top of comint mode.  This is actually cmushell with things renamed
+;; to replace its counterpart in Emacs 18.  cmushell is more
 ;; featureful, robust, and uniform than the Emacs 18 version.
 
 ;; Since this mode is built on top of the general command-interpreter-in-
 ;; featureful, robust, and uniform than the Emacs 18 version.
 
 ;; Since this mode is built on top of the general command-interpreter-in-
 ;;; Customization and Buffer Variables
 
 (defgroup shell nil
 ;;; Customization and Buffer Variables
 
 (defgroup shell nil
-  "Running shell from within Emacs buffers"
+  "Running shell from within Emacs buffers."
   :group 'processes
   :group 'unix)
 
 (defgroup shell-directories nil
   :group 'processes
   :group 'unix)
 
 (defgroup shell-directories nil
-  "Directory support in shell mode"
+  "Directory support in shell mode."
   :group 'shell)
 
 (defgroup shell-faces nil
   :group 'shell)
 
 (defgroup shell-faces nil
-  "Faces in shell buffers"
+  "Faces in shell buffers."
   :group 'shell)
 
 ;;;###autoload
   :group 'shell)
 
 ;;;###autoload
@@ -133,11 +134,12 @@ arguments."
 (defcustom shell-prompt-pattern "^[^#$%>\n]*[#$%>] *"
   "Regexp to match prompts in the inferior shell.
 Defaults to \"^[^#$%>\\n]*[#$%>] *\", which works pretty well.
 (defcustom shell-prompt-pattern "^[^#$%>\n]*[#$%>] *"
   "Regexp to match prompts in the inferior shell.
 Defaults to \"^[^#$%>\\n]*[#$%>] *\", which works pretty well.
-This variable is used to initialise `comint-prompt-regexp' in the
+This variable is used to initialize `comint-prompt-regexp' in the
 shell buffer.
 
 shell buffer.
 
-This variable is only used if the variable
-`comint-use-prompt-regexp-instead-of-fields' is non-nil.
+If `comint-use-prompt-regexp' is nil, then this variable is only used
+to determine paragraph boundaries.  See Info node `Shell Prompts' for
+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
 
 The pattern should probably not match more than one line.  If it does,
 Shell mode may become confused trying to distinguish prompt from input
@@ -158,16 +160,16 @@ This is a fine thing to set in your `.emacs' file."
   :group 'shell)
 
 (defvar shell-delimiter-argument-list '(?\| ?& ?< ?> ?\( ?\) ?\;)
   :group 'shell)
 
 (defvar shell-delimiter-argument-list '(?\| ?& ?< ?> ?\( ?\) ?\;)
-  "List of characters to recognise as separate arguments.
+  "List of characters to recognize as separate arguments.
 This variable is used to initialize `comint-delimiter-argument-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.")
 
 (defvar shell-file-name-chars
 This variable is used to initialize `comint-delimiter-argument-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.")
 
 (defvar shell-file-name-chars
-  (if (memq system-type '(ms-dos windows-nt))
+  (if (memq system-type '(ms-dos windows-nt cygwin))
       "~/A-Za-z0-9_^$!#%&{}@`'.,:()-"
       "~/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
 shell buffer.  The value may depend on the operating system or shell.
   "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.
@@ -177,7 +179,7 @@ This is a fine thing to set in your `.emacs' file.")
 (defvar shell-file-name-quote-list
   (if (memq system-type '(ms-dos windows-nt))
       nil
 (defvar shell-file-name-quote-list
   (if (memq system-type '(ms-dos windows-nt))
       nil
-    (append shell-delimiter-argument-list '(?\  ?\* ?\! ?\" ?\' ?\` ?\#)))
+    (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.
   "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.
@@ -191,7 +193,7 @@ This is a fine thing to set in your `.emacs' file.")
     shell-replace-by-expanded-directory
     comint-dynamic-complete-filename)
   "List of functions called to perform completion.
     shell-replace-by-expanded-directory
     comint-dynamic-complete-filename)
   "List of functions called to perform completion.
-This variable is used to initialise `comint-dynamic-complete-functions' in the
+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.
 
 This is a fine thing to set in your `.emacs' file.")
@@ -202,6 +204,12 @@ This is used for directory tracking and does not do a perfect job."
   :type 'regexp
   :group 'shell)
 
   :type 'regexp
   :group 'shell)
 
+(defcustom shell-command-separator-regexp "[;&|\n \t]*"
+  "*Regexp to match a single command within a pipeline.
+This is used for directory tracking and does not do a perfect job."
+  :type 'regexp
+  :group 'shell)
+
 (defcustom shell-completion-execonly t
   "*If non-nil, use executable files only for completion candidates.
 This mirrors the optional behavior of tcsh.
 (defcustom shell-completion-execonly t
   "*If non-nil, use executable files only for completion candidates.
 This mirrors the optional behavior of tcsh.
@@ -275,6 +283,24 @@ Value is a list of strings, which may be nil."
   :type '(repeat (string :tag "Argument"))
   :group 'shell)
 
   :type '(repeat (string :tag "Argument"))
   :group 'shell)
 
+(defcustom explicit-bash-args
+  ;; Tell bash not to use readline, except for bash 1.x which doesn't grook --noediting.
+  ;; Bash 1.x has -nolineediting, but process-send-eof cannot terminate bash if we use it.
+  (let* ((prog (or (and (boundp 'explicit-shell-file-name) explicit-shell-file-name)
+                  (getenv "ESHELL") shell-file-name))
+        (name (file-name-nondirectory prog)))
+    (if (and (not purify-flag)
+            (equal name "bash")
+            (file-executable-p prog)
+            (string-match "bad option"
+                          (shell-command-to-string (concat prog " --noediting"))))
+       '("-i")
+      '("--noediting" "-i")))
+  "*Args passed to inferior shell by M-x shell, if the shell is bash.
+Value is a list of strings, which may be nil."
+  :type '(repeat (string :tag "Argument"))
+  :group 'shell)
+
 (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).
 (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).
@@ -314,7 +340,8 @@ Thus, this does not include the shell's current directory.")
        (define-key shell-mode-map "\M-?"
         'comint-dynamic-list-filename-completions)
        (define-key shell-mode-map [menu-bar completion]
        (define-key shell-mode-map "\M-?"
         'comint-dynamic-list-filename-completions)
        (define-key shell-mode-map [menu-bar completion]
-        (copy-keymap (lookup-key comint-mode-map [menu-bar completion])))
+        (cons "Complete"
+              (copy-keymap (lookup-key comint-mode-map [menu-bar completion]))))
        (define-key-after (lookup-key shell-mode-map [menu-bar completion])
         [complete-env-variable] '("Complete Env. Variable Name" .
                                   shell-dynamic-complete-environment-variable)
        (define-key-after (lookup-key shell-mode-map [menu-bar completion])
         [complete-env-variable] '("Complete Env. Variable Name" .
                                   shell-dynamic-complete-environment-variable)
@@ -381,11 +408,11 @@ Variables `comint-completion-autolist', `comint-completion-addsuffix',
 `comint-completion-recexact' and `comint-completion-fignore' control the
 behavior of file name, command name and variable name completion.  Variable
 `shell-completion-execonly' controls the behavior of command name completion.
 `comint-completion-recexact' and `comint-completion-fignore' control the
 behavior of file name, command name and variable name completion.  Variable
 `shell-completion-execonly' controls the behavior of command name completion.
-Variable `shell-completion-fignore' is used to initialise the value of
+Variable `shell-completion-fignore' is used to initialize the value of
 `comint-completion-fignore'.
 
 Variables `comint-input-ring-file-name' and `comint-input-autoexpand' control
 `comint-completion-fignore'.
 
 Variables `comint-input-ring-file-name' and `comint-input-autoexpand' control
-the initialisation of the input ring history, and history expansion.
+the initialization of the input ring history, and history expansion.
 
 Variables `comint-output-filter-functions', a hook, and
 `comint-scroll-to-bottom-on-input' and `comint-scroll-to-bottom-on-output'
 
 Variables `comint-output-filter-functions', a hook, and
 `comint-scroll-to-bottom-on-input' and `comint-scroll-to-bottom-on-output'
@@ -397,6 +424,7 @@ buffer."
   (setq comint-file-name-chars shell-file-name-chars)
   (setq comint-file-name-quote-list shell-file-name-quote-list)
   (setq comint-dynamic-complete-functions shell-dynamic-complete-functions)
   (setq comint-file-name-chars shell-file-name-chars)
   (setq comint-file-name-quote-list shell-file-name-quote-list)
   (setq comint-dynamic-complete-functions shell-dynamic-complete-functions)
+  (set (make-local-variable 'paragraph-separate) "\\'")
   (make-local-variable 'paragraph-start)
   (setq paragraph-start comint-prompt-regexp)
   (make-local-variable 'font-lock-defaults)
   (make-local-variable 'paragraph-start)
   (setq paragraph-start comint-prompt-regexp)
   (make-local-variable 'font-lock-defaults)
@@ -414,28 +442,51 @@ buffer."
   (make-local-variable 'list-buffers-directory)
   (setq list-buffers-directory (expand-file-name default-directory))
   ;; shell-dependent assignments.
   (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)))))))
-    (setq comint-input-ring-file-name
-         (or (getenv "HISTFILE")
-             (cond ((string-equal shell "bash") "~/.bash_history")
-                   ((string-equal shell "ksh") "~/.sh_history")
-                   (t "~/.history"))))
-    (if (or (equal comint-input-ring-file-name "")
-           (equal (file-truename comint-input-ring-file-name)
-                  (file-truename "/dev/null")))
-       (setq comint-input-ring-file-name nil))
-    ;; Arrange to write out the input ring on exit, if the shell doesn't
-    ;; do this itself.
-    (if (and comint-input-ring-file-name
-            (string-match shell-dumb-shell-regexp shell))
-       (set-process-sentinel (get-buffer-process (current-buffer))
-                             #'shell-write-history-on-exit))
-    (setq shell-dirstack-query
-         (cond ((string-equal shell "sh") "pwd")
-               ((string-equal shell "ksh") "echo $PWD ~-")
-               (t "dirs"))))
-  (comint-read-input-ring t))
+  (when (ring-empty-p comint-input-ring)
+    (let ((shell (file-name-nondirectory (car
+                  (process-command (get-buffer-process (current-buffer)))))))
+      (setq comint-input-ring-file-name
+           (or (getenv "HISTFILE")
+               (cond ((string-equal shell "bash") "~/.bash_history")
+                     ((string-equal shell "ksh") "~/.sh_history")
+                     (t "~/.history"))))
+      (if (or (equal comint-input-ring-file-name "")
+             (equal (file-truename comint-input-ring-file-name)
+                    (file-truename "/dev/null")))
+         (setq comint-input-ring-file-name nil))
+      ;; Arrange to write out the input ring on exit, if the shell doesn't
+      ;; do this itself.
+      (if (and comint-input-ring-file-name
+              (string-match shell-dumb-shell-regexp shell))
+         (set-process-sentinel (get-buffer-process (current-buffer))
+                               #'shell-write-history-on-exit))
+      (setq shell-dirstack-query
+           (cond ((string-equal shell "sh") "pwd")
+                 ((string-equal shell "ksh") "echo $PWD ~-")
+                 (t "dirs")))
+      ;; Bypass a bug in certain versions of bash.
+      (when (string-equal shell "bash")
+        (add-hook 'comint-output-filter-functions
+                  'shell-filter-ctrl-a-ctrl-b nil t)))
+    (comint-read-input-ring t)))
+
+(defun shell-filter-ctrl-a-ctrl-b (string)
+  "Remove `^A' and `^B' characters from comint output.
+
+Bash uses these characters as internal quoting characters in its
+prompt.  Due to a bug in some bash versions (including 2.03,
+2.04, and 2.05b), they may erroneously show up when bash is
+started with the `--noediting' option and Select Graphic
+Rendition (SGR) control sequences (formerly known as ANSI escape
+sequences) are used to color the prompt.
+
+This function can be put on `comint-output-filter-functions'.
+The argument STRING is ignored."
+  (let ((pmark (process-mark (get-buffer-process (current-buffer)))))
+    (save-excursion
+      (goto-char (or comint-last-output-start (point-min)))
+      (while (re-search-forward "[\C-a\C-b]" pmark t)
+        (replace-match "")))))
 
 (defun shell-write-history-on-exit (process event)
   "Called when the shell process is stopped.
 
 (defun shell-write-history-on-exit (process event)
   "Called when the shell process is stopped.
@@ -485,28 +536,27 @@ Otherwise, one argument `-i' is passed to the shell.
   (interactive
    (list
     (and current-prefix-arg
   (interactive
    (list
     (and current-prefix-arg
-        (read-buffer "Shell buffer: " "*shell*"))))
-  (when (null buffer)
-    (setq buffer "*shell*"))
-  (if (not (comint-check-proc buffer))
-      (let* ((prog (or explicit-shell-file-name
-                      (getenv "ESHELL")
-                      (getenv "SHELL")
-                      "/bin/sh"))
-            (name (file-name-nondirectory prog))
-            (startfile (concat "~/.emacs_" name))
-            (xargs-name (intern-soft (concat "explicit-" name "-args")))
-            shell-buffer)
-       (save-excursion
-         (set-buffer (apply 'make-comint-in-buffer "shell" buffer prog
-                            (if (file-exists-p startfile) startfile)
-                            (if (and xargs-name (boundp xargs-name))
-                                (symbol-value xargs-name)
-                              '("-i"))))
-         (setq shell-buffer (current-buffer))
-         (shell-mode))
-       (pop-to-buffer shell-buffer))
-    (pop-to-buffer buffer)))
+        (read-buffer "Shell buffer: "
+                     (generate-new-buffer-name "*shell*")))))
+  (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).
+  (pop-to-buffer buffer)
+  (unless (comint-check-proc buffer)
+    (let* ((prog (or explicit-shell-file-name
+                    (getenv "ESHELL") shell-file-name))
+          (name (file-name-nondirectory prog))
+          (startfile (concat "~/.emacs_" name))
+          (xargs-name (intern-soft (concat "explicit-" name "-args"))))
+      (if (not (file-exists-p startfile))
+         (setq startfile (concat "~/.emacs.d/.emacs_" name)))
+      (apply 'make-comint-in-buffer "shell" buffer prog
+            (if (file-exists-p startfile) startfile)
+            (if (and xargs-name (boundp xargs-name))
+                (symbol-value xargs-name)
+              '("-i")))
+      (shell-mode)))
+  buffer)
 
 ;;; Don't do this when shell.el is loaded, only while dumping.
 ;;;###autoload (add-hook 'same-window-buffer-names "*shell*")
 
 ;;; Don't do this when shell.el is loaded, only while dumping.
 ;;;###autoload (add-hook 'same-window-buffer-names "*shell*")
@@ -568,7 +618,9 @@ 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 chdir-failure
   (if shell-dirtrackp
       ;; We fail gracefully if we think the command will fail in the shell.
       (condition-case chdir-failure
-         (let ((start (progn (string-match "^[; \t]*" str) ; skip whitespace
+         (let ((start (progn (string-match
+                              (concat "^" shell-command-separator-regexp)
+                              str) ; skip whitespace
                              (match-end 0)))
                end cmd arg1)
            (while (string-match shell-command-regexp str start)
                              (match-end 0)))
                end cmd arg1)
            (while (string-match shell-command-regexp str start)
@@ -594,7 +646,9 @@ Environment variables are expanded, see function `substitute-in-file-name'."
                                                "\\)\\($\\|[ \t]\\)")
                                        cmd))
                     (shell-process-cd (comint-substitute-in-file-name cmd))))
                                                "\\)\\($\\|[ \t]\\)")
                                        cmd))
                     (shell-process-cd (comint-substitute-in-file-name cmd))))
-             (setq start (progn (string-match "[; \t]*" str end) ; skip again
+             (setq start (progn (string-match shell-command-separator-regexp
+                                              str end)
+                                ;; skip again
                                 (match-end 0)))))
        (error "Couldn't cd"))))
 
                                 (match-end 0)))))
        (error "Couldn't cd"))))
 
@@ -706,7 +760,7 @@ Environment variables are expanded, see function `substitute-in-file-name'."
 ;; If STR is of the form +n, for n>0, return n. Otherwise, nil.
 (defun shell-extract-num (str)
   (and (string-match "^\\+[1-9][0-9]*$" str)
 ;; If STR is of the form +n, for n>0, return n. Otherwise, nil.
 (defun shell-extract-num (str)
   (and (string-match "^\\+[1-9][0-9]*$" str)
-       (string-to-int str)))
+       (string-to-number str)))
 
 
 (defun shell-dirtrack-mode ()
 
 
 (defun shell-dirtrack-mode ()
@@ -737,7 +791,7 @@ line output and parses it to form the new directory stack.
 DON'T issue this command unless the buffer is at a shell prompt.
 Also, note that if some other subprocess decides to do output
 immediately after the query, its output will be taken as the
 DON'T issue this command unless the buffer is at a shell prompt.
 Also, note that if some other subprocess decides to do output
 immediately after the query, its output will be taken as the
-new directory stack -- you lose. If this happens, just do the
+new directory stack -- you lose.  If this happens, just do the
 command again."
   (interactive)
   (let* ((proc (get-buffer-process (current-buffer)))
 command again."
   (interactive)
   (let* ((proc (get-buffer-process (current-buffer)))
@@ -751,12 +805,16 @@ command again."
     (let ((pt (point))) ; wait for 1 line
       ;; This extra newline prevents the user's pending input from spoofing us.
       (insert "\n") (backward-char 1)
     (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"))
+      (while (not (looking-at
+                  (concat "\\(" ; skip literal echo in case of stty echo
+                          (regexp-quote shell-dirstack-query)
+                          "\n\\)?" ; skip if present
+                          "\\(" ".+\n" "\\)")) ) ; what to actually look for
        (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.
        (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 0) (1- (match-end 0))))
+    (let* ((dl (buffer-substring (match-beginning 2) (1- (match-end 2))))
           (dl-len (length dl))
           (ds '())                     ; new dir stack
           (i 0))
           (dl-len (length dl))
           (ds '())                     ; new dir stack
           (i 0))
@@ -861,7 +919,6 @@ See `shell-command-regexp'."
        (progn (goto-char (match-beginning 1))
               (skip-chars-forward ";&|")))))
 
        (progn (goto-char (match-beginning 1))
               (skip-chars-forward ";&|")))))
 
-
 (defun shell-dynamic-complete-command ()
   "Dynamically complete the command at point.
 This function is similar to `comint-dynamic-complete-filename', except that it
 (defun shell-dynamic-complete-command ()
   "Dynamically complete the command at point.
 This function is similar to `comint-dynamic-complete-filename', except that it
@@ -887,36 +944,37 @@ Returns t if successful."
   "Dynamically complete at point as a command.
 See `shell-dynamic-complete-filename'.  Returns t if successful."
   (let* ((filename (or (comint-match-partial-filename) ""))
   "Dynamically complete at point as a command.
 See `shell-dynamic-complete-filename'.  Returns t if successful."
   (let* ((filename (or (comint-match-partial-filename) ""))
-        (pathnondir (file-name-nondirectory filename))
-        (paths (cdr (reverse exec-path)))
+        (filenondir (file-name-nondirectory filename))
+        (path-dirs (cdr (reverse exec-path)))
         (cwd (file-name-as-directory (expand-file-name default-directory)))
         (ignored-extensions
          (and comint-completion-fignore
               (mapconcat (function (lambda (x) (concat (regexp-quote x) "$")))
                          comint-completion-fignore "\\|")))
         (cwd (file-name-as-directory (expand-file-name default-directory)))
         (ignored-extensions
          (and comint-completion-fignore
               (mapconcat (function (lambda (x) (concat (regexp-quote x) "$")))
                          comint-completion-fignore "\\|")))
-        (path "") (comps-in-path ()) (file "") (filepath "") (completions ()))
-    ;; Go thru each path in the search path, finding completions.
-    (while paths
-      (setq path (file-name-as-directory (comint-directory (or (car paths) ".")))
-           comps-in-path (and (file-accessible-directory-p path)
-                              (file-name-all-completions pathnondir path)))
+        (dir "") (comps-in-dir ())
+        (file "") (abs-file-name "") (completions ()))
+    ;; Go thru each dir in the search path, finding completions.
+    (while path-dirs
+      (setq dir (file-name-as-directory (comint-directory (or (car path-dirs) ".")))
+           comps-in-dir (and (file-accessible-directory-p dir)
+                             (file-name-all-completions filenondir dir)))
       ;; Go thru each completion found, to see whether it should be used.
       ;; Go thru each completion found, to see whether it should be used.
-      (while comps-in-path
-       (setq file (car comps-in-path)
-             filepath (concat path file))
+      (while comps-in-dir
+       (setq file (car comps-in-dir)
+             abs-file-name (concat dir file))
        (if (and (not (member file completions))
                 (not (and ignored-extensions
                           (string-match ignored-extensions file)))
        (if (and (not (member file completions))
                 (not (and ignored-extensions
                           (string-match ignored-extensions file)))
-                (or (string-equal path cwd)
-                    (not (file-directory-p filepath)))
+                (or (string-equal dir cwd)
+                    (not (file-directory-p abs-file-name)))
                 (or (null shell-completion-execonly)
                 (or (null shell-completion-execonly)
-                    (file-executable-p filepath)))
+                    (file-executable-p abs-file-name)))
            (setq completions (cons file completions)))
            (setq completions (cons file completions)))
-       (setq comps-in-path (cdr comps-in-path)))
-      (setq paths (cdr paths)))
+       (setq comps-in-dir (cdr comps-in-dir)))
+      (setq path-dirs (cdr path-dirs)))
     ;; OK, we've got a list of completions.
     (let ((success (let ((comint-completion-addsuffix nil))
     ;; OK, we've got a list of completions.
     (let ((success (let ((comint-completion-addsuffix nil))
-                    (comint-dynamic-simple-complete pathnondir completions))))
+                    (comint-dynamic-simple-complete filenondir completions))))
       (if (and (memq success '(sole shortest)) comint-completion-addsuffix
               (not (file-directory-p (comint-match-partial-filename))))
          (insert " "))
       (if (and (memq success '(sole shortest)) comint-completion-addsuffix
               (not (file-directory-p (comint-match-partial-filename))))
          (insert " "))
@@ -996,7 +1054,7 @@ Returns t if successful."
        (let ((stack (cons default-directory shell-dirstack))
              (index (cond ((looking-at "=-/?")
                            (length shell-dirstack))
        (let ((stack (cons default-directory shell-dirstack))
              (index (cond ((looking-at "=-/?")
                            (length shell-dirstack))
-                          ((looking-at "=\\([0-9]+\\)")
+                          ((looking-at "=\\([0-9]+\\)/?")
                            (string-to-number
                             (buffer-substring
                              (match-beginning 1) (match-end 1)))))))
                            (string-to-number
                             (buffer-substring
                              (match-beginning 1) (match-end 1)))))))
@@ -1011,4 +1069,5 @@ Returns t if successful."
 
 (provide 'shell)
 
 
 (provide 'shell)
 
+;;; arch-tag: bcb5f12a-c1f4-4aea-a809-2504bd5bd797
 ;;; shell.el ends here
 ;;; shell.el ends here