mirror of
https://github.com/doomemacs/doomemacs
synced 2025-08-01 12:17:25 -05:00
feat(:term): make previous command output read-only
This makes the output of previous commands and prompts immutable (by default), so users can't accidentally alter them, which can leave the buffer in a half-broken state (requiring the user flush out the garbled input with a couple RETs). This targets comint shells (shell, ielm, etc), eshell, (ansi-)term, and any derivatives thereof. Fix: #8411
This commit is contained in:
@ -348,8 +348,35 @@ windows, switch to `doom-fallback-buffer'. Otherwise, delegate to original
|
||||
|
||||
|
||||
(after! comint
|
||||
(setq comint-prompt-read-only t
|
||||
comint-buffer-maximum-size 2048)) ; double the default
|
||||
(setq-default comint-buffer-maximum-size 2048) ; double the default
|
||||
|
||||
;; Protect prompts from accidental modifications.
|
||||
(setq-default comint-prompt-read-only t)
|
||||
|
||||
;; UX: Prior output in shell and comint shells (like ielm) should be
|
||||
;; read-only. Otherwise, it's trivial to make edits in visual modes (like
|
||||
;; evil's or term's term-line-mode) and leave the buffer in a half-broken
|
||||
;; state (which you have to flush out with a couple RETs, which may execute
|
||||
;; the broken text in the buffer),
|
||||
(defadvice! doom--comint-protect-output-in-visual-modes-a (process _string)
|
||||
:after #'comint-output-filter
|
||||
;; Adapted from https://github.com/michalrus/dotfiles/blob/c4421e361400c4184ea90a021254766372a1f301/.emacs.d/init.d/040-terminal.el.symlink#L33-L49
|
||||
(let* ((start-marker comint-last-output-start)
|
||||
(end-marker (or (if process (process-mark process))
|
||||
(point-max-marker))))
|
||||
(when (< start-marker end-marker) ;; Account for some of the IELM’s wilderness.
|
||||
(let ((inhibit-read-only t))
|
||||
;; Make all past output read-only (disallow buffer modifications)
|
||||
(add-text-properties comint-last-input-start (1- end-marker) '(read-only t))
|
||||
;; Disallow interleaving.
|
||||
(remove-text-properties start-marker (1- end-marker) '(rear-nonsticky))
|
||||
;; Make sure that at `max-point' you can always append. Important for
|
||||
;; bad REPLs that keep writing after giving us prompt (e.g. sbt).
|
||||
(add-text-properties (1- end-marker) end-marker '(rear-nonsticky t))
|
||||
;; Protect fence (newline of input, just before output).
|
||||
(when (eq (char-before start-marker) ?\n)
|
||||
(remove-text-properties (1- start-marker) start-marker '(rear-nonsticky))
|
||||
(add-text-properties (1- start-marker) start-marker '(read-only t))))))))
|
||||
|
||||
|
||||
(after! compile
|
||||
|
@ -95,6 +95,26 @@ You should use `set-eshell-alias!' to change this.")
|
||||
(setq buffer-undo-list old-undo-list)
|
||||
(clrhash undo-equiv-table)))
|
||||
|
||||
;; UX: Prior output in eshell buffers should be read-only. Otherwise, it's
|
||||
;; trivial to make edits in visual modes (like evil's or term's
|
||||
;; term-line-mode) and leave the buffer in a half-broken state (which you
|
||||
;; must flush out with a couple RETs, which may execute the broken text in
|
||||
;; the buffer),
|
||||
(add-hook! 'eshell-pre-command-hook
|
||||
(defun +eshell-protect-input-in-visual-modes-h ()
|
||||
(when (and eshell-last-input-start
|
||||
eshell-last-input-end)
|
||||
(add-text-properties eshell-last-input-start
|
||||
(1- eshell-last-input-end)
|
||||
'(read-only t)))))
|
||||
(add-hook! 'eshell-post-command-hook
|
||||
(defun +eshell-protect-output-in-visual-modes-h ()
|
||||
(when (and eshell-last-input-end
|
||||
eshell-last-output-start)
|
||||
(add-text-properties eshell-last-input-end
|
||||
eshell-last-output-start
|
||||
'(read-only t)))))
|
||||
|
||||
;; Enable autopairing in eshell
|
||||
(add-hook 'eshell-mode-hook #'smartparens-mode)
|
||||
|
||||
|
@ -13,3 +13,26 @@
|
||||
;; Remove hscroll-margin in shells, otherwise you get jumpiness when the cursor
|
||||
;; comes close to the left/right edges of the window.
|
||||
(setq-hook! 'term-mode-hook hscroll-margin 0)
|
||||
|
||||
;; HACK: Prior output in (ansi-)term shells should be read-only. Otherwise, it's
|
||||
;; trivial to make edits in visual modes (like evil's or term's
|
||||
;; term-line-mode) and leave the buffer in a half-broken state (which you must
|
||||
;; flush out with a couple RETs, which may execute the broken text in the
|
||||
;; buffer), Note that this does not protect the prompt in (ansi-)term buffers
|
||||
;; unless you set `term-prompt-regexp' buffer-locally! (e.g. with
|
||||
;; `setq-hook!').
|
||||
(defadvice! +term--protect-process-output-in-visual-modes-a (&rest _)
|
||||
:before #'term-line-mode
|
||||
(when (term-in-char-mode)
|
||||
(let* ((prompt?)
|
||||
(prompt-end
|
||||
(save-excursion
|
||||
(goto-char (process-mark (get-buffer-process (current-buffer))))
|
||||
(or (and (not (equal term-prompt-regexp "^"))
|
||||
(setq prompt? (re-search-backward term-prompt-regexp (line-beginning-position) t))
|
||||
(match-end 0))
|
||||
(line-beginning-position)))))
|
||||
(with-silent-modifications
|
||||
(when prompt?
|
||||
(put-text-property (1- prompt-end) prompt-end 'read-only 'fence))
|
||||
(add-text-properties (point-min) prompt-end '(read-only t))))))
|
||||
|
Reference in New Issue
Block a user