Merge from emacs-23
[bpt/emacs.git] / lisp / comint.el
index 1070652..1912cdc 100644 (file)
@@ -1,12 +1,14 @@
 ;;; comint.el --- general command interpreter in a window stuff
 
-;; Copyright (C) 1988, 1990, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-;;   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+;; Copyright (C) 1988, 1990, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+;;   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+;;   2010, 2011  Free Software Foundation, Inc.
 
 ;; Author: Olin Shivers <shivers@cs.cmu.edu>
 ;;     Simon Marshall <simon@gnu.org>
 ;; Maintainer: FSF
 ;; Keywords: processes
+;; Package: emacs
 
 ;; This file is part of GNU Emacs.
 
@@ -61,8 +63,7 @@
 ;;
 ;; M-p    comint-previous-input           Cycle backwards in input history
 ;; M-n    comint-next-input               Cycle forwards
-;; M-r     comint-previous-matching-input  Previous input matching a regexp
-;; M-s     comint-next-matching-input      Next input that matches
+;; M-r     comint-history-isearch-backward-regexp  Isearch input regexp backward
 ;; M-C-l   comint-show-output             Show last batch of process output
 ;; RET    comint-send-input
 ;; C-d    comint-delchar-or-maybe-eof     Delete char unless at end of buff
@@ -206,7 +207,7 @@ For shells, a good value is (?\\| ?& ?< ?> ?\\( ?\\) ?;).
 This is a good thing to set in mode hooks.")
 
 (defcustom comint-input-autoexpand nil
-  "*If non-nil, expand input command history references on completion.
+  "If non-nil, expand input command history references on completion.
 This mirrors the optional behavior of tcsh (its autoexpand and histlist).
 
 If the value is `input', then the expansion is seen on input.
@@ -226,14 +227,12 @@ This variable is buffer-local."
   :group 'comint)
 
 (defface comint-highlight-prompt
-  '((((min-colors 88) (background dark)) (:foreground "cyan1"))
-    (((background dark)) (:foreground "cyan"))
-    (t (:foreground "dark blue")))
+  '((t :inherit minibuffer-prompt))
   "Face to use to highlight prompts."
   :group 'comint)
 
 (defcustom comint-input-ignoredups nil
-  "*If non-nil, don't add input matching the last on the input ring.
+  "If non-nil, don't add input matching the last on the input ring.
 This mirrors the optional behavior of bash.
 
 This variable is buffer-local."
@@ -241,16 +240,16 @@ This variable is buffer-local."
   :group 'comint)
 
 (defcustom comint-input-ring-file-name nil
-  "*If non-nil, name of the file to read/write input history.
+  "If non-nil, name of the file to read/write input history.
 See also `comint-read-input-ring' and `comint-write-input-ring'.
-
-This variable is buffer-local, and is a good thing to set in mode hooks."
+`comint-mode' makes this a buffer-local variable.  You probably want
+to set this in a mode hook, rather than customize the default value."
   :type '(choice (const :tag "nil" nil)
                 file)
   :group 'comint)
 
 (defcustom comint-scroll-to-bottom-on-input nil
-  "*Controls whether input to interpreter causes window to scroll.
+  "Controls whether input to interpreter causes window to scroll.
 If nil, then do not scroll.  If t or `all', scroll all windows showing buffer.
 If `this', scroll only the selected window.
 
@@ -264,7 +263,7 @@ See `comint-preinput-scroll-to-bottom'.  This variable is buffer-local."
   :group 'comint)
 
 (defcustom comint-move-point-for-output nil
-  "*Controls whether interpreter output moves point to the end of the output.
+  "Controls whether interpreter output moves point to the end of the output.
 If nil, then output never moves point to the output.
  (If the output occurs at point, it is inserted before point.)
 If t or `all', move point in all windows showing the buffer.
@@ -286,7 +285,7 @@ This variable is buffer-local in all Comint buffers."
 (defvaralias 'comint-scroll-to-bottom-on-output 'comint-move-point-for-output)
 
 (defcustom comint-scroll-show-maximum-output t
-  "*Controls how to scroll due to interpreter output.
+  "Controls how to scroll due to interpreter output.
 This variable applies when point is at the end of the buffer
 \(either because it was originally there, or because
 `comint-move-point-for-output' said to move it there)
@@ -303,14 +302,17 @@ This variable is buffer-local in all Comint buffers."
   :group 'comint)
 
 (defcustom comint-buffer-maximum-size 1024
-  "*The maximum size in lines for Comint buffers.
+  "The maximum size in lines for Comint buffers.
 Comint buffers are truncated from the top to be no greater than this number, if
 the function `comint-truncate-buffer' is on `comint-output-filter-functions'."
   :type 'integer
   :group 'comint)
 
-(defvar comint-input-ring-size 150
-  "Size of input history ring.")
+(defcustom comint-input-ring-size 500
+  "Size of the input history ring in `comint-mode'."
+  :type 'integer
+  :group 'comint
+  :version "23.2")
 
 (defvar comint-input-ring-separator "\n"
   "Separator between commands in the history file.")
@@ -319,7 +321,7 @@ the function `comint-truncate-buffer' is on `comint-output-filter-functions'."
   "Regexp for history entries that should be ignored when Comint initializes.")
 
 (defcustom comint-process-echoes nil
-  "*If non-nil, assume that the subprocess echoes any input.
+  "If non-nil, assume that the subprocess echoes any input.
 If so, delete one copy of the input so that only one copy eventually
 appears in the buffer.
 
@@ -335,14 +337,23 @@ This variable is buffer-local."
 ;; Ubuntu's sudo prompts like `[sudo] password for user:'
 ;; Some implementations of passwd use "Password (again)" as the 2nd prompt.
 ;; Something called "perforce" uses "Enter password:".
+;; See M-x comint-testsuite--test-comint-password-prompt-regexp.
 (defcustom comint-password-prompt-regexp
-  "\\(\\(Enter \\|[Oo]ld \\|[Nn]ew \\|'s \\|login \\|\
-Kerberos \\|CVS \\|UNIX \\| SMB \\|LDAP \\|\\[sudo] \\|^\\)\
-\[Pp]assword\\( (again)\\)?\\|\
-pass phrase\\|\\(Enter \\|Repeat \\|Bad \\)?[Pp]assphrase\\)\
-\\(?:, try again\\)?\\(?: for [^:]+\\)?:\\s *\\'"
-  "*Regexp matching prompts for passwords in the inferior process.
+  (concat
+   "\\(^ *\\|"
+   (regexp-opt
+    '("Enter" "enter" "Enter same" "enter same" "Enter the" "enter the"
+      "Old" "old" "New" "new" "'s" "login"
+      "Kerberos" "CVS" "UNIX" " SMB" "LDAP" "[sudo]" "Repeat" "Bad") t)
+   " +\\)"
+   (regexp-opt
+    '("password" "Password" "passphrase" "Passphrase"
+      "pass phrase" "Pass phrase"))
+   "\\(?:\\(?:, try\\)? *again\\| (empty for no passphrase)\\| (again)\\)?\
+\\(?: for [^:]+\\)?:\\s *\\'")
+  "Regexp matching prompts for passwords in the inferior process.
 This is used by `comint-watch-for-password-prompt'."
+  :version "24.1"
   :type 'regexp
   :group 'comint)
 
@@ -400,16 +411,19 @@ massage the input string, put a different function here.
 This is called from the user command `comint-send-input'.")
 
 (defcustom comint-eol-on-send t
-  "*Non-nil means go to the end of the line before sending input.
+  "Non-nil means go to the end of the line before sending input.
 See `comint-send-input'."
   :type 'boolean
   :group 'comint)
 
+(define-obsolete-variable-alias 'comint-use-prompt-regexp-instead-of-fields
+  'comint-use-prompt-regexp "22.1")
+
 ;; Note: If it is decided to purge comint-prompt-regexp from the source
 ;; entirely, searching for uses of this variable will help to identify
 ;; places that need attention.
 (defcustom comint-use-prompt-regexp nil
-  "*If non-nil, use `comint-prompt-regexp' to recognize prompts.
+  "If non-nil, use `comint-prompt-regexp' to recognize prompts.
 If nil, then program output and user-input are given different `field'
 properties, which Emacs commands can use to distinguish them (in
 particular, common movement commands such as `beginning-of-line'
@@ -417,11 +431,6 @@ respect field boundaries in a natural way)."
   :type 'boolean
   :group 'comint)
 
-;; Autoload is necessary for Custom to recognize old alias.
-;;;###autoload
-(define-obsolete-variable-alias 'comint-use-prompt-regexp-instead-of-fields
-  'comint-use-prompt-regexp "22.1")
-
 (defcustom comint-mode-hook nil
   "Hook run upon entry to `comint-mode'.
 This is run before the process is cranked up."
@@ -444,8 +453,7 @@ executed once when the buffer is created."
     (define-key map "\en"        'comint-next-input)
     (define-key map [C-up]       'comint-previous-input)
     (define-key map [C-down]     'comint-next-input)
-    (define-key map "\er"        'comint-previous-matching-input)
-    (define-key map "\es"        'comint-next-matching-input)
+    (define-key map "\er"        'comint-history-isearch-backward-regexp)
     (define-key map [?\C-c ?\M-r] 'comint-previous-matching-input-from-input)
     (define-key map [?\C-c ?\M-s] 'comint-next-matching-input-from-input)
     (define-key map "\e\C-l"     'comint-show-output)
@@ -508,6 +516,10 @@ executed once when the buffer is created."
       '("Kill Current Input" . comint-kill-input))
     (define-key map [menu-bar inout copy-input]
       '("Copy Old Input" . comint-copy-old-input))
+    (define-key map [menu-bar inout history-isearch-backward-regexp]
+      '("Isearch Input Regexp Backward..." . comint-history-isearch-backward-regexp))
+    (define-key map [menu-bar inout history-isearch-backward]
+      '("Isearch Input String Backward..." . comint-history-isearch-backward))
     (define-key map [menu-bar inout forward-matching-history]
       '("Forward Matching Input..." . comint-forward-matching-input))
     (define-key map [menu-bar inout backward-matching-history]
@@ -555,7 +567,7 @@ This is to work around a bug in Emacs process signaling.")
   "Index of last matched history element.")
 (defvar comint-matching-input-from-input-string ""
   "Input previously used to match input history.")
-(defvar comint-save-input-ring-index
+(defvar comint-save-input-ring-index nil
   "Last input ring index which you copied.
 This is to support the command \\[comint-get-next-from-history].")
 
@@ -662,11 +674,15 @@ Entry to this mode runs the hooks on `comint-mode-hook'."
   (make-local-variable 'comint-process-echoes)
   (make-local-variable 'comint-file-name-chars)
   (make-local-variable 'comint-file-name-quote-list)
+  ;; dir tracking on remote files
+  (set (make-local-variable 'comint-file-name-prefix)
+       (or (file-remote-p default-directory) ""))
   (make-local-variable 'comint-accum-marker)
   (setq comint-accum-marker (make-marker))
   (make-local-variable 'font-lock-defaults)
   (setq font-lock-defaults '(nil t))
   (add-hook 'change-major-mode-hook 'font-lock-defontify nil t)
+  (add-hook 'isearch-mode-hook 'comint-history-isearch-setup nil t)
   ;; This behavior is not useful in comint buffers, and is annoying
   (set (make-local-variable 'next-line-add-newlines) nil))
 
@@ -685,9 +701,12 @@ PROGRAM should be either a string denoting an executable program to create
 via `start-file-process', or a cons pair of the form (HOST . SERVICE) denoting
 a TCP connection to be opened via `open-network-stream'.  If there is already
 a running process in that buffer, it is not restarted.  Optional fourth arg
-STARTFILE is the name of a file to send the contents of to the process.
+STARTFILE is the name of a file, whose contents are sent to the
+process as its initial input.
+
+If PROGRAM is a string, any more args are arguments to PROGRAM.
 
-If PROGRAM is a string, any more args are arguments to PROGRAM."
+Returns the (possibly newly created) process buffer."
   (or (fboundp 'start-file-process)
       (error "Multi-processing is not supported for this system"))
   (setq buffer (get-buffer-create (or buffer (concat "*" name "*"))))
@@ -708,9 +727,12 @@ PROGRAM should be either a string denoting an executable program to create
 via `start-file-process', or a cons pair of the form (HOST . SERVICE) denoting
 a TCP connection to be opened via `open-network-stream'.  If there is already
 a running process in that buffer, it is not restarted.  Optional third arg
-STARTFILE is the name of a file to send the contents of the process to.
+STARTFILE is the name of a file, whose contents are sent to the
+process as its initial input.
 
-If PROGRAM is a string, any more args are arguments to PROGRAM."
+If PROGRAM is a string, any more args are arguments to PROGRAM.
+
+Returns the (possibly newly created) process buffer."
   (apply #'make-comint-in-buffer name nil program startfile switches))
 
 ;;;###autoload
@@ -727,7 +749,7 @@ See `make-comint' and `comint-exec'."
 
 (defun comint-exec (buffer name command startfile switches)
   "Start up a process named NAME in buffer BUFFER for Comint modes.
-Runs the given COMMAND with SWITCHES with output to STARTFILE.
+Runs the given COMMAND with SWITCHES, and initial input from STARTFILE.
 Blasts any old process running in the buffer.  Doesn't set the buffer mode.
 You can use this to cheaply run a series of processes in the same Comint
 buffer.  The hook `comint-exec-hook' is run after each exec."
@@ -789,7 +811,7 @@ buffer.  The hook `comint-exec-hook' is run after each exec."
              default-directory
            "/"))
        proc decoding encoding changed)
-    (let ((exec-path (if (file-name-directory command)
+    (let ((exec-path (if (and command (file-name-directory command))
                         ;; If the command has slashes, make sure we
                         ;; first look relative to the current directory.
                         (cons default-directory exec-path) exec-path)))
@@ -813,13 +835,18 @@ buffer.  The hook `comint-exec-hook' is run after each exec."
 (defun comint-insert-input (event)
   "In a Comint buffer, set the current input to the previous input at point.
 If there is no previous input at point, run the command specified
-by the global keymap (usually `mouse-yank-at-point')."
+by the global keymap (usually `mouse-yank-at-click')."
   (interactive "e")
-  (mouse-set-point event)
+  ;; Don't set the mouse here, since it may otherwise change the behavior
+  ;; of the command on which we fallback if there's no field at point.
+  ;; (mouse-set-point event)
   (let ((pos (posn-point (event-end event)))
        field input)
     (with-selected-window (posn-window (event-end event))
-      (and (setq field (field-at-pos pos))
+      ;; If pos is at the very end of a field, the mouse-click was
+      ;; probably outside (to the right) of the field.
+      (and (< pos (field-end pos))
+           (setq field (field-at-pos pos))
           (setq input (field-string-no-properties pos))))
     (if (or (null comint-accum-marker)
            (not (eq field 'input)))
@@ -832,15 +859,16 @@ by the global keymap (usually `mouse-yank-at-point')."
               (fun (and last-key (lookup-key global-map (vector last-key)))))
          (and fun (not (eq fun 'comint-insert-input))
               (call-interactively fun)))
-      ;; Otherwise, insert the previous input.
-      (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 input at point
-      (insert input))))
+      (with-selected-window (posn-window (event-end event))
+        ;; Otherwise, insert the previous input.
+        (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 input at point
+        (insert input)))))
 \f
 ;; Input history processing in a buffer
 ;; ===========================================================================
@@ -890,37 +918,36 @@ See also `comint-input-ignoredups' and `comint-write-input-ring'."
             (message "Cannot read history file %s"
                      comint-input-ring-file-name)))
        (t
-        (let* ((history-buf (get-buffer-create " *temp*"))
-               (file comint-input-ring-file-name)
+        (let* ((file comint-input-ring-file-name)
                (count 0)
                (size comint-input-ring-size)
                (ring (make-ring size)))
-          (unwind-protect
-              (save-excursion
-                (set-buffer history-buf)
-                (widen)
-                (erase-buffer)
-                (insert-file-contents file)
-                ;; Save restriction in case file is already visited...
-                ;; Watch for those date stamps in history files!
-                (goto-char (point-max))
-                (let (start end history)
-                  (while (and (< count size)
-                              (re-search-backward comint-input-ring-separator nil t)
-                              (setq end (match-beginning 0)))
-                    (if (re-search-backward comint-input-ring-separator nil t)
-                        (setq start (match-end 0))
-                      (setq start (point-min)))
-                    (setq history (buffer-substring start end))
-                    (goto-char start)
-                    (if (and (not (string-match comint-input-history-ignore history))
-                             (or (null comint-input-ignoredups)
-                                 (ring-empty-p ring)
-                                 (not (string-equal (ring-ref ring 0) history))))
-                        (progn
-                          (ring-insert-at-beginning ring history)
-                          (setq count (1+ count)))))))
-            (kill-buffer history-buf))
+          (with-temp-buffer
+             (insert-file-contents file)
+             ;; Save restriction in case file is already visited...
+             ;; Watch for those date stamps in history files!
+             (goto-char (point-max))
+             (let (start end history)
+               (while (and (< count size)
+                           (re-search-backward comint-input-ring-separator
+                                               nil t)
+                           (setq end (match-beginning 0)))
+                 (setq start
+                       (if (re-search-backward comint-input-ring-separator
+                                               nil t)
+                           (match-end 0)
+                         (point-min)))
+                 (setq history (buffer-substring start end))
+                 (goto-char start)
+                 (if (and (not (string-match comint-input-history-ignore
+                                             history))
+                          (or (null comint-input-ignoredups)
+                              (ring-empty-p ring)
+                              (not (string-equal (ring-ref ring 0)
+                                                 history))))
+                     (progn
+                       (ring-insert-at-beginning ring history)
+                       (setq count (1+ count)))))))
           (setq comint-input-ring ring
                 comint-input-ring-index nil)))))
 
@@ -946,8 +973,7 @@ See also `comint-read-input-ring'."
                (index (ring-length ring)))
           ;; Write it all out into a buffer first.  Much faster, but messier,
           ;; than writing it one line at a time.
-          (save-excursion
-            (set-buffer history-buf)
+          (with-current-buffer history-buf
             (erase-buffer)
             (while (> index 0)
               (setq index (1- index))
@@ -962,7 +988,6 @@ See also `comint-read-input-ring'."
   "Choose the input history entry that point is in or next to."
   (interactive)
   (let ((buffer completion-reference-buffer)
-        (base-size completion-base-size)
         beg end completion)
     (if (and (not (eobp)) (get-text-property (point) 'mouse-face))
        (setq end (point) beg (1+ (point))))
@@ -974,10 +999,10 @@ See also `comint-read-input-ring'."
     (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)))
+    (choose-completion-string completion buffer)))
 
 (defun comint-dynamic-list-input-ring ()
-  "List in help buffer the buffer's input history."
+  "Display a list of recent inputs entered into the current buffer."
   (interactive)
   (if (or (not (ring-p comint-input-ring))
          (ring-empty-p comint-input-ring))
@@ -987,9 +1012,10 @@ See also `comint-read-input-ring'."
          (index (1- (ring-length comint-input-ring)))
          (conf (current-window-configuration)))
       ;; We have to build up a list ourselves from the ring vector.
-      (while (>= index 0)
-       (setq history (cons (ring-ref comint-input-ring index) history)
-             index (1- index)))
+      (dotimes (index (ring-length comint-input-ring))
+       (push (ring-ref comint-input-ring index) history))
+      ;; Show them most-recent-first.
+      (setq history (nreverse history))
       ;; Change "completion" to "history reference"
       ;; to make the display accurate.
       (with-output-to-temp-buffer history-buffer
@@ -1268,10 +1294,9 @@ than the logical beginning of line."
                   (message "Relative reference exceeds input history size"))))
              ((or (looking-at "!!?:?\\([0-9^$*-]+\\)") (looking-at "!!"))
               ;; Just a number of args from the previous input line.
-              (replace-match
-               (comint-args (comint-previous-input-string 0)
-                            (match-beginning 1) (match-end 1))
-               t t)
+              (replace-match (comint-args (comint-previous-input-string 0)
+                                          (match-beginning 1) (match-end 1))
+                             t t)
               (message "History item: previous"))
              ((looking-at
                "!\\??\\({\\(.+\\)}\\|\\(\\sw+\\)\\)\\(:?[0-9^$*-]+\\)?")
@@ -1320,6 +1345,198 @@ A useful command to bind to SPC.  See `comint-replace-by-expanded-history'."
   (comint-replace-by-expanded-history)
   (self-insert-command arg))
 \f
+;; Isearch in comint input history
+
+(defcustom comint-history-isearch nil
+  "Non-nil to Isearch in input history only, not in comint buffer output.
+If t, usual Isearch keys like `C-r' and `C-M-r' in comint mode search
+in the input history.
+If `dwim', Isearch keys search in the input history only when initial
+point position is at the comint command line.  When starting Isearch
+from other parts of the comint buffer, they search in the comint buffer.
+If nil, Isearch operates on the whole comint buffer."
+  :type '(choice (const :tag "Don't search in input history" nil)
+                (const :tag "When point is on command line initially, search history" dwim)
+                (const :tag "Always search in input history" t))
+  :group 'comint
+  :version "23.2")
+
+(defun comint-history-isearch-backward ()
+  "Search for a string backward in input history using Isearch."
+  (interactive)
+  (let ((comint-history-isearch t))
+    (isearch-backward)))
+
+(defun comint-history-isearch-backward-regexp ()
+  "Search for a regular expression backward in input history using Isearch."
+  (interactive)
+  (let ((comint-history-isearch t))
+    (isearch-backward-regexp)))
+
+(defvar comint-history-isearch-message-overlay nil)
+(make-variable-buffer-local 'comint-history-isearch-message-overlay)
+
+(defun comint-history-isearch-setup ()
+  "Set up a comint for using Isearch to search the input history.
+Intended to be added to `isearch-mode-hook' in `comint-mode'."
+  (when (or (eq comint-history-isearch t)
+           (and (eq comint-history-isearch 'dwim)
+                ;; Point is at command line.
+                (comint-after-pmark-p)))
+    (setq isearch-message-prefix-add "history ")
+    (set (make-local-variable 'isearch-search-fun-function)
+        'comint-history-isearch-search)
+    (set (make-local-variable 'isearch-message-function)
+        'comint-history-isearch-message)
+    (set (make-local-variable 'isearch-wrap-function)
+        'comint-history-isearch-wrap)
+    (set (make-local-variable 'isearch-push-state-function)
+        'comint-history-isearch-push-state)
+    (add-hook 'isearch-mode-end-hook 'comint-history-isearch-end nil t)))
+
+(defun comint-history-isearch-end ()
+  "Clean up the comint after terminating Isearch in comint."
+  (if comint-history-isearch-message-overlay
+      (delete-overlay comint-history-isearch-message-overlay))
+  (setq isearch-message-prefix-add nil)
+  (setq isearch-search-fun-function nil)
+  (setq isearch-message-function nil)
+  (setq isearch-wrap-function nil)
+  (setq isearch-push-state-function nil)
+  (remove-hook 'isearch-mode-end-hook 'comint-history-isearch-end t))
+
+(defun comint-goto-input (pos)
+  "Put input history item of the absolute history position POS."
+  ;; If leaving the edit line, save partial unfinished input.
+  (if (null comint-input-ring-index)
+      (setq comint-stored-incomplete-input
+           (funcall comint-get-old-input)))
+  (setq comint-input-ring-index pos)
+  (comint-delete-input)
+  (if (and pos (not (ring-empty-p comint-input-ring)))
+      (insert (ring-ref comint-input-ring pos))
+    ;; Restore partial unfinished input.
+    (when (> (length comint-stored-incomplete-input) 0)
+      (insert comint-stored-incomplete-input))))
+
+(defun comint-history-isearch-search ()
+  "Return the proper search function, for Isearch in input history."
+  (cond
+   (isearch-word
+    (if isearch-forward 'word-search-forward 'word-search-backward))
+   (t
+    (lambda (string bound noerror)
+      (let ((search-fun
+            ;; Use standard functions to search within comint text
+             (cond
+              (isearch-regexp
+               (if isearch-forward 're-search-forward 're-search-backward))
+              (t
+               (if isearch-forward 'search-forward 'search-backward))))
+           found)
+       ;; Avoid lazy-highlighting matches in the comint prompt and in the
+       ;; output when searching forward.  Lazy-highlight calls this lambda
+       ;; with the bound arg, so skip the prompt and the output.
+       (if (and bound isearch-forward (not (comint-after-pmark-p)))
+           (goto-char (process-mark (get-buffer-process (current-buffer)))))
+        (or
+        ;; 1. First try searching in the initial comint text
+        (funcall search-fun string
+                 (if isearch-forward bound (comint-line-beginning-position))
+                 noerror)
+        ;; 2. If the above search fails, start putting next/prev history
+        ;; elements in the comint successively, and search the string
+        ;; in them.  Do this only when bound is nil (i.e. not while
+        ;; lazy-highlighting search strings in the current comint text).
+        (unless bound
+          (condition-case nil
+              (progn
+                (while (not found)
+                  (cond (isearch-forward
+                         ;; Signal an error here explicitly, because
+                         ;; `comint-next-input' doesn't signal an error.
+                         (when (null comint-input-ring-index)
+                           (error "End of history; no next item"))
+                         (comint-next-input 1)
+                         (goto-char (comint-line-beginning-position)))
+                        (t
+                         ;; Signal an error here explicitly, because
+                         ;; `comint-previous-input' doesn't signal an error.
+                         (when (eq comint-input-ring-index
+                                   (1- (ring-length comint-input-ring)))
+                           (error "Beginning of history; no preceding item"))
+                         (comint-previous-input 1)
+                         (goto-char (point-max))))
+                  (setq isearch-barrier (point) isearch-opoint (point))
+                  ;; After putting the next/prev history element, search
+                  ;; the string in them again, until comint-next-input
+                  ;; or comint-previous-input raises an error at the
+                  ;; beginning/end of history.
+                  (setq found (funcall search-fun string
+                                       (unless isearch-forward
+                                         ;; For backward search, don't search
+                                         ;; in the comint prompt
+                                         (comint-line-beginning-position))
+                                       noerror)))
+                ;; Return point of the new search result
+                (point))
+            ;; Return nil on the error "no next/preceding item"
+            (error nil)))))))))
+
+(defun comint-history-isearch-message (&optional c-q-hack ellipsis)
+  "Display the input history search prompt.
+If there are no search errors, this function displays an overlay with
+the Isearch prompt which replaces the original comint prompt.
+Otherwise, it displays the standard Isearch message returned from
+`isearch-message'."
+  (if (not (and isearch-success (not isearch-error)))
+      ;; Use standard function `isearch-message' when not in comint prompt,
+      ;; or search fails, or has an error (like incomplete regexp).
+      ;; This function displays isearch message in the echo area,
+      ;; so it's possible to see what is wrong in the search string.
+      (isearch-message c-q-hack ellipsis)
+    ;; Otherwise, put the overlay with the standard isearch prompt over
+    ;; the initial comint prompt.
+    (if (overlayp comint-history-isearch-message-overlay)
+       (move-overlay comint-history-isearch-message-overlay
+                     (save-excursion (forward-line 0) (point))
+                      (comint-line-beginning-position))
+      (setq comint-history-isearch-message-overlay
+           (make-overlay (save-excursion (forward-line 0) (point))
+                          (comint-line-beginning-position)))
+      (overlay-put comint-history-isearch-message-overlay 'evaporate t))
+    (overlay-put comint-history-isearch-message-overlay
+                'display (isearch-message-prefix c-q-hack ellipsis))
+    ;; And clear any previous isearch message.
+    (message "")))
+
+(defun comint-history-isearch-wrap ()
+  "Wrap the input history search when search fails.
+Move point to the first history element for a forward search,
+or to the last history element for a backward search."
+  (unless isearch-word
+    ;; When `comint-history-isearch-search' fails on reaching the
+    ;; beginning/end of the history, wrap the search to the first/last
+    ;; input history element.
+    (if isearch-forward
+       (comint-goto-input (1- (ring-length comint-input-ring)))
+      (comint-goto-input nil))
+    (setq isearch-success t))
+  (goto-char (if isearch-forward (comint-line-beginning-position) (point-max))))
+
+(defun comint-history-isearch-push-state ()
+  "Save a function restoring the state of input history search.
+Save `comint-input-ring-index' to the additional state parameter
+in the search status stack."
+  `(lambda (cmd)
+     (comint-history-isearch-pop-state cmd ,comint-input-ring-index)))
+
+(defun comint-history-isearch-pop-state (cmd hist-pos)
+  "Restore the input history search state.
+Go to the history element by the absolute history position HIST-POS."
+  (comint-goto-input hist-pos))
+
+\f
 (defun comint-within-quotes (beg end)
   "Return t if the number of quotes between BEG and END is odd.
 Quotes are single and double."
@@ -1731,7 +1948,8 @@ Make backspaces delete the previous character."
        (let ((functions comint-preoutput-filter-functions))
          (while (and functions string)
            (if (eq (car functions) t)
-               (let ((functions (default-value 'comint-preoutput-filter-functions)))
+               (let ((functions
+                       (default-value 'comint-preoutput-filter-functions)))
                  (while (and functions string)
                    (setq string (funcall (car functions) string))
                    (setq functions (cdr functions))))
@@ -1893,7 +2111,8 @@ This function could be on `comint-output-filter-functions' or bound to a key."
     (save-excursion
       (condition-case nil
          (goto-char
-          (if (interactive-p) comint-last-input-end comint-last-output-start))
+          (if (called-interactively-p 'interactive)
+              comint-last-input-end comint-last-output-start))
        (error nil))
       (while (re-search-forward "\r+$" pmark t)
        (replace-match "" t t)))))
@@ -2075,8 +2294,6 @@ Does not delete the prompt."
        (delete-region pmark (point))))
     ;; Output message and put back prompt
     (comint-output-filter proc replacement)))
-(define-obsolete-function-alias 'comint-kill-output
-  'comint-delete-output "21.1")
 
 (defun comint-write-output (filename &optional append mustbenew)
   "Write output from interpreter since last input to FILENAME.
@@ -2426,6 +2643,7 @@ updated using `comint-update-fence', if necessary."
        (let ((inhibit-read-only t))
          (kill-region beg end yank-handler)
          (comint-update-fence))))))
+(set-advertised-calling-convention 'comint-kill-region '(beg end) "23.3")
 
 \f
 ;; Support for source-file processing commands.
@@ -2627,13 +2845,13 @@ its response can be seen."
 ;; want them present in specific modes.
 
 (defcustom comint-completion-autolist nil
-  "*If non-nil, automatically list possibilities on partial completion.
+  "If non-nil, automatically list possibilities on partial completion.
 This mirrors the optional behavior of tcsh."
   :type 'boolean
   :group 'comint-completion)
 
 (defcustom comint-completion-addsuffix t
-  "*If non-nil, add a `/' to completed directories, ` ' to file names.
+  "If non-nil, add a `/' to completed directories, ` ' to file names.
 If a cons pair, it should be of the form (DIRSUFFIX . FILESUFFIX) where
 DIRSUFFIX and FILESUFFIX are strings added on unambiguous or exact completion.
 This mirrors the optional behavior of tcsh."
@@ -2645,7 +2863,7 @@ This mirrors the optional behavior of tcsh."
   :group 'comint-completion)
 
 (defcustom comint-completion-recexact nil
-  "*If non-nil, use shortest completion if characters cannot be added.
+  "If non-nil, use shortest completion if characters cannot be added.
 This mirrors the optional behavior of tcsh.
 
 A non-nil value is useful if `comint-completion-autolist' is non-nil too."
@@ -2653,7 +2871,7 @@ A non-nil value is useful if `comint-completion-autolist' is non-nil too."
   :group 'comint-completion)
 
 (defcustom comint-completion-fignore nil
-  "*List of suffixes to be disregarded during file completion.
+  "List of suffixes to be disregarded during file completion.
 This mirrors the optional behavior of bash and tcsh.
 
 Note that this applies to `comint-dynamic-complete-filename' only."
@@ -2661,7 +2879,7 @@ Note that this applies to `comint-dynamic-complete-filename' only."
   :group 'comint-completion)
 
 ;;;###autoload
-(defvar comint-file-name-prefix ""
+(defvar comint-file-name-prefix (purecopy "")
   "Prefix prepended to absolute file names taken from process input.
 This is used by Comint's and shell's completion functions, and by shell's
 directory tracking functions.")
@@ -2724,11 +2942,8 @@ interpreter (e.g., the percent notation of cmd.exe on NT)."
              env-var-val)
          (save-match-data
            (while (string-match "%\\([^\\\\/]*\\)%" name)
-             (setq env-var-name
-                   (substring name (match-beginning 1) (match-end 1)))
-             (setq env-var-val (if (getenv env-var-name)
-                                   (getenv env-var-name)
-                                 ""))
+             (setq env-var-name (match-string 1 name))
+             (setq env-var-val (or (getenv env-var-name) ""))
              (setq name (replace-match env-var-val t t name))))))
     name))
 
@@ -2783,7 +2998,7 @@ Completes if after a filename.  See `comint-match-partial-filename' and
 This function is similar to `comint-replace-by-expanded-filename', except that
 it won't change parts of the filename already entered in the buffer; it just
 adds completion characters to the end of the filename.  A completions listing
-may be shown in a help buffer if completion is ambiguous.
+may be shown in a separate buffer if completion is ambiguous.
 
 Completion is dependent on the value of `comint-completion-addsuffix',
 `comint-completion-recexact' and `comint-completion-fignore', and the timing of
@@ -2829,7 +3044,7 @@ See `comint-dynamic-complete-filename'.  Returns t if successful."
         (completion (file-name-completion filenondir directory)))
     (cond ((null completion)
           (if minibuffer-p
-              (minibuffer-message (format " [No completions of %s]" filename))
+              (minibuffer-message "No completions of %s" filename)
             (message "No completions of %s" filename))
           (setq success nil))
          ((eq completion t)            ; Means already completed "file".
@@ -2870,11 +3085,11 @@ See `comint-dynamic-complete-filename'.  Returns t if successful."
 
 (defun comint-replace-by-expanded-filename ()
   "Dynamically expand and complete the filename at point.
-Replace the filename with an expanded, canonicalized and completed replacement.
-\"Expanded\" means environment variables (e.g., $HOME) and `~'s are replaced
-with the corresponding directories.  \"Canonicalized\" means `..'  and `.' are
-removed, and the filename is made absolute instead of relative.  For expansion
-see `expand-file-name' and `substitute-in-file-name'.  For completion see
+Replace the filename with an expanded, canonicalized and
+completed replacement, i.e. substituting environment
+variables (e.g. $HOME), `~'s, `..', and `.', and making the
+filename absolute.  For expansion see `expand-file-name' and
+`substitute-in-file-name'.  For completion see
 `comint-dynamic-complete-filename'."
   (interactive)
   (let ((filename (comint-match-partial-filename)))
@@ -2885,15 +3100,16 @@ see `expand-file-name' and `substitute-in-file-name'.  For completion see
 
 (defun comint-dynamic-simple-complete (stub candidates)
   "Dynamically complete STUB from CANDIDATES list.
-This function inserts completion characters at point by completing STUB from
-the strings in CANDIDATES.  A completions listing may be shown in a help buffer
-if completion is ambiguous.
+This function inserts completion characters at point by
+completing STUB from the strings in CANDIDATES.  If completion is
+ambiguous, possibly show a completions listing in a separate
+buffer.
 
-Returns nil if no completion was inserted.
-Returns `sole' if completed with the only completion match.
-Returns `shortest' if completed with the shortest of the completion matches.
-Returns `partial' if completed as far as possible with the completion matches.
-Returns `listed' if a completion listing was shown.
+Return nil if no completion was inserted.
+Return `sole' if completed with the only completion match.
+Return `shortest' if completed with the shortest match.
+Return `partial' if completed as far as possible.
+Return `listed' if a completion listing was shown.
 
 See also `comint-dynamic-complete-filename'."
   (let* ((completion-ignore-case (memq system-type '(ms-dos windows-nt cygwin)))
@@ -2904,7 +3120,7 @@ See also `comint-dynamic-complete-filename'."
         (completions (all-completions stub candidates)))
     (cond ((null completions)
           (if minibuffer-p
-              (minibuffer-message (format " [No completions of %s]" stub))
+              (minibuffer-message "No completions of %s" stub)
             (message "No completions of %s" stub))
           nil)
          ((= 1 (length completions))   ; Gotcha!
@@ -2941,7 +3157,7 @@ See also `comint-dynamic-complete-filename'."
 
 
 (defun comint-dynamic-list-filename-completions ()
-  "List in help buffer possible completions of the filename at point."
+  "Display a list of possible completions for the filename at point."
   (interactive)
   (let* ((completion-ignore-case read-file-name-completion-ignore-case)
         ;; If we bind this, it breaks remote directory tracking in rlogin.el.
@@ -2955,7 +3171,7 @@ See also `comint-dynamic-complete-filename'."
         (completions (file-name-all-completions filenondir directory)))
     (if (not completions)
        (if (window-minibuffer-p (selected-window))
-           (minibuffer-message (format " [No completions of %s]" filename))
+           (minibuffer-message "No completions of %s" filename)
          (message "No completions of %s" filename))
       (comint-dynamic-list-completions
        (mapcar 'comint-quote-filename completions)
@@ -2970,9 +3186,9 @@ See also `comint-dynamic-complete-filename'."
 (defvar comint-dynamic-list-completions-config nil)
 
 (defun comint-dynamic-list-completions (completions &optional common-substring)
-  "List in help buffer sorted COMPLETIONS.
+  "Display a list of sorted COMPLETIONS.
 The meaning of COMMON-SUBSTRING is the same as in `display-completion-list'.
-Typing SPC flushes the help buffer."
+Typing SPC flushes the completions buffer."
   (let ((window (get-buffer-window "*Completions*" 0)))
     (setq completions (sort completions 'string-lessp))
     (if (and (eq last-command this-command)
@@ -3005,7 +3221,7 @@ Typing SPC flushes the help buffer."
       (with-output-to-temp-buffer "*Completions*"
        (display-completion-list completions common-substring))
       (if (window-minibuffer-p (selected-window))
-         (minibuffer-message " [Type space to flush; repeat completion command to scroll]")
+         (minibuffer-message "Type space to flush; repeat completion command to scroll")
        (message "Type space to flush; repeat completion command to scroll")))
 
     ;; Read the next key, to process SPC.
@@ -3022,7 +3238,7 @@ Typing SPC flushes the help buffer."
          ;; If the user does mouse-choose-completion with the mouse,
          ;; execute the command, then delete the completion window.
          (progn
-           (mouse-choose-completion first)
+           (choose-completion first)
            (set-window-configuration comint-dynamic-list-completions-config))
        (if (eq first ?\s)
            (set-window-configuration comint-dynamic-list-completions-config)
@@ -3062,7 +3278,7 @@ from input that has not yet been sent."
   (let ((proc (or (get-buffer-process (current-buffer))
                  (error "Current buffer has no process"))))
     (goto-char (process-mark proc))
-    (when (interactive-p)
+    (when (called-interactively-p 'interactive)
       (message "Point is now at the process mark"))))
 
 (defun comint-bol-or-process-mark ()
@@ -3134,7 +3350,7 @@ the process mark is at the beginning of the accumulated input."
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defcustom comint-redirect-verbose nil
-  "*If non-nil, print messages each time the redirection filter is invoked.
+  "If non-nil, print messages each time the redirection filter is invoked.
 Also print a message when redirection is completed."
   :group 'comint
   :type 'boolean)
@@ -3289,13 +3505,15 @@ This function does not need to be invoked by the end user."
           (list comint-redirect-output-buffer)))
        (filtered-input-string input-string))
 
-    ;; If there are any filter functions, give them a chance to modify the 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)
        (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)))
+           (let ((functions
+                   (default-value 'comint-redirect-filter-functions)))
              (while (and functions filtered-input-string)
                (setq filtered-input-string
                      (funcall (car functions) filtered-input-string))
@@ -3415,8 +3633,7 @@ Return a list of expressions in the output which match REGEXP.
 REGEXP-GROUP is the regular expression group in REGEXP to use."
   (let ((output-buffer " *Comint Redirect Work Buffer*")
        results)
-    (save-excursion
-      (set-buffer (get-buffer-create output-buffer))
+    (with-current-buffer (get-buffer-create output-buffer)
       (erase-buffer)
       (comint-redirect-send-command-to-process command
                                               output-buffer process nil t)
@@ -3431,11 +3648,10 @@ REGEXP-GROUP is the regular expression group in REGEXP to use."
       (and (looking-at command)
           (forward-line))
       (while (re-search-forward regexp nil t)
-       (setq results
-             (cons (buffer-substring-no-properties
-                    (match-beginning regexp-group)
-                    (match-end regexp-group))
-                   results)))
+       (push (buffer-substring-no-properties
+               (match-beginning regexp-group)
+               (match-end regexp-group))
+              results))
       results)))
 
 (dolist (x '("^Not at command line$"
@@ -3532,5 +3748,4 @@ REGEXP-GROUP is the regular expression group in REGEXP to use."
 
 (provide 'comint)
 
-;; arch-tag: 1793314c-09db-40be-9549-9aeae3e75164
 ;;; comint.el ends here