"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 <host>:<port>")
+ "Method used to contact a server.")
(eglot--define-process-var eglot--deferred-actions
(make-hash-table :test #'equal)
(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))
(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
(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 <host>:<port>): ")
(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)
;; 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))
(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."
\f
;;; 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)