]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix eglot-completion-at-point to work with bare completion-at-point
authorJoão Távora <joaotavora@gmail.com>
Sat, 12 Oct 2019 00:57:00 +0000 (01:57 +0100)
committerJoão Távora <joaotavora@gmail.com>
Mon, 14 Oct 2019 22:30:27 +0000 (23:30 +0100)
Fixes https://github.com/joaotavora/eglot/issues/313, fixes https://github.com/joaotavora/eglot/issues/311, fixes https://github.com/joaotavora/eglot/issues/279

As is well known, LSP's and Emacs's completion mechanics don't fit
very well together, mostly because Emacs expects completion to be a
something of a pure function of a string argument and LSP treats as a
function of a concrete buffer position.

A further complication arises because some completion frontends like
"bare" completion-at-point make Emacs modify the buffer's contents
during the completion process, while other (notably company-mode)
don't do that.  Thus, 'eglot-completion-at-point' must take extra care
to answer to the questions listed in the "(elisp)Programmed
Completion" info node based on its (quite hacky) "completions" local
var and _not_ based on the intermediate buffer contents.  That var is
also used to cache the last LSP response and allow the :exit-function
callback to retrieve much more than just the completion text in

In yet another related problem, :exit-function won't be called at all
with completion-at-point if the completion table doesn't answer
properly to test-completion.  A previous use of
completion-table-dynamic was found to be unsuitable here: we must
answer all the requests separately.

* eglot.el (eglot-completion-at-point): Rework.

lisp/progmodes/eglot.el

index 7b0e3e28a6d24798359a78bfc780d628b20d0d43..421941f19556c60330bd5c262bf17f011338de0e 100644 (file)
@@ -1883,38 +1883,40 @@ is not active."
                                      (or (get-text-property 0 :sortText a) "")
                                      (or (get-text-property 0 :sortText b) ""))))))
         (metadata `(metadata . ((display-sort-function . ,sort-completions))))
-        strings)
+        completions)
     (when completion-capability
       (list
        (or (car bounds) (point))
        (or (cdr bounds) (point))
-       (lambda (string pred action)
-         (if (eq action 'metadata) metadata
-           (funcall
-            (completion-table-dynamic
-             (lambda (_ignored)
-               (let* ((resp (jsonrpc-request server
-                                             :textDocument/completion
-                                             (eglot--CompletionParams)
-                                             :deferred :textDocument/completion
-                                             :cancel-on-input t))
-                      (items (if (vectorp resp) resp (plist-get resp :items))))
-                 (setq
-                  strings
-                  (mapcar
-                   (jsonrpc-lambda
-                       (&rest all &key label insertText insertTextFormat
-                              &allow-other-keys)
-                     (let ((completion
-                            (cond ((and (eql insertTextFormat 2)
-                                        (eglot--snippet-expansion-fn))
-                                   (string-trim-left label))
-                                  (t
-                                   (or insertText (string-trim-left label))))))
-                       (put-text-property 0 1 'eglot--lsp-completion all completion)
-                       completion))
-                   items)))))
-            string pred action)))
+       (lambda (comp _pred action)
+         (cond
+          ((eq action 'metadata) metadata)                  ; metadata
+          ((eq action 'lambda) (member comp completions))   ; test-completion
+          ((eq (car-safe action) 'boundaries) nil)          ; boundaries
+          ((and (null action) (member comp completions) t)) ; try-completion
+          ((eq action t)                                    ; all-completions
+           (let* ((resp (jsonrpc-request server
+                                         :textDocument/completion
+                                         (eglot--CompletionParams)
+                                         :deferred :textDocument/completion
+                                         :cancel-on-input t))
+                  (items (if (vectorp resp) resp (plist-get resp :items))))
+             (setq
+              completions
+              (mapcar
+               (jsonrpc-lambda
+                   (&rest all &key label insertText insertTextFormat
+                          &allow-other-keys)
+                 (let ((completion
+                        (cond ((and (eql insertTextFormat 2)
+                                    (eglot--snippet-expansion-fn))
+                               (string-trim-left label))
+                              (t
+                               (or insertText (string-trim-left label))))))
+                   (put-text-property 0 1 'eglot--lsp-completion
+                                      all completion)
+                   completion))
+               items))))))
        :annotation-function
        (lambda (obj)
          (eglot--dbind ((CompletionItem) detail kind insertTextFormat)
@@ -1966,7 +1968,7 @@ is not active."
                        ;; When selecting from the *Completions*
                        ;; buffer, `comp' won't have any properties.  A
                        ;; lookup should fix that (github#148)
-                       (cl-find comp strings :test #'string=))))
+                       (cl-find comp completions :test #'string=))))
            (eglot--dbind ((CompletionItem) insertTextFormat
                           insertText
                           textEdit