* A list combining the previous two alternatives, meaning
multiple major modes will be associated with a single server
- program.
+ program. This association is such that the same resulting
+ server process will manage buffers of different major modes.
CONTACT can be:
:documentation "Short nickname for the associated project."
:accessor eglot--project-nickname
:reader eglot-project-nickname)
- (major-mode
- :documentation "Major mode symbol."
- :accessor eglot--major-mode)
+ (major-modes
+ :documentation "Major modes server is responsible for in a given project."
+ :accessor eglot--major-modes)
(language-id
:documentation "Language ID string for the mode."
:accessor eglot--language-id)
(defun eglot--lookup-mode (mode)
"Lookup `eglot-server-programs' for MODE.
-Return (LANGUAGE-ID . CONTACT-PROXY). If not specified,
-LANGUAGE-ID is determined from MODE."
+Return (MANAGED-MODES LANGUAGE-ID CONTACT-PROXY).
+
+MANAGED-MODES is a list with MODE as its first elements.
+Subsequent elements are other major modes also potentially
+managed by the server that is to manage MODE.
+
+If not specified in `eglot-server-programs' (which see),
+LANGUAGE-ID is determined from MODE's name.
+
+CONTACT-PROXY is the value of the corresponding
+`eglot-server-programs' entry."
(cl-loop
for (modes . contact) in eglot-server-programs
+ for mode-symbols = (cons mode
+ (delete mode
+ (mapcar #'car
+ (mapcar #'eglot--ensure-list
+ (eglot--ensure-list modes)))))
thereis (cl-some
(lambda (spec)
(cl-destructuring-bind (probe &key language-id &allow-other-keys)
- (if (consp spec) spec (list spec))
+ (eglot--ensure-list spec)
(and (provided-mode-derived-p mode probe)
- (cons
+ (list
+ mode-symbols
(or language-id
(or (get mode 'eglot-language-id)
(get spec 'eglot-language-id)
non-nil, maybe prompt user, else error as soon as something can't
be guessed."
(let* ((guessed-mode (if buffer-file-name major-mode))
- (managed-mode
+ (main-mode
(cond
((and interactive
(or (>= (prefix-numeric-value current-prefix-arg) 16)
((not guessed-mode)
(eglot--error "Can't guess mode to manage for `%s'" (current-buffer)))
(t guessed-mode)))
- (lang-id-and-guess (eglot--lookup-mode guessed-mode))
- (language-id (or (car lang-id-and-guess)
+ (triplet (eglot--lookup-mode main-mode))
+ (managed-modes (car triplet))
+ (language-id (or (cadr triplet)
(string-remove-suffix "-mode" (symbol-name guessed-mode))))
- (guess (cdr lang-id-and-guess))
+ (guess (caddr triplet))
(guess (if (functionp guess)
(funcall guess interactive)
guess))
(cond (current-prefix-arg base-prompt)
((null guess)
(format "[eglot] Sorry, couldn't guess for `%s'!\n%s"
- managed-mode base-prompt))
+ main-mode base-prompt))
((and program
(not (file-name-absolute-p program))
(not (eglot--executable-find program t)))
full-program-invocation
'eglot-command-history)))
guess)))
- (list managed-mode (eglot--current-project) class contact language-id)))
+ (list managed-modes (eglot--current-project) class contact language-id)))
(defvar eglot-lsp-context)
(put 'eglot-lsp-context 'variable-documentation
(interactive (list (eglot--current-server-or-lose) t))
(when (jsonrpc-running-p server)
(ignore-errors (eglot-shutdown server interactive nil 'preserve-buffers)))
- (eglot--connect (eglot--major-mode server)
+ (eglot--connect (eglot--major-modes server)
(eglot--project server)
(eieio-object-class-name server)
(eglot--saved-initargs server)
(defvar-local eglot--cached-server nil
"A cached reference to the current EGLOT server.")
-(defun eglot--connect (managed-major-mode project class contact language-id)
- "Connect to MANAGED-MAJOR-MODE, LANGUAGE-ID, PROJECT, CLASS and CONTACT.
+(defun eglot--connect (managed-modes project class contact language-id)
+ "Connect to MANAGED-MODES, LANGUAGE-ID, PROJECT, CLASS and CONTACT.
This docstring appeases checkdoc, that's all."
(let* ((default-directory (project-root project))
(nickname (file-name-base (directory-file-name default-directory)))
- (readable-name (format "EGLOT (%s/%s)" nickname managed-major-mode))
+ (readable-name (format "EGLOT (%s/%s)" nickname managed-modes))
autostart-inferior-process
server-info
(contact (if (functionp contact) (funcall contact) contact))
(setf (eglot--saved-initargs server) initargs)
(setf (eglot--project server) project)
(setf (eglot--project-nickname server) nickname)
- (setf (eglot--major-mode server) managed-major-mode)
+ (setf (eglot--major-modes server) (eglot--ensure-list managed-modes))
(setf (eglot--language-id server) language-id)
(setf (eglot--inferior-process server) autostart-inferior-process)
(run-hook-with-args 'eglot-server-initialized-hook server)
(setf (eglot--inhibit-autoreconnect server)
(null eglot-autoreconnect)))))))
(let ((default-directory (project-root project))
- (major-mode managed-major-mode))
+ (major-mode (car managed-modes)))
(hack-dir-local-variables-non-file-buffer)
(run-hook-with-args 'eglot-connect-hook server))
(eglot--message
in project `%s'."
(or (plist-get serverInfo :name)
(jsonrpc-name server))
- managed-major-mode
+ managed-modes
(eglot-project-nickname server))
(when tag (throw tag t))))
:timeout eglot-connect-timeout
being hash-values of eglot--servers-by-project
append servers))
(name (lambda (srv)
- (format "%s/%s" (eglot-project-nickname srv)
- (eglot--major-mode srv)))))
+ (format "%s %s" (eglot-project-nickname srv)
+ (eglot--major-modes srv)))))
(cond ((null servers)
(eglot--error "No servers!"))
((or (cdr servers) (not dont-if-just-the-one))
(defun eglot--plist-keys (plist) "Get keys of a plist."
(cl-loop for (k _v) on plist by #'cddr collect k))
+(defun eglot--ensure-list (x) (if (listp x) x (list x)))
+
\f
;;; Minor modes
;;;
(or eglot--cached-server
(cl-find major-mode
(gethash (eglot--current-project) eglot--servers-by-project)
- :key #'eglot--major-mode)
+ :key #'eglot--major-modes
+ :test #'memq)
(and eglot-extend-to-xref
buffer-file-name
(gethash (expand-file-name buffer-file-name)
(file-directory-p uri-path))
(file-name-as-directory uri-path)
(project-root (eglot--project server)))))
- (setq-local major-mode (eglot--major-mode server))
+ (setq-local major-mode (car (eglot--major-modes server)))
(hack-dir-local-variables-non-file-buffer)
(cl-loop for (wsection o)
on (eglot--workspace-configuration-plist server)