Add 2007 to copyright.
[bpt/emacs.git] / lisp / comint.el
index 0cae078..cd5a9a9 100644 (file)
@@ -1,7 +1,7 @@
 ;;; 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
 ;;
@@ -458,7 +458,7 @@ executed once when the buffer is created."
     (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)
@@ -502,7 +502,7 @@ executed once when the buffer is created."
     (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]
@@ -558,6 +558,9 @@ This is to support the command \\[comint-get-next-from-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)
@@ -638,6 +641,7 @@ Entry to this mode runs the hooks on `comint-mode-hook'."
   (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)
@@ -646,7 +650,10 @@ Entry to this mode runs the hooks on `comint-mode-hook'."
   (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))
@@ -761,7 +768,9 @@ buffer.  The hook `comint-exec-hook' is run after each exec."
                    (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)
@@ -793,21 +802,17 @@ buffer.  The hook `comint-exec-hook' is run after each exec."
        (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
@@ -816,9 +821,7 @@ buffer.  The hook `comint-exec-hook' is run after each exec."
           (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
@@ -1015,6 +1018,16 @@ See also `comint-read-input-ring'."
        (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
@@ -1035,9 +1048,18 @@ Moves relative to `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."
@@ -1077,6 +1099,14 @@ Moves relative to START, or `comint-input-ring-index'."
     (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.)
@@ -1088,13 +1118,13 @@ If N is negative, find the next or Nth next match."
     ;; 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)
@@ -1483,23 +1513,23 @@ Similarly for Soar, Scheme, etc."
                                (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)
@@ -1870,6 +1900,17 @@ the current line with any initial string matching the regexp
       (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."
@@ -2319,19 +2360,19 @@ preceding newline is removed."
           (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.
@@ -2672,7 +2713,7 @@ interpreter (e.g., the percent notation of cmd.exe on NT)."
     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
@@ -2942,10 +2983,9 @@ Typing SPC flushes the help buffer."
          (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 ()