;;; comint.el --- general command interpreter in a window stuff
-;; Copyright (C) 1988, 90, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
+;; Copyright (C) 1988, 90, 92, 93, 94, 95, 96, 97, 98 Free Software Foundation, Inc.
;; Author: Olin Shivers <shivers@cs.cmu.edu> then
;; Simon Marshall <simon@gnu.ai.mit.edu>
;; comint-get-old-input function Hooks for specific
;; comint-input-filter-functions hook process-in-a-buffer
;; comint-output-filter-functions hook function modes.
+;; comint-preoutput-filter-functions hook
;; comint-input-filter function ...
;; comint-input-sender function ...
;; comint-eol-on-send boolean ...
`comint-last-output-start' and the buffer's `process-mark', if other filter
functions have already modified the buffer.
+See also `comint-preoutput-filter-functions'.
+
This variable is buffer-local.")
(defvar comint-input-sender (function comint-simple-send)
(put 'comint-input-autoexpand 'permanent-local t)
(put 'comint-input-filter-functions 'permanent-local t)
(put 'comint-output-filter-functions 'permanent-local t)
+(put 'comint-preoutput-filter-functions 'permanent-local t)
(put 'comint-scroll-to-bottom-on-input 'permanent-local t)
(put 'comint-scroll-to-bottom-on-output 'permanent-local t)
(put 'comint-scroll-show-maximum-output 'permanent-local t)
Input to, and output from, the subprocess can cause the window to scroll to
the end of the buffer. See variables `comint-output-filter-functions',
-`comint-scroll-to-bottom-on-input', and `comint-scroll-to-bottom-on-output'.
+`comint-preoutput-filter-functions', `comint-scroll-to-bottom-on-input',
+and `comint-scroll-to-bottom-on-output'.
If you accidentally suspend your process, use \\[comint-continue-subjob]
to continue it.
(default-directory
(if (file-accessible-directory-p default-directory)
default-directory
- "/")))
+ (char-to-string directory-sep-char))))
(apply 'start-process name buffer command switches)))
\f
;; Input history processing in a buffer
(defun comint-regexp-arg (prompt)
;; Return list of regexp and prefix arg using PROMPT.
- (let* ((minibuffer-history-sexp-flag nil)
- ;; Don't clobber this.
+ (let* (;; Don't clobber this.
(last-command last-command)
(regexp (read-from-minibuffer prompt nil nil nil
'minibuffer-history-search-history)))
(comint-previous-matching-input-from-input (- arg)))
-(defun comint-replace-by-expanded-history (&optional silent)
+(defun comint-replace-by-expanded-history (&optional silent start)
"Expand input command history references before point.
Expansion is dependent on the value of `comint-input-autoexpand'.
If the optional argument SILENT is non-nil, never complain
even if history reference seems erroneous.
+If the optional argument START is non-nil, that specifies the
+start of the text to scan for history references, rather
+than the logical beginning of line.
+
See `comint-magic-space' and `comint-replace-by-expanded-history-before-point'.
Returns t if successful."
(looking-at comint-prompt-regexp)))
;; Looks like there might be history references in the command.
(let ((previous-modified-tick (buffer-modified-tick)))
- (message "Expanding history references...")
- (comint-replace-by-expanded-history-before-point silent)
+ (comint-replace-by-expanded-history-before-point silent start)
(/= previous-modified-tick (buffer-modified-tick)))))
-(defun comint-replace-by-expanded-history-before-point (silent)
+(defun comint-replace-by-expanded-history-before-point (silent &optional start)
"Expand directory stack reference before point.
-See `comint-replace-by-expanded-history'. Returns t if successful."
+See `comint-replace-by-expanded-history'. Returns t if successful.
+
+If the optional argument START is non-nil, that specifies the
+start of the text to scan for history references, rather
+than the logical beginning of line."
(save-excursion
(let ((toend (- (save-excursion (end-of-line nil) (point)) (point)))
- (start (progn (comint-bol nil) (point))))
+ (start (or start (progn (comint-bol nil) (point)))))
(while (progn
(skip-chars-forward "^!^"
(save-excursion
(replace-match new t t)
(message "History item: substituted"))))
(t
- (goto-char (match-end 0))))))))
+ (forward-char 1)))))))
(defun comint-magic-space (arg)
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."
- (let ((argpart "[^ \n\t\"'`]+\\|\\(\"[^\"]*\"\\|'[^']*'\\|`[^`]*`\\)")
+ ;; The first line handles ordinary characters and backslash-sequences.
+ ;; The second matches "-quoted strings.
+ ;; The third matches '-quoted strings.
+ ;; The fourth matches `-quoted strings.
+ ;; This seems to fit the syntax of BASH 2.0.
+ (let ((argpart "[^ \n\t\"'`\\]+\\|\\\\[\"'`\\]+\\|\
+\\(\"\\([^\"\\]\\|\\\\.\\)*\"\\|\
+'[^']*'\\|\
+`[^`]*`\\)")
(args ()) (pos 0)
(count 0)
beg str value quotes)
;; Just whatever's already there
intxt
;; Expand and leave it visible in buffer
- (comint-replace-by-expanded-history t)
+ (comint-replace-by-expanded-history t pmark)
(buffer-substring pmark (point))))
(history (if (not (eq comint-input-autoexpand 'history))
input
;; This is messy 'cos ultimately the original
;; functions used do insertion, rather than return
;; strings. We have to expand, then insert back.
- (comint-replace-by-expanded-history t)
+ (comint-replace-by-expanded-history t pmark)
(let ((copy (buffer-substring pmark (point)))
(start (point)))
(insert input)
;; but that scrolled the buffer in undesirable ways.
(run-hook-with-args 'comint-output-filter-functions "")))))
+(defvar comint-preoutput-filter-functions nil
+ "Functions to call before output is inserted into the buffer.
+These functions get one argument, a string containing the text to be
+inserted. They return the string as it should be inserted.
+
+This variable is buffer-local.")
+
;; The purpose of using this filter for comint processes
;; is to keep comint-last-input-end from moving forward
;; when output is inserted.
(defun comint-output-filter (process string)
;; First check for killed buffer
(let ((oprocbuf (process-buffer process)))
- (if (and oprocbuf (buffer-name oprocbuf))
+ (let ((functions comint-preoutput-filter-functions))
+ (while (and functions string)
+ (setq string (funcall (car functions) string))
+ (setq functions (cdr functions))))
+ (if (and string oprocbuf (buffer-name oprocbuf))
(let ((obuf (current-buffer))
(opoint nil) (obeg nil) (oend nil))
(set-buffer oprocbuf)
(interactive)
(let ((pmark (process-mark (get-buffer-process (current-buffer)))))
(save-excursion
- (goto-char
- (if (interactive-p) comint-last-input-end comint-last-output-start))
+ (condition-case nil
+ (goto-char
+ (if (interactive-p) comint-last-input-end comint-last-output-start))
+ (error nil))
(while (re-search-forward "\r+$" pmark t)
(replace-match "" t t)))))
(defalias 'shell-strip-ctrl-m 'comint-strip-ctrl-m)
(comint-skip-prompt)))
(defun comint-interrupt-subjob ()
- "Interrupt the current subjob."
+ "Interrupt the current subjob.
+This command also kills the pending input
+between the process-mark and point."
(interactive)
+ (comint-kill-input)
(interrupt-process nil comint-ptyp))
(defun comint-kill-subjob ()
- "Send kill signal to the current subjob."
+ "Send kill signal to the current subjob.
+This command also kills the pending input
+between the process-mark and point."
(interactive)
+ (comint-kill-input)
(kill-process nil comint-ptyp))
(defun comint-quit-subjob ()
- "Send quit signal to the current subjob."
+ "Send quit signal to the current subjob.
+This command also kills the pending input
+between the process-mark and point."
(interactive)
+ (comint-kill-input)
(quit-process nil comint-ptyp))
(defun comint-stop-subjob ()
"Stop the current subjob.
+This command also kills the pending input
+between the process-mark and point.
+
WARNING: if there is no current subjob, you can end up suspending
the top-level process running in the buffer. If you accidentally do
this, use \\[comint-continue-subjob] to resume the process. (This
is not a problem with most shells, since they ignore this signal.)"
(interactive)
+ (comint-kill-input)
(stop-process nil comint-ptyp))
(defun comint-continue-subjob ()
;; Try to position the proc window so you can see the answer.
;; This is bogus code. If you delete the (sit-for 0), it breaks.
;; I don't know why. Wizards invited to improve it.
- (if (not (pos-visible-in-window-p proc-pt proc-win))
- (let ((opoint (window-point proc-win)))
- (set-window-point proc-win proc-mark)
- (sit-for 0)
- (if (not (pos-visible-in-window-p opoint proc-win))
- (push-mark opoint)
- (set-window-point proc-win opoint)))))))
+ (unless (pos-visible-in-window-p proc-pt proc-win)
+ (let ((opoint (window-point proc-win)))
+ (set-window-point proc-win proc-mark)
+ (sit-for 0)
+ (if (not (pos-visible-in-window-p opoint proc-win))
+ (push-mark opoint)
+ (set-window-point proc-win opoint)))))))
\f
;; Filename/command/history completion in a buffer
(defvar comint-file-name-chars
(if (memq system-type '(ms-dos windows-nt))
- "~/A-Za-z0-9_^$!#%&{}@`'.()-"
+ "~/A-Za-z0-9_^$!#%&{}@`'.,:()-"
"~/A-Za-z0-9+@:_.$#%,={}-")
"String of characters valid in a file name.
+Note that all non-ASCII characters are considered valid in a file name
+regardless of what this variable says.
This is a good thing to set in mode hooks.")
(defun comint-word (word-chars)
"Return the word of WORD-CHARS at point, or nil if non is found.
Word constituents are considered to be those in WORD-CHARS, which is like the
-inside of a \"[...]\" (see `skip-chars-forward')."
+inside of a \"[...]\" (see `skip-chars-forward'),
+plus all non-ASCII characters."
(save-excursion
(let ((non-word-chars (concat "[^\\\\" word-chars "]")) (here (point)))
(while (and (re-search-backward non-word-chars nil 'move)
- ;(memq (char-after (point)) shell-file-name-quote-list)
- (eq (preceding-char) ?\\))
+ ;;(memq (char-after (point)) shell-file-name-quote-list)
+ (or (>= (following-char) 128)
+ (eq (preceding-char) ?\\)))
(backward-char 1))
;; Don't go forward over a word-char (this can happen if we're at bob).
- (if (or (not (bobp)) (looking-at non-word-chars))
- (forward-char 1))
+ (when (or (not (bobp)) (looking-at non-word-chars))
+ (forward-char 1))
;; Set match-data to match the entire string.
- (if (< (point) here)
- (progn (store-match-data (list (point) here))
- (match-string 0))))))
+ (when (< (point) here)
+ (set-match-data (list (point) here))
+ (match-string 0)))))
(defun comint-substitute-in-file-name (filename)
"Return FILENAME with environment variables substituted.
Returns t if successful."
(interactive)
- (if (comint-match-partial-filename)
- (let ((directory-sep-char (if (memq system-type '(ms-dos windows-nt))
- ?\\
- ?/)))
- (prog2 (or (window-minibuffer-p (selected-window))
- (message "Completing file name..."))
- (comint-dynamic-complete-as-filename)))))
+ (when (comint-match-partial-filename)
+ (unless (window-minibuffer-p (selected-window))
+ (message "Completing file name..."))
+ (comint-dynamic-complete-as-filename)))
(defun comint-dynamic-complete-as-filename ()
"Dynamically complete at point as a filename.
;;(file-name-handler-alist nil)
(minibuffer-p (window-minibuffer-p (selected-window)))
(success t)
- (dirsuffix (cond ((not comint-completion-addsuffix) "")
- ((not (consp comint-completion-addsuffix)) "/")
- (t (car comint-completion-addsuffix))))
- (filesuffix (cond ((not comint-completion-addsuffix) "")
- ((not (consp comint-completion-addsuffix)) " ")
- (t (cdr comint-completion-addsuffix))))
+ (dirsuffix (cond ((not comint-completion-addsuffix)
+ "")
+ ((not (consp comint-completion-addsuffix))
+ (char-to-string directory-sep-char))
+ (t
+ (car comint-completion-addsuffix))))
+ (filesuffix (cond ((not comint-completion-addsuffix)
+ "")
+ ((not (consp comint-completion-addsuffix))
+ " ")
+ (t
+ (cdr comint-completion-addsuffix))))
(filename (or (comint-match-partial-filename) ""))
(pathdir (file-name-directory filename))
(pathnondir (file-name-nondirectory filename))
(setq success nil))
((eq completion t) ; Means already completed "file".
(insert filesuffix)
- (or minibuffer-p (message "Sole completion")))
+ (unless minibuffer-p
+ (message "Sole completion")))
((string-equal completion "") ; Means completion on "directory/".
(comint-dynamic-list-filename-completions))
(t ; Completion string returned.
(cond ((symbolp (file-name-completion completion directory))
;; We inserted a unique completion.
(insert (if (file-directory-p file) dirsuffix filesuffix))
- (or minibuffer-p (message "Completed")))
+ (unless minibuffer-p
+ (message "Completed")))
((and comint-completion-recexact comint-completion-addsuffix
(string-equal pathnondir completion)
(file-exists-p file))
;; It's not unique, but user wants shortest match.
(insert (if (file-directory-p file) dirsuffix filesuffix))
- (or minibuffer-p (message "Completed shortest")))
+ (unless minibuffer-p
+ (message "Completed shortest")))
((or comint-completion-autolist
(string-equal pathnondir completion))
;; It's not unique, list possible completions.
(comint-dynamic-list-filename-completions))
(t
- (or minibuffer-p (message "Partially completed")))))))
+ (unless minibuffer-p
+ (message "Partially completed")))))))
success))