emacs-elpa-diffs
[Top][All Lists]
Advanced

[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"



reply via email to

[Prev in Thread] Current Thread [Next in Thread]