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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/eglot cef3c29 22/69: Heroically merge master into jsonr


From: João Távora
Subject: [elpa] externals/eglot cef3c29 22/69: Heroically merge master into jsonrpc-refactor (using imerge)
Date: Fri, 22 Jun 2018 11:54:57 -0400 (EDT)

branch: externals/eglot
commit cef3c29a4a2bfbb87d3fa0518626a4e0fdcb95dc
Merge: bb60c0c 24877ae
Author: João Távora <address@hidden>
Commit: João Távora <address@hidden>

    Heroically merge master into jsonrpc-refactor (using imerge)
---
 .travis.yml    |   4 +
 eglot-tests.el |  93 +++++++++++++------
 eglot.el       | 286 ++++++++++++++++++++++++++++-----------------------------
 jsonrpc.el     |  67 +++++++-------
 4 files changed, 242 insertions(+), 208 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 2f0db4c..9b0a6d8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -18,6 +18,10 @@ install:
   # Install RLS
   - rustup update
   - rustup component add rls-preview rust-analysis rust-src
+  # Install https://github.com/palantir/python-language-server
+  - virtualenv .
+  - . ./bin/activate
+  - pip install 'python-language-server[all]'
     
 script:
   - make check
diff --git a/eglot-tests.el b/eglot-tests.el
index 9359a78..a19f121 100644
--- a/eglot-tests.el
+++ b/eglot-tests.el
@@ -26,11 +26,12 @@
 (require 'eglot)
 (require 'cl-lib)
 (require 'ert)
+(require 'edebug)
 
 ;; Helpers
 
 (defmacro eglot--with-dirs-and-files (dirs &rest body)
-  (declare (indent defun) (debug t))
+  (declare (indent 1) (debug t))
   `(eglot--call-with-dirs-and-files
     ,dirs #'(lambda () ,@body)))
 
@@ -51,24 +52,24 @@
 (defun eglot--call-with-dirs-and-files (dirs fn)
   (let* ((default-directory (make-temp-file "eglot--fixture" t))
          new-buffers new-processes)
-    (with-temp-message ""
-      (unwind-protect
-          (let ((find-file-hook
-                 (cons (lambda () (push (current-buffer) new-buffers))
-                       find-file-hook))
-                (eglot-connect-hook
-                 (lambda (proc) (push proc new-processes))))
-            (mapc #'eglot--make-file-or-dirs dirs)
-            (funcall fn))
-        (eglot--message "Killing buffers %s,  deleting %s, killing %s"
-                        (mapconcat #'buffer-name new-buffers ", ")
-                        default-directory
-                        new-processes)
-        (delete-directory default-directory 'recursive)
-        (let ((eglot-autoreconnect nil))
-          (mapc #'eglot-shutdown
-                (cl-remove-if-not #'process-live-p new-processes)))
-        (mapc #'kill-buffer new-buffers)))))
+    (unwind-protect
+        (let ((find-file-hook
+               (cons (lambda () (push (current-buffer) new-buffers))
+                     find-file-hook))
+              (eglot-connect-hook
+               (lambda (proc) (push proc new-processes))))
+          (mapc #'eglot--make-file-or-dirs dirs)
+          (funcall fn))
+      (eglot--message "Killing buffers %s,  deleting %s, killing %s"
+                      (mapconcat #'buffer-name new-buffers ", ")
+                      default-directory
+                      new-processes)
+      (let ((eglot-autoreconnect nil))
+        (mapc #'eglot-shutdown
+              (cl-remove-if-not #'process-live-p new-processes)))
+      (dolist (buf new-buffers) ;; have to save otherwise will get prompted
+        (with-current-buffer buf (save-buffer) (kill-buffer)))
+      (delete-directory default-directory 'recursive))))
 
 (cl-defmacro eglot--with-test-timeout (timeout &body body)
   (declare (indent 1) (debug t))
@@ -85,8 +86,9 @@
               (catch tag
                 (setq timer
                       (run-with-timer timeout nil
-                                      (lambda () ;; (throw tag timed-out)
-                                        )))
+                                      (lambda ()
+                                        (unless edebug-active
+                                          (throw tag timed-out)))))
                 (funcall fn)))
       (cancel-timer timer)
       (when (eq retval timed-out)
@@ -109,12 +111,13 @@
 
 (ert-deftest auto-detect-running-server ()
   "Visit a file and M-x eglot, then visit a neighbour. "
+  (skip-unless (executable-find "rls"))
   (let (proc)
-    (eglot--with-test-timeout 2
-      (eglot--with-dirs-and-files
-          '(("project" . (("coiso.rs" . "bla")
-                          ("merdix.rs" . "bla")))
-            ("anotherproject" . (("cena.rs" . "bla"))))
+    (eglot--with-dirs-and-files
+        '(("project" . (("coiso.rs" . "bla")
+                        ("merdix.rs" . "bla")))
+          ("anotherproject" . (("cena.rs" . "bla"))))
+      (eglot--with-test-timeout 2
         (with-current-buffer
             (eglot--find-file-noselect "project/coiso.rs")
           (setq proc
@@ -131,12 +134,13 @@
 
 (ert-deftest auto-reconnect ()
   "Start a server. Kill it. Watch it reconnect."
+  (skip-unless (executable-find "rls"))
   (let (proc
         (eglot-autoreconnect 1))
-    (eglot--with-test-timeout 3
-      (eglot--with-dirs-and-files
-          '(("project" . (("coiso.rs" . "bla")
-                          ("merdix.rs" . "bla"))))
+    (eglot--with-dirs-and-files
+        '(("project" . (("coiso.rs" . "bla")
+                        ("merdix.rs" . "bla"))))
+      (eglot--with-test-timeout 3
         (with-current-buffer
             (eglot--find-file-noselect "project/coiso.rs")
           (setq proc
@@ -153,6 +157,35 @@
           (while (process-live-p proc) (accept-process-output nil 0.5))
           (should (not (jsonrpc-current-process))))))))
 
+(ert-deftest basic-completions ()
+  "Test basic autocompletion in a python LSP"
+  (skip-unless (executable-find "pyls"))
+  (eglot--with-dirs-and-files
+      '(("project" . (("something.py" . "import sys\nsys.exi"))))
+    (eglot--with-test-timeout 4
+      (with-current-buffer
+          (eglot--find-file-noselect "project/something.py")
+        (eglot 'python-mode `(transient . ,default-directory) '("pyls"))
+        (goto-char (point-max))
+        (completion-at-point)
+        (should (looking-back "sys.exit"))))))
+
+(ert-deftest hover-after-completions ()
+  "Test basic autocompletion in a python LSP"
+  (skip-unless (executable-find "pyls"))
+  (eglot--with-dirs-and-files
+      '(("project" . (("something.py" . "import sys\nsys.exi"))))
+    (eglot--with-test-timeout 4
+      (with-current-buffer
+          (eglot--find-file-noselect "project/something.py")
+        (eglot 'python-mode `(transient . ,default-directory) '("pyls"))
+        (goto-char (point-max))
+        (setq eldoc-last-message nil)
+        (completion-at-point)
+        (should (looking-back "sys.exit"))
+        (while (not eldoc-last-message) (accept-process-output nil 0.1))
+        (should (string-match "^exit" eldoc-last-message))))))
+
 (provide 'eglot-tests)
 ;;; eglot-tests.el ends here
 
diff --git a/eglot.el b/eglot.el
index 907c98b..41e57b4 100644
--- a/eglot.el
+++ b/eglot.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2018 Free Software Foundation, Inc.
 
-;; Version: 0.3
+;; Version: 0.4
 ;; Author: João Távora <address@hidden>
 ;; Maintainer: João Távora <address@hidden>
 ;; URL: https://github.com/joaotavora/eglot
@@ -121,11 +121,10 @@ A list (ID WHAT DONE-P).")
   "File system watches for the didChangeWatchedfiles thingy.")
 
 (defun eglot--on-shutdown (proc)
+  "Called by jsonrpc.el when PROC is already dead."
   ;; Turn off `eglot--managed-mode' where appropriate.
-  (dolist (buffer (buffer-list))
-    (with-current-buffer buffer
-      (when (eglot--buffer-managed-p proc)
-        (eglot--managed-mode -1))))
+    (dolist (buffer (eglot--managed-buffers proc))
+      (with-current-buffer buffer (eglot--managed-mode-onoff proc -1)))
   ;; Kill any expensive watches
   (maphash (lambda (_id watches)
              (mapcar #'file-notify-rm-watch watches))
@@ -141,21 +140,24 @@ A list (ID WHAT DONE-P).")
         ((timerp (eglot--inhibit-autoreconnect proc))
          (eglot--warn "Not auto-reconnecting, last one didn't last long."))))
 
-(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."
   (interactive (list (jsonrpc-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 ((jsonrpc-request-timeout 3))
         (setf (eglot--moribund proc) t)
         (jsonrpc-request proc :shutdown nil)
-        ;; this one should always fail under normal conditions
+        ;; this one should always fail, hence ignore-errors
         (ignore-errors (jsonrpc-request proc :exit nil)))
+    ;; Turn off `eglot--managed-mode' where appropriate.
+    (dolist (buffer (eglot--managed-buffers proc))
+      (with-current-buffer buffer (eglot--managed-mode-onoff proc -1)))
     (when (process-live-p proc)
-      (eglot--warn "Brutally deleting existing process %s" proc)
+      (eglot--warn "Brutally deleting non-compliant %s" proc)
       (delete-process proc))))
 
 (defun eglot--find-current-process ()
@@ -164,6 +166,9 @@ called interactively."
     (cl-find major-mode (gethash probe eglot--processes-by-project)
              :key #'eglot--major-mode)))
 
+(jsonrpc-define-process-var eglot--managed-buffers nil
+  "Buffers managed by the server.")
+
 (defun eglot--project-short-name (project)
   "Give PROJECT a short name."
   (file-name-base (directory-file-name (car (project-roots project)))))
@@ -216,35 +221,30 @@ called interactively."
               (symbol-name guessed-mode) nil (symbol-name guessed-mode) nil)))
            (t guessed-mode)))
          (project (or (project-current) `(transient . ,default-directory)))
-         (guessed-command (cdr (assoc managed-mode eglot-server-programs)))
+         (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 (integerp (cadr 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))
+                                 (combine-and-quote-strings guessed))
+                         (format ", but I can't find `%s' in PATH!" program)
                          "\n" base-prompt))))
          (contact
-          (cond ((not prompt) guessed-command)
-                (t
-                 (let ((string (read-shell-command
-                                prompt
-                                (if (listp guessed-command)
-                                    (combine-and-quote-strings 
guessed-command))
-                                'eglot-command-history)))
-                   (if (and string (string-match
-                                    "^\\([^\s\t]+\\):\\([[:digit:]]+\\)$"
-                                    (string-trim string)))
-                       (list (match-string 1 string) (match-string 2 string))
-                     (split-string-and-unquote string)))))))
+          (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
@@ -341,7 +341,8 @@ Builds a function from METHOD, passes it PROC, ID and 
PARAMS."
              (jsonrpc-obj :processId (unless (eq (process-type proc)
                                                  'network)
                                        (emacs-pid))
-                          :rootPath  (car (project-roots project))
+                          :rootPath  (expand-file-name
+                                      (car (project-roots project)))
                           :rootUri  (eglot--path-to-uri
                                      (car (project-roots project)))
                           :initializationOptions  []
@@ -383,29 +384,24 @@ Builds a function from METHOD, passes it PROC, ID and 
PARAMS."
   "Warning message with FORMAT and ARGS."
   (apply #'eglot--message (concat "(warning) " format) args)
   (let ((warning-minimum-level :error))
-    (display-warning 'eglot
-                     (apply #'format format args)
-                     :warning)))
+    (display-warning 'eglot (apply #'format format args) :warning)))
 
 (defun eglot--pos-to-lsp-position (&optional pos)
   "Convert point POS to LSP position."
   (save-excursion
-    (jsonrpc-obj :line
-                 ;; F!@(#*&#$)CKING OFF-BY-ONE
-                 (1- (line-number-at-pos pos t))
-                 :character
-                 (- (goto-char (or pos (point)))
-                    (line-beginning-position)))))
-
-(defun eglot--lsp-position-to-point (pos-plist)
-  "Convert LSP position POS-PLIST to Emacs point."
+    (jsonrpc-obj :line (1- (line-number-at-pos pos t)) ; F!@&#$CKING OFF-BY-ONE
+                 :character (- (goto-char (or pos (point)))
+                               (line-beginning-position)))))
+
+(defun eglot--lsp-position-to-point (pos-plist &optional marker)
+  "Convert LSP position POS-PLIST to Emacs point.
+If optional MARKER, return a marker instead"
   (save-excursion (goto-char (point-min))
                   (forward-line (plist-get pos-plist :line))
-                  (forward-char
-                   (min (plist-get pos-plist :character)
-                        (- (line-end-position)
-                           (line-beginning-position))))
-                  (point)))
+                  (forward-char (min (plist-get pos-plist :character)
+                                     (- (line-end-position)
+                                        (line-beginning-position))))
+                  (if marker (copy-marker (point-marker)) (point))))
 
 (defun eglot--path-to-uri (path)
   "URIfy PATH."
@@ -428,29 +424,31 @@ Builds a function from METHOD, passes it PROC, ID and 
PARAMS."
 
 (defun eglot--format-markup (markup)
   "Format MARKUP according to LSP's spec."
-  (cond ((stringp markup)
-         (with-temp-buffer
-           (ignore-errors (funcall (intern "markdown-mode"))) ;escape bytecomp
-           (font-lock-ensure)
-           (insert markup)
-           (string-trim (buffer-string))))
-        (t
-         (with-temp-buffer
-           (ignore-errors (funcall (intern (concat
-                                            (plist-get markup :language)
-                                            "-mode" ))))
-           (insert (plist-get markup :value))
-           (font-lock-ensure)
-           (buffer-string)))))
-
-(defun eglot--server-capable (feat)
-  "Determine if current server is capable of FEAT."
-  (plist-get (eglot--capabilities (jsonrpc-current-process-or-lose)) feat))
-
-(defun eglot--range-region (range)
-  "Return region (BEG . END) that represents LSP RANGE."
-  (cons (eglot--lsp-position-to-point (plist-get range :start))
-        (eglot--lsp-position-to-point (plist-get range :end))))
+  (pcase-let ((`(,string ,mode)
+               (if (stringp markup) (list (string-trim markup)
+                                          (intern "markdown-mode"))
+                 (list (plist-get markup :value)
+                       (intern (concat (plist-get markup :language) "-mode" 
))))))
+    (with-temp-buffer
+      (ignore-errors (funcall mode))
+      (insert string) (font-lock-ensure) (buffer-string))))
+
+(defun eglot--server-capable (&rest feats)
+  "Determine if current server is capable of FEATS."
+  (cl-loop for caps = (eglot--capabilities (jsonrpc-current-process-or-lose))
+           then (cadr probe)
+           for feat in feats
+           for probe = (plist-member caps feat)
+           if (not probe) do (cl-return nil)
+           if (eq (cadr probe) t) do (cl-return t)
+           if (eq (cadr probe) :json-false) do (cl-return nil)
+           finally (cl-return (or probe t))))
+
+(defun eglot--range-region (range &optional markers)
+  "Return region (BEG END) that represents LSP RANGE.
+If optional MARKERS, make markers."
+  (list (eglot--lsp-position-to-point (plist-get range :start) markers)
+        (eglot--lsp-position-to-point (plist-get range :end) markers)))
 
 
 ;;; Minor modes
@@ -490,20 +488,20 @@ Builds a function from METHOD, passes it PROC, ID and 
PARAMS."
     (remove-hook 'completion-at-point-functions #'eglot-completion-at-point t)
     (remove-function (local 'eldoc-documentation-function)
                      #'eglot-eldoc-function)
-    (remove-function (local imenu-create-index-function) #'eglot-imenu)
-    (let ((proc (eglot--find-current-process)))
-      (when (and (process-live-p proc) (y-or-n-p "[eglot] Kill server too? "))
-        (eglot-shutdown proc t))))))
+    (remove-function (local imenu-create-index-function) #'eglot-imenu))))
+
+(defun eglot--managed-mode-onoff (proc arg)
+  "Proxy for function `eglot--managed-mode' with ARG and PROC."
+  (eglot--managed-mode arg)
+  (let ((buf (current-buffer)))
+    (if eglot--managed-mode
+        (cl-pushnew buf (eglot--managed-buffers proc))
+      (setf (eglot--managed-buffers proc)
+            (delq buf (eglot--managed-buffers proc))))))
 
 (add-hook 'eglot--managed-mode-hook 'flymake-mode)
 (add-hook 'eglot--managed-mode-hook 'eldoc-mode)
 
-(defun eglot--buffer-managed-p (&optional proc)
-  "Tell if current buffer can be managed by PROC."
-  (and buffer-file-name (let ((cur (eglot--find-current-process)))
-                          (or (and (null proc) cur)
-                              (and proc (eq proc cur))))))
-
 (defvar-local eglot--current-flymake-report-fn nil
   "Current flymake report function for this buffer")
 
@@ -512,11 +510,13 @@ Builds a function from METHOD, passes it PROC, ID and 
PARAMS."
 If PROC is supplied, do it only if BUFFER is managed by it.  In
 that case, also signal textDocument/didOpen."
   ;; Called even when revert-buffer-in-progress-p
-  (when (eglot--buffer-managed-p proc)
-    (eglot--managed-mode 1)
-    (eglot--signal-textDocument/didOpen)
-    (flymake-start)
-    (funcall (or eglot--current-flymake-report-fn #'ignore) nil)))
+  (let* ((cur (and buffer-file-name (eglot--find-current-process)))
+         (proc (or (and (null proc) cur) (and proc (eq proc cur) cur))))
+    (when proc
+      (eglot--managed-mode-onoff proc 1)
+      (eglot--signal-textDocument/didOpen)
+      (flymake-start)
+      (funcall (or eglot--current-flymake-report-fn #'ignore) nil))))
 
 (add-hook 'find-file-hook 'eglot--maybe-activate-editing-mode)
 
@@ -532,7 +532,8 @@ that case, also signal textDocument/didOpen."
   (lambda (event)
     (interactive "e")
     (with-selected-window (posn-window (event-start event))
-      (call-interactively what))))
+      (call-interactively what)
+      (force-mode-line-update t))))
 
 (defun eglot--mode-line-props (thing face defs &optional prepend)
   "Helper for function `eglot--mode-line-format'.
@@ -567,7 +568,7 @@ Uses THING, FACE, DEFS and PREPEND."
              `("/" ,(eglot--mode-line-props
                      "error" 'compilation-mode-line-fail
                      '((mouse-1 eglot-events-buffer "go to events buffer")
-                       (mouse-3 eglot-clear-status  "clear this status"))
+                       (mouse-3 jrpc-clear-status  "clear this status"))
                      (format "An error occured: %s\n" status))))
          ,@(when (and doing (not done-p))
              `("/" ,(eglot--mode-line-props
@@ -577,9 +578,10 @@ Uses THING, FACE, DEFS and PREPEND."
                      '((mouse-1 eglot-events-buffer "go to events buffer")))))
          ,@(when (cl-plusp pending)
              `("/" ,(eglot--mode-line-props
-                     (format "%d" pending) 'warning
+                     (format "%d oustanding requests" pending) 'warning
                      '((mouse-1 eglot-events-buffer "go to events buffer")
-                       (mouse-3 eglot-clear-status  "clear this status"))
+                       (mouse-3 jrpc-forget-pending-continuations
+                                "fahgettaboudit"))
                      (format "%d pending requests\n" pending)))))))))
 
 (add-to-list 'mode-line-misc-info
@@ -625,7 +627,7 @@ Uses THING, FACE, DEFS and PREPEND."
   "Unreported diagnostics for this buffer.")
 
 (cl-defun eglot--server-textDocument/publishDiagnostics
-    (_process &key uri diagnostics)
+    (_proc &key uri diagnostics)
   "Handle notification publishDiagnostics"
   (if-let ((buffer (find-buffer-visiting (eglot--uri-to-path uri))))
       (with-current-buffer buffer
@@ -634,7 +636,7 @@ Uses THING, FACE, DEFS and PREPEND."
          collect (cl-destructuring-bind (&key range severity _group
                                               _code source message)
                      diag-spec
-                   (pcase-let ((`(,beg . ,end) (eglot--range-region range)))
+                   (pcase-let ((`(,beg ,end) (eglot--range-region range)))
                      (flymake-make-diagnostic (current-buffer)
                                               beg end
                                               (cond ((<= severity 1) :error)
@@ -679,15 +681,12 @@ THINGS are either registrations or unregisterations."
     (proc &key id _label edit)
   "Handle server request workspace/applyEdit"
   (condition-case err
-      (progn
-        (eglot--apply-workspace-edit edit 'confirm)
-        (jsonrpc-reply proc id :result `(:applied )))
-    (error
-     (jsonrpc-reply proc id
-                    :result `(:applied :json-false)
-                    :error
-                    (jsonrpc-obj :code -32001
-                                 :message (format "%s" err))))))
+      (progn (eglot--apply-workspace-edit edit 'confirm)
+             (jsonrpc-reply proc id :result `(:applied )))
+    (error (jsonrpc-reply proc id
+                          :result `(:applied :json-false)
+                          :error (jsonrpc-obj :code -32001
+                                              :message (format "%s" err))))))
 
 (defun eglot--TextDocumentIdentifier ()
   "Compute TextDocumentIdentifier object for current buffer."
@@ -752,7 +751,8 @@ Records START, END and PRE-CHANGE-LENGTH locally."
 (advice-add #'jsonrpc-request :before
             (cl-function (lambda (_proc _method _params &key deferred)
                            (when (and eglot--managed-mode deferred)
-                             (eglot--signal-textDocument/didChange)))))
+                             (eglot--signal-textDocument/didChange))))
+            '((name . eglot--signal-textDocument/didChange)))
 
 (defun eglot--signal-textDocument/didChange ()
   "Send textDocument/didChange to server."
@@ -945,15 +945,19 @@ DUMMY is ignored"
                                         :deferred :textDocument/completion))
                  (items (if (vectorp resp) resp (plist-get resp :items))))
             (mapcar
-             (jsonrpc-lambda (&rest all &key label &allow-other-keys)
-               (add-text-properties 0 1 all label) label)
+             (jsonrpc-lambda (&rest all &key label insertText 
&allow-other-keys)
+               (let ((insert (or insertText label)))
+                 (add-text-properties 0 1 all insert) insert))
              items))))
        :annotation-function
        (lambda (obj)
-         (propertize (concat " " (or (get-text-property 0 :detail obj)
-                                     (cdr (assoc (get-text-property 0 :kind 
obj)
-                                                 eglot--kind-names))))
-                     'face 'font-lock-function-name-face))
+         (cl-destructuring-bind (&key detail documentation kind 
&allow-other-keys)
+             (text-properties-at 0 obj)
+           (concat " " (propertize
+                        (or (and documentation
+                                 (replace-regexp-in-string "\n.*" "" 
documentation))
+                            detail (cdr (assoc kind eglot--kind-names)))
+                        'face 'font-lock-function-name-face))))
        :display-sort-function
        (lambda (items)
          (sort items (lambda (a b)
@@ -964,31 +968,27 @@ DUMMY is ignored"
        (lambda (obj)
          (let ((documentation
                 (or (get-text-property 0 :documentation obj)
-                    (plist-get (jsonrpc-request proc :completionItem/resolve
-                                                (text-properties-at 0 obj))
-                               :documentation))))
+                    (and (eglot--server-capable :completionProvider
+                                                :resolveProvider)
+                         (plist-get (jsonrpc-request proc 
:completionItem/resolve
+                                                     (text-properties-at 0 
obj))
+                                    :documentation)))))
            (when documentation
              (with-current-buffer (get-buffer-create " *eglot doc*")
-               (erase-buffer)
-               (ignore-errors (funcall (intern "markdown-mode")))
-               (font-lock-ensure)
-               (insert documentation)
+               (insert (eglot--format-markup documentation))
                (current-buffer)))))
-       :exit-function
-       (lambda (_string _status) (eglot-eldoc-function))))))
+       :exit-function (lambda (_string _status)
+                        (eglot--signal-textDocument/didChange)
+                        (eglot-eldoc-function))))))
 
 (defvar eglot--highlights nil "Overlays for textDocument/documentHighlight.")
 
 (defun eglot--hover-info (contents &optional range)
-  (concat (and range
-               (pcase-let ((`(,beg . ,end) (eglot--range-region range)))
-                 (concat (buffer-substring beg end)  ": ")))
+  (concat (and range (pcase-let ((`(,beg ,end) (eglot--range-region range)))
+                       (concat (buffer-substring beg end)  ": ")))
           (mapconcat #'eglot--format-markup
-                     (append
-                      (cond ((vectorp contents)
-                             contents)
-                            (contents
-                             (list contents)))) "\n")))
+                     (append (cond ((vectorp contents) contents)
+                                   (contents (list contents)))) "\n")))
 
 (defun eglot--sig-info (sigs active-sig active-param)
   (cl-loop
@@ -1051,9 +1051,10 @@ If SKIP-SIGNATURE, don't try to send 
textDocument/signatureHelp."
          proc :textDocument/hover position-params
          :success-fn (jsonrpc-lambda (&key contents range)
                        (unless sig-showing
-                         (when-buffer-window
-                          (eldoc-message
-                           (eglot--hover-info contents range)))))
+                         ;; for eglot-tests.el's sake, set this unconditionally
+                         (setq eldoc-last-message
+                               (eglot--hover-info contents range))
+                         (when-buffer-window (eldoc-message 
eldoc-last-message))))
          :deferred :textDocument/hover))
       (when (eglot--server-capable :documentHighlightProvider)
         (jsonrpc-async-request
@@ -1065,7 +1066,7 @@ If SKIP-SIGNATURE, don't try to send 
textDocument/signatureHelp."
                  (when-buffer-window
                   (mapcar
                    (jsonrpc-lambda (&key range _kind)
-                     (pcase-let ((`(,beg . ,end)
+                     (pcase-let ((`(,beg ,end)
                                   (eglot--range-region range)))
                        (let ((ov (make-overlay beg end)))
                          (overlay-put ov 'face 'highlight)
@@ -1100,14 +1101,14 @@ If SKIP-SIGNATURE, don't try to send 
textDocument/signatureHelp."
   (unless (or (not version) (equal version eglot--versioned-identifier))
     (eglot--error "Edits on `%s' require version %d, you have %d"
                   (current-buffer) version eglot--versioned-identifier))
-  (mapc (jsonrpc-lambda
-            (&key range newText)
-          (save-restriction
-            (widen)
-            (save-excursion
-              (pcase-let ((`(,beg . ,end) (eglot--range-region range)))
-                (goto-char beg) (delete-region beg end) (insert newText)))))
-        edits)
+  (save-restriction
+    (widen)
+    (save-excursion
+      (mapc (jsonrpc-lambda (newText beg end)
+              (goto-char beg) (delete-region beg end) (insert newText))
+            (mapcar (jsonrpc-lambda (&key range newText)
+                      (cons newText (eglot--range-region range 'markers)))
+                    edits))))
   (eglot--message "%s: Performed %s edits" (current-buffer) (length edits)))
 
 (defun eglot--apply-workspace-edit (wedit &optional confirm)
@@ -1223,11 +1224,10 @@ Proceed? "
   "Handle notification window/progress"
   (setf (eglot--spinner process) (list id title done message))
   (when (and (equal "Indexing" title) done)
-    (dolist (buffer (buffer-list))
+    (dolist (buffer (eglot--managed-buffers process))
       (with-current-buffer buffer
-        (when (eglot--buffer-managed-p process)
-          (funcall (or eglot--current-flymake-report-fn #'ignore)
-                   eglot--unreported-diagnostics))))))
+        (funcall (or eglot--current-flymake-report-fn #'ignore)
+                 eglot--unreported-diagnostics)))))
 
 (provide 'eglot)
 ;;; eglot.el ends here
diff --git a/jsonrpc.el b/jsonrpc.el
index 251ebf4..d5f7745 100644
--- a/jsonrpc.el
+++ b/jsonrpc.el
@@ -168,17 +168,13 @@ FORMAT as the message."
     (var-sym initval &optional doc)
   "Define VAR-SYM as a generalized process-local variable.
 INITVAL is the default value.  DOC is the documentation."
-  (declare (indent 2))
+  (declare (indent 2) (doc-string 3))
   `(progn
-     (put ',var-sym 'function-documentation ,doc)
-     (defun ,var-sym (proc)
+     (defun ,var-sym (proc) ,doc
        (let* ((plist (process-plist proc))
               (probe (plist-member plist ',var-sym)))
-         (if probe
-             (cadr probe)
-           (let ((def ,initval))
-             (process-put proc ',var-sym def)
-             def))))
+         (if probe (cadr probe)
+           (let ((def ,initval)) (process-put proc ',var-sym def) def))))
      (gv-define-setter ,var-sym (to-store process)
        `(let ((once ,to-store)) (process-put ,process ',',var-sym once) 
once))))
 
@@ -551,7 +547,7 @@ TIMEOUT is nil)"
                      (funcall (or timeout-fn
                                   (lambda ()
                                     (jsonrpc-log-event
-                                     proc `(:timed-out ,method :id id
+                                     proc `(:timed-out ,method :id ,id
                                                        :params 
,params))))))))))))
     (when deferred
       (let* ((buf (current-buffer))
@@ -583,14 +579,14 @@ TIMEOUT is nil)"
     (puthash id
              (list (or success-fn
                        (jsonrpc-lambda (&rest _ignored)
-                                       (jsonrpc-log-event
-                                        proc (jsonrpc-obj :message "success 
ignored" :id id))))
+                         (jsonrpc-log-event
+                          proc (jsonrpc-obj :message "success ignored" :id 
id))))
                    (or error-fn
                        (jsonrpc-lambda (&key code message &allow-other-keys)
-                                       (setf (jsonrpc-status proc) `(,message 
t))
-                                       (jsonrpc-log-event
-                                        proc (jsonrpc-obj :message "error 
ignored, status set"
-                                                          :id id :error 
code))))
+                         (setf (jsonrpc-status proc) `(,message t))
+                         (jsonrpc-log-event
+                          proc (jsonrpc-obj :message "error ignored, status 
set"
+                                            :id id :error code))))
                    (setq timer (funcall make-timer)))
              (jsonrpc--request-continuations proc))
     (list id timer)))
@@ -604,33 +600,34 @@ only exit locally (and return the JSONRPC result object) 
if the
 request is successful, otherwise exit non-locally with an error.
 
 DEFERRED is passed to `jsonrpc-async-request', which see."
-  (let* ((tag (cl-gensym "jsonrpc-request-catch-tag"))
-         req-id req-timer
+  (let* ((tag (cl-gensym "jsonrpc-request-catch-tag")) id-and-timer
          (retval
           (unwind-protect ; protect against user-quit, for example
               (catch tag
-                (pcase-let
-                    ((`(,id ,timer)
-                      (jsonrpc-async-request
-                       proc method params
-                       :success-fn (lambda (result) (throw tag `(done 
,result)))
-                       :error-fn
-                       (jsonrpc-lambda
-                        (&key code message data)
-                        (throw tag `(error (jsonrpc-error-code . ,code)
-                                           (jsonrpc-error-message . ,message)
-                                           (jsonrpc-error-data . ,data))))
-                       :timeout-fn
-                       (lambda ()
-                         (throw tag '(error (jsonrpc-error-message . "Timed 
out"))))
-                       :deferred deferred)))
-                  (setq req-id (or id 'deferred) req-timer timer))
+                (setq
+                 id-and-timer
+                 (jsonrpc-async-request
+                  proc method params
+                  :success-fn (lambda (result) (throw tag `(done ,result)))
+                  :error-fn
+                  (jsonrpc-lambda
+                      (&key code message data)
+                    (throw tag `(error (jsonrpc-error-code . ,code)
+                                       (jsonrpc-error-message . ,message)
+                                       (jsonrpc-error-data . ,data))))
+                  :timeout-fn
+                  (lambda ()
+                    (throw tag '(error (jsonrpc-error-message . "Timed out"))))
+                  :deferred deferred))
                 (while t (accept-process-output nil 30)))
-            (when req-timer (cancel-timer req-timer)))))
+            (pcase-let ((`(,id ,timer) id-and-timer))
+              (when id (remhash id (jsonrpc--request-continuations proc)))
+              (when timer (cancel-timer timer))))))
     (when (eq 'error (car retval))
       (signal 'error
               (cons
-               (format "[jsonrpc] jsonrpc-request (%s) failed:" req-id) (cdr 
retval))))
+               (format "[jsonrpc] jsonrpc-request (%s) failed:" (car 
id-and-timer))
+               (cdr retval))))
     (cadr retval)))
 
 (cl-defun jsonrpc-notify (proc method params)



reply via email to

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