Search code examples
emacselispadvising-functionsdefadvice

Write-only buffer?


I would like to imitate the way how most consoles work in a buffer, is there any way to do that? I.e. only allow appending text to the buffer, but not deleting?

Probably I could disable or advise some built-in functions which delete characters, but I'm afraid this isn't a very scalable solution... I could miss some.


Solution

  • As mentioned, you can set the read-only text-property. Or more simply you can set the buffer-read-only variable and then write a few commands that override it. For example (guaranteed 100% untested code ahead):

    (defun append-only-s-i-c ()
      (let ((inhibit-read-only (eobp)))
        (call-interactively 'self-insert-command)))
    
    (defvar append-only-mode-map
      (let ((map (make-sparse-keymap)))
        (define-key map [remap self-insert-command] 'append-only-s-i-c)
        map))
    
    (define-derived-mode append-only-mode nil "Append-Only"
      "Here's the doc."
      (set (make-local-variable 'buffer-read-only) t))
    

    As demonstrated by this example, the read-only-ness of text can be overriden by a command, so even the read-only text-property won't guarantee 100% that the text will never be modified, but fairly few commands override the read-only information, so it should not be a serious problem in practice.

    Another approach would be to use before-change-functions and signal an error from there if the modification takes place before EOB. Might be a better approach:

    (defun append-only-b-c-f (beg end)
      (if (< beg (point-max)) (error "Can't modify text: append-only!")))
    
    (define-derived-mode append-only-mode nil "Append-Only"
      "Here's the doc."
      (add-hook 'before-change-functions #'append-only-b-c-f nil 'local))