Skip to content

Instantly share code, notes, and snippets.

@nicferrier
Created October 28, 2011 19:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nicferrier/1323226 to your computer and use it in GitHub Desktop.
Save nicferrier/1323226 to your computer and use it in GitHub Desktop.
a macro for doing async shell commands a little easier
(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