Eglot: cosmetic refactor of eglot-completion-at-point
* lisp/progmodes/eglot.el (eglot-completion-at-point): rework.
This commit is contained in:
parent
96dc5deddc
commit
5f9982eded
1 changed files with 84 additions and 84 deletions
|
@ -3343,81 +3343,79 @@ for which LSP on-type-formatting should be requested."
|
|||
(add-to-list 'completion-category-defaults '(eglot-capf (styles eglot--dumb-flex)))
|
||||
(add-to-list 'completion-styles-alist '(eglot--dumb-flex eglot--dumb-tryc eglot--dumb-allc))
|
||||
|
||||
(defun eglot-completion-at-point ()
|
||||
(cl-defun eglot-completion-at-point (&aux completion-capability)
|
||||
"Eglot's `completion-at-point' function."
|
||||
;; Commit logs for this function help understand what's going on.
|
||||
(when-let* ((completion-capability (eglot-server-capable :completionProvider)))
|
||||
(let* ((server (eglot--current-server-or-lose))
|
||||
(bounds (or (bounds-of-thing-at-point 'symbol)
|
||||
(cons (point) (point))))
|
||||
(bounds-string (buffer-substring (car bounds) (cdr bounds)))
|
||||
(sort-completions
|
||||
(lambda (completions)
|
||||
(cl-sort completions
|
||||
#'string-lessp
|
||||
:key (lambda (c)
|
||||
(plist-get
|
||||
(get-text-property 0 'eglot--lsp-item c)
|
||||
:sortText)))))
|
||||
(metadata `(metadata (category . eglot-capf)
|
||||
(display-sort-function . ,sort-completions)))
|
||||
(local-cache :none)
|
||||
(orig-pos (point))
|
||||
(resolved (make-hash-table))
|
||||
(proxies
|
||||
(lambda ()
|
||||
(if (listp local-cache) local-cache
|
||||
(let* ((resp (eglot--request server
|
||||
:textDocument/completion
|
||||
(eglot--CompletionParams)
|
||||
:cancel-on-input t))
|
||||
(items (append
|
||||
(if (vectorp resp) resp (plist-get resp :items))
|
||||
nil))
|
||||
(cachep (and (listp resp) items
|
||||
eglot-cache-session-completions
|
||||
(eq (plist-get resp :isIncomplete) :json-false)))
|
||||
(retval
|
||||
(mapcar
|
||||
(jsonrpc-lambda
|
||||
(&rest item &key label insertText insertTextFormat
|
||||
textEdit &allow-other-keys)
|
||||
(let ((proxy
|
||||
;; Snippet or textEdit, it's safe to
|
||||
;; display/insert the label since
|
||||
;; it'll be adjusted. If no usable
|
||||
;; insertText at all, label is best,
|
||||
;; too.
|
||||
(cond ((or (eql insertTextFormat 2)
|
||||
textEdit
|
||||
(null insertText)
|
||||
(string-empty-p insertText))
|
||||
(string-trim-left label))
|
||||
(t insertText))))
|
||||
(unless (zerop (length proxy))
|
||||
(put-text-property 0 1 'eglot--lsp-item item proxy))
|
||||
proxy))
|
||||
items)))
|
||||
;; (trace-values "Requested" (length proxies) cachep bounds)
|
||||
(setq eglot--capf-session
|
||||
(if cachep (list bounds retval resolved orig-pos
|
||||
bounds-string) :none))
|
||||
(setq local-cache retval)))))
|
||||
(resolve-maybe
|
||||
;; Maybe completion/resolve JSON object `lsp-comp' into
|
||||
;; another JSON object, if at all possible. Otherwise,
|
||||
;; just return lsp-comp.
|
||||
(lambda (lsp-comp &optional dont-cancel-on-input)
|
||||
(or (gethash lsp-comp resolved)
|
||||
(setf (gethash lsp-comp resolved)
|
||||
(if (and (eglot-server-capable :completionProvider
|
||||
:resolveProvider)
|
||||
(plist-get lsp-comp :data))
|
||||
(eglot--request server :completionItem/resolve
|
||||
lsp-comp :cancel-on-input
|
||||
(not dont-cancel-on-input)
|
||||
:immediate t)
|
||||
lsp-comp))))))
|
||||
(setq completion-capability (eglot-server-capable :completionProvider))
|
||||
(unless completion-capability (cl-return-from eglot-completion-at-point))
|
||||
(let* ((server (eglot--current-server-or-lose))
|
||||
(bounds (or (bounds-of-thing-at-point 'symbol)
|
||||
(cons (point) (point))))
|
||||
(bounds-string (buffer-substring (car bounds) (cdr bounds)))
|
||||
(local-cache :none)
|
||||
(orig-pos (point))
|
||||
(resolved (make-hash-table)))
|
||||
(cl-labels
|
||||
((sort-completions (completions)
|
||||
(cl-sort completions
|
||||
#'string-lessp
|
||||
:key (lambda (c)
|
||||
(plist-get
|
||||
(get-text-property 0 'eglot--lsp-item c)
|
||||
:sortText))))
|
||||
(proxies ()
|
||||
(if (listp local-cache) local-cache
|
||||
(let* ((resp (eglot--request server
|
||||
:textDocument/completion
|
||||
(eglot--CompletionParams)
|
||||
:cancel-on-input t))
|
||||
(items (append
|
||||
(if (vectorp resp) resp (plist-get resp :items))
|
||||
nil))
|
||||
(cachep (and (listp resp) items
|
||||
eglot-cache-session-completions
|
||||
(eq (plist-get resp :isIncomplete) :json-false)))
|
||||
(retval
|
||||
(mapcar
|
||||
(jsonrpc-lambda
|
||||
(&rest item &key label insertText insertTextFormat
|
||||
textEdit &allow-other-keys)
|
||||
(let ((proxy
|
||||
;; Snippet or textEdit, it's safe to
|
||||
;; display/insert the label since
|
||||
;; it'll be adjusted. If no usable
|
||||
;; insertText at all, label is best,
|
||||
;; too.
|
||||
(cond ((or (eql insertTextFormat 2)
|
||||
textEdit
|
||||
(null insertText)
|
||||
(string-empty-p insertText))
|
||||
(string-trim-left label))
|
||||
(t insertText))))
|
||||
(unless (zerop (length proxy))
|
||||
(put-text-property 0 1 'eglot--lsp-item item proxy))
|
||||
proxy))
|
||||
items)))
|
||||
;; (trace-values "Requested" (length proxies) cachep bounds)
|
||||
(setq eglot--capf-session
|
||||
(if cachep (list bounds retval resolved orig-pos
|
||||
bounds-string)
|
||||
:none))
|
||||
(setq local-cache retval))))
|
||||
(ensure-resolved (lsp-comp &optional dont-cancel-on-input)
|
||||
;; Maybe completion/resolve JSON object `lsp-comp' into
|
||||
;; another JSON object, if at all possible. Otherwise,
|
||||
;; just return lsp-comp.
|
||||
(or (gethash lsp-comp resolved)
|
||||
(setf (gethash lsp-comp resolved)
|
||||
(if (and (eglot-server-capable :completionProvider
|
||||
:resolveProvider)
|
||||
(plist-get lsp-comp :data))
|
||||
(eglot--request server :completionItem/resolve
|
||||
lsp-comp :cancel-on-input
|
||||
(not dont-cancel-on-input)
|
||||
:immediate t)
|
||||
lsp-comp)))))
|
||||
(when (and (consp eglot--capf-session)
|
||||
(= (car bounds) (car (nth 0 eglot--capf-session)))
|
||||
(>= (cdr bounds) (cdr (nth 0 eglot--capf-session))))
|
||||
|
@ -3432,14 +3430,16 @@ for which LSP on-type-formatting should be requested."
|
|||
(cdr bounds)
|
||||
(lambda (pattern pred action)
|
||||
(cond
|
||||
((eq action 'metadata) metadata) ; metadata
|
||||
((eq action 'metadata) ; metadata
|
||||
`(metadata (category . eglot-capf)
|
||||
(display-sort-function . ,#'sort-completions)))
|
||||
((eq action 'lambda) ; test-completion
|
||||
(test-completion pattern (funcall proxies)))
|
||||
(test-completion pattern (proxies)))
|
||||
((eq (car-safe action) 'boundaries) nil) ; boundaries
|
||||
((null action) ; try-completion
|
||||
(try-completion pattern (funcall proxies)))
|
||||
(try-completion pattern (proxies)))
|
||||
((eq action t) ; all-completions
|
||||
(let ((comps (funcall proxies)))
|
||||
(let ((comps (proxies)))
|
||||
(dolist (c comps) (eglot--dumb-flex pattern c completion-ignore-case))
|
||||
(all-completions
|
||||
""
|
||||
|
@ -3486,14 +3486,15 @@ for which LSP on-type-formatting should be requested."
|
|||
;; FIXME: autoImportText is specific to the pyright language server
|
||||
(lambda (proxy)
|
||||
(when-let* ((lsp-comp (get-text-property 0 'eglot--lsp-item proxy))
|
||||
(data (plist-get (funcall resolve-maybe lsp-comp) :data))
|
||||
(data (plist-get (ensure-resolved lsp-comp) :data))
|
||||
(import-text (plist-get data :autoImportText)))
|
||||
import-text))
|
||||
:company-doc-buffer
|
||||
(lambda (proxy)
|
||||
(let* ((documentation
|
||||
(let ((lsp-comp (get-text-property 0 'eglot--lsp-item proxy)))
|
||||
(plist-get (funcall resolve-maybe lsp-comp) :documentation)))
|
||||
(let* ((resolved
|
||||
(ensure-resolved (get-text-property 0 'eglot--lsp-item proxy)))
|
||||
(documentation
|
||||
(plist-get resolved :documentation))
|
||||
(formatted (and documentation
|
||||
(eglot--format-markup documentation))))
|
||||
(when formatted
|
||||
|
@ -3524,15 +3525,14 @@ for which LSP on-type-formatting should be requested."
|
|||
(current-buffer))
|
||||
(eglot--dbind ((CompletionItem) insertTextFormat
|
||||
insertText textEdit additionalTextEdits label)
|
||||
(funcall
|
||||
resolve-maybe
|
||||
(ensure-resolved
|
||||
(or (get-text-property 0 'eglot--lsp-item proxy)
|
||||
;; When selecting from the *Completions*
|
||||
;; buffer, `proxy' won't have any properties.
|
||||
;; A lookup should fix that (github#148)
|
||||
(get-text-property
|
||||
0 'eglot--lsp-item
|
||||
(cl-find proxy (funcall proxies) :test #'string=)))
|
||||
(cl-find proxy (proxies) :test #'string=)))
|
||||
;; Be sure to pass non-nil here since we don't want
|
||||
;; any quick typing after the soon-to-be-undone
|
||||
;; insertion to potentially cancel an essential
|
||||
|
|
Loading…
Add table
Reference in a new issue