;;; comint.el --- general command interpreter in a window stuff -*- lexical-binding: t -*-
-;; Copyright (C) 1988, 1990, 1992-2012 Free Software Foundation, Inc.
+;; Copyright (C) 1988, 1990, 1992-2013 Free Software Foundation, Inc.
;; Author: Olin Shivers <shivers@cs.cmu.edu>
;; Simon Marshall <simon@gnu.org>
"Completion facilities in comint."
:group 'comint)
-(defgroup comint-source nil
- "Source finding facilities in comint."
- :prefix "comint-"
- :group 'comint)
+;; Unused.
+;;; (defgroup comint-source nil
+;;; "Source finding facilities in comint."
+;;; :prefix "comint-"
+;;; :group 'comint)
(defvar comint-prompt-regexp "^"
"Regexp to recognize prompts in the inferior process.
If the value is `input', then the expansion is seen on input.
If the value is `history', then the expansion is only when inserting
into the buffer's input ring. See also `comint-magic-space' and
-`comint-dynamic-complete'.
+`completion-at-point'.
This variable is buffer-local."
:type '(choice (const :tag "off" nil)
'("password" "Password" "passphrase" "Passphrase"
"pass phrase" "Pass phrase" "Response"))
"\\(?:\\(?:, try\\)? *again\\| (empty for no passphrase)\\| (again)\\)?\
-\\(?: for [^:]+\\)?:\\s *\\'")
+\\(?: for .+\\)?:\\s *\\'")
"Regexp matching prompts for passwords in the inferior process.
This is used by `comint-watch-for-password-prompt'."
:version "24.1"
'(comint-c-a-p-replace-by-expanded-history comint-filename-completion)
"List of functions called to perform completion.
Works like `completion-at-point-functions'.
-See also `comint-dynamic-complete'.
+See also `completion-at-point'.
This is a good thing to set in mode hooks.")
and addition is controlled by the variable `comint-input-ignoredups'.
Commands with no default key bindings include `send-invisible',
-`comint-dynamic-complete', `comint-dynamic-list-filename-completions', and
+`completion-at-point', `comint-dynamic-list-filename-completions', and
`comint-magic-space'.
Input to, and output from, the subprocess can cause the window to scroll to
Entry to this mode runs the hooks on `comint-mode-hook'."
(setq mode-line-process '(":%s"))
- (set (make-local-variable 'window-point-insertion-type) t)
- (set (make-local-variable 'comint-last-input-start) (point-min-marker))
- (set (make-local-variable 'comint-last-input-end) (point-min-marker))
- (set (make-local-variable 'comint-last-output-start) (make-marker))
+ (setq-local window-point-insertion-type t)
+ (setq-local comint-last-input-start (point-min-marker))
+ (setq-local comint-last-input-end (point-min-marker))
+ (setq-local comint-last-output-start (make-marker))
(make-local-variable 'comint-last-prompt-overlay)
(make-local-variable 'comint-prompt-regexp) ; Don't set; default
(make-local-variable 'comint-input-ring-size) ; ...to global val.
(make-local-variable 'comint-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))
+ (setq-local comint-file-name-prefix
+ (or (file-remote-p default-directory) ""))
+ (setq-local comint-accum-marker (make-marker))
+ (setq-local 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)
(add-hook 'completion-at-point-functions 'comint-completion-at-point nil t)
;; This behavior is not useful in comint buffers, and is annoying
- (set (make-local-variable 'next-line-add-newlines) nil))
+ (setq-local next-line-add-newlines nil))
(defun comint-check-proc (buffer)
"Return non-nil if there is a living process associated w/buffer BUFFER.
(open-network-stream name buffer (car command) (cdr command))
(comint-exec-1 name buffer command switches))))
(set-process-filter proc 'comint-output-filter)
- (make-local-variable 'comint-ptyp)
- (setq comint-ptyp process-connection-type) ; t if pty, nil if pipe.
+ (setq-local comint-ptyp process-connection-type) ; t if pty, nil if pipe.
;; Jump to the end, and set the process mark.
(goto-char (point-max))
(set-marker (process-mark proc) (point))
(setq comint-stored-incomplete-input
(funcall comint-get-old-input)))
(setq comint-input-ring-index pos)
- (message "History item: %d" (1+ pos))
+ (unless isearch-mode
+ (message "History item: %d" (1+ pos)))
(comint-delete-input)
(insert (ring-ref comint-input-ring pos)))))
(let ((comint-history-isearch t))
(isearch-backward-regexp)))
-(defvar comint-history-isearch-message-overlay nil)
-(make-variable-buffer-local 'comint-history-isearch-message-overlay)
+(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.
;; 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)
+ (setq-local isearch-search-fun-function
+ #'comint-history-isearch-search)
+ (setq-local isearch-message-function
+ #'comint-history-isearch-message)
+ (setq-local isearch-wrap-function
+ #'comint-history-isearch-wrap)
+ (setq-local 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 ()
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'."
+the function `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).
(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 "")))
+ (if (and comint-input-ring-index (not ellipsis))
+ ;; Display the current history index.
+ (message "History item: %d" (1+ comint-input-ring-index))
+ ;; Or clear a previous isearch message.
+ (message ""))))
(defun comint-history-isearch-wrap ()
"Wrap the input history search when search fails.
(concat input "\n")))
(let ((beg (marker-position pmark))
- (end (if no-newline (point) (1- (point))))
- (inhibit-modification-hooks t))
- (when (> end beg)
- (add-text-properties beg end
- '(front-sticky t
- font-lock-face comint-highlight-input))
- (unless comint-use-prompt-regexp
- ;; Give old user input a field property of `input', to
- ;; distinguish it from both process output and unsent
- ;; input. The terminating newline is put into a special
- ;; `boundary' field to make cursor movement between input
- ;; and output fields smoother.
- (add-text-properties
- beg end
- '(mouse-face highlight
- help-echo "mouse-2: insert after prompt as new input"))))
- (unless (or no-newline comint-use-prompt-regexp)
- ;; Cover the terminating newline
- (add-text-properties end (1+ end)
- '(rear-nonsticky t
- field boundary
- inhibit-line-move-field-capture t))))
+ (end (if no-newline (point) (1- (point)))))
+ (with-silent-modifications
+ (when (> end beg)
+ (add-text-properties beg end
+ '(front-sticky t
+ font-lock-face comint-highlight-input))
+ (unless comint-use-prompt-regexp
+ ;; Give old user input a field property of `input', to
+ ;; distinguish it from both process output and unsent
+ ;; input. The terminating newline is put into a special
+ ;; `boundary' field to make cursor movement between input
+ ;; and output fields smoother.
+ (add-text-properties
+ beg end
+ '(mouse-face highlight
+ help-echo "mouse-2: insert after prompt as new input"))))
+ (unless (or no-newline comint-use-prompt-regexp)
+ ;; Cover the terminating newline
+ (add-text-properties end (1+ end)
+ '(rear-nonsticky t
+ field boundary
+ inhibit-line-move-field-capture t)))))
(comint-snapshot-last-prompt)
(let ((echo-len (- comint-last-input-end
comint-last-input-start)))
;; Wait for all input to be echoed:
- (while (and (accept-process-output proc)
- (> (+ comint-last-input-end echo-len)
+ (while (and (> (+ comint-last-input-end echo-len)
(point-max))
+ (accept-process-output proc)
(zerop
(compare-buffer-substrings
nil comint-last-input-start
Freeze its attributes in place, even when more input comes along
and moves the prompt overlay."
(when comint-last-prompt-overlay
- (let ((inhibit-read-only t)
- (inhibit-modification-hooks t))
- (add-text-properties (overlay-start comint-last-prompt-overlay)
- (overlay-end comint-last-prompt-overlay)
- (overlay-properties comint-last-prompt-overlay)))))
+ (let ((inhibit-read-only t))
+ (with-silent-modifications
+ (add-text-properties
+ (overlay-start comint-last-prompt-overlay)
+ (overlay-end comint-last-prompt-overlay)
+ (overlay-properties comint-last-prompt-overlay))))))
(defun comint-carriage-motion (start end)
"Interpret carriage control characters in the region from START to END.
(run-hook-with-args 'comint-output-filter-functions string)
(set-marker saved-point (point))
- (goto-char (process-mark process)) ; in case a filter moved it
+ (goto-char (process-mark process)) ; In case a filter moved it.
(unless comint-use-prompt-regexp
- (let ((inhibit-read-only t)
- (inhibit-modification-hooks t))
+ (with-silent-modifications
(add-text-properties comint-last-output-start (point)
'(front-sticky
(field inhibit-line-move-field-capture)
;; Highlight the prompt, where we define `prompt' to mean
;; the most recent output that doesn't end with a newline.
(let ((prompt-start (save-excursion (forward-line 0) (point)))
- (inhibit-read-only t)
- (inhibit-modification-hooks t))
+ (inhibit-read-only t))
(when comint-prompt-read-only
- (or (= (point-min) prompt-start)
- (get-text-property (1- prompt-start) 'read-only)
- (put-text-property
- (1- prompt-start) prompt-start 'read-only 'fence))
- (add-text-properties
- prompt-start (point)
- '(read-only t rear-nonsticky t front-sticky (read-only))))
+ (with-silent-modifications
+ (or (= (point-min) prompt-start)
+ (get-text-property (1- prompt-start) 'read-only)
+ (put-text-property
+ (1- prompt-start) prompt-start 'read-only 'fence))
+ (add-text-properties
+ prompt-start (point)
+ '(read-only t rear-nonsticky t front-sticky (read-only)))))
(unless (and (bolp) (null comint-last-prompt-overlay))
;; Need to create or move the prompt overlay (in the case
;; where there is no prompt ((bolp) == t), we still do
(if (and comint-scroll-to-bottom-on-input
(memq this-command '(self-insert-command comint-magic-space yank
hilit-yank)))
- (let* ((selected (selected-window))
- (current (current-buffer))
+ (let* ((current (current-buffer))
(process (get-buffer-process current))
(scroll comint-scroll-to-bottom-on-input))
(if (and process (< (point) (process-mark process)))
(lambda (window)
(if (and (eq (window-buffer window) current)
(or (eq scroll t) (eq scroll 'all)))
- (progn
- (select-window window)
- (goto-char (point-max))
- (select-window selected))))
+ (with-selected-window window
+ (goto-char (point-max)))))
nil t))))))
(defvar follow-mode)
((bound-and-true-p follow-mode)
(follow-comint-scroll-to-bottom))
(t
- (let ((selected (selected-window)))
- (dolist (w (get-buffer-window-list current nil t))
- (select-window w)
- (unwind-protect
- (progn
- (comint-adjust-point selected)
- ;; Optionally scroll to the bottom of the window.
- (and comint-scroll-show-maximum-output
- (eobp)
- (recenter (- -1 scroll-margin))))
- (select-window selected))))))
+ (dolist (w (get-buffer-window-list current nil t))
+ (comint-adjust-window-point w process)
+ ;; Optionally scroll to the bottom of the window.
+ (and comint-scroll-show-maximum-output
+ (eq (window-point w) (point-max))
+ (with-selected-window w
+ (recenter (- -1 scroll-margin)))))))
(set-buffer current))))
+
+(defun comint-adjust-window-point (window process)
+ "Move point in WINDOW based on Comint settings.
+For point adjustment use the process-mark of PROCESS."
+ (and (< (window-point window) (process-mark process))
+ (or (memq comint-move-point-for-output '(t all))
+ ;; Maybe user wants point to jump to end.
+ (eq comint-move-point-for-output
+ (if (eq (selected-window) window) 'this 'others))
+ ;; If point was at the end, keep it at end.
+ (and (marker-position comint-last-output-start)
+ (>= (window-point window) comint-last-output-start)))
+ (set-window-point window (process-mark process))))
+
+
+;; this function is nowhere used
(defun comint-adjust-point (selected)
"Move point in the selected window based on Comint settings.
SELECTED is the window that was originally selected."
(comint-next-prompt (- n)))
;; State used by `comint-insert-previous-argument' when cycling.
-(defvar comint-insert-previous-argument-last-start-pos nil)
-(make-variable-buffer-local 'comint-insert-previous-argument-last-start-pos)
-(defvar comint-insert-previous-argument-last-index nil)
-(make-variable-buffer-local 'comint-insert-previous-argument-last-index)
+(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
If the character after point does not have a front-sticky
read-only property, any read-only property of `fence' on the
preceding newline is removed."
- (let* ((pt (point)) (lst (get-text-property pt 'front-sticky))
- (inhibit-modification-hooks t))
+ (let* ((pt (point)) (lst (get-text-property pt 'front-sticky)))
(and (bolp)
(not (bobp))
- (if (and (get-text-property pt 'read-only)
- (if (listp lst) (memq 'read-only lst) t))
- (unless (get-text-property (1- pt) 'read-only)
- (put-text-property (1- pt) pt 'read-only 'fence))
- (when (eq (get-text-property (1- pt) 'read-only) 'fence)
- (remove-list-of-text-properties (1- pt) pt '(read-only)))))))
+ (with-silent-modifications
+ (if (and (get-text-property pt 'read-only)
+ (if (listp lst) (memq 'read-only lst) t))
+ (unless (get-text-property (1- pt) 'read-only)
+ (put-text-property (1- pt) pt 'read-only 'fence))
+ (when (eq (get-text-property (1- pt) 'read-only) 'fence)
+ (remove-list-of-text-properties (1- pt) pt '(read-only))))))))
(defun comint-kill-whole-line (&optional count)
"Kill current line, ignoring read-only and field properties.
(if (and buff
(buffer-modified-p buff)
(y-or-n-p (format "Save buffer %s first? " (buffer-name buff))))
- ;; save BUFF.
- (let ((old-buffer (current-buffer)))
- (set-buffer buff)
- (save-buffer)
- (set-buffer old-buffer)))))
+ (with-current-buffer buff
+ (save-buffer)))))
(defun comint-extract-string ()
"Return string around point, or nil."
;; Useful completion functions, courtesy of the Ergo group.
;; Six commands:
-;; comint-dynamic-complete Complete or expand command, filename,
+;; completion-at-point Complete or expand command, filename,
;; history at point.
;; comint-dynamic-complete-filename Complete filename at point.
;; comint-dynamic-list-filename-completions List completions in help buffer.
;; These are not installed in the comint-mode keymap. But they are
;; available for people who want them. Shell-mode installs them:
-;; (define-key shell-mode-map "\t" 'comint-dynamic-complete)
+;; (define-key shell-mode-map "\t" 'completion-at-point)
;; (define-key shell-mode-map "\M-?"
;; 'comint-dynamic-list-filename-completions)))
;;
;; Read the next key, to process SPC.
(let (key first)
(if (with-current-buffer (get-buffer "*Completions*")
- (set (make-local-variable 'comint-displayed-dynamic-completions)
- completions)
+ (setq-local comint-displayed-dynamic-completions
+ completions)
(setq key (read-key-sequence nil)
first (aref key 0))
(and (consp first) (consp (event-start first))
string, and that there ought to be at least one copy of your prompt string
in the process buffer already.")
-(defvar comint-redirect-original-filter-function nil
- "The process filter that was in place when redirection is started.
-When redirection is completed, the process filter is restored to
-this value.")
-
(defvar comint-redirect-subvert-readonly nil
"Non-nil means `comint-redirect' can insert into read-only buffers.
This works by binding `inhibit-read-only' around the insertion.
This is useful, for instance, for insertion into Help mode buffers.
You probably want to set it locally to the output buffer.")
+(defvar comint-redirect-previous-input-string nil
+ "Last redirected line of text.
+Allows detection of the end of the redirection in case the
+completion string is split between two output segments.")
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
and does not normally need to be invoked by the end user or programmer."
(with-current-buffer comint-buffer
- (make-local-variable 'comint-redirect-original-mode-line-process)
- (setq comint-redirect-original-mode-line-process mode-line-process)
+ (setq-local comint-redirect-original-mode-line-process mode-line-process)
- (make-local-variable 'comint-redirect-output-buffer)
- (setq comint-redirect-output-buffer output-buffer)
+ (setq-local comint-redirect-output-buffer output-buffer)
- (make-local-variable 'comint-redirect-finished-regexp)
- (setq comint-redirect-finished-regexp finished-regexp)
+ (setq-local comint-redirect-finished-regexp finished-regexp)
- (make-local-variable 'comint-redirect-echo-input)
- (setq comint-redirect-echo-input echo-input)
+ (setq-local comint-redirect-echo-input echo-input)
- (make-local-variable 'comint-redirect-completed)
- (setq comint-redirect-completed nil)
+ (setq-local comint-redirect-completed nil)
+
+ (setq-local comint-redirect-previous-input-string "")
(setq mode-line-process
(if mode-line-process
(defun comint-redirect-cleanup ()
"End a Comint redirection. See `comint-redirect-send-command'."
(interactive)
+ ;; Release the last redirected string
+ (setq comint-redirect-previous-input-string nil)
;; Restore the process filter
- (set-process-filter (get-buffer-process (current-buffer))
- comint-redirect-original-filter-function)
+ (remove-function (process-filter (get-buffer-process (current-buffer)))
+ #'comint-redirect-filter)
;; Restore the mode line
(setq mode-line-process comint-redirect-original-mode-line-process)
;; Set the completed flag
;; that it really occurs.
(defalias 'comint-redirect-remove-redirection 'comint-redirect-cleanup)
-(defun comint-redirect-filter (process input-string)
+(defun comint-redirect-filter (orig-filter process input-string)
"Filter function which redirects output from PROCESS to a buffer or buffers.
The variable `comint-redirect-output-buffer' says which buffer(s) to
place output in.
(comint-redirect-preoutput-filter input-string)
;; If we have to echo output, give it to the original filter function
(and comint-redirect-echo-input
- comint-redirect-original-filter-function
- (funcall comint-redirect-original-filter-function
- process input-string)))))
+ orig-filter
+ (funcall orig-filter process input-string)))))
(defun comint-redirect-preoutput-filter (input-string)
;; Message
(and comint-redirect-verbose
- (message "Redirected output to buffer(s) %s"
- (mapconcat 'identity output-buffer-list " ")))
+ (message "Redirected output to buffer(s) %s" output-buffer-list))
;; If we see the prompt, tidy up
;; We'll look for the prompt in the original string, so nobody can
;; clobber it
- (and (string-match comint-redirect-finished-regexp input-string)
+ (and (string-match comint-redirect-finished-regexp
+ (concat comint-redirect-previous-input-string
+ input-string))
(progn
(and comint-redirect-verbose
(message "Redirection completed"))
(comint-redirect-cleanup)
(run-hooks 'comint-redirect-hook)))
+ (setq comint-redirect-previous-input-string input-string)
+
;; Echo input?
(if comint-redirect-echo-input
filtered-input-string
comint-prompt-regexp ; Finished Regexp
echo) ; Echo input
- ;; Set the filter
- (setq comint-redirect-original-filter-function ; Save the old filter
- (process-filter proc))
- (set-process-filter proc 'comint-redirect-filter)
+ ;; Set the filter.
+ (add-function :around (process-filter proc) #'comint-redirect-filter)
;; Send the command
(process-send-string (current-buffer) (concat command "\n"))
;; (setq shell-mode-map (copy-keymap comint-mode-map))
;; (define-key shell-mode-map "\C-c\C-f" 'shell-forward-command)
;; (define-key shell-mode-map "\C-c\C-b" 'shell-backward-command)
-;; (define-key shell-mode-map "\t" 'comint-dynamic-complete)
+;; (define-key shell-mode-map "\t" 'completion-at-point)
;; (define-key shell-mode-map "\M-?"
;; 'comint-dynamic-list-filename-completions)))
;;
;; (setq major-mode 'shell-mode)
;; (setq mode-name "Shell")
;; (use-local-map shell-mode-map)
-;; (make-local-variable 'shell-directory-stack)
-;; (setq shell-directory-stack nil)
+;; (setq-local shell-directory-stack nil)
;; (add-hook 'comint-input-filter-functions 'shell-directory-tracker)
;; (run-mode-hooks 'shell-mode-hook))
;;