(Fexpand_file_name): In the no-handler case, after
[bpt/emacs.git] / lisp / comint.el
index d3b6cd0..126f05b 100644 (file)
@@ -1,6 +1,6 @@
 ;;; comint.el --- general command interpreter in a window stuff
 
 ;;; comint.el --- general command interpreter in a window stuff
 
-;; Copyright (C) 1988, 90, 92, 93, 94, 95, 96, 97, 98, 99, 2000, 2001
+;; Copyright (C) 1988, 90, 92, 93, 94, 95, 96, 97, 98, 99, 2000, 2001, 2002
 ;;     Free Software Foundation, Inc.
 
 ;; Author: Olin Shivers <shivers@cs.cmu.edu>
 ;;     Free Software Foundation, Inc.
 
 ;; Author: Olin Shivers <shivers@cs.cmu.edu>
 ;;  comint-scroll-to-bottom-on-output  symbol  ...
 ;;  comint-scroll-show-maximum-output  boolean ...
 ;;  comint-accum-marker                        maker     For comint-accumulate
 ;;  comint-scroll-to-bottom-on-output  symbol  ...
 ;;  comint-scroll-show-maximum-output  boolean ...
 ;;  comint-accum-marker                        maker     For comint-accumulate
-;;  comint-last-output-overlay          overlay
 ;;
 ;; Comint mode non-buffer local variables:
 ;;  comint-completion-addsuffix                boolean/cons    For file name
 ;;
 ;; Comint mode non-buffer local variables:
 ;;  comint-completion-addsuffix                boolean/cons    For file name
@@ -204,26 +203,14 @@ This variable is buffer-local."
                 (other :tag "on" t))
   :group 'comint)
 
                 (other :tag "on" t))
   :group 'comint)
 
-(defcustom comint-highlight-input t
-  "*If non-nil, highlight input; also allow choosing previous input with a mouse.
-The face used is `comint-highlight-input'."
-  :type 'boolean
-  :group 'comint)
-
-(defface comint-highlight-input '((t (:bold t)))
-  "Face to use to highlight input when `comint-highlight-input' is non-nil."
-  :group 'comint)
-
-(defcustom comint-highlight-prompt t
-  "*If non-nil, highlight program prompts.
-The face used is `comint-highlight-prompt'."
-  :type 'boolean
+(defface comint-highlight-input '((t (:weight bold)))
+  "Face to use to highlight user input."
   :group 'comint)
 
 (defface comint-highlight-prompt
   '((((background dark)) (:foreground "cyan"))
     (t (:foreground "dark blue")))
   :group 'comint)
 
 (defface comint-highlight-prompt
   '((((background dark)) (:foreground "cyan"))
     (t (:foreground "dark blue")))
-  "Face to use to highlight prompt when `comint-highlight-prompt' is non-nil."
+  "Face to use to highlight prompts."
   :group 'comint)
 
 (defcustom comint-input-ignoredups nil
   :group 'comint)
 
 (defcustom comint-input-ignoredups nil
@@ -274,7 +261,7 @@ See variable `comint-scroll-show-maximum-output' and function
                 (const others))
   :group 'comint)
 
                 (const others))
   :group 'comint)
 
-(defcustom comint-scroll-show-maximum-output nil
+(defcustom comint-scroll-show-maximum-output t
   "*Controls how interpreter output causes window to scroll.
 If non-nil, then show the maximum output when the window is scrolled.
 
   "*Controls how interpreter output causes window to scroll.
 If non-nil, then show the maximum output when the window is scrolled.
 
@@ -314,8 +301,10 @@ This variable is buffer-local."
 ;; ssh-add prints a prompt like `Enter passphrase: '.
 ;; Some implementations of passwd use "Password (again)" as the 2nd prompt.
 (defcustom comint-password-prompt-regexp
 ;; ssh-add prints a prompt like `Enter passphrase: '.
 ;; Some implementations of passwd use "Password (again)" as the 2nd prompt.
 (defcustom comint-password-prompt-regexp
-  "\\(\\([Oo]ld \\|[Nn]ew \\|Kerberos \\|'s \\|login \\|CVS \\|^\\)\
-[Pp]assword\\( (again)\\)?\\|pass phrase\\|Enter passphrase\\)\
+  "\\(\\([Oo]ld \\|[Nn]ew \\|'s \\|login \\|\
+Kerberos \\|CVS \\|UNIX \\| SMB \\|^\\)\
+[Pp]assword\\( (again)\\)?\\|\
+pass phrase\\|\\(Enter\\|Repeat\\) passphrase\\)\
 \\( for [^:]+\\)?:\\s *\\'"
   "*Regexp matching prompts for passwords in the inferior process.
 This is used by `comint-watch-for-password-prompt'."
 \\( for [^:]+\\)?:\\s *\\'"
   "*Regexp matching prompts for passwords in the inferior process.
 This is used by `comint-watch-for-password-prompt'."
@@ -350,7 +339,8 @@ history list.  Default is to save anything that isn't all whitespace.")
   "Functions to call before input is sent to the process.
 These functions get one argument, a string containing the text to send.
 
   "Functions to call before input is sent to the process.
 These functions get one argument, a string containing the text to send.
 
-This variable is buffer-local.")
+You can use `add-hook' to add functions to this list
+either globally or locally.")
 
 (defvar comint-output-filter-functions '(comint-postoutput-scroll-to-bottom)
   "Functions to call after output is inserted into the buffer.
 
 (defvar comint-output-filter-functions '(comint-postoutput-scroll-to-bottom)
   "Functions to call after output is inserted into the buffer.
@@ -362,13 +352,18 @@ functions have already modified the buffer.
 
 See also `comint-preoutput-filter-functions'.
 
 
 See also `comint-preoutput-filter-functions'.
 
-This variable is buffer-local.")
+You can use `add-hook' to add functions to this list
+either globally or locally.")
+
+(defvar comint-input-sender-no-newline nil
+  "Non-nil directs the `comint-input-sender' function not to send a newline.")
 
 (defvar comint-input-sender (function comint-simple-send)
   "Function to actually send to PROCESS the STRING submitted by user.
 Usually this is just `comint-simple-send', but if your mode needs to
 massage the input string, put a different function here.
 `comint-simple-send' just sends the string plus a newline.
 
 (defvar comint-input-sender (function comint-simple-send)
   "Function to actually send to PROCESS the STRING submitted by user.
 Usually this is just `comint-simple-send', but if your mode needs to
 massage the input string, put a different function here.
 `comint-simple-send' just sends the string plus a newline.
+\(If `comint-input-sender-no-newline' is non-nil, it omits the newline.)
 This is called from the user command `comint-send-input'.")
 
 (defcustom comint-eol-on-send t
 This is called from the user command `comint-send-input'.")
 
 (defcustom comint-eol-on-send t
@@ -389,7 +384,7 @@ field boundaries in a natural way)."
   :type 'boolean
   :group 'comint)
 
   :type 'boolean
   :group 'comint)
 
-(defcustom comint-mode-hook '()
+(defcustom comint-mode-hook '(turn-on-font-lock)
   "Called upon entry into `comint-mode'
 This is run before the process is cranked up."
   :type 'hook
   "Called upon entry into `comint-mode'
 This is run before the process is cranked up."
   :type 'hook
@@ -478,15 +473,9 @@ to continue it.
 
 Entry to this mode runs the hooks on `comint-mode-hook'."
   (setq mode-line-process '(":%s"))
 
 Entry to this mode runs the hooks on `comint-mode-hook'."
   (setq mode-line-process '(":%s"))
-  (make-local-variable 'comint-last-input-start)
-  (setq comint-last-input-start (make-marker))
-  (set-marker comint-last-input-start (point-min))
-  (make-local-variable 'comint-last-input-end)
-  (setq comint-last-input-end (make-marker))
-  (set-marker comint-last-input-end (point-min))
-  (make-local-variable 'comint-last-output-start)
-  (setq comint-last-output-start (make-marker))
-  (make-local-variable 'comint-last-output-overlay)
+  (set (make-local-variable 'comint-last-input-start) (point-min-marker))
+  (set (make-local-variable 'comint-last-input-end) (point-min-marker))
+  (set (make-local-variable 'comint-last-output-start) (make-marker))
   (make-local-variable 'comint-last-prompt-overlay)
   (make-local-variable 'comint-prompt-regexp)        ; Don't set; default
   (make-local-variable 'comint-input-ring-size)      ; ...to global val.
   (make-local-variable 'comint-last-prompt-overlay)
   (make-local-variable 'comint-prompt-regexp)        ; Don't set; default
   (make-local-variable 'comint-input-ring-size)      ; ...to global val.
@@ -504,26 +493,24 @@ Entry to this mode runs the hooks on `comint-mode-hook'."
   (make-local-variable 'comint-input-autoexpand)
   (make-local-variable 'comint-input-ignoredups)
   (make-local-variable 'comint-delimiter-argument-list)
   (make-local-variable 'comint-input-autoexpand)
   (make-local-variable 'comint-input-ignoredups)
   (make-local-variable 'comint-delimiter-argument-list)
-  (make-local-hook 'comint-dynamic-complete-functions)
   (make-local-variable 'comint-completion-fignore)
   (make-local-variable 'comint-get-old-input)
   (make-local-variable 'comint-completion-fignore)
   (make-local-variable 'comint-get-old-input)
-  (make-local-hook 'comint-input-filter-functions)
   (make-local-variable 'comint-input-filter)
   (make-local-variable 'comint-input-sender)
   (make-local-variable 'comint-eol-on-send)
   (make-local-variable 'comint-scroll-to-bottom-on-input)
   (make-local-variable 'comint-scroll-to-bottom-on-output)
   (make-local-variable 'comint-scroll-show-maximum-output)
   (make-local-variable 'comint-input-filter)
   (make-local-variable 'comint-input-sender)
   (make-local-variable 'comint-eol-on-send)
   (make-local-variable 'comint-scroll-to-bottom-on-input)
   (make-local-variable 'comint-scroll-to-bottom-on-output)
   (make-local-variable 'comint-scroll-show-maximum-output)
+  ;; This makes it really work to keep point at the bottom.
+  (make-local-variable 'scroll-conservatively)
+  (setq scroll-conservatively 10000)
   (add-hook 'pre-command-hook 'comint-preinput-scroll-to-bottom t t)
   (add-hook 'pre-command-hook 'comint-preinput-scroll-to-bottom t t)
-  (make-local-hook 'comint-output-filter-functions)
-  (make-local-hook 'comint-exec-hook)
   (make-local-variable 'comint-ptyp)
   (make-local-variable 'comint-process-echoes)
   (make-local-variable 'comint-file-name-chars)
   (make-local-variable 'comint-file-name-quote-list)
   (make-local-variable 'comint-ptyp)
   (make-local-variable 'comint-process-echoes)
   (make-local-variable 'comint-file-name-chars)
   (make-local-variable 'comint-file-name-quote-list)
-  (make-local-variable 'comint-accum-marker)
-  (setq comint-accum-marker (make-marker))
-  (set-marker comint-accum-marker nil)
+  (set (make-local-variable 'comint-accum-marker) (make-marker))
+  (add-hook 'change-major-mode-hook 'font-lock-defontify nil t)
   ;; This behavior is not useful in comint buffers, and is annoying
   (set (make-local-variable 'next-line-add-newlines) nil))
 
   ;; This behavior is not useful in comint buffers, and is annoying
   (set (make-local-variable 'next-line-add-newlines) nil))
 
@@ -660,7 +647,8 @@ If PROGRAM is a string, any more args are arguments to PROGRAM."
   ;; comint mode.  Otherwise, leave buffer and existing process alone.
   (unless (comint-check-proc buffer)
     (with-current-buffer buffer
   ;; comint mode.  Otherwise, leave buffer and existing process alone.
   (unless (comint-check-proc buffer)
     (with-current-buffer buffer
-      (comint-mode)) ; Install local vars, mode, keymap, ...
+      (unless (derived-mode-p 'comint-mode)
+       (comint-mode))) ; Install local vars, mode, keymap, ...
     (comint-exec buffer name program startfile switches))
   buffer)
 
     (comint-exec buffer name program startfile switches))
   buffer)
 
@@ -705,7 +693,7 @@ buffer.  The hook `comint-exec-hook' is run after each exec."
             (comint-exec-1 name buffer command switches))))
       (set-process-filter proc 'comint-output-filter)
       (make-local-variable 'comint-ptyp)
             (comint-exec-1 name buffer command switches))))
       (set-process-filter proc 'comint-output-filter)
       (make-local-variable 'comint-ptyp)
-      (setq comint-ptyp process-connection-type) ; T if pty, NIL if pipe.
+      (setq comint-ptyp process-connection-type) ; t if pty, nil if pipe.
       ;; Jump to the end, and set the process mark.
       (goto-char (point-max))
       (set-marker (process-mark proc) (point))
       ;; Jump to the end, and set the process mark.
       (goto-char (point-max))
       (set-marker (process-mark proc) (point))
@@ -738,6 +726,7 @@ buffer.  The hook `comint-exec-hook' is run after each exec."
          ;; and there is no way for us to define it here.
          ;; Some programs that use terminfo get very confused
          ;; if TERM is not a valid terminal type.
          ;; and there is no way for us to define it here.
          ;; Some programs that use terminfo get very confused
          ;; if TERM is not a valid terminal type.
+         ;; ;; There is similar code in compile.el.
          (if (and (boundp 'system-uses-terminfo) system-uses-terminfo)
              (list "TERM=dumb" "TERMCAP="
                    (format "COLUMNS=%d" (window-width)))
          (if (and (boundp 'system-uses-terminfo) system-uses-terminfo)
              (list "TERM=dumb" "TERMCAP="
                    (format "COLUMNS=%d" (window-width)))
@@ -779,27 +768,25 @@ buffer.  The hook `comint-exec-hook' is run after each exec."
 (defun comint-insert-clicked-input (event)
   "In a comint buffer, set the current input to the clicked-on previous input."
   (interactive "e")
 (defun comint-insert-clicked-input (event)
   "In a comint buffer, set the current input to the clicked-on previous input."
   (interactive "e")
-  (let ((over (catch 'found
-               ;; Ignore non-input overlays
-               (dolist (ov (overlays-at (posn-point (event-end event))))
-                 (when (eq (overlay-get ov 'field) 'input)
-                   (throw 'found ov))))))
-    ;; Do we have input in this area?
-    (if over
-       (let ((input-str (buffer-substring (overlay-start over)
-                                          (overlay-end over))))
-         (goto-char (point-max))
-         (delete-region
-          ;; Can't use kill-region as it sets this-command
-          (or  (marker-position comint-accum-marker)
-               (process-mark (get-buffer-process (current-buffer))))
-          (point))
-         (insert input-str))
-      ;; Fall back to the global definition.
-      (let* ((keys (this-command-keys))
-            (last-key (and (vectorp keys) (aref keys (1- (length keys)))))
-            (fun (and last-key (lookup-key global-map (vector last-key)))))
-       (if fun (call-interactively fun))))))
+  (let ((pos (posn-point (event-end event))))
+    (if (not (eq (get-char-property pos 'field) 'input))
+       ;; No input at POS, fall back to the global definition.
+       (let* ((keys (this-command-keys))
+              (last-key (and (vectorp keys) (aref keys (1- (length keys)))))
+              (fun (and last-key (lookup-key global-map (vector last-key)))))
+         (and fun (call-interactively fun)))
+      ;; There's previous input at POS, insert it at the end of the buffer.
+      (goto-char (point-max))
+      ;; First delete any old unsent input at the end
+      (delete-region
+       (or (marker-position comint-accum-marker)
+          (process-mark (get-buffer-process (current-buffer))))
+       (point))
+      ;; Insert the clicked-upon input
+      (insert (buffer-substring-no-properties
+              (previous-single-char-property-change (1+ pos) 'field)
+              (next-single-char-property-change pos 'field))))))
+
 
 \f
 ;; Input history processing in a buffer
 
 \f
 ;; Input history processing in a buffer
@@ -916,6 +903,25 @@ See also `comint-read-input-ring'."
             (kill-buffer nil))))))
 
 
             (kill-buffer nil))))))
 
 
+(defvar comint-dynamic-list-input-ring-window-conf)
+
+(defun comint-dynamic-list-input-ring-select ()
+  "Choose the input history entry that point is in or next to."
+  (interactive)
+  (let (beg end completion (buffer completion-reference-buffer)
+       (base-size completion-base-size))
+    (if (and (not (eobp)) (get-text-property (point) 'mouse-face))
+       (setq end (point) beg (1+ (point))))
+    (if (and (not (bobp)) (get-text-property (1- (point)) 'mouse-face))
+       (setq end (1- (point)) beg (point)))
+    (if (null beg)
+       (error "No history entry here"))
+    (setq beg (previous-single-property-change beg 'mouse-face))
+    (setq end (or (next-single-property-change end 'mouse-face) (point-max)))
+    (setq completion (buffer-substring beg end))
+    (set-window-configuration comint-dynamic-list-input-ring-window-conf)
+    (choose-completion-string completion buffer base-size)))
+
 (defun comint-dynamic-list-input-ring ()
   "List in help buffer the buffer's input history."
   (interactive)
 (defun comint-dynamic-list-input-ring ()
   "List in help buffer the buffer's input history."
   (interactive)
@@ -935,11 +941,16 @@ See also `comint-read-input-ring'."
       (with-output-to-temp-buffer history-buffer
        (display-completion-list history)
        (set-buffer history-buffer)
       (with-output-to-temp-buffer history-buffer
        (display-completion-list history)
        (set-buffer history-buffer)
+       (let ((keymap (make-sparse-keymap)))
+         (set-keymap-parent keymap (current-local-map))
+         (define-key keymap "\C-m" 'comint-dynamic-list-input-ring-select)
+         (use-local-map keymap))
        (forward-line 3)
        (while (search-backward "completion" nil 'move)
          (replace-match "history reference")))
       (sit-for 0)
       (message "Hit space to flush")
        (forward-line 3)
        (while (search-backward "completion" nil 'move)
          (replace-match "history reference")))
       (sit-for 0)
       (message "Hit space to flush")
+      (setq comint-dynamic-list-input-ring-window-conf conf)
       (let ((ch (read-event)))
        (if (eq ch ?\ )
            (set-window-configuration conf)
       (let ((ch (read-event)))
        (if (eq ch ?\ )
            (set-window-configuration conf)
@@ -1350,15 +1361,13 @@ Ignore duplicates if `comint-input-ignoredups' is non-nil."
                                  cmd))))
       (ring-insert comint-input-ring cmd)))
 
                                  cmd))))
       (ring-insert comint-input-ring cmd)))
 
-(defun comint-send-input ()
+(defun comint-send-input (&optional no-newline)
   "Send input to process.
 After the process output mark, sends all text from the process mark to
   "Send input to process.
 After the process output mark, sends all text from the process mark to
-point as input to the process.  Before the process output mark, calls value
-of variable `comint-get-old-input' to retrieve old input, copies it to the
-process mark, and sends it.  If variable `comint-process-echoes' is nil,
-a terminal newline is also inserted into the buffer and sent to the process
-\(if it is non-nil, all text from the process mark to point is deleted,
-since it is assumed the remote process will re-echo it).
+point as input to the process.  Before the process output mark, calls
+value of variable `comint-get-old-input' to retrieve old input, copies
+it to the process mark, and sends it.  A terminal newline is also
+inserted into the buffer and sent to the process.
 
 Any history reference may be expanded depending on the value of the variable
 `comint-input-autoexpand'.  The list of function names contained in the value
 
 Any history reference may be expanded depending on the value of the variable
 `comint-input-autoexpand'.  The list of function names contained in the value
@@ -1369,6 +1378,10 @@ The input is entered into the input history ring, if the value of variable
 If variable `comint-eol-on-send' is non-nil, then point is moved to the
 end of line before sending the input.
 
 If variable `comint-eol-on-send' is non-nil, then point is moved to the
 end of line before sending the input.
 
+After the input has been sent, if `comint-process-echoes' is non-nil,
+then comint-send-input waits to see if the process outputs a string
+matching the input, and if so, deletes that part of the output.
+
 The values of `comint-get-old-input', `comint-input-filter-functions', and
 `comint-input-filter' are chosen according to the command interpreter running
 in the buffer.  E.g.,
 The values of `comint-get-old-input', `comint-input-filter-functions', and
 `comint-input-filter' are chosen according to the command interpreter running
 in the buffer.  E.g.,
@@ -1423,38 +1436,38 @@ Similarly for Soar, Scheme, etc."
                            (delete-region pmark start)
                            copy))))
 
                            (delete-region pmark start)
                            copy))))
 
-         (insert ?\n)
+         (unless no-newline
+           (insert ?\n))
 
          (comint-add-to-input-history history)
 
          (run-hook-with-args 'comint-input-filter-functions
 
          (comint-add-to-input-history history)
 
          (run-hook-with-args 'comint-input-filter-functions
-                             (concat input "\n"))
+                             (if no-newline input
+                               (concat input "\n")))
 
          (let ((beg (marker-position pmark))
 
          (let ((beg (marker-position pmark))
-               (end (1- (point))))
-           (when (not (> beg end))     ; handle a special case
-             ;; Make an overlay for the input field
-             (let ((over (make-overlay beg end nil nil t)))
-               (unless comint-use-prompt-regexp-instead-of-fields
-                 ;; Give old user input a field property of `input', to
-                 ;; distinguish it from both process output and unsent
-                 ;; input.  The terminating newline is put into a special
-                 ;; `boundary' field to make cursor movement between input
-                 ;; and output fields smoother.
-                 (overlay-put over 'field 'input))
-               (when comint-highlight-input
-                 (overlay-put over 'face 'comint-highlight-input)
-                 (overlay-put over 'mouse-face 'highlight)
-                 (overlay-put over
-                              'help-echo
-                              "mouse-2: insert after prompt as new input")
-                 (overlay-put over 'evaporate t))))
-           (unless comint-use-prompt-regexp-instead-of-fields
-             ;; Make an overlay for the terminating newline
-             (let ((over (make-overlay end (1+ end) nil t nil)))
-               (overlay-put over 'field 'boundary)
-               (overlay-put over 'inhibit-line-move-field-capture t)
-               (overlay-put over 'evaporate t))))
+               (end (if no-newline (point) (1- (point)))))
+           (when (> end beg)
+             ;; Set text-properties for the input field
+             (add-text-properties
+              beg end
+              '(front-sticky t
+                font-lock-face comint-highlight-input
+                mouse-face highlight
+                help-echo "mouse-2: insert after prompt as new input"))
+             (unless comint-use-prompt-regexp-instead-of-fields
+               ;; Give old user input a field property of `input', to
+               ;; distinguish it from both process output and unsent
+               ;; input.  The terminating newline is put into a special
+               ;; `boundary' field to make cursor movement between input
+               ;; and output fields smoother.
+               (put-text-property beg end 'field 'input)))
+           (unless (or no-newline comint-use-prompt-regexp-instead-of-fields)
+             ;; Cover the terminating newline
+             (add-text-properties end (1+ end)
+                                  '(rear-nonsticky t
+                                    field boundary
+                                    inhibit-line-move-field-capture t))))
 
          (comint-snapshot-last-prompt)
 
 
          (comint-snapshot-last-prompt)
 
@@ -1467,7 +1480,8 @@ Similarly for Soar, Scheme, etc."
          (set-marker (process-mark proc) (point))
          ;; clear the "accumulation" marker
          (set-marker comint-accum-marker nil)
          (set-marker (process-mark proc) (point))
          ;; clear the "accumulation" marker
          (set-marker comint-accum-marker nil)
-         (funcall comint-input-sender proc input)
+         (let ((comint-input-sender-no-newline no-newline))
+           (funcall comint-input-sender proc input))
 
          ;; Optionally delete echoed input (after checking it).
          (when comint-process-echoes
 
          ;; Optionally delete echoed input (after checking it).
          (when comint-process-echoes
@@ -1512,61 +1526,60 @@ given the string returned by the previous one.  The string returned by
 the last function is the text that is actually inserted in the
 redirection buffer.
 
 the last function is the text that is actually inserted in the
 redirection buffer.
 
-This variable is permanent-local.")
+You can use `add-hook' to add functions to this list
+either globally or locally.")
 
 
-;; When non-nil, this is the last overlay used for output.
-;; It is kept around so that we can extend it instead of creating
-;; multiple contiguous overlays for multiple contiguous output chunks.
-(defvar comint-last-output-overlay nil)
+(defvar comint-inhibit-carriage-motion nil
+  "If nil, comint will interpret `carriage control' characters in output.
+See `comint-carriage-motion' for details.")
 
 ;; When non-nil, this is an overlay over the last recognized prompt in
 ;; the buffer; it is used when highlighting the prompt.
 (defvar comint-last-prompt-overlay nil)
 
 
 ;; When non-nil, this is an overlay over the last recognized prompt in
 ;; the buffer; it is used when highlighting the prompt.
 (defvar comint-last-prompt-overlay nil)
 
-;; `snapshot' any current comint-last-prompt-overlay, freezing it in place.
-;; Any further output will then create a new comint-last-prompt-overlay.
+;; `snapshot' any current comint-last-prompt-overlay, freezing its
+;; attributes in place, even when more input comes a long and moves the
+;; prompt overlay.
 (defun comint-snapshot-last-prompt ()
   (when comint-last-prompt-overlay
 (defun comint-snapshot-last-prompt ()
   (when comint-last-prompt-overlay
-    (overlay-put comint-last-prompt-overlay 'evaporate t)
-    (setq comint-last-prompt-overlay nil)))
+    (let ((inhibit-read-only t))
+      (add-text-properties (overlay-start comint-last-prompt-overlay)
+                           (overlay-end comint-last-prompt-overlay)
+                           (overlay-properties comint-last-prompt-overlay)))))
 
 
-(defun comint-carriage-motion (string)
-  "Handle carriage control characters in comint output.
+(defun comint-carriage-motion (start end)
+  "Interpret carriage control characters in the region from START to END.
 Translate carriage return/linefeed sequences to linefeeds.
 Make single carriage returns delete to the beginning of the line.
 Translate carriage return/linefeed sequences to linefeeds.
 Make single carriage returns delete to the beginning of the line.
-Make backspaces delete the previous character.
-
-This function should be in the list `comint-output-filter-functions'."
-  (save-match-data
-    ;; We first check to see if STRING contains any magic characters, to
-    ;; avoid overhead in the common case where it does not
-    (when (string-match "[\r\b]" string)
-      (let ((pmark (process-mark (get-buffer-process (current-buffer)))))
-       (save-excursion
-         (save-restriction
-           (widen)
-           (let ((inhibit-field-text-motion t)
-                 (buffer-read-only nil))
-             ;; CR LF -> LF
-             ;; Note that this won't work properly when the CR and LF
-             ;; are in different output chunks, but this is probably an
-             ;; exceedingly rare case (because they are generally
-             ;; written as a unit), and to delay interpretation of a
-             ;; trailing CR in a chunk would result in odd interactive
-             ;; behavior (and this case is probably far more common).
-             (goto-char comint-last-output-start)
-             (while (re-search-forward "\r$" pmark t)
-               (delete-char -1))
-             ;; bare CR -> delete preceding line
-             (goto-char comint-last-output-start)
-             (while (search-forward "\r" pmark t)
-               (delete-region (point) (line-beginning-position)))
-             ;; BS -> delete preceding character
-             (goto-char comint-last-output-start)
-             (while (search-forward "\b" pmark t)
-               (delete-char -2)))))))))
-
-(add-hook 'comint-output-filter-functions 'comint-carriage-motion)
+Make backspaces delete the previous character."
+  (save-excursion
+    ;; First do a quick check to see if there are any applicable
+    ;; characters, so we can avoid calling save-match-data and
+    ;; save-restriction if not.
+    (goto-char start)
+    (when (< (skip-chars-forward "^\b\r" end) (- end start))
+      (save-match-data
+       (save-restriction
+         (widen)
+         (let ((inhibit-field-text-motion t)
+               (buffer-read-only nil))
+           ;; CR LF -> LF
+           ;; Note that this won't work properly when the CR and LF
+           ;; are in different output chunks, but this is probably an
+           ;; exceedingly rare case (because they are generally
+           ;; written as a unit), and to delay interpretation of a
+           ;; trailing CR in a chunk would result in odd interactive
+           ;; behavior (and this case is probably far more common).
+           (while (re-search-forward "\r$" end t)
+             (delete-char -1))
+           ;; bare CR -> delete preceding line
+           (goto-char start)
+           (while (search-forward "\r" end t)
+             (delete-region (point) (line-beginning-position)))
+           ;; BS -> delete preceding character
+           (goto-char start)
+           (while (search-forward "\b" end t)
+             (delete-char -2))))))))
 
 ;; The purpose of using this filter for comint processes
 ;; is to keep comint-last-input-end from moving forward
 
 ;; The purpose of using this filter for comint processes
 ;; is to keep comint-last-input-end from moving forward
@@ -1579,7 +1592,12 @@ This function should be in the list `comint-output-filter-functions'."
        ;; Run preoutput filters
        (let ((functions comint-preoutput-filter-functions))
          (while (and functions string)
        ;; Run preoutput filters
        (let ((functions comint-preoutput-filter-functions))
          (while (and functions string)
-           (setq string (funcall (car functions) string))
+           (if (eq (car functions) t)
+               (let ((functions (default-value 'comint-preoutput-filter-functions)))
+                 (while (and functions string)
+                   (setq string (funcall (car functions) string))
+                   (setq functions (cdr functions))))
+             (setq string (funcall (car functions) string)))
            (setq functions (cdr functions))))
 
        ;; Insert STRING
            (setq functions (cdr functions))))
 
        ;; Insert STRING
@@ -1646,45 +1664,39 @@ This function should be in the list `comint-output-filter-functions'."
            ;; Advance process-mark
            (set-marker (process-mark process) (point))
 
            ;; Advance process-mark
            (set-marker (process-mark process) (point))
 
+           (unless comint-inhibit-carriage-motion
+             ;; Interpret any carriage motion characters (newline, backspace)
+             (comint-carriage-motion comint-last-output-start (point)))
+
+           (run-hook-with-args 'comint-output-filter-functions string)
+
+           (goto-char (process-mark process)) ; in case a filter moved it
+
            (unless comint-use-prompt-regexp-instead-of-fields
            (unless comint-use-prompt-regexp-instead-of-fields
-             ;; We check to see if the last overlay used for output is
-             ;; adjacent to the new input, and if so, just extend it.
-             (if (and comint-last-output-overlay
-                      (equal (overlay-end comint-last-output-overlay)
-                             (marker-position comint-last-output-start)))
-                 ;; Extend comint-last-output-overlay to include the
-                 ;; most recent output
-                 (move-overlay comint-last-output-overlay
-                               (overlay-start comint-last-output-overlay)
-                               (point))
-               ;; Create a new overlay
-               (let ((over (make-overlay comint-last-output-start (point))))
-                 (overlay-put over 'field 'output)
-                 (overlay-put over 'inhibit-line-move-field-capture t)
-                 (overlay-put over 'evaporate t)
-                 (setq comint-last-output-overlay over))))
-
-           (when comint-highlight-prompt
-             ;; Highlight the prompt, where we define `prompt' to mean
-             ;; the most recent output that doesn't end with a newline.
-             (unless (and (bolp) (null comint-last-prompt-overlay))
-               ;; Need to create or move the prompt overlay (in the case
-               ;; where there is no prompt ((bolp) == t), we still do
-               ;; this if there's already an existing overlay).
-               (let ((prompt-start (save-excursion (forward-line 0) (point))))
-                 (if comint-last-prompt-overlay
-                     ;; Just move an existing overlay
-                     (move-overlay comint-last-prompt-overlay
-                                   prompt-start (point))
-                   ;; Need to create the overlay
-                   (setq comint-last-prompt-overlay
-                         (make-overlay prompt-start (point)))
-                   (overlay-put comint-last-prompt-overlay
-                                'face 'comint-highlight-prompt)))))
-
-           (goto-char saved-point)
-
-           (run-hook-with-args 'comint-output-filter-functions string)))))))
+              (let ((inhibit-read-only t))
+                (add-text-properties comint-last-output-start (point)
+                                     '(rear-nonsticky t
+                                       field output
+                                       inhibit-line-move-field-capture t))))
+
+           ;; Highlight the prompt, where we define `prompt' to mean
+           ;; the most recent output that doesn't end with a newline.
+           (unless (and (bolp) (null comint-last-prompt-overlay))
+             ;; Need to create or move the prompt overlay (in the case
+             ;; where there is no prompt ((bolp) == t), we still do
+             ;; this if there's already an existing overlay).
+             (let ((prompt-start (save-excursion (forward-line 0) (point))))
+               (if comint-last-prompt-overlay
+                   ;; Just move an existing overlay
+                   (move-overlay comint-last-prompt-overlay
+                                 prompt-start (point))
+                 ;; Need to create the overlay
+                 (setq comint-last-prompt-overlay
+                       (make-overlay prompt-start (point)))
+                 (overlay-put comint-last-prompt-overlay
+                              'font-lock-face 'comint-highlight-prompt))))
+
+           (goto-char saved-point)))))))
 
 (defun comint-preinput-scroll-to-bottom ()
   "Go to the end of buffer in all windows showing it.
 
 (defun comint-preinput-scroll-to-bottom ()
   "Go to the end of buffer in all windows showing it.
@@ -1744,7 +1756,7 @@ This function should be in the list `comint-output-filter-functions'."
                     ;; Optionally scroll so that the text
                     ;; ends at the bottom of the window.
                     (if (and comint-scroll-show-maximum-output
                     ;; Optionally scroll so that the text
                     ;; ends at the bottom of the window.
                     (if (and comint-scroll-show-maximum-output
-                             (>= (point) (process-mark process)))
+                             (= (point) (point-max)))
                         (save-excursion
                           (goto-char (point-max))
                           (recenter -1)))
                         (save-excursion
                           (goto-char (point-max))
                           (recenter -1)))
@@ -1792,9 +1804,9 @@ the current line with any initial string matching the regexp
 `comint-prompt-regexp' removed."
   (let ((bof (field-beginning)))
     (if (eq (get-char-property bof 'field) 'input)
 `comint-prompt-regexp' removed."
   (let ((bof (field-beginning)))
     (if (eq (get-char-property bof 'field) 'input)
-       (field-string bof)
+       (field-string-no-properties bof)
       (comint-bol)
       (comint-bol)
-      (buffer-substring (point) (line-end-position)))))
+      (buffer-substring-no-properties (point) (line-end-position)))))
 
 (defun comint-copy-old-input ()
   "Insert after prompt old input at point as new input to be edited.
 
 (defun comint-copy-old-input ()
   "Insert after prompt old input at point as new input to be edited.
@@ -1825,7 +1837,10 @@ If this takes us past the end of the current line, don't skip at all."
 This just sends STRING plus a newline. To override this,
 set the hook `comint-input-sender'."
   (comint-send-string proc string)
 This just sends STRING plus a newline. To override this,
 set the hook `comint-input-sender'."
   (comint-send-string proc string)
-  (comint-send-string proc "\n"))
+  (if comint-input-sender-no-newline
+      (if (not (string-equal string ""))
+         (process-send-eof))
+    (comint-send-string proc "\n")))
 
 (defun comint-line-beginning-position ()
   "Returns the buffer position of the beginning of the line, after any prompt.
 
 (defun comint-line-beginning-position ()
   "Returns the buffer position of the beginning of the line, after any prompt.
@@ -1947,6 +1962,8 @@ process if STRING contains a password prompt defined by
 
 This function could be in the list `comint-output-filter-functions'."
   (when (string-match comint-password-prompt-regexp string)
 
 This function could be in the list `comint-output-filter-functions'."
   (when (string-match comint-password-prompt-regexp string)
+    (when (string-match "^[ \n\r\t\v\f\b\a]+" string)
+      (setq string (replace-match "" t t string)))
     (let ((pw (comint-read-noecho string t)))
       (send-invisible pw))))
 \f
     (let ((pw (comint-read-noecho string t)))
       (send-invisible pw))))
 \f
@@ -2051,7 +2068,7 @@ Sets mark to the value of point when this command is run."
 This command also kills the pending input
 between the process-mark and point."
   (interactive)
 This command also kills the pending input
 between the process-mark and point."
   (interactive)
-  (comint-kill-input)
+  (comint-skip-input)
   (interrupt-process nil comint-ptyp))
 
 (defun comint-kill-subjob ()
   (interrupt-process nil comint-ptyp))
 
 (defun comint-kill-subjob ()
@@ -2059,7 +2076,7 @@ between the process-mark and point."
 This command also kills the pending input
 between the process-mark and point."
   (interactive)
 This command also kills the pending input
 between the process-mark and point."
   (interactive)
-  (comint-kill-input)
+  (comint-skip-input)
   (kill-process nil comint-ptyp))
 
 (defun comint-quit-subjob ()
   (kill-process nil comint-ptyp))
 
 (defun comint-quit-subjob ()
@@ -2067,7 +2084,7 @@ between the process-mark and point."
 This command also kills the pending input
 between the process-mark and point."
   (interactive)
 This command also kills the pending input
 between the process-mark and point."
   (interactive)
-  (comint-kill-input)
+  (comint-skip-input)
   (quit-process nil comint-ptyp))
 
 (defun comint-stop-subjob ()
   (quit-process nil comint-ptyp))
 
 (defun comint-stop-subjob ()
@@ -2080,7 +2097,7 @@ the top-level process running in the buffer. If you accidentally do
 this, use \\[comint-continue-subjob] to resume the process. (This
 is not a problem with most shells, since they ignore this signal.)"
   (interactive)
 this, use \\[comint-continue-subjob] to resume the process. (This
 is not a problem with most shells, since they ignore this signal.)"
   (interactive)
-  (comint-kill-input)
+  (comint-skip-input)
   (stop-process nil comint-ptyp))
 
 (defun comint-continue-subjob ()
   (stop-process nil comint-ptyp))
 
 (defun comint-continue-subjob ()
@@ -2089,6 +2106,19 @@ Useful if you accidentally suspend the top-level process."
   (interactive)
   (continue-process nil comint-ptyp))
 
   (interactive)
   (continue-process nil comint-ptyp))
 
+(defun comint-skip-input ()
+  "Skip all pending input, from last stuff output by interpreter to point.
+This means mark it as if it had been sent as input, without sending it."
+  (let ((comint-input-sender 'ignore)
+       (comint-input-filter-functions nil))
+    (comint-send-input t))
+  (end-of-line)
+  (let ((pos (point))
+       (marker (process-mark (get-buffer-process (current-buffer)))))
+    (insert "  " (key-description (this-command-keys)))
+    (if (= marker pos)
+       (set-marker marker (point)))))
+
 (defun comint-kill-input ()
   "Kill all text from last stuff output by interpreter to point."
   (interactive)
 (defun comint-kill-input ()
   "Kill all text from last stuff output by interpreter to point."
   (interactive)
@@ -2108,7 +2138,7 @@ Sends an EOF only if point is at the end of the buffer and there is no input."
 (defun comint-send-eof ()
   "Send an EOF to the current buffer's process."
   (interactive)
 (defun comint-send-eof ()
   "Send an EOF to the current buffer's process."
   (interactive)
-  (comint-snapshot-last-prompt)
+  (comint-send-input t)
   (process-send-eof))
 
 
   (process-send-eof))
 
 
@@ -2159,7 +2189,7 @@ If N is negative, find the previous or Nth previous match."
   "Move to end of Nth next prompt in the buffer.
 If `comint-use-prompt-regexp-instead-of-fields' is nil, then this means
 the beginning of the Nth next `input' field, otherwise, it means the Nth
   "Move to end of Nth next prompt in the buffer.
 If `comint-use-prompt-regexp-instead-of-fields' is nil, then this means
 the beginning of the Nth next `input' field, otherwise, it means the Nth
-occurance of text matching `comint-prompt-regexp'."
+occurrence of text matching `comint-prompt-regexp'."
   (interactive "p")
   (if comint-use-prompt-regexp-instead-of-fields
       ;; Use comint-prompt-regexp
   (interactive "p")
   (if comint-use-prompt-regexp-instead-of-fields
       ;; Use comint-prompt-regexp
@@ -2196,7 +2226,7 @@ occurance of text matching `comint-prompt-regexp'."
   "Move to end of Nth previous prompt in the buffer.
 If `comint-use-prompt-regexp-instead-of-fields' is nil, then this means
 the beginning of the Nth previous `input' field, otherwise, it means the Nth
   "Move to end of Nth previous prompt in the buffer.
 If `comint-use-prompt-regexp-instead-of-fields' is nil, then this means
 the beginning of the Nth previous `input' field, otherwise, it means the Nth
-occurance of text matching `comint-prompt-regexp'."
+occurrence of text matching `comint-prompt-regexp'."
   (interactive "p")
   (comint-next-prompt (- n)))
 
   (interactive "p")
   (comint-next-prompt (- n)))
 
@@ -2256,8 +2286,8 @@ This command is like `M-.' in bash."
 ;;============================================================================
 ;; Many command-interpreters (e.g., Lisp, Scheme, Soar) have
 ;; commands that process files of source text (e.g. loading or compiling
 ;;============================================================================
 ;; Many command-interpreters (e.g., Lisp, Scheme, Soar) have
 ;; commands that process files of source text (e.g. loading or compiling
-;; files). So the corresponding process-in-a-buffer modes have commands
-;; for doing this (e.g., lisp-load-file). The functions below are useful
+;; files).  So the corresponding process-in-a-buffer modes have commands
+;; for doing this (e.g., lisp-load-file).  The functions below are useful
 ;; for defining these commands.
 ;;
 ;; Alas, these guys don't do exactly the right thing for Lisp, Scheme
 ;; for defining these commands.
 ;;
 ;; Alas, these guys don't do exactly the right thing for Lisp, Scheme
@@ -2265,9 +2295,9 @@ This command is like `M-.' in bash."
 ;; So the compile/load interface gets the wrong default occasionally.
 ;; The load-file/compile-file default mechanism could be smarter -- it
 ;; doesn't know about the relationship between filename extensions and
 ;; So the compile/load interface gets the wrong default occasionally.
 ;; The load-file/compile-file default mechanism could be smarter -- it
 ;; doesn't know about the relationship between filename extensions and
-;; whether the file is source or executable. If you compile foo.lisp
+;; whether the file is source or executable.  If you compile foo.lisp
 ;; with compile-file, then the next load-file should use foo.bin for
 ;; with compile-file, then the next load-file should use foo.bin for
-;; the default, not foo.lisp. This is tricky to do right, particularly
+;; the default, not foo.lisp.  This is tricky to do right, particularly
 ;; because the extension for executable files varies so much (.o, .bin,
 ;; .lbin, .mo, .vo, .ao, ...).
 
 ;; because the extension for executable files varies so much (.o, .bin,
 ;; .lbin, .mo, .vo, .ao, ...).
 
@@ -2288,18 +2318,18 @@ This command is like `M-.' in bash."
 ;; commands for tea, soar, cmulisp, and cmuscheme modes.
 ;;
 ;; - PREVIOUS-DIR/FILE is a pair (directory . filename) from the last
 ;; commands for tea, soar, cmulisp, and cmuscheme modes.
 ;;
 ;; - PREVIOUS-DIR/FILE is a pair (directory . filename) from the last
-;; source-file processing command. NIL if there hasn't been one yet.
+;; source-file processing command.  nil if there hasn't been one yet.
 ;; - SOURCE-MODES is a list used to determine what buffers contain source
 ;; files: if the major mode of the buffer is in SOURCE-MODES, it's source.
 ;; Typically, (lisp-mode) or (scheme-mode).
 ;;
 ;; If the command is given while the cursor is inside a string, *and*
 ;; the string is an existing filename, *and* the filename is not a directory,
 ;; - SOURCE-MODES is a list used to determine what buffers contain source
 ;; files: if the major mode of the buffer is in SOURCE-MODES, it's source.
 ;; Typically, (lisp-mode) or (scheme-mode).
 ;;
 ;; If the command is given while the cursor is inside a string, *and*
 ;; the string is an existing filename, *and* the filename is not a directory,
-;; then the string is taken as default. This allows you to just position
+;; then the string is taken as default.  This allows you to just position
 ;; your cursor over a string that's a filename and have it taken as default.
 ;;
 ;; If the command is given in a file buffer whose major mode is in
 ;; your cursor over a string that's a filename and have it taken as default.
 ;;
 ;; If the command is given in a file buffer whose major mode is in
-;; SOURCE-MODES, then the the filename is the default file, and the
+;; SOURCE-MODES, then the filename is the default file, and the
 ;; file's directory is the default directory.
 ;;
 ;; If the buffer isn't a source file buffer (e.g., it's the process buffer),
 ;; file's directory is the default directory.
 ;;
 ;; If the buffer isn't a source file buffer (e.g., it's the process buffer),
@@ -2377,7 +2407,7 @@ This command is like `M-.' in bash."
                       (and (search-forward "\"" eol t)
                            (1- (point))))))
       (and start end
                       (and (search-forward "\"" eol t)
                            (1- (point))))))
       (and start end
-          (buffer-substring start end)))))
+          (buffer-substring-no-properties start end)))))
 
 (defun comint-get-source (prompt prev-dir/file source-modes mustmatch-p)
   (let* ((def (comint-source-default prev-dir/file source-modes))
 
 (defun comint-get-source (prompt prev-dir/file source-modes mustmatch-p)
   (let* ((def (comint-source-default prev-dir/file source-modes))
@@ -2506,7 +2536,7 @@ This is used by comint's and shell's completion functions, and by shell's
 directory tracking functions.")
 
 (defvar comint-file-name-chars
 directory tracking functions.")
 
 (defvar comint-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+@:_.$#%,={}-")
   "String of characters valid in a file name.
       "~/A-Za-z0-9_^$!#%&{}@`'.,:()-"
     "~/A-Za-z0-9+@:_.$#%,={}-")
   "String of characters valid in a file name.
@@ -2631,7 +2661,7 @@ Returns t if successful."
 (defun comint-dynamic-complete-as-filename ()
   "Dynamically complete at point as a filename.
 See `comint-dynamic-complete-filename'.  Returns t if successful."
 (defun comint-dynamic-complete-as-filename ()
   "Dynamically complete at point as a filename.
 See `comint-dynamic-complete-filename'.  Returns t if successful."
-  (let* ((completion-ignore-case (memq system-type '(ms-dos windows-nt)))
+  (let* ((completion-ignore-case (memq system-type '(ms-dos windows-nt cygwin)))
         (completion-ignored-extensions comint-completion-fignore)
         ;; If we bind this, it breaks remote directory tracking in rlogin.el.
         ;; I think it was originally bound to solve file completion problems,
         (completion-ignored-extensions comint-completion-fignore)
         ;; If we bind this, it breaks remote directory tracking in rlogin.el.
         ;; I think it was originally bound to solve file completion problems,
@@ -2701,8 +2731,10 @@ removed, and the filename is made absolute instead of relative.  For expansion
 see `expand-file-name' and `substitute-in-file-name'.  For completion see
 `comint-dynamic-complete-filename'."
   (interactive)
 see `expand-file-name' and `substitute-in-file-name'.  For completion see
 `comint-dynamic-complete-filename'."
   (interactive)
-  (replace-match (expand-file-name (comint-match-partial-filename)) t t)
-  (comint-dynamic-complete-filename))
+  (let ((filename (comint-match-partial-filename)))
+    (when filename
+      (replace-match (expand-file-name filename) t t)
+      (comint-dynamic-complete-filename))))
 
 
 (defun comint-dynamic-simple-complete (stub candidates)
 
 
 (defun comint-dynamic-simple-complete (stub candidates)
@@ -2718,7 +2750,7 @@ Returns `partial' if completed as far as possible with the completion matches.
 Returns `listed' if a completion listing was shown.
 
 See also `comint-dynamic-complete-filename'."
 Returns `listed' if a completion listing was shown.
 
 See also `comint-dynamic-complete-filename'."
-  (let* ((completion-ignore-case (memq system-type '(ms-dos windows-nt)))
+  (let* ((completion-ignore-case (memq system-type '(ms-dos windows-nt cygwin)))
         (suffix (cond ((not comint-completion-addsuffix) "")
                       ((not (consp comint-completion-addsuffix)) " ")
                       (t (cdr comint-completion-addsuffix))))
         (suffix (cond ((not comint-completion-addsuffix) "")
                       ((not (consp comint-completion-addsuffix)) " ")
                       (t (cdr comint-completion-addsuffix))))
@@ -2759,7 +2791,7 @@ See also `comint-dynamic-complete-filename'."
 (defun comint-dynamic-list-filename-completions ()
   "List in help buffer possible completions of the filename at point."
   (interactive)
 (defun comint-dynamic-list-filename-completions ()
   "List in help buffer possible completions of the filename at point."
   (interactive)
-  (let* ((completion-ignore-case (memq system-type '(ms-dos windows-nt)))
+  (let* ((completion-ignore-case (memq system-type '(ms-dos windows-nt cygwin)))
         ;; If we bind this, it breaks remote directory tracking in rlogin.el.
         ;; I think it was originally bound to solve file completion problems,
         ;; but subsequent changes may have made this unnecessary.  sm.
         ;; If we bind this, it breaks remote directory tracking in rlogin.el.
         ;; I think it was originally bound to solve file completion problems,
         ;; but subsequent changes may have made this unnecessary.  sm.
@@ -2775,30 +2807,64 @@ See also `comint-dynamic-complete-filename'."
        (mapcar 'comint-quote-filename completions)))))
 
 
        (mapcar 'comint-quote-filename completions)))))
 
 
+;; This is bound locally in a *Completions* buffer to the list of
+;; completions displayed, and is used to detect the case where the same
+;; command is repeatedly used without the set of completions changing.
+(defvar comint-displayed-dynamic-completions nil)
+
 (defun comint-dynamic-list-completions (completions)
   "List in help buffer sorted COMPLETIONS.
 Typing SPC flushes the help buffer."
 (defun comint-dynamic-list-completions (completions)
   "List in help buffer sorted COMPLETIONS.
 Typing SPC flushes the help buffer."
-  (let ((conf (current-window-configuration)))
-    (with-output-to-temp-buffer "*Completions*"
-      (display-completion-list (sort completions 'string-lessp)))
-    (message "Hit space to flush")
-    (let (key first)
-      (if (save-excursion
-           (set-buffer (get-buffer "*Completions*"))
-           (setq key (read-key-sequence nil)
-                 first (aref key 0))
-           (and (consp first) (consp (event-start first))
-                (eq (window-buffer (posn-window (event-start first)))
-                    (get-buffer "*Completions*"))
-                (eq (key-binding key) 'mouse-choose-completion)))
-         ;; If the user does mouse-choose-completion with the mouse,
-         ;; execute the command, then delete the completion window.
-         (progn
-           (mouse-choose-completion first)
-           (set-window-configuration conf))
-       (if (eq first ?\ )
-           (set-window-configuration conf)
-         (setq unread-command-events (listify-key-sequence key)))))))
+  (let ((window (get-buffer-window "*Completions*")))
+    (setq completions (sort completions 'string-lessp))
+    (if (and (eq last-command this-command)
+            window (window-live-p window) (window-buffer window)
+            (buffer-name (window-buffer window))
+            ;; The above tests are not sufficient to detect the case where we
+            ;; should scroll, because the top-level interactive command may
+            ;; not have displayed a completions window the last time it was
+            ;; invoked, and there may be such a window left over from a
+            ;; previous completion command with a different set of
+            ;; completions.  To detect that case, we also test that the set
+            ;; of displayed completions is in fact the same as the previously
+            ;; displayed set.
+            (equal completions
+                   (buffer-local-value 'comint-displayed-dynamic-completions
+                                       (window-buffer window))))
+       ;; If this command was repeated, and
+       ;; there's a fresh completion window with a live buffer,
+       ;; and this command is repeated, scroll that window.
+       (with-current-buffer (window-buffer window)
+         (if (pos-visible-in-window-p (point-max) window)
+             (set-window-start window (point-min))
+           (save-selected-window
+             (select-window window)
+             (scroll-up))))
+
+      (let ((conf (current-window-configuration)))
+       (with-output-to-temp-buffer "*Completions*"
+         (display-completion-list completions))
+       (message "Type space to flush; repeat completion command to scroll")
+       (let (key first)
+         (if (save-excursion
+               (set-buffer (get-buffer "*Completions*"))
+               (set (make-local-variable
+                     'comint-displayed-dynamic-completions)
+                    completions)
+               (setq key (read-key-sequence nil)
+                     first (aref key 0))
+               (and (consp first) (consp (event-start first))
+                    (eq (window-buffer (posn-window (event-start first)))
+                        (get-buffer "*Completions*"))
+                    (eq (key-binding key) 'mouse-choose-completion)))
+             ;; If the user does mouse-choose-completion with the mouse,
+             ;; execute the command, then delete the completion window.
+             (progn
+               (mouse-choose-completion first)
+               (set-window-configuration conf))
+           (if (eq first ?\ )
+               (set-window-configuration conf)
+             (setq unread-command-events (listify-key-sequence key)))))))))
 
 \f
 (defun comint-get-next-from-history ()
 
 \f
 (defun comint-get-next-from-history ()
@@ -2862,7 +2928,7 @@ the process mark is at the beginning of the accumulated input."
     (message "Process mark set")))
 
 \f
     (message "Process mark set")))
 
 \f
-;; Author:  Peter Breton <pbreton@ne.mediaone.net>
+;; Author:  Peter Breton <pbreton@cs.umb.edu>
 
 ;; This little add-on for comint is intended to make it easy to get
 ;; output from currently active comint buffers into another buffer,
 
 ;; This little add-on for comint is intended to make it easy to get
 ;; output from currently active comint buffers into another buffer,
@@ -2919,9 +2985,10 @@ string.
 
 The functions on the list are called sequentially, and each one is given
 the string returned by the previous one.  The string returned by the
 
 The functions on the list are called sequentially, and each one is given
 the string returned by the previous one.  The string returned by the
-last function is the text that is actually inserted in the redirection buffer.")
+last function is the text that is actually inserted in the redirection buffer.
 
 
-(make-variable-buffer-local 'comint-redirect-filter-functions)
+You can use `add-hook' to add functions to this list
+either globally or locally.")
 
 ;; Internal variables
 
 
 ;; Internal variables
 
@@ -3055,8 +3122,16 @@ This function does not need to be invoked by the end user."
     ;; If there are any filter functions, give them a chance to modify the string
     (let ((functions comint-redirect-filter-functions))
       (while (and functions filtered-input-string)
     ;; If there are any filter functions, give them a chance to modify the string
     (let ((functions comint-redirect-filter-functions))
       (while (and functions filtered-input-string)
-       (setq filtered-input-string
-             (funcall (car functions) filtered-input-string))
+       (if (eq (car functions) t)
+           ;; If a local value says "use the default value too",
+           ;; do that.
+           (let ((functions (default-value 'comint-redirect-filter-functions)))
+             (while (and functions filtered-input-string)
+               (setq filtered-input-string
+                     (funcall (car functions) filtered-input-string))
+               (setq functions (cdr functions))))
+         (setq filtered-input-string
+               (funcall (car functions) filtered-input-string)))
        (setq functions (cdr functions))))
 
     ;; Clobber `comint-redirect-finished-regexp'
        (setq functions (cdr functions))))
 
     ;; Clobber `comint-redirect-finished-regexp'
@@ -3123,52 +3198,52 @@ If NO-DISPLAY is non-nil, do not show the output buffer."
                           process))
         (proc (get-buffer-process process-buffer)))
     ;; Change to the process buffer
                           process))
         (proc (get-buffer-process process-buffer)))
     ;; Change to the process buffer
-    (set-buffer process-buffer)
+    (with-current-buffer process-buffer
 
 
-    ;; Make sure there's a prompt in the current process buffer
-    (and comint-redirect-perform-sanity-check
-        (save-excursion
-          (goto-char (point-max))
-          (or (re-search-backward comint-prompt-regexp nil t)
-              (error "No prompt found or `comint-prompt-regexp' not set properly"))))
+      ;; Make sure there's a prompt in the current process buffer
+      (and comint-redirect-perform-sanity-check
+          (save-excursion
+            (goto-char (point-max))
+            (or (re-search-backward comint-prompt-regexp nil t)
+                (error "No prompt found or `comint-prompt-regexp' not set properly"))))
 
     ;;;;;;;;;;;;;;;;;;;;;
 
     ;;;;;;;;;;;;;;;;;;;;;
-    ;; Set up for redirection
+      ;; Set up for redirection
     ;;;;;;;;;;;;;;;;;;;;;
     ;;;;;;;;;;;;;;;;;;;;;
-    (comint-redirect-setup
-     ;; Output Buffer
-     output-buffer
-     ;; Comint Buffer
-     (current-buffer)
-     ;; Finished Regexp
-     comint-prompt-regexp
-     ;; Echo input
-     echo)
+      (comint-redirect-setup
+       ;; Output Buffer
+       output-buffer
+       ;; Comint Buffer
+       (current-buffer)
+       ;; Finished Regexp
+       comint-prompt-regexp
+       ;; Echo input
+       echo)
 
     ;;;;;;;;;;;;;;;;;;;;;
 
     ;;;;;;;;;;;;;;;;;;;;;
-    ;; Set the filter
+      ;; Set the filter
     ;;;;;;;;;;;;;;;;;;;;;
     ;;;;;;;;;;;;;;;;;;;;;
-    ;; Save the old filter
-    (setq comint-redirect-original-filter-function
-         (process-filter proc))
-    (set-process-filter proc 'comint-redirect-filter)
+      ;; Save the old filter
+      (setq comint-redirect-original-filter-function
+           (process-filter proc))
+      (set-process-filter proc 'comint-redirect-filter)
 
     ;;;;;;;;;;;;;;;;;;;;;
 
     ;;;;;;;;;;;;;;;;;;;;;
-    ;; Send the command
+      ;; Send the command
     ;;;;;;;;;;;;;;;;;;;;;
     ;;;;;;;;;;;;;;;;;;;;;
-    (process-send-string
-     (current-buffer)
-     (concat command "\n"))
+      (process-send-string
+       (current-buffer)
+       (concat command "\n"))
 
     ;;;;;;;;;;;;;;;;;;;;;
 
     ;;;;;;;;;;;;;;;;;;;;;
-    ;; Show the output
+      ;; Show the output
     ;;;;;;;;;;;;;;;;;;;;;
     ;;;;;;;;;;;;;;;;;;;;;
-    (or no-display
-        (display-buffer
-         (get-buffer-create
-          (if (listp output-buffer)
-              (car output-buffer)
-            output-buffer))))))
+      (or no-display
+         (display-buffer
+          (get-buffer-create
+           (if (listp output-buffer)
+               (car output-buffer)
+             output-buffer)))))))
 
 ;;;###autoload
 (defun comint-redirect-results-list (command regexp regexp-group)
 
 ;;;###autoload
 (defun comint-redirect-results-list (command regexp regexp-group)