2

When using ansi-term in line mode emacs lets you edit the buffer arbitrarily, not just after the last prompt. I'm trying to make it read only so I stop fudging with command output. The problem is all the solutions I've come up with also prevent me from entering any commands while in line mode. Here's my attempt:

(defvar-local etc-last-read-only 0)

(defun etc-make-term-output-read-only (&rest args)
  (interactive)
  (let ((inhibit-modification-hooks t))
    (when (= 0 etc-last-read-only)
      (setq etc-last-read-only (point-min)))
    (let ((end-prompt (ignore-errors (save-excursion
                                       (goto-char (point-max))
                                       (term-previous-prompt 1)
                                       ;; (backward-char)
                                       (point)))))
      (when (and end-prompt (> end-prompt etc-last-read-only))
        (add-text-properties etc-last-read-only end-prompt
                             '(read-only t rear-sticky t
                                         front-sticky nil))
        (setq etc-last-read-only end-prompt)))))

(add-hook 'term-mode-hook 
    (lambda () (add-hook 'after-change-functions #'etc-make-term-output-read-only nil t))

The idea is that whenever the buffer changes we try to make everything before the most recent prompt read only. I have term-prompt-regexp set to match my PS1 and I can tell that the regexp works correctly because C-c C-p and C-c C-n correctly jump between prompt instances, and I've manually verified with string-match that I get the right result, matching the prompt and one following space. To make the hook more efficient we track how much of the buffer we've made read only so far so we don't have to apply the read only property to the whole buffer every time.

If the backward-char call is included, then I can enter commands as long as I never hit backspace at the beginning of the prompt. If I do then I get a text is read only error from then on and can never enter commands again. If I don't include it, then I never get to enter commands in the first place because it thinks everything is read only. I thought maybe this was an issue with stickiness from the earlier characters, so I tried disabling the stickiness as you can see but it made no difference.

There are some more changes that are needed to make this more robust (I put advice on term-emulate-terminal to inhibit read only and probably need it elsewhere) but first I just want this proof of concept working. What am I doing wrong? How do I get everything up to term-bol marked read only without preventing typing commands there?

  • In my comments in the attached link, I have some sample code that makes the output read-only for shell-mode -- the buffer-name *shell* is not expressly included. I am not familiar with how to implement that feature in ansi-term, and am unsure whether it would be similar. superuser.com/q/868680/206164 My notes indicate that the code snippet only works when comint-use-prompt-regexp is non-nil. – lawlist Mar 7 '15 at 7:05
  • I actually already have that set up, I really want the experience in ANSI term :/ – Joseph Garvin Mar 7 '15 at 21:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.