- (widen)
- (let* ((pmark (process-mark proc))
- (intxt (if (>= (point) (marker-position pmark))
- (progn (if comint-eol-on-send (end-of-line))
- (buffer-substring pmark (point)))
- (let ((copy (funcall comint-get-old-input)))
- (goto-char pmark)
- (insert copy)
- copy)))
- (input (if (not (eq comint-input-autoexpand 'input))
- ;; Just whatever's already there
- intxt
- ;; Expand and leave it visible in buffer
- (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 pmark)
- (let ((copy (buffer-substring pmark (point)))
- (start (point)))
- (insert input)
- (delete-region pmark start)
- copy))))
-
- (unless no-newline
- (insert ?\n))
-
- (comint-add-to-input-history history)
-
- (run-hook-with-args 'comint-input-filter-functions
- (if no-newline input
- (concat input "\n")))
-
- (let ((beg (marker-position pmark))
- (end (if no-newline (point) (1- (point))))
- (inhibit-modification-hooks t))
- (when (> end beg)
- (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.
- (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)
- '(rear-nonsticky t
- field boundary
- inhibit-line-move-field-capture t))))
-
- (comint-snapshot-last-prompt)
-
- (setq comint-save-input-ring-index comint-input-ring-index)
- (setq comint-input-ring-index nil)
- ;; Update the markers before we send the input
- ;; in case we get output amidst sending the input.
- (set-marker comint-last-input-start pmark)
- (set-marker comint-last-input-end (point))
- (set-marker (process-mark proc) (point))
- ;; clear the "accumulation" marker
- (set-marker comint-accum-marker nil)
- (let ((comint-input-sender-no-newline no-newline))
- (funcall comint-input-sender proc input))
-
- ;; Optionally delete echoed input (after checking it).
- (when (and comint-process-echoes (not artificial))
- (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))))
- ;; Certain parts of the text to be deleted may have
- ;; been mistaken for prompts. We have to prevent
- ;; problems when `comint-prompt-read-only' is non-nil.
- (let ((inhibit-read-only t))
- (delete-region comint-last-input-end
- (+ comint-last-input-end echo-len))
- (when comint-prompt-read-only
- (save-excursion
- (goto-char comint-last-input-end)
- (comint-update-fence)))))))
-
- ;; This used to call comint-output-filter-functions,
- ;; but that scrolled the buffer in undesirable ways.
- (run-hook-with-args 'comint-output-filter-functions "")))))
+ (widen)
+ (let* ((pmark (process-mark proc))
+ (intxt (if (>= (point) (marker-position pmark))
+ (progn (if comint-eol-on-send (end-of-line))
+ (buffer-substring pmark (point)))
+ (let ((copy (funcall comint-get-old-input)))
+ (goto-char pmark)
+ (insert copy)
+ copy)))
+ (input (if (not (eq comint-input-autoexpand 'input))
+ ;; Just whatever's already there
+ intxt
+ ;; Expand and leave it visible in buffer
+ (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 pmark)
+ (let ((copy (buffer-substring pmark (point)))
+ (start (point)))
+ (insert input)
+ (delete-region pmark start)
+ copy))))
+
+ (unless no-newline
+ (insert ?\n))
+
+ (comint-add-to-input-history history)
+
+ (run-hook-with-args 'comint-input-filter-functions
+ (if no-newline input
+ (concat input "\n")))
+
+ (let ((beg (marker-position pmark))
+ (end (if no-newline (point) (1- (point))))
+ (inhibit-modification-hooks t))
+ (when (> end beg)
+ (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.
+ (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)
+ '(rear-nonsticky t
+ field boundary
+ inhibit-line-move-field-capture t))))
+
+ (comint-snapshot-last-prompt)
+
+ (setq comint-save-input-ring-index comint-input-ring-index)
+ (setq comint-input-ring-index nil)
+ ;; Update the markers before we send the input
+ ;; in case we get output amidst sending the input.
+ (set-marker comint-last-input-start pmark)
+ (set-marker comint-last-input-end (point))
+ (set-marker (process-mark proc) (point))
+ ;; clear the "accumulation" marker
+ (set-marker comint-accum-marker nil)
+ (let ((comint-input-sender-no-newline no-newline))
+ (funcall comint-input-sender proc input))
+
+ ;; Optionally delete echoed input (after checking it).
+ (when (and comint-process-echoes (not artificial))
+ (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))))
+ ;; Certain parts of the text to be deleted may have
+ ;; been mistaken for prompts. We have to prevent
+ ;; problems when `comint-prompt-read-only' is non-nil.
+ (let ((inhibit-read-only t))
+ (delete-region comint-last-input-end
+ (+ comint-last-input-end echo-len))
+ (when comint-prompt-read-only
+ (save-excursion
+ (goto-char comint-last-input-end)
+ (comint-update-fence)))))))
+
+ ;; This used to call comint-output-filter-functions,
+ ;; but that scrolled the buffer in undesirable ways.
+ (run-hook-with-args 'comint-output-filter-functions "")))))
- (when (< (skip-chars-forward "^\b\r" end) (- end start))
- (save-match-data
- (save-restriction
- (widen)
- (let ((inhibit-field-text-motion t)
- (inhibit-read-only t))
- ;; 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).
- (while (re-search-forward "\r$" end t)
- (delete-char -1))
- ;; bare CR -> delete preceding line
- (goto-char start)
- (while (search-forward "\r" end t)
- (delete-region (point) (line-beginning-position)))
- ;; BS -> delete preceding character
- (goto-char start)
- (while (search-forward "\b" end t)
- (delete-char -2))))))))
+ (let* ((inhibit-field-text-motion t)
+ (inhibit-read-only t)
+ (lbeg (line-beginning-position))
+ delete-end ch)
+ ;; If the preceding text is marked as "must-overwrite", record
+ ;; it in delete-end.
+ (when (and (> start (point-min))
+ (get-text-property (1- start) 'comint-must-overwrite))
+ (setq delete-end (point-marker))
+ (remove-text-properties lbeg start '(comint-must-overwrite nil)))
+ (narrow-to-region lbeg end)
+ ;; Handle BS, LF, and CR specially.
+ (while (and (skip-chars-forward "^\b\n\r") (not (eobp)))
+ (setq ch (following-char))
+ (cond ((= ch ?\b) ; CH = BS
+ (delete-char 1)
+ (if (> (point) lbeg)
+ (delete-char -1)))
+ ((= ch ?\n)
+ (when delete-end ; CH = LF
+ (if (< delete-end (point))
+ (delete-region lbeg delete-end))
+ (set-marker delete-end nil)
+ (setq delete-end nil))
+ (forward-char 1)
+ (setq lbeg (point)))
+ (t ; CH = CR
+ (delete-char 1)
+ (if delete-end
+ (when (< delete-end (point))
+ (delete-region lbeg delete-end)
+ (move-marker delete-end (point)))
+ (setq delete-end (point-marker))))))
+ (when delete-end
+ (if (< delete-end (point))
+ ;; As there's a text after the last CR, make the current
+ ;; line contain only that text.
+ (delete-region lbeg delete-end)
+ ;; Remember that the process output ends by CR, and thus we
+ ;; must overwrite the contents of the current line next
+ ;; time.
+ (put-text-property lbeg delete-end 'comint-must-overwrite t))
+ (set-marker delete-end nil))
+ (widen))))
- ;;
- ;; It is used here to force window-point markers (used to
- ;; store the value of point in non-selected windows) to
- ;; advance, but it also screws up any other markers that we
- ;; don't _want_ to advance, such as the start-marker of some
- ;; of the overlays we create.
- ;;
- ;; We work around the problem with the overlays by
- ;; explicitly adjusting them after we do the insertion, but
- ;; in the future this problem should be solved correctly, by
- ;; using `insert', and making the insertion-type of
- ;; window-point markers settable (via a buffer-local
- ;; variable). In comint buffers, this variable would be set
- ;; to `t', to cause point in non-select windows to advance.
- (insert-before-markers string)
- ;; Fixup markers and overlays that got screwed up because we
- ;; used `insert-before-markers'.
- (let ((old-point (- (point) (length string))))
- ;; comint-last-output-start
- (set-marker comint-last-output-start old-point)
- ;; comint-last-input-end
- (when (and comint-last-input-end
- (equal (marker-position comint-last-input-end)
- (point)))
- (set-marker comint-last-input-end old-point))
- ;; No overlays we create are set to advance upon insertion
- ;; (at the start/end), so we assume that any overlay which
- ;; is at the current point was incorrectly advanced by
- ;; insert-before-markers. First fixup overlays that might
- ;; start at point:
- (dolist (over (overlays-at (point)))
- (when (= (overlay-start over) (point))
- (let ((end (overlay-end over)))
- (move-overlay over
- old-point
- (if (= end (point)) old-point end)))))
- ;; Then do overlays that might end at point:
- (dolist (over (overlays-at (1- (point))))
- (when (= (overlay-end over) (point))
- (move-overlay over
- (min (overlay-start over) old-point)
- old-point))))
+ ;; Luckily we don't have to use it any more, we use
+ ;; window-point-insertion-type instead.
+ (insert string)
- (function (lambda (window)
- (if (eq (window-buffer window) current)
- (progn
- (select-window window)
- (if (and (< (point) (process-mark process))
- (or (eq scroll t) (eq scroll 'all)
- ;; Maybe user wants point to jump to end.
- (and (eq scroll 'this) (eq selected window))
- (and (eq scroll 'others) (not (eq selected window)))
- ;; If point was at the end, keep it at end.
- (and (marker-position comint-last-output-start)
- (>= (point) comint-last-output-start))))
- (goto-char (process-mark process)))
- ;; Optionally scroll so that the text
- ;; ends at the bottom of the window.
- (if (and comint-scroll-show-maximum-output
- (= (point) (point-max)))
- (save-excursion
- (goto-char (point-max))
- (recenter (- -1 scroll-margin))))
- (select-window selected)))))
+ (lambda (window)
+ (when (eq (window-buffer window) current)
+ (select-window window)
+ (if (and (< (point) (process-mark process))
+ (or (eq scroll t) (eq scroll 'all)
+ ;; Maybe user wants point to jump to end.
+ (and (eq scroll 'this) (eq selected window))
+ (and (eq scroll 'others) (not (eq selected window)))
+ ;; If point was at the end, keep it at end.
+ (and (marker-position comint-last-output-start)
+ (>= (point) comint-last-output-start))))
+ (goto-char (process-mark process)))
+ ;; Optionally scroll so that the text
+ ;; ends at the bottom of the window.
+ (if (and comint-scroll-show-maximum-output
+ (= (point) (point-max)))
+ (save-excursion
+ (goto-char (point-max))
+ (recenter (- -1 scroll-margin))))
+ (select-window selected)))