5

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?

5
  • could you let know if Tobias' answer statisied you?
    – ReneFroger
    Commented Jan 2, 2016 at 0:16
  • 1
    I was waiting for a more complete answer, but his answer works for eshell. Since no other answer was coming, I chose his answer.
    – user8780
    Commented Jan 2, 2016 at 0:32
  • Do you mean the lisp-scratch buffer by repl buffer?
    – Tobias
    Commented Jan 2, 2016 at 0:54
  • @Tobias In my case, it is REPL buffers launched by cider-jack-in and nodejs-repl. But, I want everything except the current input line on all REPL buffers and all shell buffers to be immutable against keyboard inputs.
    – user8780
    Commented Jan 2, 2016 at 1:53
  • nodejs-repl is derived from comint-mode -- as it should be. Therefore, the added section on comint in the already existing answer should work. It looks like this is not the case for cider because cider is not based on comint but they do their own stuff for process communication.
    – Tobias
    Commented Jan 2, 2016 at 11:25

1 Answer 1

5

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))))
2
  • Notably, a lot of these modes fail to take advantage of the fields feature of Emacs. For example, if I was writing eshell, I would propertize the prompt with '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.
    – mtraceur
    Commented Apr 13, 2023 at 19:54
  • The relevant tie-in to this answer is that if these modes actually annotated the different pieces of text, then the solution to marking pieces read-only becomes more elegant - more universally reusable and composable - because then we could scan the text for the relevant field properties, reducing the mode-specific logic. And incidentally, for example in 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.
    – mtraceur
    Commented Apr 13, 2023 at 20:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.