branch: externals/eglot commit a7ddce694ac1f35c240700ff6f9edd379704feeb Author: João Távora <joaotav...@gmail.com> Commit: João Távora <joaotav...@gmail.com>
Support javascript's javascript-typescript-langserver * README.md: Improve a bit * eglot.el (eglot--make-process): Take MANAGED-MAJOR-MODE arg (eglot-executables): Add basic javascript support. (eglot--connect): Pass mode to eglot--make-process (eglot--interactive): Check that guessed command is a listp. (eglot): Minor improvement to message. (eglot--current-buffer-TextDocumentItem): Guess language from mode symbol. --- README.md | 42 +++++++++++++++++++++++++++++++++++++----- eglot.el | 41 +++++++++++++++++++++++------------------ 2 files changed, 60 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 8809421..0314664 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,41 @@ M-x eglot ``` *That's it*. Either this guesses the local LSP program to start for -the language of your choice or it prompts you for such a thing. You -can also enter a `server:port` pattern to connect to an LSP server. To -skip the guess and always be prompted use `C-u M-x eglot`. +the language of your choice or it prompts you for such a +thing. Currently, if you have these programs installed, it works +out-of-the-box for: -## Differences to lsp-mode.el +* Javascript's [javascript-typescript-stdio][javascript-typescript-langserver] +* Rust's [rls][rls] +* Python's [pyls][pyls] + +You can also enter a `server:port` pattern to connect to an LSP +server. To skip the guess and always be prompted use `C-u M-x eglot`. + +# Supported Protocol features + +- [x] textDocument/didChange (incremental) +- [x] textDocument/didClose +- [x] textDocument/didOpen +- [x] textDocument/didSave + +- [ ] textDocument/codeAction +- [ ] textDocument/completion (incl. completion/resolve) +- [x] textDocument/definition +- [ ] textDocument/documentHighlight +- [ ] textDocument/documentSymbol +- [ ] textDocument/executeCommand +- [ ] textDocument/format +- [ ] textDocument/hover +- [ ] textDocument/rename +- [x] textDocument/references +- [ ] textDocument/signatureHelp +- [x] workspace/symbol + +# Differences to lsp-mode.el This is really beta and currently does less than -[lsp-mode.el](https://github.com/emacs-lsp/lsp-mode) which is more +[lsp-mode.el][emacs-lsp] which is more mature. Though I think `eglot.el` will eventually beat it, you could be better served with `lsp-mode.el` for now. @@ -45,5 +72,10 @@ Differences under the hood: tiny change. - Its missing tests! This is *not good* +[rls]: https://github.com/rust-lang-nursery/rls +[pyls]: https://github.com/palantir/python-language-server +[javascript-typescript-langserver]: https://github.com/sourcegraph/javascript-typescript-langserver +[emacs-lsp]: https://github.com/emacs-lsp/lsp-mode + diff --git a/eglot.el b/eglot.el index cd48519..045588d 100644 --- a/eglot.el +++ b/eglot.el @@ -42,8 +42,10 @@ :prefix "eglot-" :group 'applications) -(defvar eglot-executables '((rust-mode . ("rls")) - (python-mode . ("pyls"))) +(defvar eglot-executables + '((rust-mode . ("rls")) + (python-mode . ("pyls")) + (js-mode . ("javascript-typescript-stdio"))) "Alist mapping major modes to server executables.") (defface eglot-mode-line @@ -145,23 +147,24 @@ list of a single string of the form <host>:<port>") (eglot--define-process-var eglot--buffer-open-count (make-hash-table) "Keeps track of didOpen/didClose notifs for each buffer.") -(defun eglot--make-process (name contact) +(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. +MANAGED-MAJOR-MODE is a symbol naming a major mode. CONTACT is as `eglot--contact'. Returns a process object." - (let* ((readable-name (format "EGLOT server (%s)" name)) + (let* ((readable-name (format "EGLOT server (%s/%s)" name managed-major-mode)) (buffer (get-buffer-create (format "*%s inferior*" readable-name))) - (singleton (and (null (cdr contact)) (car contact))) + singleton (proc - (if (and - singleton - (string-match "^[\s\t]*\\(.*\\):\\([[:digit:]]+\\)[\s\t]*$" - singleton)) + (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))) + (string-to-number + (match-string 2 singleton))) (make-process :name readable-name :buffer buffer @@ -236,7 +239,7 @@ CONTACT is as `eglot--contact'. Returns a process object." short-name contact &optional success-fn) "Connect for PROJECT, MANAGED-MAJOR-MODE, SHORT-NAME and CONTACT. SUCCESS-FN with no args if all goes well." - (let* ((proc (eglot--make-process short-name contact)) + (let* ((proc (eglot--make-process short-name managed-major-mode contact)) (buffer (process-buffer proc))) (setf (eglot--contact proc) contact (eglot--project proc) project @@ -297,15 +300,16 @@ SUCCESS-FN with no args if all goes well." managed-major-mode (let ((prompt (cond (current-prefix-arg - "[eglot] Execute program (or connect to <host>:<port>) ") + "[eglot] Enter program to execute (or <host>:<port>): ") ((null guessed-command) (format "[eglot] Sorry, couldn't guess for `%s'!\n\ -Execute program (or connect to <host>:<port>) " +Enter program to execute (or <host>:<port>): " managed-major-mode))))) (if prompt (split-string-and-unquote (read-shell-command prompt - (combine-and-quote-strings guessed-command) + (if (listp guessed-command) + (combine-and-quote-strings guessed-command)) 'eglot-command-history)) guessed-command)) t))) @@ -347,7 +351,7 @@ INTERACTIVE is t if called interactively." command (lambda (proc) (eglot--message "Connected! Process `%s' now managing `%s' \ -buffers in project %s." +buffers in project `%s'." proc managed-major-mode short-name))))))) @@ -1101,9 +1105,10 @@ running. INTERACTIVE is t if called interactively." "Compute TextDocumentItem object for current buffer." (append (eglot--current-buffer-VersionedTextDocumentIdentifier) - (eglot--obj :languageId (cdr (assoc major-mode - '((rust-mode . rust) - (emacs-lisp-mode . emacs-lisp)))) + (eglot--obj :languageId + (if (string-match "\\(.*\\)-mode" (symbol-name major-mode)) + (match-string 1 (symbol-name major-mode)) + "unknown") :text (save-restriction (widen)