Created
October 29, 2011 14:01
-
-
Save nicferrier/1324488 to your computer and use it in GitHub Desktop.
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 elnode-worker-elisp (output-stream &rest body) | |
"Evaluate the BODY in a child Emacs connected to OUTPUT-STREAM. | |
The child Emacs has a 'load-path' exactly as the 'load-path' of | |
the parent Emacs at execution. | |
The created child Emacs process is returned. It's possible to | |
kill the child Emacs process or do other things to it directly. | |
This could be very dangerous however, you should know what you | |
are doing before attempting it. | |
The OUTPUT-STREAM could be a buffer, a function or another | |
process. | |
If the OUTPUT-STREAM is another process it may have a process | |
property ':send-string-function' evaluating to a function to send | |
data to that process. The function should take the same | |
arguments as the standard Emacs Lisp 'process-send-string'. | |
Furthermore, if the OUTPUT-STREAM is another process, when the | |
child Emacs finishes an EOF is sent to that process. If the | |
OUTPUT-STREAM process has a process property ':send-eof-function' | |
then that is used to send the EOF. The function should take the | |
same arguments as the standard Emacs Lisp 'process-send-eof'. | |
An example: | |
(elnode-worker-elisp http-connection | |
(require 'creole) | |
(creole-wiki some-file-name)) | |
Presuming http-connection is a process (in the manner of Elnode, | |
for example) this will cause a child Emacs to be created, within | |
which 'some-file-name' will be loaded and converted from | |
WikiCreole to HTML and then sent to the standard output | |
stream. The child's standard output stream is connected directly | |
to the 'http-connection'. In this case, presumably the | |
'http-connection' would have functions attached to the properties | |
'':send-string-function' and ':send-eof-function' to do HTTP | |
chunk encoding and to end the HTTP connection correctly." | |
(declare (indent defun)) | |
(let ((loadpathvar (make-symbol "load-path-form")) | |
(childlispvar (make-symbol "child-lisp")) | |
(lispvar (make-symbol "lisp")) | |
(filtervar (make-symbol "filter-function")) | |
(cmdvar (make-symbol "command")) | |
(procvar (make-symbol "process")) | |
(namevar (make-symbol "process-name")) | |
(bufvar (make-symbol "buffer")) | |
(outvar (make-symbol "output-stream"))) | |
`(let* ((,outvar ,output-stream) | |
(,childlispvar ; the lisp to run | |
(format "(progn (setq load-path (quote %S)) %S)\n" | |
load-path | |
'(progn ,@body))) | |
(,cmdvar "emacs -q -batch --eval '(eval (read))' 2> /dev/null") | |
(,namevar (concat | |
(number-to-string (random)) | |
(number-to-string (float-time)))) | |
;; We have to make a buffer unless the output-stream is a buffer | |
(,bufvar (cond | |
((bufferp ,outvar) ,outvar) | |
(t | |
(get-buffer-create (format "* %s *" ,namevar))))) | |
(,procvar (start-process-shell-command ,namevar ,bufvar ,cmdvar))) | |
;; If the output stream is not a buffer we need a filter function | |
(cond | |
;; We wrap output to filters functions or buffers just a little | |
((or (bufferp ,outvar) | |
(functionp ,outvar)) | |
(set-process-filter | |
,procvar | |
(lambda (process data) | |
(if (equal data "Lisp expression: ") | |
(process-send-string process ,childlispvar) | |
(if (bufferp ,outvar) | |
(with-current-buffer ,outvar | |
(insert data)) | |
(funcall ,outvar process data)))))) | |
;; A process - setup a filter function | |
((processp ,outvar) | |
(set-process-filter | |
,procvar | |
(lambda (process data) | |
;; We get this as a signal to read a lisp expression | |
(if (equal data "Lisp expression: ") | |
(process-send-string process ,childlispvar) | |
(if (not (equal "closed" (process-status ,procvar))) | |
(when (processp ,outvar) | |
(funcall | |
;; Does the output-stream have a specific function? | |
(or (process-get ,outvar :send-string-function) | |
'process-send-string) | |
;; The data to sent to the output-stream process | |
,outvar data)))))))) | |
;; Now setup the sentinel | |
(set-process-sentinel | |
,procvar | |
(lambda (process status) | |
(let ((send-eof-function | |
;; Does the output-stream have a send-eof? | |
(and (processp ,outvar) | |
(or (process-get ,outvar :send-eof-function) | |
'process-send-eof)))) | |
(cond | |
((equal status "finished\n") | |
(message "%s completed" ,namevar) | |
(when send-eof-function | |
(funcall send-eof-function ,outvar))) | |
((string-match "exited abnormally with code \\([0-9]+\\)\n" status) | |
(message "%s completed with an error" ,namevar) | |
(when send-eof-function | |
(funcall send-eof-function ,outvar)) | |
(delete-process process) | |
(unless (bufferp ,outvar) | |
(kill-buffer (process-buffer process)))) | |
;; Any other signal status is ignored | |
(t))))) | |
,procvar))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment