Since command outputs are easily mutable, I have to be careful when I work with eshell and REPL buffers.
Is there a way to protect them?
Modes that communicate with external shells should inherit from comint
mode. eshell
is an exception w.r.t this principle since it emulates almost all commands on elisp-base. First, setting output read-only is described for eshell
afterwards for comint
-based modes.
eshell
The following lisp snippet demonstrates the usage of eshell-output-filter-functions
for setting the output read-only.
It is not very sophisticated and not thoroughly tested.
(defun eshell-interactive-output-readonly ()
"Make output of interactive commands in eshell read-only.
This should be the last entry in eshell-output-filter-functions!"
(let ((end eshell-last-output-end))
(save-excursion
(goto-char end)
(end-of-line 0)
(setq end (point)))
(when (< eshell-last-output-block-begin end)
(put-text-property eshell-last-output-block-begin end 'read-only "Read-only interactive eshell output"))))
(defun eshell-make-interactive-output-readonly ()
(add-hook 'eshell-output-filter-functions 'eshell-interactive-output-readonly 'append))
(add-hook 'eshell-mode-hook 'eshell-make-interactive-output-readonly)
comint
based modes:It looks like one cannot use comint-output-filter-functions
for setting the command output read-only in comint
-based modes.
The reason is that comint-output-filter
sets unconditionally the rear-nonsticky
text property to t
. Therefore you can insert text into the output despite of the read-only
-property even if already existing output characters cannot be modified.
The only chance to protect the output is an after
-advice for comint-output-filter
. The following code-snippet demonstrates the principle.
(defadvice comint-output-filter (after output-readonly activate)
"Set last process output read-only."
(add-text-properties comint-last-output-start (line-end-position 0)
'(read-only "Process output is read-only."
rear-nonsticky (inhibit-line-move-field-capture))))
'field 'prompt
, the user-typed input with 'field 'input
, and command output with 'field 'output
. This wouldn't be perfect in the edge cases (an interactive external command which prompts for its own input wouldn't get detected by eshell, for example), but it's far better than no fields at all. Even something as little as tagging the prompt with a field is huge.
eshell
at least, we can inject a field
property to the prompt and add field
to its rear-nonsticky
property, by overriding eshell-prompt-function
(and disabling the default prompt highlighting) or advising eshell-emit-prompt
.
repl
buffer?cider-jack-in
andnodejs-repl
. But, I want everything except the current input line on all REPL buffers and all shell buffers to be immutable against keyboard inputs.nodejs-repl
is derived fromcomint
-mode -- as it should be. Therefore, the added section oncomint
in the already existing answer should work. It looks like this is not the case forcider
becausecider
is not based oncomint
but they do their own stuff for process communication.