2

I'trying to insert a row of characters into a buffer, where the first four characters should be read-only. Here's the relevant part of the code :

(insert (propertize "cn) " 'read-only t))
(insert (propertize (format "%s\n" hanzi) 'face 'kaiti-red))

When this code is run, I get a "Text is read-only" message, the buffer holds just the "cn) " string, read-only as expected, but nothing can be inserted after.

It seems that the second 'insert' is inheriting the read-only property, even though the "Stickiness of Text Properties" node in the emacs lisp manual says "The ordinary text insertion functions, such as insert, do not inherit any properties."

Can someone please explain what's going on here ? I'm using Emacs 26.2 on Windows 7.

1

It seems it is intentional according to read-only's info manual (info "(elisp) Special Properties"):

read-only

Insertion next to a read-only character is an error if inserting ordinary text there would inherit the read-only property due to stickiness. Thus, you can control permission to insert next to read-only text by controlling the stickiness. See Sticky Properties.

Since changing properties counts as modifying the buffer, it is not possible to remove a read-only property unless you know the special trick: bind inhibit-read-only to a non-nil value and then remove the property. See Read Only Buffers.

As it says, when insert text next a read-only character, we does get a text-read-only error:

(condition-case err
    (with-temp-buffer
      (insert (propertize "hello" 'read-only t) "world"))
  (text-read-only (error-message-string err)))
;; => "Text is read-only"

To work-around this, the above info manual suggests two options. The first option is by controlling the stickiness, for example, we set rear-nonsticky to (read-only) to disable inheriting only the read-only text property, you can also set it to t to disable inheriting all text properties:

(with-temp-buffer
  (insert (propertize "hello" 'read-only t 'rear-nonsticky '(read-only))
          "world")
  (buffer-string))
;; => #("helloworld" 0 5 (rear-nonsticky (read-only) read-only t))

The second option is let-binding the inhibit-read-only variable, e.g.,

(with-temp-buffer
  (insert (propertize "hello" 'read-only t))
  (let ((inhibit-read-only t))
    (insert "hello"))
  (buffer-string))
;; => #("hellohello" 0 5 (read-only t))
  • I still think there's a problem with the documentation. The part you quoted says that we should expect to get the read-only error if the insertion "would inherit the read-only property due to stickiness", and the part I quoted says that the insert function does not inherit, that's a clear contradiction. But anyway, your workaround really solved my problem, so I was more than happy to accept your answer. – joao Jul 13 at 17:43
  • OP: If you think the doc could use some improvement then please submit an enhancement request: M-x report-emacs-bug. – Drew Jul 13 at 17:53

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.