[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/eglot 258e3b0 07/69: Merge master into jsonrpc-refactor
From: |
João Távora |
Subject: |
[elpa] externals/eglot 258e3b0 07/69: Merge master into jsonrpc-refactor (using imerge) |
Date: |
Fri, 22 Jun 2018 11:54:54 -0400 (EDT) |
branch: externals/eglot
commit 258e3b068c9715aa20eb7d5ec714069fd70eee87
Merge: 5cda0ec 1f8c238
Author: João Távora <address@hidden>
Commit: João Távora <address@hidden>
Merge master into jsonrpc-refactor (using imerge)
---
README.md | 38 +++++++++++++----
eglot-tests.el | 2 +-
eglot.el | 131 +++++++++++++++++++++++++++++++++++----------------------
jrpc.el | 16 +++----
4 files changed, 120 insertions(+), 67 deletions(-)
diff --git a/README.md b/README.md
index 7550a30..b87666c 100644
--- a/README.md
+++ b/README.md
@@ -4,10 +4,10 @@ Eglot
*E*macs Poly*glot*. An Emacs client to [Language Server Protocol][lsp] servers.
-```
-(add-to-list 'load-path "/path/to/eglot")
-(require 'eglot) ; Requires emacs 26!
+Eglot is [in ELPA][gnuelpa]. Installation is straightforward:
+```
+(package-install 'eglot) ; Requires Emacs 26!
;; Now find some source file, any source file
M-x eglot
```
@@ -15,14 +15,15 @@ M-x eglot
*That's it*. If you're lucky, this guesses the LSP executable to start
for the language of your choice. Otherwise, it prompts you to enter one:
-`M-x eglot` currently guesses and works out-of-the-box with:
+`M-x eglot` can guess and work out-of-the-box with these servers:
* Javascript's [javascript-typescript-stdio][javascript-typescript-langserver]
* Rust's [rls][rls]
* Python's [pyls][pyls]
* Bash's [bash-language-server][bash-language-server]
+* PHP's [php-language-server][php-language-server]
-I'll add more as I test more features. In the meantime you can
+I'll add to this list as I test more servers. In the meantime you can
customize `eglot-server-programs`:
```lisp
@@ -41,7 +42,9 @@ Here's a summary of available commands:
- `M-x eglot-reconnect` reconnects to the server;
-- `M-x eglot-rename` asks the server to rename the symbol at point
+- `M-x eglot-shutdown` says bye-bye to the server;
+
+- `M-x eglot-rename` asks the server to rename the symbol at point;
- `M-x eglot-help-at-point` asks the server for help for symbol at
point. Currently this is what `eldoc-mode` displays in the echo
@@ -60,6 +63,23 @@ either:
(define-key eglot-mode-map (kbd "<f6>") 'xref-find-definitions)
```
+# How does this work exactly?
+
+`M-x eglot` starts a server via a shell-command guessed from
+`eglot-server-programs`, using the current major-mode (for whatever
+language you're programming in) as a hint.
+
+If the connection is successful, you see an `[eglot:<server>]`
+indicator pop up in your mode-line. More importantly, this means
+current *and future* file buffers of that major mode *inside your
+current project* automatically become \"managed\" by the LSP server,
+i.e. information about their contents is exchanged periodically to
+provide enhanced code analysis via `xref-find-definitions`,
+`flymake-mode`, `eldoc-mode`, `completion-at-point`, among others.
+
+To "unmanage" these buffers, shutdown the server with `M-x
+eglot-shutdown`.
+
# Supported Protocol features (3.6)
## General
@@ -104,7 +124,7 @@ either:
- [x] textDocument/completion
- [x] completionItem/resolve (works quite well with
[company-mode][company-mode])
- [x] textDocument/hover
-- [x] textDocument/signatureHelp (fancy stuff with Python's [pyls[pyls]])
+- [x] textDocument/signatureHelp (fancy stuff with Python's [pyls][pyls])
- [x] textDocument/definition
- [ ] textDocument/typeDefinition (3.6.0)
- [ ] textDocument/implementation (3.6.0)
@@ -152,7 +172,7 @@ User-visible differences:
Under the hood:
-- Message parser is much much simpler.
+- Message parser is much simpler.
- Defers signature requests like `textDocument/hover` until server is
ready. Also sends `textDocument/didChange` for groups of edits, not
one per each tiny change.
@@ -169,10 +189,12 @@ Under the hood:
[lsp]: https://microsoft.github.io/language-server-protocol/
[rls]: https://github.com/rust-lang-nursery/rls
[pyls]: https://github.com/palantir/python-language-server
+[gnuelpa]: https://elpa.gnu.org/packages/eglot.html
[javascript-typescript-langserver]:
https://github.com/sourcegraph/javascript-typescript-langserver
[emacs-lsp]: https://github.com/emacs-lsp/lsp-mode
[emacs-lsp-plugins]: https://github.com/emacs-lsp
[bash-language-server]: https://github.com/mads-hartmann/bash-language-server
+[php-language-server]: https://github.com/felixfbecker/php-language-server
[company-mode]: https://github.com/company-mode/company-mode
diff --git a/eglot-tests.el b/eglot-tests.el
index e0ed324..7a832dd 100644
--- a/eglot-tests.el
+++ b/eglot-tests.el
@@ -1,6 +1,6 @@
;;; eglot-tests.el --- Tests for eglot.el -*- lexical-binding: t;
-*-
-;; Copyright (C) 2018 João Távora
+;; Copyright (C) 2018 Free Software Foundation, Inc.
;; Author: João Távora <address@hidden>
;; Keywords: tests
diff --git a/eglot.el b/eglot.el
index 11d048e..13c1b49 100644
--- a/eglot.el
+++ b/eglot.el
@@ -2,7 +2,7 @@
;; Copyright (C) 2018 Free Software Foundation, Inc.
-;; Version: 0.1
+;; Version: 0.2
;; Author: João Távora <address@hidden>
;; Maintainer: João Távora <address@hidden>
;; URL: https://github.com/joaotavora/eglot
@@ -24,8 +24,28 @@
;;; Commentary:
-;; Simply M-x eglot should be enough to get you started, but see README.md.
-
+;; Simply M-x eglot should be enough to get you started, but here's a
+;; little info (see the accompanying README.md or the URL for more).
+;;
+;; M-x eglot starts a server via a shell-command guessed from
+;; `eglot-server-programs', using the current major-mode (for whatever
+;; language you're programming in) as a hint. If it can't guess, it
+;; prompts you in the mini-buffer for these things. Actually, the
+;; server needen't be locally started: you can connect to a running
+;; server via TCP by entering a <host:port> syntax.
+;;
+;; Anyway, if the connection is successful, you should see an `eglot'
+;; indicator pop up in your mode-line. More importantly, this means
+;; current *and future* file buffers of that major mode *inside your
+;; current project* automatically become \"managed\" by the LSP
+;; server, i.e. information about their contents is exchanged
+;; periodically to provide enhanced code analysis via
+;; `xref-find-definitions', `flymake-mode', `eldoc-mode',
+;; `completion-at-point', among others.
+;;
+;; To "unmanage" these buffers, shutdown the server with M-x
+;; eglot-shutdown.
+;;
;;; Code:
(require 'json)
@@ -52,7 +72,9 @@
(defvar eglot-server-programs '((rust-mode . ("rls"))
(python-mode . ("pyls"))
(js-mode . ("javascript-typescript-stdio"))
- (sh-mode . ("bash-language-server" "start")))
+ (sh-mode . ("bash-language-server" "start"))
+ (php-mode . ("php" "vendor/felixfbecker/\
+language-server/bin/php-language-server.php")))
"Alist mapping major modes to server executables.")
(defface eglot-mode-line
@@ -112,9 +134,9 @@ A list (ID WHAT DONE-P).")
(gethash (eglot--project proc) eglot--processes-by-project)))
(cond ((eglot--moribund proc))
((not (eglot--inhibit-autoreconnect proc))
- (eglot--warn "Reconnecting unexpected server exit.")
+ (eglot--warn "Reconnecting after unexpected server exit.")
(eglot-reconnect proc))
- (t
+ ((timerp (eglot--inhibit-autoreconnect proc))
(eglot--warn "Not auto-reconnecting, last one didn't last long."))))
(defun eglot-shutdown (proc &optional interactive)
@@ -220,9 +242,22 @@ called interactively."
;;;###autoload
(defun eglot (managed-major-mode project command &optional interactive)
- "Start a Language Server Protocol server.
-Server is started with COMMAND and manages buffers of
-MANAGED-MAJOR-MODE for the current project.
+ "Manage a project with a Language Server Protocol (LSP) server.
+
+The LSP server is started (or contacted) via COMMAND. If this
+operation is successful, current *and future* file buffers of
+MANAGED-MAJOR-MODE inside PROJECT automatically become
+\"managed\" by the LSP server, meaning information about their
+contents is exchanged periodically to provide enhanced
+code-analysis via `xref-find-definitions', `flymake-mode',
+`eldoc-mode', `completion-at-point', among others.
+
+Interactively, the command attempts to guess MANAGED-MAJOR-MODE
+from current buffer, COMMAND from `eglot-server-programs' and
+PROJECT from `project-current'. If it can't guess, the user is
+prompted. With a single \\[universal-argument] prefix arg, it
+always prompt for COMMAND. With two \\[universal-argument]
+prefix args, also prompts for MANAGED-MAJOR-MODE.
PROJECT is a project instance as returned by `project-current'.
@@ -234,12 +269,6 @@ is also know as the server's \"contact\".
MANAGED-MAJOR-MODE is an Emacs major mode.
-Interactively, guess MANAGED-MAJOR-MODE from current buffer and
-COMMAND from `eglot-server-programs'. With a single
-\\[universal-argument] prefix arg, prompt for COMMAND. With two
-\\[universal-argument] prefix args, also prompt for
-MANAGED-MAJOR-MODE.
-
INTERACTIVE is t if called interactively."
(interactive (eglot--interactive))
(let* ((short-name (eglot--project-short-name project)))
@@ -253,8 +282,7 @@ INTERACTIVE is t if called interactively."
(let ((proc (eglot--connect project
managed-major-mode
(format "%s/%s" short-name
managed-major-mode)
- command
- interactive)))
+ command)))
(eglot--message "Connected! Process `%s' now \
managing `%s' buffers in project `%s'."
proc managed-major-mode short-name)
@@ -269,8 +297,7 @@ INTERACTIVE is t if called interactively."
(eglot--connect (eglot--project process)
(eglot--major-mode process)
(jrpc-name process)
- (jrpc-contact process)
- interactive)
+ (jrpc-contact process))
(eglot--message "Reconnected!"))
(defalias 'eglot-events-buffer 'jrpc-events-buffer)
@@ -278,7 +305,8 @@ INTERACTIVE is t if called interactively."
(defvar eglot-connect-hook nil "Hook run after connecting in
`eglot--connect'.")
(defun eglot--dispatch (proc method id &rest params)
- ;; a server notification or a server request
+ "Dispatcher passed to `jrpc-connect'.
+Builds a function from METHOD, passes it PROC, ID and PARAMS."
(let* ((handler-sym (intern (concat "eglot--server-" method))))
(if (functionp handler-sym)
(apply handler-sym proc (append params (if id `(:id ,id))))
@@ -286,40 +314,43 @@ INTERACTIVE is t if called interactively."
proc id
:error (jrpc-obj :code -32601 :message "Unimplemented")))))
-(defun eglot--connect (project managed-major-mode name command
- dont-inhibit)
- (let ((proc (jrpc-connect name command #'eglot--dispatch
#'eglot--on-shutdown)))
+(defun eglot--connect (project managed-major-mode name command)
+ (let ((proc (jrpc-connect name command #'eglot--dispatch
#'eglot--on-shutdown))
+ success)
(setf (eglot--project proc) project)
(setf (eglot--major-mode proc)managed-major-mode)
(push proc (gethash project eglot--processes-by-project))
(run-hook-with-args 'eglot-connect-hook proc)
- (cl-destructuring-bind (&key capabilities)
- (jrpc-request
- proc
- :initialize
- (jrpc-obj :processId (unless (eq (process-type proc)
- 'network)
- (emacs-pid))
- :rootUri (eglot--path-to-uri
- (car (project-roots project)))
- :initializationOptions []
- :capabilities (eglot--client-capabilities)))
- (setf (eglot--capabilities proc) capabilities)
- (setf (jrpc-status proc) nil)
- (dolist (buffer (buffer-list))
- (with-current-buffer buffer
- (eglot--maybe-activate-editing-mode proc)))
- (jrpc-notify proc :initialized (jrpc-obj :__dummy__ t))
- (setf (eglot--inhibit-autoreconnect proc)
- (cond
- ((booleanp eglot-autoreconnect) (not eglot-autoreconnect))
- (dont-inhibit nil)
- ((cl-plusp eglot-autoreconnect)
- (run-with-timer eglot-autoreconnect nil
- (lambda ()
- (setf (eglot--inhibit-autoreconnect proc)
- (null eglot-autoreconnect)))))))
- proc)))
+ (unwind-protect
+ (cl-destructuring-bind (&key capabilities)
+ (jrpc-request
+ proc
+ :initialize
+ (jrpc-obj :processId (unless (eq (process-type proc)
+ 'network)
+ (emacs-pid))
+ :rootPath (car (project-roots project))
+ :rootUri (eglot--path-to-uri
+ (car (project-roots project)))
+ :initializationOptions []
+ :capabilities (eglot--client-capabilities)))
+ (setf (eglot--capabilities proc) capabilities)
+ (setf (jrpc-status proc) nil)
+ (dolist (buffer (buffer-list))
+ (with-current-buffer buffer
+ (eglot--maybe-activate-editing-mode proc)))
+ (jrpc-notify proc :initialized (jrpc-obj :__dummy__ t))
+ (setf (eglot--inhibit-autoreconnect proc)
+ (cond
+ ((booleanp eglot-autoreconnect) (not eglot-autoreconnect))
+ ((cl-plusp eglot-autoreconnect)
+ (run-with-timer eglot-autoreconnect nil
+ (lambda ()
+ (setf (eglot--inhibit-autoreconnect proc)
+ (null eglot-autoreconnect)))))))
+ (setq success proc))
+ (unless (or success (not (process-live-p proc)) (eglot--moribund proc))
+ (eglot-shutdown proc)))))
(defun eglot--server-ready-p (_what _proc)
"Tell if server of PROC ready for processing deferred WHAT."
diff --git a/jrpc.el b/jrpc.el
index ea0122b..6773e12 100644
--- a/jrpc.el
+++ b/jrpc.el
@@ -427,9 +427,9 @@ timeout keeps counting."
(remhash id (jrpc--request-continuations proc))
(funcall (or timeout-fn
(lambda ()
- (jrpc-error
- "Tired of waiting for reply to %s, id=%s"
- method id))))))))))
+ (jrpc-log-event
+ proc `(:timed-out ,method :id id
+ :params ,params)))))))))))
(when deferred
(let* ((buf (current-buffer))
(existing (gethash (list deferred buf) (jrpc--deferred-actions
proc))))
@@ -453,13 +453,13 @@ timeout keeps counting."
(puthash id
(list (or success-fn
(jrpc-lambda (&rest _ignored)
- (jrpc-log-event
- proc (jrpc-obj :message "success ignored" :id id))))
+ (jrpc-log-event
+ proc (jrpc-obj :message "success ignored"
:id id))))
(or error-fn
(jrpc-lambda (&key code message &allow-other-keys)
- (setf (jrpc-status proc) `(,message t))
- proc (jrpc-obj :message "error ignored, status set"
- :id id :error code)))
+ (setf (jrpc-status proc) `(,message t))
+ proc (jrpc-obj :message "error ignored,
status set"
+ :id id :error code)))
(funcall make-timeout))
(jrpc--request-continuations proc))
(jrpc--process-send proc (jrpc-obj :jsonrpc "2.0"
- [elpa] externals/eglot e5ba4f6 18/69: Automatically reply with error if dispatcher doesn't, (continued)
- [elpa] externals/eglot e5ba4f6 18/69: Automatically reply with error if dispatcher doesn't, João Távora, 2018/06/22
- [elpa] externals/eglot 33ae871 09/69: More flexible jrpc.el and improve eglot.el's doc, João Távora, 2018/06/22
- [elpa] externals/eglot 3265c1d 10/69: Simpler callback protocol for JSONRPC parameters and results, João Távora, 2018/06/22
- [elpa] externals/eglot e906d25 14/69: Overhaul JSON and JSRONRPC error handling, João Távora, 2018/06/22
- [elpa] externals/eglot 7cd94b9 12/69: Improve jrpc.el's doc (and change jrpc-request's protocol a tiny bit), João Távora, 2018/06/22
- [elpa] externals/eglot 489182d 24/69: New jsonrpc-error error type, João Távora, 2018/06/22
- [elpa] externals/eglot 5cea412 20/69: Fix typos and phrasing in commentary and docstrings, João Távora, 2018/06/22
- [elpa] externals/eglot c30f0f3 23/69: Get rid of jsonrpc.el customization group and timeout, João Távora, 2018/06/22
- [elpa] externals/eglot 5e8fe4c 26/69: Add jsonrpc-tests.el, João Távora, 2018/06/22
- [elpa] externals/eglot 05ff697 29/69: Document current API breaches a bit, João Távora, 2018/06/22
- [elpa] externals/eglot 258e3b0 07/69: Merge master into jsonrpc-refactor (using imerge),
João Távora <=
- [elpa] externals/eglot 4bbf810 25/69: Don't return implementation details in jsonrpc-async-request, João Távora, 2018/06/22
- [elpa] externals/eglot 5874af9 32/69: Fix deferred actions (forgot the crucial non-local exit), João Távora, 2018/06/22
- [elpa] externals/eglot 481f16e 33/69: * eglot.el (eglot-eldoc-function): Remove spurious log message, João Távora, 2018/06/22
- [elpa] externals/eglot c43dff4 35/69: On request timeout, clear it from the deferred actions, João Távora, 2018/06/22
- [elpa] externals/eglot 870c60a 04/69: Merge master into jsonrpc-refactor (using imerge), João Távora, 2018/06/22
- [elpa] externals/eglot 980f3e7 34/69: Fix another merge-related bug in eglot-eldoc-function, João Távora, 2018/06/22
- [elpa] externals/eglot fab7f8b 44/69: Improve Makefile test targets, João Távora, 2018/06/22
- [elpa] externals/eglot d7e1b92 42/69: * jsonrpc.el (jsonrpc-message): Fix formatting bug., João Távora, 2018/06/22
- [elpa] externals/eglot 0ba7964 40/69: * jsonrpc.el (jsonrpc-log-event): Log time of event., João Távora, 2018/06/22
- [elpa] externals/eglot f594dd7 36/69: jsonrpc-request also calls for deferred action cleanup, João Távora, 2018/06/22