;;; 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, 2009
-;; 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.
;;
;; 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
: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-ring-file-name nil
"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)
: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.")
;; 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 *\\'"
+ (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)
: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.
: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."
(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)
'("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]
(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))
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 "*"))))
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
(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)))
(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
- (with-current-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)))
- (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)))))))
- (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)))))
(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))
(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-previous-input-string 0) 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^$*-]+\\)?")
(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."
(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.
(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.
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
(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)))
(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)))
(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.
(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)
(provide 'comint)
-;; arch-tag: 1793314c-09db-40be-9549-9aeae3e75164
;;; comint.el ends here