I've written an Emacs Lisp function which calls a shell command to
process a given string and return the resulting string. Here is a
simplified example which just calls tr to convert text to uppercase:
(defun test-shell-command (str)
"Apply tr to STR to convert lowercase letters to uppercase."
(let ((buffer (generate-new-buffer "*temp*")))
(with-current-buffer buffer
(insert str)
(call-process-region (point-min) (point-max) "tr" t t nil "'a-z'" "'A-Z'")
(buffer-string))))
This function creates a temporary buffer, inserts the text, calls
tr, replaces the text with the result, and returns the result.
The above function works as expected, however, when I write a wrapper
around this function to apply the command to the region, two steps are
being added to the undo history. Here's another example:
(defun test-shell-command-region (begin end)
"Apply tr to region from BEGIN to END."
(interactive "*r")
(insert (test-shell-command (delete-and-extract-region begin end))))
When I call M-x test-shell-command-on-region, the region is replaced
with the uppercase text, but when I press C-_ (undo), the first
step in the undo history is the state with the text deleted. Going
two steps back, the original text is restored.
My question is, how does one prevent the intermediate step from being
added to the undo history? I've read the Emacs documentation on undo,
but it doesn't seem to address this as far as I can tell.
Here's a function which accomplishes the same thing by calling the
built-in Emacs function upcase, just as before: on the result of
delete-and-extract-region with the result being handed off to
insert:
(defun test-upcase-region (begin end)
"Apply upcase to region from BEGIN to END."
(interactive "*r")
(insert (upcase (delete-and-extract-region begin end))))
When calling M-x test-upcase-region, there is only one step in the
undo history, as expected. So, it seems to be the case that calling
test-shell-command creates an undo boundary. Can that be avoided
somehow?
The key is the buffer name. See Maintaining Undo:
Recording of undo information in a newly created buffer is normally enabled to start with; but if the buffer name starts with a space, the undo recording is initially disabled. You can explicitly enable or disable undo recording with the following two functions, or by setting buffer-undo-list yourself.
with-temp-buffer creates a buffer named ␣*temp* (note the leading whitespace), whereas your function uses *temp*.
To remove the undo boundary in your code, either use a buffer name with a leading space, or explicitly disable undo recoding in the temporary buffer with buffer-disable-undo.
But generally, use with-temp-buffer, really. It's the standard way for such things in Emacs, making your intention clear to anyone who reads your code. Also, with-temp-buffer tries hard to clean up the temporary buffer properly.
As for why undo in the temporary buffer creates an undo boundary in the current one: If the previous change was undoable and made in some other buffer (the temporary one in this case), an implicit boundary is created. From undo-boundary:
All buffer modifications add a boundary whenever the previous undoable change was made in some other buffer. This is to ensure that each command makes a boundary in each buffer where it makes changes.
Hence, inhibiting undo in the temporary buffer removes the undo boundary in the current buffer, too: The previous change is simply not undoable anymore, and thus no implicit boundary is created.
There are many situations where using a temporary buffer is not practical. It's hard to debug what's going on for example.
In these cases you can let-bind undo-inhibit-record-point to prevent Emacs from deciding where to put boundaries:
(let ((undo-inhibit-record-point t))
;; Then record boundaries manually
(undo-boundary)
(do-lots-of-stuff)
(undo-boundary))
The solution in this case was to create the temporary output buffer
using with-temp-buffer, rather than explicitly creating one with
generate-new-buffer. The following alternative version of the
first function does not create an undo boundary:
(defun test-shell-command (str)
"Apply tr to STR to convert lowercase letters to uppercase."
(with-temp-buffer
(insert str)
(call-process-region (point-min) (point-max) "tr" t t nil "'a-z'" "'A-Z'")
(buffer-string)))
I was not able to determine whether generate-new-buffer is indeed
creating the undo boundary, but this fixed the problem.
generate-new-buffer calls get-buffer-create, which is defined in
the C source code, but I could not quickly determine what was
happening in terms of the undo history.
I suspect that the issue may be related to the following passage in
the Emacs Lisp Manual entry for undo-boundary:
All buffer modifications add a boundary whenever the previous
undoable change was made in some other buffer. This is to ensure
that each command makes a boundary in each buffer where it makes
changes.
Even though the with-temp-buffer macro calls generate-new-buffer
much as in the original function, the documentation for
with-temp-buffer states that no undo information is saved (even
though there is nothing in the Emacs Lisp source that suggests this
would be the case):
By default, undo (see Undo) is not recorded in the buffer created by
this macro (but body can enable that, if needed).
Related
Switch-to-buffer is the function bound to C-x b. Occasionally I mistype the buffer I am intending to switch to and this causes me to open a fresh buffer with the incorrect name. The preferred behavior (in my case) is to fail to open the buffer... perhaps a failure to complete the buffer name. I recall encountering a few years back a technique that disallows switch-to-buffer to open new buffers. Perhaps someone on StackOverflow can identify that technique?
Thanks!
Setjmp
I think you want to customize confirm-nonexistent-file-or-buffer. E.g. with something like:
(setq confirm-nonexistent-file-or-buffer t)
The default is to only ask for confirmation if you've just hit completion before RET.
I was able to track down the solution in Writing GNU Emacs Extensions by Bob Glickstein. (In knew I had seen it somewhere, but it took some time to figure out where). I have the 1997 edition, and the answer is given in Chapter 2, under a section called "Advised Buffer Switching." Glickstein demonstrates the customization of switch-to-buffer as a method of instructing the reader on giving "advice" to functions.
(defadvice switch-to-buffer (before existing-buffer
activate compile)
"When interactive, switch to existing buffers only, unless given a prefix argument."
(interactive
(list (read-buffer "Switch to buffer: "
(other-buffer)
(null current-prefix-arg)))))
The function read-buffer reads the name of the buffer and returns a string. That string is passed to switch-to-buffer. The first argument is the default. The second argument is a boolean determining whether non-existing buffers are allowed.
Setjmp
I think an even better solution than preventing open a wrong buffer is switching to the buffer you meant to.
This can be done by ido.el, which is one of my favorite package. Install that package and configure as the following, then you can type much less (and ignore case) to switch to a buffer.
(ido-mode 'buffer)
(setq ido-enable-flex-matching t)
For instance, you have buffers "abcd.el", "hijk.el" "ABC.c", simply C-x b then type "a.c" and . Now, you are in "ABC.c" buffer. C-x b followed by a single character "h" will lead you to "hijk.el" buffer.
I have not been able to get the minibuffer-exit-hook to play nice with read-string. As far as I can tell, I should no longer be in the minibuffer after finishing up with read-string. However, the condition (minibufferp) says I'm still in the minibuffer even though read-string finished. read-string is written in C, so I can't add the hook there (i.e., at the tail end of the read-string function).
"Documentation [minibuffer-exit-hook]: Normal hook run just after exit from minibuffer.
[After thinking a little more about this, I'm pretty sure it's a bug -- so I filed a bug report: bug#16524. As I learn more, I'll update this thread.
(defun test ()
(interactive)
(read-string "Prompt: " "testing"))
(add-hook 'minibuffer-exit-hook (lambda ()
(cond
((minibufferp)
(message "Focus is still in the minibuffer: %s" (buffer-name)))
(t (message "Contragulations -- focus is now in: %s." (buffer-name))))))
The doc string is not exact; that's all. The hook is run when inputting text in the minibuffer is done (no longer possible). The buffer that is current when it is run is still the minibuffer. (And that's the way it should be, FWIW.)
Note that the Elisp manual puts it slightly differently (but again, not very precisely):
This is a normal hook that is run whenever the minibuffer is
entered.
("Whenever", meaning about the same time as, not necessarily after.)
If you want to do something after every use of read-string in your code, then define a function that does the following: first (read-string...), then whatever you want done next. And use that function.
If you need to affect also other invocations of read-string, besides those you write in your code, then advise function read-string to perform whatever action after the vanilla code finishes.
For example:
(defadvice read-string (after fooness activate)
(message "buffer: %S" (current-buffer)))
[Note: Yes, you can advise primitives (functions written in C). You used to even be able to advise special forms, but they regressively took away that feature.]
Running a hook after you truly exited the minibuffer is rather pointless: you could be in any kind of buffer (since minibuffer use can be triggered from anywhere) and you hence know very little about the current context (unless you use a buffer-local exit-hook, I guess).
If you want to run a hook when the selected window changes, then your best option is probably to use a post-command-hook that stores the current selected-window in an auxiliary variable and uses it to compare to the previous selected-window.
The Emacs Help page for the function shell-command-on-region says (elided for space):
(shell-command-on-region START END COMMAND &optional OUTPUT-BUFFER
REPLACE ERROR-BUFFER DISPLAY-ERROR-BUFFER)
...
The noninteractive arguments are START, END, COMMAND,
OUTPUT-BUFFER, REPLACE, ERROR-BUFFER, and DISPLAY-ERROR-BUFFER.
...
If the optional fourth argument OUTPUT-BUFFER is non-nil,
that says to put the output in some other buffer.
If OUTPUT-BUFFER is a buffer or buffer name, put the output there.
If OUTPUT-BUFFER is not a buffer and not nil,
insert output in the current buffer.
In either case, the output is inserted after point (leaving mark after it).
If REPLACE, the optional fifth argument, is non-nil, that means insert
the output in place of text from START to END, putting point and mark
around it.
This isn't the clearest, but the last few sentences just quoted seem to say that if I want the output of the shell command to be inserted in the current buffer at point, leaving the other contents of the buffer intact, I should pass a non-nil argument for OUTPUT-BUFFER and nil for REPLACE.
However, if I execute this code in the *scratch* buffer (not the real code I'm working on, but the minimal case that demonstrates the issue):
(shell-command-on-region
(point-min) (point-max) "wc" t nil)
the entire contents of the buffer are deleted and replaced with the output of wc!
Is shell-command-on-region broken when used non-interactively, or am I misreading the documentation? If the latter, how could I change the code above to insert the output of wc at point rather than replacing the contents of the buffer? Ideally I'd like a general solution that works not only to run a command on the entire buffer as in the minimal example (i.e., (point-min) through (point-max)), but also for the case of running a command with the region as input and then inserting the results at point without deleting the region.
You are wrong
It is not a good idea to use an interactive command like shell-command-on-region in emacs lisp code. Use call-process-region instead.
Emacs is wrong
There is a bug in shell-command-on-region: it does not pass the replace argument down to call-process-region; here is the fix:
=== modified file 'lisp/simple.el'
--- lisp/simple.el 2013-05-16 03:41:52 +0000
+++ lisp/simple.el 2013-05-23 18:44:16 +0000
## -2923,7 +2923,7 ## interactively, this is t."
(goto-char start)
(and replace (push-mark (point) 'nomsg))
(setq exit-status
- (call-process-region start end shell-file-name t
+ (call-process-region start end shell-file-name replace
(if error-file
(list t error-file)
t)
I will commit it shortly.
If you follow the link to the functions' source code, you'll quickly see that it does:
(if (or replace
(and output-buffer
(not (or (bufferp output-buffer) (stringp output-buffer)))))
I don't know why it does that, tho. In any case, this is mostly meant as a command rather than a function; from Elisp I recomend you use call-process-region instead.
In my case (emacs 24.3, don't know what version you're using), the documentation is slightly different in the optional argument:
Optional fourth arg OUTPUT-BUFFER specifies where to put the
command's output. If the value is a buffer or buffer name, put
the output there. Any other value, including nil, means to
insert the output in the current buffer. In either case, the
output is inserted after point (leaving mark after it).
The code that checks whether to delete the output (current) buffer contents is the following:
(if (or replace
(and output-buffer
(not (or (bufferp output-buffer) (stringp output-buffer)))))
So clearly putting t as in your case, it is not a string or a buffer, and it is not nil, so it will replace current buffer contents with the output. However, if I try:
(shell-command-on-region
(point-min) (point-max) "wc" nil nil)
then the buffer is not deleted, and the output put into the "Shell Command Output" buffer. At first sight, I'd say the function is not correctly implemented. Even the two versions of the documentation seem not to correspond with the code.
This happens to me all the time:
I have a file open in emacs,
I save it ('save-buffer),
the file changes on disk (or get's deleted, moved, etc.)
but I want it back, so I try to save again in emacs ('save-buffer) and instead of saving it says "(no changes need to be saved)" and does nothing.
Is there a different function, or a setting, that I can use to force emacs to save?
Wrap a function around save-buffer that marks the buffer modified first:
(defun save-buffer-always ()
"Save the buffer even if it is not modified."
(interactive)
(set-buffer-modified-p t)
(save-buffer))
You can save as, with C-x C-w. That should save unconditionally. You can also just type a space then backspace over it. Emacs is smart enough to realize that if you undo everything you've done so far the buffer has no changes, but if you make changes and then manually reverse them it will consider the buffer to have been changed.
You can mark the current buffer as modified using the Emacs-Lisp function not-modified with a prefix arg, bound to:
C-u M-~
The answer above won't work if you don't call the new function directly.
If you want to seamlessly change emacs saving behavior. The best solution is to create an advice:
(defadvice save-buffer (before save-buffer-always activate)
"always save buffer"
(set-buffer-modified-p t))
As a slight alternative to scottfrazer's answer:
(defun my-save-buffer-always-sometimes (prefix)
"Save the buffer even if it is not modified."
(interactive "P")
(when prefix
(set-buffer-modified-p t))
(save-buffer))
This was you can force it when you want to with a prefix (C-u C-x C-s) but not unnecessarily change a file otherwise. The last modified timestamp is very useful (e.g. source code control) that it seems a shame to change it arbitrarily. YMMV, of course.
A similar problem brought me online to look for a solution. Then it hits me that all I have to do is type a space (or any character) and delete it, which marks the buffer as changed. Then I can type C-x C-s as normal. Maybe not sophisticated or advanced, but it works.
Like Tagore Smith said, you can force Emacs to save the buffer with C-x C-w.
If you're using Evil mode, you can also achieve this behavior by typing :w! in normal state. Unlike C-x C-w, :w! will not prompt you for the filename to save to.
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))))