From af56249cadefef58ca628a566e70a8a71e306bb9 Mon Sep 17 00:00:00 2001 From: Spencer Baugh Date: Sat, 10 Sep 2016 15:49:33 -0400 Subject: [PATCH 5/5] emacsclient, server.el: add -proxy-stdio and use When the client gets -proxy-stdio it will stop listening for or sending commands and instead just blindly copy its stdin to Emacs and from Emacs to its stdout. This mode can be activated by running a function like server-pager through emacsclient --eval "(server-pager)". --- lib-src/emacsclient.c | 43 +++++++++++++++++++++++++++++++++++++++++++ lisp/server.el | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c index aeef93d..f1a2c71 100644 --- a/lib-src/emacsclient.c +++ b/lib-src/emacsclient.c @@ -1622,6 +1622,35 @@ start_daemon_and_retry_set_socket (void) #endif /* WINDOWSNT */ } +int write_all (int fd, char *buf, size_t size); +int +write_all (int fd, char *buf, size_t size) +{ + int ret; + while (size > 0) { + ret = write (fd, buf, size); + if (ret == -1) return -1; + size -= ret; + } + return 0; +} + +int start_proxying (char *buf, size_t size); +int +start_proxying (char *buf, size_t size) +{ + int ret; + + /* not actually proxying output from emacs to our stdout yet */ + for (;;) { + ret = read (fileno (stdin), buf, size); + if (ret == 0) return EXIT_SUCCESS; + if (ret == -1) return EXIT_FAILURE; + ret = write_all (emacs_socket, buf, ret); + if (ret == -1) return EXIT_FAILURE; + } +} + int main (int argc, char **argv) { @@ -1918,6 +1947,20 @@ main (int argc, char **argv) kill (0, SIGSTOP); } #endif + else if (strprefix ("-proxy-stdio ", p)) + { + /* -proxy-stdio: Begin proxying stdio */ + /* All further data sent to us by Emacs (including the + * rest of this message), we should write out verbatim + * to stdout. */ + /* And we should start reading stdin and sending it + * verbatim to Emacs. */ + if (write_all (fileno(stdout), end_p, (string + rl) - end_p) != 0) + return EXIT_FAILURE; + /* We'll do this forever and do nothing else. */ + return start_proxying(string, sizeof(string)); + } + else { /* Unknown command. */ diff --git a/lisp/server.el b/lisp/server.el index 93b3ca4..c47ef74 100644 --- a/lisp/server.el +++ b/lisp/server.el @@ -1279,9 +1279,11 @@ server-execute (with-local-quit (condition-case err (let ((buffers (server-visit-files files proc nowait)) - (server-emacsclient-proc proc)) + (server-emacsclient-proc proc) + pager-func) (mapc 'funcall (nreverse commands)) + (setq pager-func (process-get proc 'server-client-pager-func)) ;; If we were told only to open a new client, obey ;; `initial-buffer-choice' if it specifies a file ;; or a function. @@ -1301,10 +1303,17 @@ server-execute ;; Client requested nowait; return immediately. (server-log "Close nowait client" proc) (server-delete-client proc)) - ((and (not dontkill) (null buffers)) + ((and (not dontkill) (null buffers) (not pager-func)) ;; This client is empty; get rid of it immediately. (server-log "Close empty client" proc) - (server-delete-client proc))) + (server-delete-client proc)) + ((and (not dontkill) (null buffers) pager-func) + ;; We've been instructed to turn this emacsclient into a pager + ;; this passes it outside the control of server.el, so for us it's like killing it + (server-send-string proc "-proxy-stdio \n") + ;; pager-func should set up a new process-filter and return promptly + (funcall pager-func proc) + (setq server-clients (delq proc server-clients)))) (cond ((or isearch-mode (minibufferp)) nil) @@ -1324,6 +1333,24 @@ server-execute (message "Quit emacsclient request")) (server-return-error proc err))))) +(defun server-pager () + "Create a buffer holding the stdin of the current client. +This function will create a buffer *pager* which will receive +input from the stdin of the current emacsclient. + +This function should only be run by passing --eval to emacsclient, +like so: + echo some data | emacsclient --eval '(server-pager)'" + (when (null server-emacsclient-proc) + (error "Cannot be run out of emacsclient --eval context")) + (process-put server-emacsclient-proc 'server-client-pager-func + (lambda (proc) + (let ((buffer (generate-new-buffer "*pager*"))) + (set-process-buffer proc buffer) + (set-process-filter proc nil) + (pop-to-buffer buffer)))) + nil) + (defun server-return-error (proc err) (ignore-errors (server-send-string -- 2.9.3