Created
October 28, 2011 19:25
-
-
Save nicferrier/1323226 to your computer and use it in GitHub Desktop.
a macro for doing async shell commands a little easier
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defmacro with-process-shell-command (command buffer-or-filter &rest forms) | |
"Run COMMAND through /in the BUFFER-OR-FILTER using FORMS as the sentinel. | |
FORMS is a 'cond' like you'd use in a sentinel, for example: | |
(with-process-shell-command \"ls\" some-buffer | |
((equal signal \"finished\\n\") | |
;; Clean up? | |
(with-current-buffer (get-buffer \"* log *\") | |
(insert \"some text\\\n\"))) | |
) | |
Additionally, while processing the forms, the current buffer is | |
set to the buffer of the process. | |
If there exists a buffer '*process-shell-command-log*' then the | |
command is logged there before being using to create the | |
process. The command is prefixed with a unique identifier for the | |
process which is also used as a the process name. | |
BUFFER-OR-FILTER can be either a buffer or a function. If it is a | |
function it is used as the filter function for the asynchronous | |
process that is created. | |
If a function is supplied for BUFFER-OR-FILTER then it must be a | |
filter function, see 'set-process-filter'. | |
When a filter function is provided a buffer is created for the | |
process based on the unique identifier for the process. If such a | |
buffer exists when the process finishes then it is | |
destroyed. This is done after the FORMS have executed." | |
(declare (indent defun)) | |
(let ((streamvar (make-symbol "stream")) | |
(bufvar (make-symbol "buffer")) | |
(cmdvar (make-symbol "command")) | |
(procvar (make-symbol "process")) | |
(namevar (make-symbol "process-name")) | |
(sentinel-cb (make-symbol "sentinel"))) | |
`(let* ((,streamvar ,buffer-or-filter) | |
(,namevar (concat | |
(number-to-string (random)) | |
(number-to-string (float-time)))) | |
(,bufvar (cond | |
((bufferp ,streamvar) | |
,streamvar) | |
((functionp ,streamvar) | |
(get-buffer-create (format "* %s *" ,namevar))))) | |
(,cmdvar ,command)) | |
;; Update the command log if necessary | |
(if (get-buffer "*process-shell-command-log*") | |
(with-current-buffer command-log | |
(insert ,namevar " " ,cmdvar "\n"))) | |
;; Now start the shell process | |
(let ((,procvar (start-process-shell-command ,namevar ,bufvar ,cmdvar))) | |
;; If stream is a function it must be a filter function | |
(if (functionp ,streamvar) | |
(set-process-filter ,procvar ,streamvar)) | |
;; Capture the sentinel | |
(let ((,sentinel-cb | |
(lambda (process signal) | |
(with-current-buffer (process-buffer process) | |
(cond ,@sentinel-cond) | |
(if (and (equal signal "finished\n") | |
(get-buffer (buffer-name ,bufvar))) | |
(kill-buffer (buffer-name ,bufvar))))))) | |
;; This makes the standard form for error checking hard. | |
;;(funcall ,sentinel-cb ,procvar "__BEGIN__\n") | |
(set-process-sentinel ,procvar ,sentinel-cb)))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment