I would like emacs to process some time-consuming tasks, without blocking input. For this purpose, I tried (where the insert is meant to be replaced by the time-consuming task)
(call-process "emacs" nil 0 nil "--eval=(insert \"a\")")
This works. However, when I want to pass a frame parameter, it doesn't work:
(call-process "emacs" nil 0 nil "--geometry 30x5")
Emacs says "Unknown option `--geometry 30x5".
Any ideas to use call-process to start another emacs session with refined frame size? Thanks!
It sounds like you might want async.el, which does indeed run additional instances of Emacs to carry out the specified processing.
(although I'm unsure of your requirement for a visible frame.)
Follow the link for details of all the other functionality on offer, but the simplest usage example given (which seemed like it might be applicable) is:
(async-start
;; What to do in the child process
(lambda ()
(message "This is a test")
(sleep-for 3)
222)
;; What to do when it finishes
(lambda (result)
(message "Async process done, result should be 222: %s" result)))
When using call-process, each argument to the program being started must be in a separate string - spaces don't count as separators. Your first example works, because it's a single argument, but the second example requires two parameters and should be written like this:
(call-process "emacs" nil 0 nil "--geometry" "30x5")
Related
I want to read the output of a buffer after process started by comint finishes.
(comint-redirect-send-command-to-process
command-string ;; tested to work in the commint buffer
output-buffer-name ;; random text
buffer-process ;; (get-buffer-process (current-buffer))
nil ;; don't echo input back
t) ;; don't show output buffer immediatly
This sexp is evaluated in a buffer running a comint process. I want to read all the text of output-buffer-name once the process has finished.
I have tried applying the solution posted to this question: sleep in emacs lisp by adding this below the process start command:
(defun on-status-change (process status)
(message "status done"))
(set-process-sentinel buffer-process 'on-status-change)
This message does not appear in *Messages*.
There is no prompt in the output-buffer text, but I can write a function that returns t when the output is finished based on the full output text.
How can I react to the buffer finishing/changing, or how can I force comint to run this function synchronously.
The source for comint-redirect-send-command-to-process is here on line 3717
If anyone else has a similar issue, I ended up "solving" this.
(while (not comint-redirect-completed)
(sleep-for 0.01))
comint-redirect-completed’s value is nil
Documentation:
Non-nil if redirection has completed in the current buffer.
Obviously not a great solution, but I couldn't get anything else working.
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.
I'm having some difficulties when trying to set something up that saves some persistent state, so that I can use the data between emacs invocations.
Using as a starting point some code from another question, I came up with the following little code snippet for something I'm wanting to do:
(defmacro with-output-to-file (path &rest body)
"record output of commands in body to file"
`(save-excursion
(let* ((buf (find-file-noselect ,path))
(standard-output buf))
(set-buffer buf)
(erase-buffer)
,#body
(save-buffer)
(kill-buffer))))
I then have a function that uses this, like:
(defun my-save-some-data ()
(with-output-to-file my-data-save-file
(prin1 my-data)))
EDIT: These both follow code like the following (previously, these were both setq; thanks to a comment from #phils for inspiring me to switch them to devfar and defcustom):
; note: my actual variable names (and filename value) are different;
; changed for example sake:
(defvar my-data (make-hash-table :test 'equal) "Data for a thing")
(defcustom my-data-save-file "~/tmp/my-data.el" "File to save my data to")
(Note: I also have a function to read the data back in, which happens automatically at load time, or on demand.)
I've set that up to run in a few circumstances (maybe too many? maybe poor choices? Anyway, this is what I set up):
(add-hook 'auto-save-hook 'my-save-some-data)
(add-hook 'kill-emacs-hook 'my-save-some-data)
(add-hook 'post-gc-hook 'my-save-some-data)
Most of the time, this works fine. However, every once in a while, I'm getting a problem where the data gets written to one of my previously-open buffers (killing all previous content there!), and then that buffer gets killed, with the saved changes.
Suffice it to say, this is highly annoying, as the buffer where this happens is frequently somewhere where I've been doing some work, and not necessarily checked it in yet.
I tried altering the macro above, replacing from (set-buffer buf) on with:
(with-current-buffer buf ; because set-buffer wasn't working??
(erase-buffer)
,#body
(if (eq buf (current-buffer))
(progn
(save-buffer)
(kill-buffer))
(message "buffer changed?!"))))))
This has somehow managed to cause it to append to the buffer, instead of overwriting it... so my if statement does seem to be working to some degree... however I don't see the message in my *Messages* buffer, so... I'm not quite sure what's going on.
One thing I think I've noticed (though it's hard to be certain, since I may not be actively paying attention when this happens) is that this happens in a not-then-currently-active buffer, rather than a buffer I'm currently editing.
So, the questions:
Am I doing something wrong here?
Are there other/better ways of doing this?
Are there standard ways to save state in a programatic way, that I could be using? (I poked around a bit in apropos, but failed to find anything... though perhaps I just don't know what to look for.)
What can I do to help myself track this down? (is there a way I can set breakpoints or something?)
Are there other protections I could use in code like this?
Any other thoughts welcome. I'm adding some more (message) forms in hopes of getting more debugging info in the mean time.
UPDATE: I've figured out that this only happens with the post-gc-hook. I don't know if my variables were somehow getting clobbered (and perhaps switching to defvar and defcustom will solve that?), or if there's some sort of obscure bug in the post-gc-hook processing... checking for reproducing the test-case with this latest change.
You can indeed set breakpoints, an easy way to do this is to put (edebug) in the place where you want to break. Then you can use, n for next, SPC for step, and e to eval. You can read more about edebug here.
So you can set a conditional breakpoint as a protection/warning, like this, before your call to (set-buffer):
(when (get-file-buffer my-data-save-file)
(read-from-minibuffer
(format "Warning: %s is already being visited by a buffer, contents will be overwritten! Entering edebug" my-data-save-file))
(edebug))
This will warn you and then enter the debugger if a file you are visiting in some buffer is about to be overwritten by your macro, where you can inspect what is going on.
Here is part the docstring of find-file-no-select:
Read file FILENAME into a buffer and return the buffer.
If a buffer exists visiting FILENAME, return that one, but
verify that the file has not changed since visited or saved.
My guess is that the my-data-save-file is already being visited by a buffer, so that is the buffer that is returned (and subsequently overwritten). But you can really find out what is happening with (edebug).
Just a quick reply to some of what you said. Your message never appears probably because you test whether the buffer of with-current-buffer is the current-buffer, which it always is, unless body changes the current buffer.
But you are right to use with-current-buffer instead of save-excursion followed by set-buffer.
As for other ways: why not put your data in a temporary buffer and then use write-file or append-to-fileor write-region?
FWIW, I tried your code briefly and saw no problem. But I just tried a simple (prin1 (symbol-function 'my-save-some-data)) for the body and a constant file name for the file. I tried with pre-existing file or not, and with pre-existing buffer or not, and with pre-existing unsaved modified buffer or not.
Are you testing with the interpreted code (e.g., macro present) or byte-compiled code?
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.
I'm trying to augment the etags-select functions so it will fall-back to a normal find-tag if find-tag at point failed. The code I've tried is:
(defun my-etags-find-tag ()
"Find at point or fall back"
(interactive)
(unless (etags-select-find-tag-at-point)
(etags-select-find-tag)))
(global-set-key (kbd "C-f") 'my-etags-find-tag)
However this fails when point is not at a valid tag. Instead I get a error thrown by etags-select-find-tag-at-point:
etags-select-find-tag-at-point: Wrong type argument: char-or-string-p, nil
In this case I just have to repeat the test done by etags-select-find-tag-at-point:
(defun my-etags-find-tag ()
"Find at point or fall back"
(interactive)
(if (find-tag-default)
(etags-select-find-tag-at-point)
(etags-select-find-tag)))
But it does seem a little redundant. Is it possible to trap exceptions and do alternate processing in elisp?
Try ignore-errors; eg,
(unless (ignore-errors (etags-select-find-tag-at-point))
(etags-select-find-tag))
Normally, (ignore-errors body) returns whatever body returns; when there's error, it returns nil.
Also look at condition-case for more general condition handling.
If you have Elisp info manual installed, you can get more details from
C-hSignore-errors.
Edit:
I failed to consider the possibility that the function may return nil on success; so we probably need
(unless (ignore-errors (or (etags-select-find-tag-at-point) t))
(etags-select-find-tag))
Without modifying the original source code of etags-select.el, I see it the more reasonable option, even when it calls twice to find-tag-default. You can cheat the dynamic environment within the call to avoid the repetition of the call by memoizing it with something like:
(defun my-etags-find-tag ()
"Find at point or fall back"
(interactive)
(let ((ftd (find-tag-default)))
(flet ((find-tag-default () ftd))
(if (find-tag-default)
(etags-select-find-tag-at-point)
(etags-select-find-tag)))))
EDIT: OK, as per your request, an explanation of the code. First, note that this code achieves both questions:
It does not fail
It is more efficient than the code you show (the one you say it is redundant).
Why is it more efficient? The problem with your redundant code is that you call find-tag-default to see if it is nil, and, if it is, you call etags-select-find-tag-at-point. This function calls again to find-tag-default to obtain a default value. What my code does is to cache the value of find-tag-default by redefining the function by being just the value you calculated. The flet does that, so when etags-select-find-tag-at-point calls find-tag-default, the calculated value is returned without any further processing.