Fix typo.
[bpt/emacs.git] / lisp / comint.el
index a3cc276..e6f0fad 100644 (file)
@@ -1,9 +1,9 @@
 ;;; 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
@@ -88,7 +88,6 @@
 ;; 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.
@@ -211,13 +210,14 @@ The face used is `comint-highlight-input'."
   :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
@@ -296,6 +296,9 @@ the function `comint-truncate-buffer' is on `comint-output-filter-functions'."
 (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
@@ -311,9 +314,9 @@ This variable is buffer-local."
 ;; 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
@@ -475,14 +478,9 @@ to continue it.
 
 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
@@ -501,27 +499,22 @@ Entry to this mode runs the hooks on `comint-mode-hook'."
   (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
@@ -555,6 +548,7 @@ Entry to this mode runs the hooks on `comint-mode-hook'."
   (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:
@@ -574,10 +568,10 @@ Entry to this mode runs the hooks on `comint-mode-hook'."
     (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]
@@ -637,6 +631,29 @@ BUFFER can be either a buffer or the name of one."
   (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.
@@ -648,16 +665,7 @@ 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"))
-  (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)
@@ -687,7 +695,7 @@ buffer.  The hook `comint-exec-hook' is run after each exec."
             (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))
@@ -720,11 +728,12 @@ buffer.  The hook `comint-exec-hook' is run after each exec."
          ;; 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
@@ -766,19 +775,21 @@ buffer.  The hook `comint-exec-hook' is run after each exec."
                (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
@@ -817,7 +828,9 @@ failure to read the history file.
 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)
@@ -851,9 +864,10 @@ See also `comint-input-ignoredups' and `comint-write-input-ring'."
                       (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)))))))
@@ -893,6 +907,25 @@ See also `comint-read-input-ring'."
             (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)
@@ -912,11 +945,16 @@ See also `comint-read-input-ring'."
       (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)
@@ -1090,14 +1128,15 @@ See `comint-magic-space' and `comint-replace-by-expanded-history-before-point'.
 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)
@@ -1114,6 +1153,7 @@ than the logical beginning of line."
   (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)))
@@ -1314,16 +1354,24 @@ Argument 0 is the command name."
 ;;
 ;; 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
@@ -1334,15 +1382,22 @@ The input is entered into the input history ring, if the value of variable
 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
@@ -1385,17 +1440,9 @@ Similarly for Soar, Scheme, etc."
                            (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"))
@@ -1415,11 +1462,15 @@ Similarly for Soar, Scheme, etc."
                (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)
@@ -1434,6 +1485,34 @@ Similarly for Soar, Scheme, etc."
          ;; 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 "")))))
@@ -1468,6 +1547,44 @@ This variable is permanent-local.")
     (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.
@@ -1684,19 +1801,17 @@ This function could be on `comint-output-filter-functions' or bound to a key."
 
 (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.
@@ -1856,15 +1971,24 @@ This function could be in the list `comint-output-filter-functions'."
 
 (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
 
@@ -1915,6 +2039,14 @@ otherwise."
     (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."
@@ -2054,14 +2186,21 @@ occurance of text matching `comint-prompt-regexp'."
        (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)))
@@ -2077,13 +2216,65 @@ the beginning of the Nth previous `input' field, otherwise, it means the Nth
 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
@@ -2091,9 +2282,9 @@ occurance of text matching `comint-prompt-regexp'."
 ;; 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, ...).
 
@@ -2114,14 +2305,14 @@ occurance of text matching `comint-prompt-regexp'."
 ;; 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
@@ -2303,7 +2494,11 @@ This mirrors the optional behavior of tcsh."
 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
@@ -2621,6 +2816,7 @@ Typing SPC flushes the help buffer."
        (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.
@@ -2655,7 +2851,8 @@ from input that has not yet been sent."
   (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.
@@ -3036,6 +3233,7 @@ REGEXP-GROUP is the regular expression group in REGEXP to use."
        "^No history$"
        "^Not found$"                   ; Too common?
        "^Current buffer has no process$"))
+
 \f
 ;; Converting process modes to use comint mode
 ;; ===========================================================================
@@ -3120,6 +3318,7 @@ REGEXP-GROUP is the regular expression group in REGEXP to use."
 ;; 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