From 2290ce100fc56560c63cbd0d50816e725023315a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sat, 19 May 2018 09:29:52 +0100 Subject: [PATCH] Simplify some infrastructure fucntions * eglot.el (eglot--contact): Simplify docstring. (eglot--make-process): Simplify. (eglot--connect): Simplify. (eglot--interactive): Simplify and correct odd bug. (eglot--process-sentinel): Correct messages. Delete before attempting reconnection. (eglot-shutdown): Simplify. --- lisp/progmodes/eglot.el | 113 +++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 60 deletions(-) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 4a847bb6029..0a2fcf5955c 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -163,9 +163,7 @@ A list (WHAT SERIOUS-P).") "If non-nil, don't autoreconnect on unexpected quit.") (eglot--define-process-var eglot--contact nil - "Method used to contact a server. -Either a list of strings (a shell command and arguments), or a -list of a single string of the form :") + "Method used to contact a server.") (eglot--define-process-var eglot--deferred-actions (make-hash-table :test #'equal) @@ -176,29 +174,23 @@ list of a single string of the form :") (defun eglot--make-process (name managed-major-mode contact) "Make a process from CONTACT. -NAME is a name to give the inferior process or connection. +NAME is used to name the the started process or connection. MANAGED-MAJOR-MODE is a symbol naming a major mode. -CONTACT is as `eglot--contact'. Returns a process object." +CONTACT is in `eglot'. Returns a process object." (let* ((readable-name (format "EGLOT server (%s/%s)" name managed-major-mode)) - (buffer (get-buffer-create - (format "*%s inferior*" readable-name))) - singleton - (proc - (if (and (setq singleton (and (null (cdr contact)) (car contact))) - (string-match "^[\s\t]*\\(.*\\):\\([[:digit:]]+\\)[\s\t]*$" - singleton)) - (open-network-stream readable-name - buffer - (match-string 1 singleton) - (string-to-number - (match-string 2 singleton))) - (make-process :name readable-name - :buffer buffer - :command contact - :coding 'no-conversion - :connection-type 'pipe - :stderr (get-buffer-create (format "*%s stderr*" - name)))))) + (buffer (get-buffer-create (format "*%s stdout*" readable-name))) + (proc (cond + ((processp contact) contact) + ((integerp (cadr contact)) + (apply #'open-network-stream readable-name buffer contact)) + (t (make-process + :name readable-name + :command contact + :coding 'no-conversion + :connection-type 'pipe + :stderr (get-buffer-create (format "*%s stderr*" name))))))) + (set-process-buffer proc buffer) + (set-marker (process-mark proc) (with-current-buffer buffer (point-min))) (set-process-filter proc #'eglot--process-filter) (set-process-sentinel proc #'eglot--process-sentinel) proc)) @@ -250,7 +242,9 @@ CONTACT is as `eglot--contact'. Returns a process object." (defun eglot--connect (project managed-major-mode short-name contact _interactive) "Connect for PROJECT, MANAGED-MAJOR-MODE, SHORT-NAME and CONTACT. INTERACTIVE is t if inside interactive call." - (let* ((proc (eglot--make-process short-name managed-major-mode contact)) + (let* ((proc (eglot--make-process + short-name managed-major-mode (if (functionp contact) + (funcall contact) contact))) (buffer (process-buffer proc))) (setf (eglot--contact proc) contact (eglot--project proc) project @@ -309,32 +303,32 @@ INTERACTIVE is t if inside interactive call." (mapcar #'symbol-name (eglot--all-major-modes)) nil t (symbol-name guessed-mode) nil (symbol-name guessed-mode) nil))) (t guessed-mode))) - (guessed-command (cdr (assoc managed-mode eglot-server-programs))) + (project (or (project-current) `(transient . ,default-directory))) + (guessed (cdr (assoc managed-mode eglot-server-programs))) + (program (and (listp guessed) (stringp (car guessed)) (car guessed))) (base-prompt "[eglot] Enter program to execute (or :): ") (prompt (cond (current-prefix-arg base-prompt) - ((null guessed-command) - (concat (format "[eglot] Sorry, couldn't guess for `%s'!" - managed-mode) - "\n" base-prompt)) - ((and (listp guessed-command) - (not (executable-find (car guessed-command)))) + ((null guessed) + (format "[eglot] Sorry, couldn't guess for `%s'\n%s!" + managed-mode base-prompt)) + ((and program (not (executable-find program))) (concat (format "[eglot] I guess you want to run `%s'" - (combine-and-quote-strings guessed-command)) - (format ", but I can't find `%s' in PATH!" - (car guessed-command)) - "\n" base-prompt))))) - (list - managed-mode - (or (project-current) `(transient . ,default-directory)) - (if prompt - (split-string-and-unquote - (read-shell-command prompt - (if (listp guessed-command) - (combine-and-quote-strings guessed-command)) - 'eglot-command-history)) - guessed-command) - t))) + (combine-and-quote-strings guessed)) + (format ", but I can't find `%s' in PATH!" program) + "\n" base-prompt)))) + (contact + (if prompt + (let ((s (read-shell-command + prompt + (if program (combine-and-quote-strings guessed)) + 'eglot-command-history))) + (if (string-match "^\\([^\s\t]+\\):\\([[:digit:]]+\\)$" + (string-trim s)) + (list (match-string 1 s) (string-to-number (match-string 2 s))) + (split-string-and-unquote s))) + guessed))) + (list managed-mode project contact t))) ;;;###autoload (defun eglot (managed-major-mode project command &optional interactive) @@ -417,7 +411,7 @@ INTERACTIVE is t if called interactively." ;; Call all outstanding error handlers (maphash (lambda (_id triplet) (cl-destructuring-bind (_success error _timeout) triplet - (funcall error :code -1 :message (format "Server died")))) + (funcall error `(:code -1 :message "Server died")))) (eglot--pending-continuations proc)) ;; Turn off `eglot--managed-mode' where appropriate. (dolist (buffer (buffer-list)) @@ -428,14 +422,16 @@ INTERACTIVE is t if called interactively." (setf (gethash (eglot--project proc) eglot--processes-by-project) (delq proc (gethash (eglot--project proc) eglot--processes-by-project))) - (eglot--message "Server exited with status %s" (process-exit-status proc)) + ;; Say last words + (eglot--message "%s exited with status %s" proc (process-exit-status proc)) + (delete-process proc) + ;; Consider autoreconnecting (cond ((eglot--moribund proc)) ((not (eglot--inhibit-autoreconnect proc)) (eglot--warn "Reconnecting after unexpected server exit") (eglot-reconnect proc)) ((timerp (eglot--inhibit-autoreconnect proc)) - (eglot--warn "Not auto-reconnecting, last on didn't last long."))) - (delete-process proc)))) + (eglot--warn "Not auto-reconnecting, last on didn't last long.")))))) (defun eglot--process-filter (proc string) "Called when new data STRING has arrived for PROC." @@ -934,23 +930,20 @@ Uses THING, FACE, DEFS and PREPEND." ;;; Protocol implementation (Requests, notifications, etc) ;;; -(defun eglot-shutdown (proc &optional interactive) +(defun eglot-shutdown (proc &optional _interactive) "Politely ask the server PROC to quit. Forcefully quit it if it doesn't respond. Don't leave this -function with the server still running. INTERACTIVE is t if -called interactively." +function with the server still running." (interactive (list (eglot--current-process-or-lose) t)) - (when interactive (eglot--message "Asking %s politely to terminate" proc)) + (eglot--message "Asking %s politely to terminate" proc) (unwind-protect (let ((eglot-request-timeout 3)) (setf (eglot--moribund proc) t) - (eglot--request proc - :shutdown - nil) - ;; this one should always fail + (eglot--request proc :shutdown nil) + ;; this one is supposed to always fail, hence ignore-errors (ignore-errors (eglot--request proc :exit nil))) (when (process-live-p proc) - (eglot--warn "Brutally deleting existing process %s" proc) + (eglot--warn "Brutally deleting non-compliant existing process %s" proc) (delete-process proc)))) (cl-defun eglot--server-window/showMessage (_process &key type message) -- 2.39.2