Function: server--process-filter-1
server--process-filter-1 is a byte-compiled function defined in
server.el.gz.
Signature
(server--process-filter-1 PROC STRING)
Source Code
;; Defined in /usr/src/emacs/lisp/server.el.gz
(cl-defun server--process-filter-1 (proc string)
(server-log (concat "Received " string) proc)
;; First things first: let's check the authentication
(unless (process-get proc :authenticated)
(if (and (string-match "-auth \\([!-~]+\\)\n?" string)
(equal (match-string 1 string) (process-get proc :auth-key)))
(progn
(setq string (substring string (match-end 0)))
(process-put proc :authenticated t)
(server-log "Authentication successful" proc))
(server-log "Authentication failed" proc)
;; Display the error as a message and give the user time to see
;; it, in case the error written by emacsclient to stderr is not
;; visible for some reason.
(server--message-sit-for 2 "Authentication failed")
(server-send-string
proc (concat "-error " (server-quote-arg "Authentication failed")))
(unless (eq system-type 'windows-nt)
(let ((terminal (process-get proc 'terminal)))
;; Only delete the terminal if it is non-nil.
(when (and terminal (eq (terminal-live-p terminal) t))
(delete-terminal terminal))))
;; Before calling `delete-process', give emacsclient time to
;; receive the error string and shut down on its own.
;; FIXME: Why do we wait 1s here but 5s in the other one?
(run-with-timer 1 nil #'delete-process proc)
;; We return immediately.
(cl-return-from server--process-filter-1)))
(let ((prev (process-get proc 'previous-string)))
(when prev
(setq string (concat prev string))
(process-put proc 'previous-string nil)))
(condition-case err
(progn
(server-add-client proc)
;; Send our pid
(server-send-string proc (concat "-emacs-pid "
(number-to-string (emacs-pid)) "\n"))
(if (not (string-match "\n" string))
;; Save for later any partial line that remains.
(when (> (length string) 0)
(process-put proc 'previous-string string))
;; In earlier versions of server.el (where we used an `emacsserver'
;; process), there could be multiple lines. Nowadays this is not
;; supported any more.
(cl-assert (eq (match-end 0) (length string)))
(let ((request (substring string 0 (match-beginning 0)))
(coding-system (or file-name-coding-system
default-file-name-coding-system))
nowait ; t if emacsclient does not want to wait for us.
frame ; Frame opened for the client (if any).
display ; Open frame on this display.
parent-id ; Window ID for XEmbed
dontkill ; t if client should not be killed.
commands
evalexprs
dir
use-current-frame
frame-parameters ;parameters for newly created frame
tty-name ; nil, `window-system', or the tty name.
tty-type ; string.
files
filepos
args-left)
;; Remove this line from STRING.
(setq string (substring string (match-end 0)))
(setq args-left
(mapcar #'server-unquote-arg (split-string request " " t)))
(while args-left
(pcase (pop args-left)
;; -version CLIENT-VERSION: obsolete at birth.
("-version" (pop args-left))
;; -nowait: Emacsclient won't wait for a result.
("-nowait" (setq nowait t))
;; -current-frame: Don't create frames.
("-current-frame" (setq use-current-frame t))
;; -frame-parameters: Set frame parameters
("-frame-parameters"
(let ((alist (pop args-left)))
(if coding-system
(setq alist (decode-coding-string alist coding-system)))
(setq frame-parameters (car (read-from-string alist)))))
;; -display DISPLAY:
;; Open X frames on the given display instead of the default.
("-display"
(setq display (pop args-left))
(if (zerop (length display)) (setq display nil)))
;; -parent-id ID:
;; Open X frame within window ID, via XEmbed.
("-parent-id"
(setq parent-id (pop args-left))
(if (zerop (length parent-id)) (setq parent-id nil)))
;; -window-system: Open a new X frame.
("-window-system"
(if (fboundp 'x-create-frame)
(setq dontkill t
tty-name 'window-system)))
;; -resume: Resume a suspended tty frame.
("-resume"
(let ((terminal (process-get proc 'terminal)))
(setq dontkill t)
(push (lambda ()
(when (eq (terminal-live-p terminal) t)
(resume-tty terminal)))
commands)))
;; -suspend: Suspend the client's frame. (In case we
;; get out of sync, and a C-z sends a SIGTSTP to
;; emacsclient.)
("-suspend"
(let ((terminal (process-get proc 'terminal)))
(setq dontkill t)
(push (lambda ()
(when (eq (terminal-live-p terminal) t)
(suspend-tty terminal)))
commands)))
;; -ignore COMMENT: Noop; useful for debugging emacsclient.
;; (The given comment appears in the server log.)
("-ignore"
(setq dontkill t)
(pop args-left))
;; -tty DEVICE-NAME TYPE: Open a new tty frame.
;; (But if we see -window-system later, use that.)
("-tty"
(setq tty-name (pop args-left)
tty-type (pop args-left)
dontkill (or dontkill
(not use-current-frame)))
;; On Windows, emacsclient always asks for a tty
;; frame. If running a GUI server, force the frame
;; type to GUI. (Cygwin is perfectly happy with
;; multi-tty support, so don't override the user's
;; choice there.) In daemon mode on Windows, we can't
;; make tty frames, so force the frame type to GUI
;; there too.
(when (or (and (eq system-type 'windows-nt)
(or (daemonp)
(eq window-system 'w32)))
;; Client runs on Windows, but the server
;; runs on a Posix host.
(equal tty-name "CONOUT$"))
(push "-window-system" args-left)))
;; -position +LINE[:COLUMN]: Set point to the given
;; position in the next file.
("-position"
(if (not (string-match "\\+\\([0-9]+\\)\\(?::\\([0-9]+\\)\\)?"
(car args-left)))
(error "Invalid -position command in client args"))
(let ((arg (pop args-left)))
(setq filepos
(cons (string-to-number (match-string 1 arg))
(string-to-number (or (match-string 2 arg)
""))))))
;; -file FILENAME: Load the given file.
("-file"
(let ((file (pop args-left)))
(if coding-system
(setq file (decode-coding-string file coding-system)))
;; Allow Cygwin's emacsclient to be used as a file
;; handler on MS-Windows, in which case FILENAME
;; might start with a drive letter.
(when (and (fboundp 'cygwin-convert-file-name-from-windows)
(string-match "\\`[A-Za-z]:" file))
(setq file (cygwin-convert-file-name-from-windows file)))
(setq file (expand-file-name file dir))
(push (cons file filepos) files)
(server-log (format "New file: %s %s"
file (or filepos ""))
proc))
(setq filepos nil))
;; -eval EXPR: Evaluate a Lisp expression.
("-eval"
(if use-current-frame
(setq use-current-frame 'always))
(let ((expr (pop args-left)))
(if coding-system
(setq expr (decode-coding-string expr coding-system)))
(push expr evalexprs)
(setq filepos nil)))
;; -env NAME=VALUE: An environment variable.
("-env"
(let ((var (pop args-left)))
;; XXX Variables should be encoded as in getenv/setenv.
(process-put proc 'env
(cons var (process-get proc 'env)))))
;; -dir DIRNAME: The cwd of the emacsclient process.
("-dir"
(setq dir (pop args-left))
(if coding-system
(setq dir (decode-coding-string dir coding-system)))
(setq dir (command-line-normalize-file-name dir))
(process-put proc 'server-client-directory dir))
;; Unknown command.
(arg (error "Unknown command: %s" arg))))
;; If both -no-wait and -tty are given with file or sexp
;; arguments, use an existing frame.
(and nowait
(not (eq tty-name 'window-system))
(or files commands evalexprs)
(setq use-current-frame t))
(setq frame
(cond
((and use-current-frame
(or (eq use-current-frame 'always)
;; We can't use the Emacs daemon's
;; terminal frame.
(not (and (daemonp)
(null (cdr (frame-list)))
(eq (selected-frame)
terminal-frame)))))
(setq tty-name nil tty-type nil)
(if display (server-select-display display)))
((equal tty-type "dumb")
(server-create-dumb-terminal-frame nowait proc
frame-parameters))
((or (and (eq system-type 'windows-nt)
(daemonp)
(setq display "w32"))
(eq tty-name 'window-system))
(server-create-window-system-frame display nowait proc
parent-id
frame-parameters))
;; When resuming on a tty, tty-name is nil.
(tty-name
(server-create-tty-frame tty-name tty-type proc
frame-parameters))
;; If there won't be a current frame to use, fall
;; back to trying to create a new one.
((and use-current-frame
(daemonp)
(null (cdr (frame-list)))
(eq (selected-frame) terminal-frame)
display)
(setq tty-name nil tty-type nil)
(server-select-display display))))
(process-put
proc 'continuation
(lambda ()
(with-current-buffer (get-buffer-create server-buffer)
;; Use the same cwd as the emacsclient, if possible, so
;; relative file names work correctly, even in `eval'.
(let ((default-directory
(if (and dir (file-directory-p dir))
dir default-directory)))
(server-execute proc files nowait commands evalexprs
dontkill frame tty-name)))))
(when (or frame files)
(server-goto-toplevel proc))
(server-execute-continuation proc))))
;; condition-case
(t (server-return-error proc err))))