I want most of a buffer to be read-only, except for one small region (part of a line).
I first tried something like
(setq buffer-read-only t)
(let ((inhibit-read-only t))
(add-text-properties start end '(read-only nil)))
but apparently buffer-read-only takes precedence over the read-only property.
I now have buffer-read-only set to nil, and set the read-only property to t on everything except the editable region. (Or read-only nil is regarded as a no-op.)
Is there a better way?
EDIT:
A more detailed description of my use case is that I want my buffer to display the output of an asynchronous process. The output is mostly for read-only viewing. However, a small part of a line is editable. This part will become input to the process if it is run again.
There's no simple way to do what you need in Emacs 24 and earlier. I agree with your solution to mark everything with the read-only property except the parts that you want to be editable.
Emacs 25 will have the inhibit-read-only property, which does exactly what you want. It was implemented by larsi on 16 November, and is used by eww.
Related
Is there a way to get some elements truncated in the (excellent) Emacs Powerline? I'm thinking, in particular, at the which-func-mode section in the default mode line. It'd be good to see only the first N characters of a function name or section name (when in Org mode), N to be defined.
A side question is: can we simply get components being disabled (that is, not displayed) if the frame is too narrow (80 chars wide, for example)?
Generally you can customize which-func-format accordingly, e.g.:
(setq which-func-format
`("["
(:propertize (:eval (my-which-func-current))
local-map ,which-func-keymap
face which-func
mouse-face mode-line-highlight
help-echo "mouse-1: go to beginning\n\
mouse-2: toggle rest visibility\n\
mouse-3: go to end")
"]")
)
Where my-which-func-current is a function that truncates the current function name accordingly:
(defun my-which-func-current ()
(let ((current (gethash (selected-window) which-func-table)))
(if current
(truncate-string-to-width current 20 nil nil "…")
which-func-unknown)))
This approach works with the standard mode line, and with any mode line extension package that supports standard mode line data. I know that Smart Mode Line does, but I am not sure of Powerline. I don't use either of these packages.
I'd like to tell Emacs to 'watch' a particular form (identified by its car) within a buffer and evaluate it whenever I edit it.
One approach I can think of is to add a function to post-self-insert-hook, which would find and parse the targeted form and compare it with its previously stored state.
It doesn't sound too inefficient, especially if a 'calls per second' maximum is enforced (e.g. using current-time).
Is there is a higher level / more idiomatic way to accomplish this? It sounds like the sort of problem that has been solved already.
I think the most natural way is to create an overlay that would span from the beginning to the end of the form.
Overlays have a modification-hooks property, and you can add a watcher function to it.
The overlay will contract or expand appropriately if you modify buffer contents strictly inside it, but you'll need to decide what to do when buffer is edited at the edges of the form. See insert-in-front-hooks, insert-behind-hooks and the last two arguments to make-overlay. I'd probably just re-create the overlay in most of these cases, just to be sure about the new bounds.
About the "calls per second" thing, you can use run-with-idle-timer.
Part of what #Dmitry mentioned can be turn into simple prototype. Mark (message "text") and run M-xeval-on-modify-add
(defun eval-on-modify-add ()
(interactive)
(let ((ov (make-overlay (region-beginning) (region-end))))
(overlay-put ov 'modification-hooks '(eval-on-modify-execute))))
(defun eval-on-modify-execute (ov &optional flag &rest rv)
(if flag
(eval-region (overlay-start ov) (overlay-end ov))))
(message "test")
Over the course of the last few years I've been slowly growing my Emacs configuration, adding bits and pieces, add new modes etc. Around a year ago a problem started to occur regularly: some code is setting the modified bit on my buffers. It doesn't actually change anything, it just sets this flags. It is slightly annoying since each time I run compile or save-some-buffers I have to manually discard the changes in these buffers to reset the modified bit. How can I find the offending code?
Contrary to phils, I expect that your modified-p flag is not set by set-buffer-modified-p but rather by actual changes to the buffer. The reason this is possible is that text-properties are treated by Emacs as belonging to the content of the buffer, so changing them sets the modified-p flag, even tho in many cases the result is invisible and even if it is visible it is generally not perceived by the user as a modification (which users generally understand as something like "affects the file when I save the buffer").
So, most of the code that sets text-properties needs to be careful to reset the modified-p flag afterwards. The best way to do that is usually by wrapping the code that sets the properties inside a with-silent-modification.
One way try to track down the culprit is by trying to undo the modification (e.g. with C-/), but of course, if the modification is not visible, undoing it won't be visible either. So instead you may want to look at C-h v buffer-undo-list RET which is the internal data used to keep track of the modifications. With luck, not only was the modified-p set but the undo-list as well, and that list will tell you what was changed. For example, that list could look like (nil (nil face nil 12345708 . 12345713)) which means that the change was to set the face property to a new value between positions 12345708 and 12345713 and that the old value of that property was nil (that's the 3rd nil in the above). Sometimes looking at the affected positions with M-: (goto-char 12345708) RET is sufficient to figure out who's to blame. Othertimes looking at M-: (get-text-property 12345708 'face) RET, which gives you the new value that was set, is more useful.
If something really is explicitly setting the buffer as modified without changing anything, then I guess it ought to be calling set-buffer-modified-p.
I was originally going to suggest debug-on-entry for set-buffer-modified-p, but a cursory test showed that was extremely disruptive in general, so here's a way you can indicate which buffers you are interested in:
(defvar my-debug-set-buffer-modified-p-buffers nil)
(defadvice set-buffer-modified-p
(before my-debug-set-buffer-modified-p-advice)
(when (memq (current-buffer) my-debug-set-buffer-modified-p-buffers)
(debug)))
(ad-activate 'set-buffer-modified-p)
(defun my-debug-set-buffer-modified-p (buffer)
(interactive (list (current-buffer)))
(if (memq buffer my-debug-set-buffer-modified-p-buffers)
(progn (setq my-debug-set-buffer-modified-p-buffers
(delq buffer my-debug-set-buffer-modified-p-buffers))
(message "Disabled for %s" buffer))
(add-to-list 'my-debug-set-buffer-modified-p-buffers buffer)
(message "Enabled for %s" buffer)))
How does one make a specific region in a text file read only when using emacs. I know ctrl+X+Q
to make the whole file a read only.
I am currently writing a code and I do not want to modify by accident the first 40 lines of my code while working on lines 41 and upwards.
Use text properties:
(defun set-region-read-only (begin end)
(interactive "r")
(add-text-properties begin end '(read-only t)))
Relevant Docs:
Text-Properties
Changing Properties
Special Properties (like read-only)
You can use narrow-to-region (C-x n n) to narrow the buffer just to the part you want to change. Then you won't see or be able to change the region you don't want to change.
You can also apply highlight-changes-mode. That way you can see which text is changed as it is in different color. narrow-to-region is a good solution. You can also use that with 2 buffer, so you can see the read-only text too, if needed.
The documentation on Text Properties says:
Since text properties are considered part of the contents of the buffer (or string), and can affect how a buffer looks on the screen, any change in buffer text properties marks the buffer as modified.
First, I don't understand that policy. Can anyone explain? The text props are not actually saved in the file, when the buffer is saved. So why mark the buffer as modified? For me, buffer-modified indicates "some changes have not yet been saved." but understanding the policy is just for my own amusement.
More importantly, is there an already-established way that, in code, I can change syntax text properties on the text in a buffer, while keeping the buffer-modified flag set to whatever it was, prior to those changes? I'm thinking of something like save-excursion.
It would be pretty easy to write, but this seems like a common case and I'd like to use the standard function, if possible.
For more on the scenario - I have a mode that does a full text scan and sets syntax-table properties on the text. After opening a buffer, the scan runs, but it results in a buffer with buffer-modified set to t .
As always, thanks.
Newer versions of Emacs include the macro "with-silent-modifications" for this:
C-h f with-silent-modifications
------------------------------------------------------
with-silent-modifications is a Lisp macro in `subr.el'.
(with-silent-modifications &rest BODY)
Execute BODY, pretending it does not modify the buffer.
If BODY performs real modifications to the buffer's text, other
than cosmetic ones, undo data may become corrupted.
Typically used around modifications of text-properties which do not really
affect the buffer's content.
Wait! I found this in cc-defs.el
;; The following is essentially `save-buffer-state' from lazy-lock.el.
;; It ought to be a standard macro.
(defmacro c-save-buffer-state (varlist &rest body)
"Bind variables according to VARLIST (in `let*' style) and eval BODY,
then restore the buffer state under the assumption that no significant
modification has been made in BODY. A change is considered
significant if it affects the buffer text in any way that isn't
completely restored again. Changes in text properties like `face' or
`syntax-table' are considered insignificant. This macro allows text
properties to be changed, even in a read-only buffer.
This macro should be placed around all calculations which set
\"insignificant\" text properties in a buffer, even when the buffer is
known to be writeable. That way, these text properties remain set
even if the user undoes the command which set them.
This macro should ALWAYS be placed around \"temporary\" internal buffer
changes \(like adding a newline to calculate a text-property then
deleting it again\), so that the user never sees them on his
`buffer-undo-list'. See also `c-tentative-buffer-changes'.
However, any user-visible changes to the buffer \(like auto-newlines\)
must not be within a `c-save-buffer-state', since the user then
wouldn't be able to undo them.
The return value is the value of the last form in BODY."
`(let* ((modified (buffer-modified-p)) (buffer-undo-list t)
(inhibit-read-only t) (inhibit-point-motion-hooks t)
before-change-functions after-change-functions
deactivate-mark
buffer-file-name buffer-file-truename ; Prevent primitives checking
; for file modification
,#varlist)
(unwind-protect
(progn ,#body)
(and (not modified)
(buffer-modified-p)
(set-buffer-modified-p nil)))))
Perhaps it is simply because they are considered a part of the string... (like the docs say). Remember, Emacs is buffer-centric, not file-centric, so the fact that the contents get saved out on disk is somewhat irrelevant (when thinking buffer-centric).
Also, the properties are undo-able, and that definitely fits with having the buffer marked as modified.
I don't know that there is a standard way of saving the buffer-modified state, but I do see one in the pabbrev.el library:
(defmacro pabbrev-save-buffer-modified-p (&rest body)
"Eval BODY without affected buffer modification status"
`(let ((buffer-modified (buffer-modified-p))
(buffer-undo-list t))
,#body
(set-buffer-modified-p buffer-modified)))
It doesn't protect against nonlocal exits, so perhaps you'd want to add a call to unwind-protect, like so:
(defmacro save-buffer-modified-p (&rest body)
"Eval BODY without affected buffer modification status"
`(let ((buffer-modified (buffer-modified-p))
(buffer-undo-list t))
(unwind-protect
,#body
(set-buffer-modified-p buffer-modified))))