;;; comint.el --- general command interpreter in a window stuff
;; Copyright (C) 1988, 1990, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-;; 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+;; 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
;; Author: Olin Shivers <shivers@cs.cmu.edu>
;; Simon Marshall <simon@gnu.org>
;; comint-eol-on-send boolean ...
;; comint-process-echoes boolean ...
;; comint-scroll-to-bottom-on-input symbol For scroll behavior
-;; comint-scroll-to-bottom-on-output symbol ...
+;; comint-move-point-for-output symbol ...
;; comint-scroll-show-maximum-output boolean ...
;; comint-accum-marker maker For comint-accumulate
;;
(define-key map "\C-c\C-c" 'comint-interrupt-subjob)
(define-key map "\C-c\C-z" 'comint-stop-subjob)
(define-key map "\C-c\C-\\" 'comint-quit-subjob)
- (define-key map "\C-c\C-m" 'comint-insert-input)
+ (define-key map "\C-c\C-m" 'comint-copy-old-input)
(define-key map "\C-c\C-o" 'comint-delete-output)
(define-key map "\C-c\C-r" 'comint-show-output)
(define-key map "\C-c\C-e" 'comint-show-maximum-output)
(define-key map [menu-bar inout kill-input]
'("Kill Current Input" . comint-kill-input))
(define-key map [menu-bar inout copy-input]
- '("Copy Old Input" . comint-insert-input))
+ '("Copy Old Input" . comint-copy-old-input))
(define-key map [menu-bar inout forward-matching-history]
'("Forward Matching Input..." . comint-forward-matching-input))
(define-key map [menu-bar inout backward-matching-history]
"Non-nil if you are accumulating input lines to send as input together.
The command \\[comint-accumulate] sets this.")
+(defvar comint-stored-incomplete-input nil
+ "Stored input for history cycling.")
+
(put 'comint-replace-by-expanded-history 'menu-enable 'comint-input-autoexpand)
(put 'comint-input-ring 'permanent-local t)
(put 'comint-input-ring-index 'permanent-local t)
(make-local-variable 'comint-scroll-to-bottom-on-input)
(make-local-variable 'comint-move-point-for-output)
(make-local-variable 'comint-scroll-show-maximum-output)
+ (make-local-variable 'comint-stored-incomplete-input)
;; This makes it really work to keep point at the bottom.
(make-local-variable 'scroll-conservatively)
(setq scroll-conservatively 10000)
(make-local-variable 'comint-process-echoes)
(make-local-variable 'comint-file-name-chars)
(make-local-variable 'comint-file-name-quote-list)
- (set (make-local-variable 'comint-accum-marker) (make-marker))
+ (make-local-variable 'comint-accum-marker)
+ (setq comint-accum-marker (make-marker))
+ (make-local-variable 'font-lock-defaults)
+ (setq font-lock-defaults '(nil))
(add-hook 'change-major-mode-hook 'font-lock-defontify nil t)
;; This behavior is not useful in comint buffers, and is annoying
(set (make-local-variable 'next-line-add-newlines) nil))
(format "COLUMNS=%d" (window-width)))
(list "TERM=emacs"
(format "TERMCAP=emacs:co#%d:tc=unknown:" (window-width))))
- (if (getenv "EMACS") nil (list "EMACS=t"))
+ (unless (getenv "EMACS")
+ (list "EMACS=t"))
+ (list (format "INSIDE_EMACS=%s,comint" emacs-version))
process-environment))
(default-directory
(if (file-accessible-directory-p default-directory)
(set-process-coding-system proc decoding encoding))
proc))
-(defun comint-insert-input (&optional event)
+(defun comint-insert-input (event)
"In a Comint buffer, set the current input to the previous input at point."
- ;; This doesn't use "e" because it is supposed to work
- ;; for events without parameters.
- (interactive (list last-input-event))
+ (interactive "e")
+ (mouse-set-point event)
(let ((pos (point)))
- (if event (posn-set-point (event-end event)))
- (if (not (eq (get-char-property (point) 'field) 'input))
+ (if (not (eq (field-at-pos pos) 'input))
;; No input at POS, 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)))))
- (goto-char pos)
(and fun (call-interactively fun)))
- (setq pos (point))
;; There's previous input at POS, insert it at the end of the buffer.
(goto-char (point-max))
;; First delete any old unsent input at the end
(process-mark (get-buffer-process (current-buffer))))
(point))
;; Insert the input at point
- (insert (buffer-substring-no-properties
- (previous-single-char-property-change (1+ pos) 'field)
- (next-single-char-property-change pos 'field))))))
+ (insert (field-string-no-properties pos)))))
\f
;; Input history processing in a buffer
(t
arg)))
+(defun comint-restore-input ()
+ "Restore unfinished input."
+ (interactive)
+ (when comint-input-ring-index
+ (comint-delete-input)
+ (when (> (length comint-stored-incomplete-input) 0)
+ (insert comint-stored-incomplete-input)
+ (message "Input restored"))
+ (setq comint-input-ring-index nil)))
+
(defun comint-search-start (arg)
"Index to start a directional search, starting at `comint-input-ring-index'."
(if comint-input-ring-index
arg)))
(defun comint-previous-input (arg)
- "Cycle backwards through input history."
+ "Cycle backwards through input history, saving input."
(interactive "*p")
- (comint-previous-matching-input "." arg))
+ (if (and comint-input-ring-index
+ (or ;; leaving the "end" of the ring
+ (and (< arg 0) ; going down
+ (eq comint-input-ring-index 0))
+ (and (> arg 0) ; going up
+ (eq comint-input-ring-index
+ (1- (ring-length comint-input-ring)))))
+ comint-stored-incomplete-input)
+ (comint-restore-input)
+ (comint-previous-matching-input "." arg)))
(defun comint-next-input (arg)
"Cycle forwards through input history."
(if (string-match regexp (ring-ref comint-input-ring n))
n)))
+(defun comint-delete-input ()
+ "Delete all input between accumulation or process mark and point."
+ (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-max)))
+
(defun comint-previous-matching-input (regexp n)
"Search backwards through input history for match for REGEXP.
\(Previous history elements are earlier commands.)
;; Has a match been found?
(if (null pos)
(error "Not found")
+ ;; If leaving the edit line, save partial input
+ (if (null comint-input-ring-index) ;not yet on ring
+ (setq comint-stored-incomplete-input
+ (funcall comint-get-old-input)))
(setq comint-input-ring-index pos)
(message "History item: %d" (1+ pos))
- (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))
+ (comint-delete-input)
(insert (ring-ref comint-input-ring pos)))))
(defun comint-next-matching-input (regexp n)
(concat input "\n")))
(let ((beg (marker-position pmark))
- (end (if no-newline (point) (1- (point))))
- (inhibit-modification-hooks t))
+ (end (if no-newline (point) (1- (point))))
+ (inhibit-modification-hooks t))
(when (> end beg)
- ;; Set text-properties for the input field
- (add-text-properties
- beg end
- '(front-sticky t
- font-lock-face comint-highlight-input
- mouse-face highlight
- help-echo "mouse-2: insert after prompt as new input"))
+ (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.
- (put-text-property beg end 'field 'input)))
+ (add-text-properties
+ beg end
+ '(mouse-face highlight
+ help-echo "mouse-2: insert after prompt as new input"
+ field input))))
(unless (or no-newline comint-use-prompt-regexp)
;; Cover the terminating newline
(add-text-properties end (1+ end)
(comint-bol)
(buffer-substring-no-properties (point) (line-end-position)))))
+(defun comint-copy-old-input ()
+ "Insert after prompt old input at point as new input to be edited.
+Calls `comint-get-old-input' to get old input."
+ (interactive)
+ (let ((input (funcall comint-get-old-input))
+ (process (get-buffer-process (current-buffer))))
+ (if (not process)
+ (error "Current buffer has no process")
+ (goto-char (process-mark process))
+ (insert input))))
+
(defun comint-skip-prompt ()
"Skip past the text matching regexp `comint-prompt-regexp'.
If this takes us past the end of the current line, don't skip at all."
(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 arg)
+(defun comint-kill-whole-line (&optional count)
"Kill current line, ignoring read-only and field properties.
-With prefix arg, kill that many lines starting from the current line.
-If arg is negative, kill backward. Also kill the preceding newline,
+With prefix arg COUNT, kill that many lines starting from the current line.
+If COUNT is negative, kill backward. Also kill the preceding newline,
instead of the trailing one. \(This is meant to make \\[repeat] work well
with negative arguments.)
-If arg is zero, kill current line but exclude the trailing newline.
+If COUNT is zero, kill current line but exclude the trailing newline.
The read-only status of newlines is updated with `comint-update-fence',
if necessary."
(interactive "p")
(let ((inhibit-read-only t) (inhibit-field-text-motion t))
- (kill-whole-line arg)
- (when (>= arg 0) (comint-update-fence))))
+ (kill-whole-line count)
+ (when (>= count 0) (comint-update-fence))))
(defun comint-kill-region (beg end &optional yank-handler)
"Like `kill-region', but ignores read-only properties, if safe.
name))
(defun comint-match-partial-filename ()
- "Return the filename at point, or nil if non is found.
+ "Return the filename at point, or nil if none is found.
Environment variables are substituted. See `comint-word'."
(let ((filename (comint-word comint-file-name-chars)))
(and filename (comint-substitute-in-file-name
(progn
(mouse-choose-completion first)
(set-window-configuration comint-dynamic-list-completions-config))
- (unless (eq first ?\s)
- (setq unread-command-events (listify-key-sequence key)))
- (unless (eq first ?\t)
- (set-window-configuration comint-dynamic-list-completions-config))))))
+ (if (eq first ?\s)
+ (set-window-configuration comint-dynamic-list-completions-config)
+ (setq unread-command-events (listify-key-sequence key)))))))
\f
(defun comint-get-next-from-history ()