Pfuture
What it is
pfuture.el offers a set of simple functions wrapping Emacs’ existing process creation functionality. It attaches
the output of a process to the process itself - turning it into a “future” and making it conveniently easy to pass around to other
functions, wait for it to complete and access its output. In other words what this package offers is an asynchronous version
of shell-command-to-string without the need to deal with process creation and filter functions.
How to use it
pfuture-new (cmd &rest cmd-args)Create a new future process for command CMD and arguments CMD-ARGS. This will return a process object with one additional ~’result~ property which can be read via(process-get process 'result)or alternatively with(pfuture-result process).Note that CMD-ARGS must be a sequence of strings, such that this is wrong: (pfuture-new “git status”) this is right: (pfuture-new “git” “status”)
pfuture-await (process &key (timeout 1) (just-this-one t))Block until PROCESS has produced output and return it.Will accept the following optional keyword arguments:
TIMEOUT: The timeout in seconds to wait for the process. May be a float to specify fractional number of seconds. In case of a timeout nil will be returned.
JUST-THIS-ONE: When t only read from the process of FUTURE and no other. For details see documentation of
accept-process-output.pfuture-await-to-finish (process)Keep reading the output of PROCESS until it is done. Same aspfuture-await, but will keep reading (and blocking) so long as the process is alive.If the process never quits this method will block forever. Use with caution!”
pfuture-result (process)Return the output of PROCESS.
Practical example
Given this artificially slow_status.sh bash script
sleep 3 && git statusdespite running the script twice the following code will execute within 3 seconds on account of being asynchronous:
(let ((start (float-time))
(future1 (pfuture-new "bash" "slow_status.sh"))
(future2 (pfuture-new "bash" "slow_status.sh"))
(future3 (pfuture-new "echo" "Foo" "Bar")))
(pfuture-await future1 :timeout 4 :just-this-one nil)
(pfuture-await future2 :timeout 4 :just-this-one nil)
(message "%s finished after %s seconds" (pfuture-result future3) (round (- (float-time) start))))