summaryrefslogtreecommitdiff
path: root/lisp/comint.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/comint.el')
-rw-r--r--lisp/comint.el221
1 files changed, 113 insertions, 108 deletions
diff --git a/lisp/comint.el b/lisp/comint.el
index 782833cc8fd..d52623c00ae 100644
--- a/lisp/comint.el
+++ b/lisp/comint.el
@@ -330,12 +330,12 @@ This variable is buffer-local in all 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
+ :type 'natnum
:group 'comint)
(defcustom comint-input-ring-size 500
"Size of the input history ring in `comint-mode'."
- :type 'integer
+ :type 'natnum
:group 'comint
:version "23.2")
@@ -385,10 +385,12 @@ This variable is buffer-local."
"\\(?: [[:alpha:]]+ .+\\)?[[:blank:]]*[::៖][[:space:]]*\\'"
;; The ccrypt encryption dialogue doesn't end with a colon, so
;; treat it specially.
- "\\|^Enter encryption key: (repeat) *\\'")
+ "\\|^Enter encryption key: (repeat) *\\'"
+ ;; openssh-8.6p1 format: "(user@host) Password:".
+ "\\|^([^)@ \t\n]+@[^)@ \t\n]+) Password: *\\'")
"Regexp matching prompts for passwords in the inferior process.
This is used by `comint-watch-for-password-prompt'."
- :version "28.1"
+ :version "29.1"
:type 'regexp
:group 'comint)
@@ -728,6 +730,8 @@ Entry to this mode runs the hooks on `comint-mode-hook'."
(or (file-remote-p default-directory) ""))
(setq-local comint-accum-marker (make-marker))
(setq-local font-lock-defaults '(nil t))
+ (add-function :filter-return (local 'filter-buffer-substring-function)
+ #'comint--unmark-string-as-output)
(add-hook 'change-major-mode-hook 'font-lock-defontify nil t)
(add-hook 'isearch-mode-hook 'comint-history-isearch-setup nil t)
(add-hook 'completion-at-point-functions 'comint-completion-at-point nil t)
@@ -889,12 +893,13 @@ series of processes in the same Comint buffer. The hook
;; 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.
- (if (and (boundp 'system-uses-terminfo) system-uses-terminfo)
- (list (format "TERM=%s" comint-terminfo-terminal)
- "TERMCAP="
- (format "COLUMNS=%d" (window-width)))
- (list "TERM=emacs"
- (format "TERMCAP=emacs:co#%d:tc=unknown:" (window-width)))))
+ (with-connection-local-variables
+ (if system-uses-terminfo
+ (list (format "TERM=%s" comint-terminfo-terminal)
+ "TERMCAP="
+ (format "COLUMNS=%d" (window-width)))
+ (list "TERM=emacs"
+ (format "TERMCAP=emacs:co#%d:tc=unknown:" (window-width))))))
(defun comint-nonblank-p (str)
"Return non-nil if STR contains non-whitespace syntax."
@@ -1105,7 +1110,8 @@ See also `comint-read-input-ring'."
(use-local-map keymap))
(forward-line 3)
(while (search-backward "completion" nil 'move)
- (replace-match "history reference")))
+ (replace-match (apply #'propertize "history reference"
+ (text-properties-at (point))))))
(sit-for 0)
(message "Hit space to flush")
(setq comint-dynamic-list-input-ring-window-conf conf)
@@ -1460,7 +1466,7 @@ A useful command to bind to SPC. See `comint-replace-by-expanded-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
+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
@@ -1510,6 +1516,7 @@ Intended to be added to `isearch-mode-hook' in `comint-mode'."
#'comint-history-isearch-wrap)
(setq-local isearch-push-state-function
#'comint-history-isearch-push-state)
+ (setq-local isearch-lazy-count nil)
(add-hook 'isearch-mode-end-hook 'comint-history-isearch-end nil t)))
(defun comint-history-isearch-end ()
@@ -1521,6 +1528,7 @@ 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)
+ (kill-local-variable 'isearch-lazy-count)
(remove-hook 'isearch-mode-end-hook 'comint-history-isearch-end t)
(unless isearch-suspended
(custom-reevaluate-setting 'comint-history-isearch)))
@@ -1812,7 +1820,8 @@ Ignore duplicates if `comint-input-ignoredups' is non-nil."
(ring-insert comint-input-ring cmd)))
(defconst comint--prompt-rear-nonsticky
- '(field inhibit-line-move-field-capture read-only font-lock-face)
+ '( field inhibit-line-move-field-capture read-only font-lock-face
+ insert-in-front-hooks)
"Text properties we set on the prompt and don't want to leak past it.")
(defun comint-send-input (&optional no-newline artificial)
@@ -1904,6 +1913,14 @@ Similarly for Soar, Scheme, etc."
(delete-region pmark start)
copy))))
+ ;; Delete and reinsert input. This seems like a no-op, except
+ ;; for the resulting entries in the undo list: undoing this
+ ;; insertion will delete the region, moving the process mark
+ ;; back to its original position.
+ (let ((inhibit-read-only t))
+ (delete-region pmark (point))
+ (insert input))
+
(unless no-newline
(insert ?\n))
@@ -1947,7 +1964,7 @@ Similarly for Soar, Scheme, etc."
;; in case we get output amidst sending the input.
(set-marker comint-last-input-start pmark)
(set-marker comint-last-input-end (point))
- (set-marker (process-mark proc) (point))
+ (set-marker pmark (point))
;; clear the "accumulation" marker
(set-marker comint-accum-marker nil)
(let ((comint-input-sender-no-newline no-newline))
@@ -2022,7 +2039,7 @@ the start, the cdr to the end of the last prompt recognized.")
Freezes the `font-lock-face' text property in place."
(when comint-last-prompt
(with-silent-modifications
- (font-lock-prepend-text-property
+ (font-lock-append-text-property
(car comint-last-prompt)
(cdr comint-last-prompt)
'font-lock-face 'comint-highlight-prompt))
@@ -2141,14 +2158,7 @@ Make backspaces delete the previous character."
(goto-char (process-mark process)) ; In case a filter moved it.
(unless comint-use-prompt-regexp
- (with-silent-modifications
- (add-text-properties comint-last-output-start (point)
- `(rear-nonsticky
- ,comint--prompt-rear-nonsticky
- front-sticky
- (field inhibit-line-move-field-capture)
- field output
- inhibit-line-move-field-capture t))))
+ (comint--mark-as-output comint-last-output-start (point)))
;; Highlight the prompt, where we define `prompt' to mean
;; the most recent output that doesn't end with a newline.
@@ -2180,6 +2190,46 @@ Make backspaces delete the previous character."
,comint--prompt-rear-nonsticky)))
(goto-char saved-point)))))))
+(defun comint--mark-as-output (beg end)
+ (with-silent-modifications
+ (add-text-properties
+ beg end
+ `(rear-nonsticky
+ ,comint--prompt-rear-nonsticky
+ front-sticky
+ (field inhibit-line-move-field-capture)
+ field output
+ inhibit-line-move-field-capture t
+ ;; Text inserted by a user in the middle of process output
+ ;; should be marked as output. This is needed for commands
+ ;; such as `yank' or `just-one-space' which don't use
+ ;; `insert-and-inherit' and thus bypass default text property
+ ;; inheritance.
+ insert-in-front-hooks
+ (,#'comint--mark-as-output ,#'comint--mark-yanked-as-output)))))
+
+(defun comint--mark-yanked-as-output (beg end)
+ ;; `yank' removes the field text property from the text it inserts
+ ;; due to `yank-excluded-properties', so arrange for this text
+ ;; property to be reapplied in the `after-change-functions'.
+ (let (fun)
+ (setq
+ fun
+ (lambda (beg1 end1 _len1)
+ (remove-hook 'after-change-functions fun t)
+ (when (and (= beg beg1)
+ (= end end1))
+ (comint--mark-as-output beg1 end1))))
+ (add-hook 'after-change-functions fun nil t)))
+
+(defun comint--unmark-string-as-output (string)
+ (remove-list-of-text-properties
+ 0 (length string)
+ '( rear-nonsticky front-sticky field
+ inhibit-line-move-field-capture insert-in-front-hooks)
+ string)
+ string)
+
(defun comint-preinput-scroll-to-bottom ()
"Go to the end of buffer in all windows showing it.
Movement occurs if point in the selected window is not after the process mark,
@@ -2455,11 +2505,20 @@ This function could be in the list `comint-output-filter-functions'."
(when (let ((case-fold-search t))
(string-match comint-password-prompt-regexp
(string-replace "\r" "" string)))
- (let ((comint--prompt-recursion-depth (1+ comint--prompt-recursion-depth)))
- (if (> comint--prompt-recursion-depth 10)
- (message "Password prompt recursion too deep")
- (comint-send-invisible
- (string-trim string "[ \n\r\t\v\f\b\a]+" "\n+"))))))
+ ;; Use `run-at-time' in order not to pause execution of the
+ ;; process filter with a minibuffer
+ (run-at-time
+ 0 nil
+ (lambda (current-buf)
+ (with-current-buffer current-buf
+ (let ((comint--prompt-recursion-depth
+ (1+ comint--prompt-recursion-depth)))
+ (if (> comint--prompt-recursion-depth 10)
+ (message "Password prompt recursion too deep")
+ (when (get-buffer-process (current-buffer))
+ (comint-send-invisible
+ (string-trim string "[ \n\r\t\v\f\b\a]+" "\n+")))))))
+ (current-buffer))))
;; Low-level process communication
@@ -2753,7 +2812,7 @@ 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). Values of INDEX < 0 count from the end, so
-INDEX = -1 is the last argument. This command is like `M-.' in
+INDEX = -1 is the last argument. This command is like \"M-.\" in
Bash and zsh."
(interactive "P")
(unless (null index)
@@ -3136,8 +3195,8 @@ inside of a \"[...]\" (see `skip-chars-forward'), plus all non-ASCII characters.
(while (not giveup)
(let ((startpoint (point)))
(skip-chars-backward (concat "\\\\" word-chars))
- (if (and comint-file-name-quote-list
- (eq (char-before (1- (point))) ?\\))
+ (if (and (eq (char-before (1- (point))) ?\\)
+ (memq (char-before) comint-file-name-quote-list))
(forward-char -2))
;; FIXME: This isn't consistent with Bash, at least -- not
;; all non-ASCII chars should be word constituents.
@@ -3240,10 +3299,6 @@ Magic characters are those in `comint-file-name-quote-list'."
(defun comint-completion-at-point ()
(run-hook-with-args-until-success 'comint-dynamic-complete-functions))
-(define-obsolete-function-alias
- 'comint-dynamic-complete
- 'completion-at-point "24.1")
-
(defun comint-dynamic-complete-filename ()
"Dynamically complete the filename at point.
Completes if after a filename.
@@ -3324,13 +3379,6 @@ See `completion-table-with-quoting' and `comint-unquote-function'.")
(goto-char (match-end 0))
(insert filesuffix)))))))))
-(defun comint-dynamic-complete-as-filename ()
- "Dynamically complete at point as a filename.
-See `comint-dynamic-complete-filename'. Returns t if successful."
- (declare (obsolete comint-filename-completion "24.1"))
- (let ((data (comint--complete-file-name-data)))
- (completion-in-region (nth 0 data) (nth 1 data) (nth 2 data))))
-
(defun comint-replace-by-expanded-filename ()
"Dynamically expand and complete the filename at point.
Replace the filename with an expanded, canonicalized and
@@ -3345,65 +3393,6 @@ filename absolute. For expansion see `expand-file-name' and
(replace-match (expand-file-name filename) t t)
(comint-dynamic-complete-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. If completion is
-ambiguous, possibly show a completions listing in a separate
-buffer.
-
-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'."
- (declare (obsolete completion-in-region "24.1"))
- (let* ((completion-ignore-case (memq system-type '(ms-dos windows-nt cygwin)))
- (minibuffer-p (window-minibuffer-p))
- (suffix (cond ((not comint-completion-addsuffix) "")
- ((not (consp comint-completion-addsuffix)) " ")
- (t (cdr comint-completion-addsuffix))))
- (completions (all-completions stub candidates)))
- (cond ((null completions)
- (if minibuffer-p
- (minibuffer-message "No completions of %s" stub)
- (message "No completions of %s" stub))
- nil)
- ((= 1 (length completions)) ; Gotcha!
- (let ((completion (car completions)))
- (if (string-equal completion stub)
- (unless minibuffer-p
- (message "Sole completion"))
- (insert (substring completion (length stub)))
- (unless minibuffer-p
- (message "Completed")))
- (insert suffix)
- 'sole))
- (t ; There's no unique completion.
- (let ((completion (try-completion stub candidates)))
- ;; Insert the longest substring.
- (insert (substring completion (length stub)))
- (cond ((and comint-completion-recexact comint-completion-addsuffix
- (string-equal stub completion)
- (member completion completions))
- ;; It's not unique, but user wants shortest match.
- (insert suffix)
- (unless minibuffer-p
- (message "Completed shortest"))
- 'shortest)
- ((or comint-completion-autolist
- (string-equal stub completion))
- ;; It's not unique, list possible completions.
- (comint-dynamic-list-completions completions stub)
- 'listed)
- (t
- (unless minibuffer-p
- (message "Partially completed"))
- 'partial)))))))
-
(defun comint-dynamic-list-filename-completions ()
"Display a list of possible completions for the filename at point."
(interactive)
@@ -3509,6 +3498,20 @@ to send all the accumulated input, at once.
The entire accumulated text becomes one item in the input history
when you send it."
(interactive)
+ (when-let* ((proc (get-buffer-process (current-buffer)))
+ (pmark (process-mark proc))
+ ((or (marker-position comint-accum-marker)
+ (set-marker comint-accum-marker pmark)
+ t))
+ ((>= (point) comint-accum-marker pmark)))
+ ;; Delete and reinsert input. This seems like a no-op, except for
+ ;; the resulting entries in the undo list: undoing this insertion
+ ;; will delete the region, moving the accumulation marker back to
+ ;; its original position.
+ (let ((text (buffer-substring comint-accum-marker (point)))
+ (inhibit-read-only t))
+ (delete-region comint-accum-marker (point))
+ (insert text)))
(insert "\n")
(set-marker comint-accum-marker (point))
(if comint-input-ring-index
@@ -3906,10 +3909,12 @@ REGEXP-GROUP is the regular expression group in REGEXP to use."
;;; OSC escape sequences (Operating System Commands)
;;============================================================================
-;; Adding `comint-osc-process-output' to `comint-output-filter-functions'
-;; enables the interpretation of OSC escape sequences. By default, only
-;; OSC 8, for hyperlinks, is acted upon. Adding more entries to
-;; `comint-osc-handlers' allows a customized treatment of further sequences.
+;; Adding `comint-osc-process-output' to
+;; `comint-output-filter-functions' enables the interpretation of OSC
+;; escape sequences. By default, OSC 7 and 8 (for current directory
+;; and hyperlinks respectively) are acted upon. Adding more entries
+;; to `comint-osc-handlers' allows a customized treatment of further
+;; sequences.
(defvar-local comint-osc-handlers '(("7" . comint-osc-directory-tracker)
("8" . comint-osc-hyperlink-handler))
@@ -3954,9 +3959,9 @@ arguments, with point where the escape sequence was located."
;; Current directory tracking (OSC 7)
-(declare-function url-host "url-parse.el")
-(declare-function url-type "url-parse.el")
-(declare-function url-filename "url-parse.el")
+(declare-function url-host "url/url-parse.el")
+(declare-function url-type "url/url-parse.el")
+(declare-function url-filename "url/url-parse.el")
(defun comint-osc-directory-tracker (_ text)
"Update `default-directory' from OSC 7 escape sequences.