diff options
Diffstat (limited to 'lisp/comint.el')
-rw-r--r-- | lisp/comint.el | 149 |
1 files changed, 84 insertions, 65 deletions
diff --git a/lisp/comint.el b/lisp/comint.el index 56e38e24aca..fbb67360df6 100644 --- a/lisp/comint.el +++ b/lisp/comint.el @@ -78,7 +78,7 @@ ;; ;; Not bound by default in comint-mode (some are in shell mode) ;; comint-run Run a program under comint-mode -;; send-invisible Read a line w/o echo, and send to proc +;; comint-send-invisible Read a line w/o echo, and send to proc ;; comint-dynamic-complete-filename Complete filename at point. ;; comint-dynamic-list-filename-completions List completions in help buffer. ;; comint-replace-by-expanded-filename Expand and complete filename at point; @@ -263,6 +263,8 @@ See `comint-preinput-scroll-to-bottom'. This variable is buffer-local." (const this)) :group 'comint) +(defvaralias 'comint-scroll-to-bottom-on-output 'comint-move-point-for-output) + (defcustom comint-move-point-for-output nil "Controls whether interpreter output moves point to the end of the output. If nil, then output never moves point to the output. @@ -295,8 +297,6 @@ end of the current logical (not visual) line after insertion." (const :tag "Move to end of line" end-of-line)) :group 'comint) -(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. This variable applies when point is at the end of the buffer @@ -350,24 +350,26 @@ 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. +;; OpenVPN prints a prompt like: "Enter Auth Password:". +;; See ert test `comint-test-password-regexp'. (defcustom comint-password-prompt-regexp (concat "\\(^ *\\|" (regexp-opt '("Enter" "enter" "Enter same" "enter same" "Enter the" "enter the" - "Old" "old" "New" "new" "'s" "login" + "Enter Auth" "enter auth" "Old" "old" "New" "new" "'s" "login" "Kerberos" "CVS" "UNIX" " SMB" "LDAP" "PEM" "SUDO" "[sudo]" "Repeat" "Bad" "Retype") t) - " +\\)" + ;; Allow for user name to precede password equivalent (Bug#31075). + " +.*\\)" "\\(?:" (regexp-opt password-word-equivalents) "\\|Response\\)" "\\(?:\\(?:, try\\)? *again\\| (empty for no passphrase)\\| (again)\\)?" ;; "[[:alpha:]]" used to be "for", which fails to match non-English. - "\\(?: [[:alpha:]]+ .+\\)?[::៖]\\s *\\'") + "\\(?: [[:alpha:]]+ .+\\)?[[:blank:]]*[::៖][[:blank:]]*\\'") "Regexp matching prompts for passwords in the inferior process. This is used by `comint-watch-for-password-prompt'." - :version "26.1" + :version "27.1" :type 'regexp :group 'comint) @@ -429,9 +431,6 @@ 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. @@ -635,7 +634,7 @@ Input ring history expansion can be achieved with the commands Input ring expansion is controlled by the variable `comint-input-autoexpand', and addition is controlled by the variable `comint-input-ignoredups'. -Commands with no default key bindings include `send-invisible', +Commands with no default key bindings include `comint-send-invisible', `completion-at-point', `comint-dynamic-list-filename-completions', and `comint-magic-space'. @@ -1434,24 +1433,32 @@ If nil, Isearch operates on the whole comint buffer." (defun comint-history-isearch-backward () "Search for a string backward in input history using Isearch." (interactive) - (let ((comint-history-isearch t)) - (isearch-backward nil t))) + (setq comint-history-isearch t) + (isearch-backward nil t)) (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 nil t))) + (setq comint-history-isearch t) + (isearch-backward-regexp nil t)) (defvar-local comint-history-isearch-message-overlay nil) (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))) + (when (and + ;; Prompt is not empty like in Async Shell Command buffers + ;; or in finished shell buffers + (not (eq (save-excursion + (goto-char (comint-line-beginning-position)) + (forward-line 0) + (point)) + (comint-line-beginning-position))) + (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 ") (setq-local isearch-search-fun-function #'comint-history-isearch-search) @@ -1472,7 +1479,9 @@ Intended to be added to `isearch-mode-hook' in `comint-mode'." (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)) + (remove-hook 'isearch-mode-end-hook 'comint-history-isearch-end t) + (unless isearch-suspended + (custom-reevaluate-setting 'comint-history-isearch))) (defun comint-goto-input (pos) "Put input history item of the absolute history position POS." @@ -1610,8 +1619,8 @@ Go to the history element by the absolute history position HIST-POS." (defun comint-within-quotes (beg end) "Return t if the number of quotes between BEG and END is odd. Quotes are single and double." - (let ((countsq (comint-how-many-region "\\(^\\|[^\\\\]\\)'" beg end)) - (countdq (comint-how-many-region "\\(^\\|[^\\\\]\\)\"" beg end))) + (let ((countsq (comint-how-many-region "\\(^\\|[^\\]\\)'" beg end)) + (countdq (comint-how-many-region "\\(^\\|[^\\]\\)\"" beg end))) (or (= (mod countsq 2) 1) (= (mod countdq 2) 1)))) (defun comint-how-many-region (regexp beg end) @@ -1676,11 +1685,13 @@ characters), and are not considered to be delimiters." (defun comint-arguments (string nth mth) "Return from STRING the NTH to MTH arguments. NTH and/or MTH can be nil, which means the last argument. -Returned arguments are separated by single spaces. -We assume whitespace separates arguments, except within quotes -and except for a space or tab that immediately follows a backslash. -Also, a run of one or more of a single character -in `comint-delimiter-argument-list' is a separate argument. +NTH and MTH can be negative to count from the end; -1 means +the last argument. +Returned arguments are separated by single spaces. We assume +whitespace separates arguments, except within quotes and except +for a space or tab that immediately follows a backslash. Also, a +run of one or more of a single character in +`comint-delimiter-argument-list' is a separate argument. Argument 0 is the command name." ;; The first line handles ordinary characters and backslash-sequences ;; (except with w32 msdos-like shells, where backslashes are valid). @@ -1702,7 +1713,7 @@ Argument 0 is the command name." (count 0) beg str quotes) ;; Build a list of all the args until we have as many as we want. - (while (and (or (null mth) (<= count mth)) + (while (and (or (null mth) (< mth 0) (<= count mth)) (string-match argpart string pos)) ;; Apply the `literal' text property to backslash-escaped ;; characters, so that `comint-delim-arg' won't break them up. @@ -1729,8 +1740,14 @@ Argument 0 is the command name." args (if quotes (cons str args) (nconc (comint-delim-arg str) args)))) (setq count (length args)) - (let ((n (or nth (1- count))) - (m (if mth (1- (- count mth)) 0))) + (let ((n (cond + ((null nth) (1- count)) + ((>= nth 0) nth) + (t (+ count nth)))) + (m (cond + ((null mth) 0) + ((>= mth 0) (1- (- count mth))) + (t (1- (- mth)))))) (mapconcat (function (lambda (a) a)) (nthcdr n (nreverse (nthcdr m args))) " ")))) @@ -2056,20 +2073,6 @@ Make backspaces delete the previous character." (goto-char (process-mark process)) (set-marker comint-last-output-start (point)) - ;; Try to skip repeated prompts, which can occur as a result of - ;; commands sent without inserting them in the buffer. - (let ((bol (save-excursion (forward-line 0) (point)))) ;No fields. - (when (and (not (bolp)) - (looking-back comint-prompt-regexp bol)) - (let* ((prompt (buffer-substring bol (point))) - (prompt-re (concat "\\`" (regexp-quote prompt)))) - (while (string-match prompt-re string) - (setq string (substring string (match-end 0))))))) - (while (string-match (concat "\\(^" comint-prompt-regexp - "\\)\\1+") - string) - (setq string (replace-match "\\1" nil nil string))) - ;; insert-before-markers is a bad thing. XXX ;; Luckily we don't have to use it any more, we use ;; window-point-insertion-type instead. @@ -2232,7 +2235,7 @@ This function could be on `comint-output-filter-functions' or bound to a key." (error nil)) (while (re-search-forward "\r+$" pmark t) (replace-match "" t t))))) -(defalias 'shell-strip-ctrl-m 'comint-strip-ctrl-m) +(define-obsolete-function-alias 'shell-strip-ctrl-m #'comint-strip-ctrl-m "27.1") (defun comint-show-maximum-output () "Put the end of the buffer at the bottom of the window." @@ -2281,8 +2284,10 @@ If this takes us past the end of the current line, don't skip at all." (defun comint-after-pmark-p () "Return t if point is after the process output marker." - (let ((pmark (process-mark (get-buffer-process (current-buffer))))) - (<= (marker-position pmark) (point)))) + (let ((process (get-buffer-process (current-buffer)))) + (when process + (let ((pmark (process-mark process))) + (<= (marker-position pmark) (point)))))) (defun comint-simple-send (proc string) "Default function for sending to PROC input STRING. @@ -2340,9 +2345,9 @@ a buffer local variable." ;; These three functions are for entering text you don't want echoed or ;; saved -- typically passwords to ftp, telnet, or somesuch. -;; Just enter m-x send-invisible and type in your line. +;; Just enter m-x comint-send-invisible and type in your line. -(defun send-invisible (&optional prompt) +(defun comint-send-invisible (&optional prompt) "Read a string without echoing. Then send it to the process running in the current buffer. The string is sent using `comint-input-sender'. @@ -2365,18 +2370,19 @@ Security bug: your string can still be temporarily recovered with (message "Warning: text will be echoed"))) (error "Buffer %s has no process" (current-buffer))))) +(define-obsolete-function-alias 'send-invisible #'comint-send-invisible "27.1") + (defun comint-watch-for-password-prompt (string) "Prompt in the minibuffer for password and send without echoing. -This function uses `send-invisible' to read and send a password to the buffer's -process if STRING contains a password prompt defined by -`comint-password-prompt-regexp'. +Looks for a match to `comint-password-prompt-regexp' in order +to detect the need to (prompt and) send a password. This function could be in the list `comint-output-filter-functions'." (when (let ((case-fold-search t)) (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))) - (send-invisible string))) + (comint-send-invisible string))) ;; Low-level process communication @@ -2517,13 +2523,16 @@ Useful if you accidentally suspend the top-level process." (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." +This means mark it as if it had been sent as input, without +sending it. The command keys used to trigger the command that +called this function are inserted into the buffer." (let ((comint-input-sender 'ignore) (comint-input-filter-functions nil)) (comint-send-input t t)) (end-of-line) (let ((pos (point)) - (marker (process-mark (get-buffer-process (current-buffer))))) + (marker (process-mark (get-buffer-process (current-buffer)))) + (inhibit-read-only t)) (insert " " (key-description (this-command-keys))) (if (= marker pos) (set-marker marker (point))))) @@ -2643,8 +2652,17 @@ text matching `comint-prompt-regexp'." (defvar-local comint-insert-previous-argument-last-start-pos nil) (defvar-local comint-insert-previous-argument-last-index nil) -;; Needs fixing: -;; make comint-arguments understand negative indices as bash does +(defcustom comint-insert-previous-argument-from-end nil + "If non-nil, `comint-insert-previous-argument' counts args from the end. +If this variable is nil, the default, `comint-insert-previous-argument' +counts the arguments from the beginning; if non-nil, it counts from +the end instead. This allows to emulate the behavior of `ESC-NUM ESC-.' +in both Bash and zsh: in Bash, `number' counts from the +beginning (variable is nil), while in zsh, it counts from the end." + :type 'boolean + :group 'comint + :version "27.1") + (defun comint-insert-previous-argument (index) "Insert the INDEXth argument from the previous Comint command-line at point. Spaces are added at beginning and/or end of the inserted string if @@ -2652,8 +2670,9 @@ necessary to ensure that it's separated from adjacent arguments. Interactively, if no prefix argument is given, the last argument is inserted. Repeated interactive invocations will cycle through the same argument from progressively earlier commands (using the value of INDEX specified -with the first command). -This command is like `M-.' in bash." +with the first command). Values of INDEX < 0 count from the end, so +INDEX = -1 is the last argument. This command is like `M-.' in +Bash and zsh." (interactive "P") (unless (null index) (setq index (prefix-numeric-value index))) @@ -2663,6 +2682,9 @@ This command is like `M-.' in bash." (setq index comint-insert-previous-argument-last-index)) (t ;; This is a non-repeat invocation, so initialize state. + (when (and index + comint-insert-previous-argument-from-end) + (setq index (- index))) (setq comint-input-ring-index nil) (setq comint-insert-previous-argument-last-index index) (when (null comint-insert-previous-argument-last-start-pos) @@ -2678,9 +2700,6 @@ This command is like `M-.' in bash." (set-marker comint-insert-previous-argument-last-start-pos (point)) ;; Insert the argument. (let ((input-string (comint-previous-input-string 0))) - (when (string-match "[ \t\n]*&" input-string) - ;; strip terminating '&' - (setq input-string (substring input-string 0 (match-beginning 0)))) (insert (comint-arguments input-string index index))) ;; Make next invocation return arg from previous input (setq comint-input-ring-index (1+ (or comint-input-ring-index 0))) @@ -3060,7 +3079,7 @@ interpreter (e.g., the percent notation of cmd.exe on Windows)." (let (env-var-name env-var-val) (save-match-data - (while (string-match "%\\([^\\\\/]*\\)%" name) + (while (string-match "%\\([^\\/]*\\)%" 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)))))) @@ -3452,7 +3471,7 @@ the process mark is at the beginning of the accumulated input." (message "Process mark set"))) -;; Author: Peter Breton <pbreton@cs.umb.edu> +;; 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, |