Skip to content

Commit

Permalink
Fix eglot-completion-at-point to work with bare completion-at-point
Browse files Browse the repository at this point in the history
Fixes joaotavora/eglot#313, fixes joaotavora/eglot#311, fixes joaotavora/eglot#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.
  • Loading branch information
joaotavora committed Oct 14, 2019
1 parent fa7a779 commit b53869d
Showing 1 changed file with 31 additions and 29 deletions.
60 changes: 31 additions & 29 deletions eglot.el
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit b53869d

Please sign in to comment.