;;; comint.el --- general command interpreter in a window stuff
-;; Copyright (C) 1988, 90, 92, 93, 94, 95, 96, 97, 98, 99, 2000
+;; Copyright (C) 1988, 90, 92, 93, 94, 95, 96, 97, 98, 99, 2000, 2001
;; Free Software Foundation, Inc.
-;; Author: Olin Shivers <shivers@cs.cmu.edu> then
+;; Author: Olin Shivers <shivers@cs.cmu.edu>
;; Simon Marshall <simon@gnu.org>
;; Maintainer: FSF
;; Keywords: processes
;; comint-run Run a program under comint-mode
;; send-invisible Read a line w/o echo, and send to proc
;; comint-dynamic-complete-filename Complete filename at point.
-;; comint-dynamic-complete-variable Complete variable name at point.
;; comint-dynamic-list-filename-completions List completions in help buffer.
;; comint-replace-by-expanded-filename Expand and complete filename at point;
;; replace with expanded/completed name.
:type 'boolean
:group 'comint)
-(defface comint-highlight-input '((t (:bold t)))
+(defface comint-highlight-input '((t (:weight bold)))
"Face to use to highlight input when `comint-highlight-input' is non-nil."
:group 'comint)
(defcustom comint-highlight-prompt t
"*If non-nil, highlight program prompts.
The face used is `comint-highlight-prompt'."
+ :type 'boolean
:group 'comint)
(defface comint-highlight-prompt
(defvar comint-input-ring-separator "\n"
"Separator between commands in the history file.")
+(defvar comint-input-history-ignore "^#"
+ "Regexp for history entries that should be ignored when comint initializes.")
+
(defcustom comint-process-echoes nil
"*If non-nil, assume that the subprocess echoes any input.
If so, delete one copy of the input so that only one copy eventually
;; ssh-add prints a prompt like `Enter passphrase: '.
;; Some implementations of passwd use "Password (again)" as the 2nd prompt.
(defcustom comint-password-prompt-regexp
- "\\(\\([Oo]ld \\|[Nn]ew \\|Kerberos \\|'s \\|login \\|^\\)\
+ "\\(\\([Oo]ld \\|[Nn]ew \\|Kerberos \\|'s \\|login \\|CVS \\|UNIX \\|^\\)\
[Pp]assword\\( (again)\\)?\\|pass phrase\\|Enter passphrase\\)\
-\\( for [^@ \t\n]+@[^@ \t\n]+\\)?:\\s *\\'"
+\\( for [^:]+\\)?:\\s *\\'"
"*Regexp matching prompts for passwords in the inferior process.
This is used by `comint-watch-for-password-prompt'."
:type 'regexp
Entry to this mode runs the hooks on `comint-mode-hook'."
(setq mode-line-process '(":%s"))
- (make-local-variable 'comint-last-input-start)
- (setq comint-last-input-start (make-marker))
- (set-marker comint-last-input-start (point-min))
- (make-local-variable 'comint-last-input-end)
- (setq comint-last-input-end (make-marker))
- (set-marker comint-last-input-end (point-min))
- (make-local-variable 'comint-last-output-start)
- (setq comint-last-output-start (make-marker))
+ (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))
(make-local-variable 'comint-last-output-overlay)
(make-local-variable 'comint-last-prompt-overlay)
(make-local-variable 'comint-prompt-regexp) ; Don't set; default
(make-local-variable 'comint-input-autoexpand)
(make-local-variable 'comint-input-ignoredups)
(make-local-variable 'comint-delimiter-argument-list)
- (make-local-hook 'comint-dynamic-complete-functions)
(make-local-variable 'comint-completion-fignore)
(make-local-variable 'comint-get-old-input)
- (make-local-hook 'comint-input-filter-functions)
(make-local-variable 'comint-input-filter)
(make-local-variable 'comint-input-sender)
(make-local-variable 'comint-eol-on-send)
(make-local-variable 'comint-scroll-to-bottom-on-input)
(make-local-variable 'comint-scroll-to-bottom-on-output)
(make-local-variable 'comint-scroll-show-maximum-output)
- (make-local-hook 'pre-command-hook)
(add-hook 'pre-command-hook 'comint-preinput-scroll-to-bottom t t)
- (make-local-hook 'comint-output-filter-functions)
- (make-local-hook 'comint-exec-hook)
(make-local-variable 'comint-ptyp)
(make-local-variable 'comint-process-echoes)
(make-local-variable 'comint-file-name-chars)
(make-local-variable 'comint-file-name-quote-list)
- (make-local-variable 'comint-accum-marker)
- (setq comint-accum-marker (make-marker))
- (set-marker comint-accum-marker nil))
+ (set (make-local-variable 'comint-accum-marker) (make-marker))
+ ;; This behavior is not useful in comint buffers, and is annoying
+ (set (make-local-variable 'next-line-add-newlines) nil))
(if comint-mode-map
nil
(define-key comint-mode-map "\C-c\C-p" 'comint-previous-prompt)
(define-key comint-mode-map "\C-c\C-d" 'comint-send-eof)
(define-key comint-mode-map "\C-c\C-s" 'comint-write-output)
+ (define-key comint-mode-map "\C-c." 'comint-insert-previous-argument)
;; Mouse Buttons:
(define-key comint-mode-map [mouse-2] 'comint-insert-clicked-input)
;; Menu bars:
(cons "In/Out" (make-sparse-keymap "In/Out")))
(define-key comint-mode-map [menu-bar inout delete-output]
'("Delete Current Output Group" . comint-delete-output))
- (define-key comint-mode-map [menu-bar inout write-output]
- '("Write Current Output Group to File" . comint-write-output))
(define-key comint-mode-map [menu-bar inout append-output-to-file]
'("Append Current Output Group to File" . comint-append-output-to-file))
+ (define-key comint-mode-map [menu-bar inout write-output]
+ '("Write Current Output Group to File" . comint-write-output))
(define-key comint-mode-map [menu-bar inout next-prompt]
'("Forward Output Group" . comint-next-prompt))
(define-key comint-mode-map [menu-bar inout previous-prompt]
(let ((proc (get-buffer-process buffer)))
(and proc (memq (process-status proc) '(open run stop)))))
+;;;###autoload
+(defun make-comint-in-buffer (name buffer program &optional startfile &rest switches)
+ "Make a comint process NAME in BUFFER, running PROGRAM.
+If BUFFER is nil, it defaults to NAME surrounded by `*'s.
+PROGRAM should be either a string denoting an executable program to create
+via `start-process', or a cons pair of the form (HOST . SERVICE) denoting a TCP
+connection to be opened via `open-network-stream'. If there is already a
+running process in that buffer, it is not restarted. Optional third arg
+STARTFILE is the name of a file to send the contents of to the process.
+
+If PROGRAM is a string, any more args are arguments to PROGRAM."
+ (or (fboundp 'start-process)
+ (error "Multi-processing is not supported for this system"))
+ (setq buffer (get-buffer-create (or buffer (concat "*" name "*"))))
+ ;; If no process, or nuked process, crank up a new one and put buffer in
+ ;; comint mode. Otherwise, leave buffer and existing process alone.
+ (unless (comint-check-proc buffer)
+ (with-current-buffer buffer
+ (unless (derived-mode-p 'comint-mode)
+ (comint-mode))) ; Install local vars, mode, keymap, ...
+ (comint-exec buffer name program startfile switches))
+ buffer)
+
;;;###autoload
(defun make-comint (name program &optional startfile &rest switches)
"Make a comint process NAME in a buffer, running PROGRAM.
STARTFILE is the name of a file to send the contents of to the process.
If PROGRAM is a string, any more args are arguments to PROGRAM."
- (or (fboundp 'start-process)
- (error "Multi-processing is not supported for this system"))
- (let ((buffer (get-buffer-create (concat "*" name "*"))))
- ;; If no process, or nuked process, crank up a new one and put buffer in
- ;; comint mode. Otherwise, leave buffer and existing process alone.
- (unless (comint-check-proc buffer)
- (with-current-buffer buffer
- (comint-mode)) ; Install local vars, mode, keymap, ...
- (comint-exec buffer name program startfile switches))
- buffer))
+ (apply #'make-comint-in-buffer name nil program startfile switches))
;;;###autoload
(defun comint-run (program)
(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 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))
;; 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.
+ ;; ;; There is similar code in compile.el.
(if (and (boundp 'system-uses-terminfo) system-uses-terminfo)
(list "TERM=dumb" "TERMCAP="
- (format "COLUMNS=%d" (frame-width)))
+ (format "COLUMNS=%d" (window-width)))
(list "TERM=emacs"
- (format "TERMCAP=emacs:co#%d:tc=unknown:" (frame-width))))
+ (format "TERMCAP=emacs:co#%d:tc=unknown:" (window-width))))
(if (getenv "EMACS") nil (list "EMACS=t"))
process-environment))
(default-directory
(dolist (ov (overlays-at (posn-point (event-end event))))
(when (eq (overlay-get ov 'field) 'input)
(throw 'found ov))))))
- ;; do we have input in this area?
+ ;; Do we have input in this area?
(if over
(let ((input-str (buffer-substring (overlay-start over)
(overlay-end over))))
+ (goto-char (point-max))
(delete-region
;; Can't use kill-region as it sets this-command
(or (marker-position comint-accum-marker)
(process-mark (get-buffer-process (current-buffer))))
(point))
(insert input-str))
- ;; fall back to the user's previous definition if we aren't
- ;; on previous input region.
- (let ((fun (lookup-key global-map (this-command-keys))))
+ ;; Fall back to the global definition.
+ (let* ((keys (this-command-keys))
+ (last-key (and (vectorp keys) (aref keys (1- (length keys)))))
+ (fun (and last-key (lookup-key global-map (vector last-key)))))
(if fun (call-interactively fun))))))
\f
This function is useful for major mode commands and mode hooks.
The commands stored in the history file are separated by the
-`comint-input-ring-separator'. The most recent command comes last.
+`comint-input-ring-separator', and entries that match
+`comint-input-history-ignore' are ignored. The most recent command
+comes last.
See also `comint-input-ignoredups' and `comint-write-input-ring'."
(cond ((or (null comint-input-ring-file-name)
(setq start (point-min)))
(setq history (buffer-substring start end))
(goto-char start)
- (if (or (null comint-input-ignoredups)
- (ring-empty-p ring)
- (not (string-equal (ring-ref ring 0) history)))
+ (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 nil))))))
+(defvar comint-dynamic-list-input-ring-window-conf)
+
+(defun comint-dynamic-list-input-ring-select ()
+ "Choose the input history entry that point is in or next to."
+ (interactive)
+ (let (beg end completion (buffer completion-reference-buffer)
+ (base-size completion-base-size))
+ (if (and (not (eobp)) (get-text-property (point) 'mouse-face))
+ (setq end (point) beg (1+ (point))))
+ (if (and (not (bobp)) (get-text-property (1- (point)) 'mouse-face))
+ (setq end (1- (point)) beg (point)))
+ (if (null beg)
+ (error "No history entry here"))
+ (setq beg (previous-single-property-change beg 'mouse-face))
+ (setq end (or (next-single-property-change end 'mouse-face) (point-max)))
+ (setq completion (buffer-substring beg end))
+ (set-window-configuration comint-dynamic-list-input-ring-window-conf)
+ (choose-completion-string completion buffer base-size)))
+
(defun comint-dynamic-list-input-ring ()
"List in help buffer the buffer's input history."
(interactive)
(with-output-to-temp-buffer history-buffer
(display-completion-list history)
(set-buffer history-buffer)
+ (let ((keymap (make-sparse-keymap)))
+ (set-keymap-parent keymap (current-local-map))
+ (define-key keymap "\C-m" 'comint-dynamic-list-input-ring-select)
+ (use-local-map keymap))
(forward-line 3)
(while (search-backward "completion" nil 'move)
(replace-match "history reference")))
(sit-for 0)
(message "Hit space to flush")
+ (setq comint-dynamic-list-input-ring-window-conf conf)
(let ((ch (read-event)))
(if (eq ch ?\ )
(set-window-configuration conf)
Returns t if successful."
(interactive)
(if (and comint-input-autoexpand
- (string-match "!\\|^\\^" (funcall comint-get-old-input))
(if comint-use-prompt-regexp-instead-of-fields
;; Use comint-prompt-regexp
- (save-excursion (beginning-of-line)
- (looking-at comint-prompt-regexp))
+ (save-excursion
+ (beginning-of-line)
+ (looking-at (concat comint-prompt-regexp "!\\|\\^")))
;; Use input fields. User input that hasn't been entered
;; yet, at the end of the buffer, has a nil `field' property.
- (null (get-char-property (point) 'field))))
+ (and (null (get-char-property (point) 'field))
+ (string-match "!\\|^\\^" (field-string)))))
;; Looks like there might be history references in the command.
(let ((previous-modified-tick (buffer-modified-tick)))
(comint-replace-by-expanded-history-before-point silent start)
(save-excursion
(let ((toend (- (line-end-position) (point)))
(start (comint-line-beginning-position)))
+ (goto-char start)
(while (progn
(skip-chars-forward "^!^" (- (line-end-position) toend))
(< (point) (- (line-end-position) toend)))
;;
;; Input processing stuff
;;
+(defun comint-add-to-input-history (cmd)
+ "Add CMD to the input history.
+Ignore duplicates if `comint-input-ignoredups' is non-nil."
+ (if (and (funcall comint-input-filter cmd)
+ (or (null comint-input-ignoredups)
+ (not (ring-p comint-input-ring))
+ (ring-empty-p comint-input-ring)
+ (not (string-equal (ring-ref comint-input-ring 0)
+ cmd))))
+ (ring-insert comint-input-ring cmd)))
(defun comint-send-input ()
"Send input to process.
After the process output mark, sends all text from the process mark to
-point as input to the process. Before the process output mark, calls value
-of variable `comint-get-old-input' to retrieve old input, copies it to the
-process mark, and sends it. If variable `comint-process-echoes' is nil,
-a terminal newline is also inserted into the buffer and sent to the process
-\(if it is non-nil, all text from the process mark to point is deleted,
-since it is assumed the remote process will re-echo it).
+point as input to the process. Before the process output mark, calls
+value of variable `comint-get-old-input' to retrieve old input, copies
+it to the process mark, and sends it. A terminal newline is also
+inserted into the buffer and sent to the process.
Any history reference may be expanded depending on the value of the variable
`comint-input-autoexpand'. The list of function names contained in the value
If variable `comint-eol-on-send' is non-nil, then point is moved to the
end of line before sending the input.
+After the input has been sent, if `comint-process-echoes' is non-nil,
+then comint-send-input waits to see if the process outputs a string
+matching the input, and if so, deletes that part of the output.
+
The values of `comint-get-old-input', `comint-input-filter-functions', and
`comint-input-filter' are chosen according to the command interpreter running
in the buffer. E.g.,
If the interpreter is the csh,
- comint-get-old-input is the default: either return the current
- field, or take the current line and discard any
- initial string matching regexp `comint-prompt-regexp', depending
- on the value of `comint-use-prompt-regexp-instead-of-fields'.
+ comint-get-old-input is the default:
+ If `comint-use-prompt-regexp-instead-of-fields' is nil, then
+ either return the current input field, if point is on an input
+ field, or the current line, if point is on an output field.
+ If `comint-use-prompt-regexp-instead-of-fields' is non-nil, then
+ return the current line with any initial string matching the
+ regexp `comint-prompt-regexp' removed.
comint-input-filter-functions monitors input for \"cd\", \"pushd\", and
\"popd\" commands. When it sees one, it cd's the buffer.
comint-input-filter is the default: returns t if the input isn't all white
(delete-region pmark start)
copy))))
- (if comint-process-echoes
- (delete-region pmark (point))
- (insert ?\n))
+ (insert ?\n)
- (if (and (funcall comint-input-filter history)
- (or (null comint-input-ignoredups)
- (not (ring-p comint-input-ring))
- (ring-empty-p comint-input-ring)
- (not (string-equal (ring-ref comint-input-ring 0)
- history))))
- (ring-insert comint-input-ring history))
+ (comint-add-to-input-history history)
(run-hook-with-args 'comint-input-filter-functions
(concat input "\n"))
(when comint-highlight-input
(overlay-put over 'face 'comint-highlight-input)
(overlay-put over 'mouse-face 'highlight)
+ (overlay-put over
+ 'help-echo
+ "mouse-2: insert after prompt as new input")
(overlay-put over 'evaporate t))))
(unless comint-use-prompt-regexp-instead-of-fields
;; Make an overlay for the terminating newline
(let ((over (make-overlay end (1+ end) nil t nil)))
(overlay-put over 'field 'boundary)
+ (overlay-put over 'inhibit-line-move-field-capture t)
(overlay-put over 'evaporate t))))
(comint-snapshot-last-prompt)
;; clear the "accumulation" marker
(set-marker comint-accum-marker nil)
(funcall comint-input-sender proc input)
+
+ ;; Optionally delete echoed input (after checking it).
+ (when comint-process-echoes
+ (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)
+ (point-max))
+ (zerop
+ (compare-buffer-substrings
+ nil comint-last-input-start
+ (- (point-max) echo-len)
+ ;; Above difference is equivalent to
+ ;; (+ comint-last-input-start
+ ;; (- (point-max) comint-last-input-end))
+ nil comint-last-input-end (point-max)))))
+ (if (and
+ (<= (+ comint-last-input-end echo-len)
+ (point-max))
+ (zerop
+ (compare-buffer-substrings
+ nil comint-last-input-start comint-last-input-end
+ nil comint-last-input-end
+ (+ comint-last-input-end echo-len))))
+ (delete-region comint-last-input-end
+ (+ comint-last-input-end echo-len)))))
+
;; This used to call comint-output-filter-functions,
;; but that scrolled the buffer in undesirable ways.
(run-hook-with-args 'comint-output-filter-functions "")))))
(overlay-put comint-last-prompt-overlay 'evaporate t)
(setq comint-last-prompt-overlay nil)))
+(defun comint-carriage-motion (string)
+ "Handle carriage control characters in comint output.
+Translate carriage return/linefeed sequences to linefeeds.
+Make single carriage returns delete to the beginning of the line.
+Make backspaces delete the previous character.
+
+This function should be in the list `comint-output-filter-functions'."
+ (save-match-data
+ ;; We first check to see if STRING contains any magic characters, to
+ ;; avoid overhead in the common case where it does not
+ (when (string-match "[\r\b]" string)
+ (let ((pmark (process-mark (get-buffer-process (current-buffer)))))
+ (save-excursion
+ (save-restriction
+ (widen)
+ (let ((inhibit-field-text-motion t)
+ (buffer-read-only nil))
+ ;; CR LF -> LF
+ ;; Note that this won't work properly when the CR and LF
+ ;; are in different output chunks, but this is probably an
+ ;; exceedingly rare case (because they are generally
+ ;; written as a unit), and to delay interpretation of a
+ ;; trailing CR in a chunk would result in odd interactive
+ ;; behavior (and this case is probably far more common).
+ (goto-char comint-last-output-start)
+ (while (re-search-forward "\r$" pmark t)
+ (delete-char -1))
+ ;; bare CR -> delete preceding line
+ (goto-char comint-last-output-start)
+ (while (search-forward "\r" pmark t)
+ (delete-region (point) (line-beginning-position)))
+ ;; BS -> delete preceding character
+ (goto-char comint-last-output-start)
+ (while (search-forward "\b" pmark t)
+ (delete-char -2)))))))))
+
+(add-hook 'comint-output-filter-functions 'comint-carriage-motion)
+
;; 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-get-old-input-default ()
"Default for `comint-get-old-input'.
-Returns either the current field, or the current line with any initial
-text matching `comint-prompt-regexp' stripped off, depending on the
-value of `comint-use-prompt-regexp-instead-of-fields'."
- (if comint-use-prompt-regexp-instead-of-fields
- (save-excursion
- (beginning-of-line)
- (comint-skip-prompt)
- (let ((beg (point)))
- (end-of-line)
- (buffer-substring beg (point))))
- ;; Return the contents of the field at the current point.
- (field-string)))
-
+If `comint-use-prompt-regexp-instead-of-fields' is nil, then either
+return the current input field, if point is on an input field, or the
+current line, if point is on an output field.
+If `comint-use-prompt-regexp-instead-of-fields' is non-nil, then return
+the current line with any initial string matching the regexp
+`comint-prompt-regexp' removed."
+ (let ((bof (field-beginning)))
+ (if (eq (get-char-property bof 'field) 'input)
+ (field-string bof)
+ (comint-bol)
+ (buffer-substring (point) (line-end-position)))))
(defun comint-copy-old-input ()
"Insert after prompt old input at point as new input to be edited.
(defun comint-send-string (process string)
"Like `process-send-string', but also does extra bookkeeping for comint mode."
- (with-current-buffer (process-buffer process)
+ (if process
+ (with-current-buffer (if (processp process)
+ (process-buffer process)
+ (get-buffer process))
+ (comint-snapshot-last-prompt))
(comint-snapshot-last-prompt))
(process-send-string process string))
(defun comint-send-region (process start end)
"Like `process-send-region', but also does extra bookkeeping for comint mode."
- (with-current-buffer (process-buffer process)
+ (if process
+ (with-current-buffer (if (processp process)
+ (process-buffer process)
+ (get-buffer process))
+ (comint-snapshot-last-prompt))
(comint-snapshot-last-prompt))
(process-send-region process start end))
+
\f
;; Random input hackage
(write-region comint-last-input-end (point) filename
append nil nil mustbenew)))
+;; This function exists for the benefit of the menu; from the keyboard,
+;; users can just use `comint-write-output' with a prefix arg.
+(defun comint-append-output-to-file (filename)
+ "Append output from interpreter since last input to FILENAME.
+Any prompt at the end of the output is not written."
+ (interactive "fAppend output to file: ")
+ (comint-write-output filename t))
+
(defun comint-show-output ()
"Display start of this batch of interpreter output at top of window.
Sets mark to the value of point when this command is run."
(comint-skip-prompt))
;; Use input fields
(let ((pos (point))
- (input-pos nil))
+ (input-pos nil)
+ prev-pos)
(while (/= n 0)
+ (setq prev-pos pos)
(setq pos
(if (> n 0)
(next-single-char-property-change pos 'field)
(previous-single-char-property-change pos 'field)))
- (cond ((null pos)
+ (cond ((or (null pos) (= pos prev-pos))
;; Ran off the end of the buffer.
+ (when (> n 0)
+ ;; There's always an input field at the end of the
+ ;; buffer, but it has a `field' property of nil.
+ (setq input-pos (point-max)))
+ ;; stop iterating
(setq n 0))
((eq (get-char-property pos 'field) 'input)
(setq n (if (< n 0) (1+ n) (1- n)))
occurance of text matching `comint-prompt-regexp'."
(interactive "p")
(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)
+
+;; Needs fixing:
+;; make comint-arguments understand negative indices as bash does
+(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
+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."
+ (interactive "P")
+ (unless (null index)
+ (setq index (prefix-numeric-value index)))
+ (cond ((eq last-command this-command)
+ ;; Delete last input inserted by this command.
+ (delete-region comint-insert-previous-argument-last-start-pos (point))
+ (setq index comint-insert-previous-argument-last-index))
+ (t
+ ;; This is a non-repeat invocation, so initialize state.
+ (setq comint-input-ring-index nil)
+ (setq comint-insert-previous-argument-last-index index)
+ (when (null comint-insert-previous-argument-last-start-pos)
+ ;; First usage; initialize to a marker
+ (setq comint-insert-previous-argument-last-start-pos
+ (make-marker)))))
+ ;; Make sure we're not in the prompt, and add a beginning space if necess.
+ (if (<= (point) (comint-line-beginning-position))
+ (comint-bol)
+ (just-one-space))
+ ;; Remember the beginning of what we insert, so we can delete it if
+ ;; the command is repeated.
+ (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)))
+ ;; Add a terminating space if necessary.
+ (unless (eolp)
+ (just-one-space)))
+
\f
;; Support for source-file processing commands.
;;============================================================================
;; Many command-interpreters (e.g., Lisp, Scheme, Soar) have
;; commands that process files of source text (e.g. loading or compiling
-;; files). So the corresponding process-in-a-buffer modes have commands
-;; for doing this (e.g., lisp-load-file). The functions below are useful
+;; files). So the corresponding process-in-a-buffer modes have commands
+;; for doing this (e.g., lisp-load-file). The functions below are useful
;; for defining these commands.
;;
;; Alas, these guys don't do exactly the right thing for Lisp, Scheme
;; So the compile/load interface gets the wrong default occasionally.
;; The load-file/compile-file default mechanism could be smarter -- it
;; doesn't know about the relationship between filename extensions and
-;; whether the file is source or executable. If you compile foo.lisp
+;; whether the file is source or executable. If you compile foo.lisp
;; with compile-file, then the next load-file should use foo.bin for
-;; the default, not foo.lisp. This is tricky to do right, particularly
+;; the default, not foo.lisp. This is tricky to do right, particularly
;; because the extension for executable files varies so much (.o, .bin,
;; .lbin, .mo, .vo, .ao, ...).
;; commands for tea, soar, cmulisp, and cmuscheme modes.
;;
;; - PREVIOUS-DIR/FILE is a pair (directory . filename) from the last
-;; source-file processing command. NIL if there hasn't been one yet.
+;; source-file processing command. nil if there hasn't been one yet.
;; - SOURCE-MODES is a list used to determine what buffers contain source
;; files: if the major mode of the buffer is in SOURCE-MODES, it's source.
;; Typically, (lisp-mode) or (scheme-mode).
;;
;; If the command is given while the cursor is inside a string, *and*
;; the string is an existing filename, *and* the filename is not a directory,
-;; then the string is taken as default. This allows you to just position
+;; then the string is taken as default. This allows you to just position
;; your cursor over a string that's a filename and have it taken as default.
;;
;; If the command is given in a file buffer whose major mode is in
If a cons pair, it should be of the form (DIRSUFFIX . FILESUFFIX) where
DIRSUFFIX and FILESUFFIX are strings added on unambiguous or exact completion.
This mirrors the optional behavior of tcsh."
- :type 'boolean
+ :type '(choice (const :tag "None" nil)
+ (const :tag "Add /" t)
+ (cons :tag "Suffix pair"
+ (string :tag "Directory suffix")
+ (string :tag "File suffix")))
:group 'comint-completion)
(defcustom comint-completion-recexact nil
(if (eq first ?\ )
(set-window-configuration conf)
(setq unread-command-events (listify-key-sequence key)))))))
+
\f
(defun comint-get-next-from-history ()
"After fetching a line from input history, this fetches the following line.
(let ((proc (or (get-buffer-process (current-buffer))
(error "Current buffer has no process"))))
(goto-char (process-mark proc))
- (message "Point is now at the process mark")))
+ (when (interactive-p)
+ (message "Point is now at the process mark"))))
(defun comint-bol-or-process-mark ()
"Move point to beginning of line (after prompt) or to the process mark.
"^No history$"
"^Not found$" ; Too common?
"^Current buffer has no process$"))
+
\f
;; Converting process modes to use comint mode
;; ===========================================================================
;; You could use comint-dynamic-simple-complete to do the bulk of the
;; completion job.
\f
+
(provide 'comint)
-;; comint.el ends here
+;;; comint.el ends here