Using Emacs Threads To Execute Commands Asynchronously
1 Executive Summary
Emacs 26 has threads for executing functions asynchronously. Emacs
commands that call an external process and wait for that process to
finish make a good candidate for asynchronous execution — e.g.,
smtpmail-send-it for sending mail. The arrival of threads provides
an interesting option for running such commands asynchronously.
2 First Attempt — Custom Async
I initially wrote a custom command for launching
— it was a one-line function that ran the following:
The above worked well — except when command
gnus needed user input
— so I just had to be thoughtful about when I called it. But a few
weeks later, I wanted the equivalent for function
for sending mail. I almost wrote myself one more command before
stepping back to create a more generic solution.
3 One Command To Thread Them All
I have now defined command
Note that this command, though part of module
no emacspeak dependencies.
(defun emacspeak-wizards-execute-asynchronously (key) "Read key-sequence, then execute its command on a new thread." (interactive (list (read-key-sequence "Key Sequence: "))) (let ((l (local-key-binding key)) (g (global-key-binding key))) (cond ( (commandp l) (make-thread l) (message "Running %s on a new thread." l)) ((commandp g) (make-thread g) (message "Running %s on a new thread." g)) (t (error "%s is not bound to a command." key))))) (global-set-key (kbd "C-' a") 'emacspeak-wizards-execute-asynchronously)
With this command bound to
C-' a, I can now get rid of my custom
gnus-async command and its associated key-binding. I already have
gnus bound to
C-; g, so I can just press
C-' a C-; g to
fetch news/mail asynchronously.
Similarly, when sending mail using
smtpmail I can press
C-' a C-c in the
*mail* buffer to send mail without Emacs blocking.
4 Final Caveats
Like other asynchronous solutions (see package
async for instance)
one needs to make sure that the command being executed asynchronously
will not require user input. In the case of package
asynchronous Emacs will block waiting for input; in the case of
make-thread, Emacs enters a blocking loop with the minibuffer
No catch for ...
The only way to come out is to kill Emacs — so make sure to use
emacspeak-wizards-execute-asynchronously only when you're
sure that the command being run asynchronously will not require user
Date: 2018-07-03 Tue 00:00
Created: 2018-07-03 Tue 14:37