From c2e084bc23f3e717605d54b334ead0816f6d445d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sat, 12 Oct 2019 01:57:00 +0100 Subject: [PATCH] Fix eglot-completion-at-point to work with bare completion-at-point 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 | 60 +++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 7b0e3e28a6d..421941f1955 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -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 -- 2.39.2