Skip to content

Commit 6ecb0e1

Browse files
committed
lsp-completion: support async detail completion resolve and more lazy properties
1 parent e178115 commit 6ecb0e1

File tree

2 files changed

+81
-58
lines changed

2 files changed

+81
-58
lines changed

lsp-completion.el

+78-57
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,76 @@ This will help minimize popup flickering issue in `company-mode'."
177177
'lsp-completion-markers markers
178178
'lsp-completion-prefix prefix)))
179179

180+
(defun lsp-completion--fix-resolve-data (item)
181+
"Patch `CompletionItem' ITEM for rust-analyzer otherwise resolve will fail.
182+
See #2675"
183+
(let ((data (lsp:completion-item-data? item)))
184+
(when (lsp-member? data :import_for_trait_assoc_item)
185+
(unless (lsp-get data :import_for_trait_assoc_item)
186+
(lsp-put data :import_for_trait_assoc_item :json-false)))))
187+
188+
(defun lsp-completion--resolve (item)
189+
"Resolve completion ITEM.
190+
ITEM can be string or a CompletionItem"
191+
(cl-assert item nil "Completion item must not be nil")
192+
(-let (((completion-item . resolved)
193+
(pcase item
194+
((pred stringp) (cons (get-text-property 0 'lsp-completion-item item)
195+
(get-text-property 0 'lsp-completion-resolved item)))
196+
(_ (cons item nil)))))
197+
(if resolved item
198+
(lsp-completion--fix-resolve-data completion-item)
199+
(setq completion-item
200+
(or (ignore-errors
201+
(when (lsp-feature? "completionItem/resolve")
202+
(lsp-request "completionItem/resolve"
203+
(lsp-delete (lsp-copy completion-item) :_emacsStartPoint))))
204+
completion-item))
205+
(pcase item
206+
((pred stringp)
207+
(let ((len (length item)))
208+
(put-text-property 0 len 'lsp-completion-item completion-item item)
209+
(put-text-property 0 len 'lsp-completion-resolved t item)
210+
item))
211+
(_ completion-item)))))
212+
213+
(defun lsp-completion--resolve-async (item callback &optional cleanup-fn)
214+
"Resolve completion ITEM asynchronously with CALLBACK.
215+
The CLEANUP-FN will be called to cleanup."
216+
(cl-assert item nil "Completion item must not be nil")
217+
(-let (((completion-item . resolved)
218+
(pcase item
219+
((pred stringp) (cons (get-text-property 0 'lsp-completion-item item)
220+
(get-text-property 0 'lsp-completion-resolved item)))
221+
(_ (cons item nil)))))
222+
(ignore-errors
223+
(if (and (lsp-feature? "completionItem/resolve") (not resolved))
224+
(progn
225+
(lsp-completion--fix-resolve-data completion-item)
226+
(lsp-request-async "completionItem/resolve"
227+
(lsp-delete (lsp-copy completion-item) :_emacsStartPoint)
228+
(lambda (completion-item)
229+
(when (stringp item)
230+
(let ((len (length item)))
231+
(put-text-property 0 len 'lsp-completion-item completion-item item)
232+
(put-text-property 0 len 'lsp-completion-resolved t item)
233+
item))
234+
(funcall callback completion-item)
235+
(when cleanup-fn (funcall cleanup-fn)))
236+
:error-handler (lambda (err)
237+
(when cleanup-fn (funcall cleanup-fn))
238+
(error (lsp:json-error-message err)))
239+
:cancel-handler cleanup-fn
240+
:mode 'alive))
241+
(funcall callback completion-item)
242+
(when cleanup-fn (funcall cleanup-fn))))))
243+
180244
(defun lsp-completion--annotate (item)
181245
"Annotate ITEM detail."
182-
(-let (((&CompletionItem :detail? :kind? :label-details?) (plist-get (text-properties-at 0 item)
183-
'lsp-completion-item)))
246+
(-let (((completion-item &as &CompletionItem :detail? :kind? :label-details?)
247+
(get-text-property 0 'lsp-completion-item item)))
248+
(lsp-completion--resolve-async item #'ignore)
249+
184250
(concat (when (and lsp-completion-show-detail detail?)
185251
(concat " " (s-replace "\r" "" detail?)))
186252
(when (and lsp-completion-show-label-description label-details?)
@@ -388,15 +454,8 @@ The MARKERS and PREFIX value will be attached to each candidate."
388454

389455
(defun lsp-completion--get-documentation (item)
390456
"Get doc comment for completion ITEM."
391-
(unless (get-text-property 0 'lsp-completion-resolved item)
392-
(let ((resolved-item
393-
(-some->> item
394-
(get-text-property 0 'lsp-completion-item)
395-
(lsp-completion--resolve)))
396-
(len (length item)))
397-
(put-text-property 0 len 'lsp-completion-item resolved-item item)
398-
(put-text-property 0 len 'lsp-completion-resolved t item)))
399457
(-some->> item
458+
(lsp-completion--resolve)
400459
(get-text-property 0 'lsp-completion-item)
401460
(lsp:completion-item-documentation?)
402461
(lsp--render-element)))
@@ -556,6 +615,12 @@ Others: CANDIDATES"
556615
'lsp-completion-item)
557616
candidate
558617
(cl-find candidate (funcall candidates) :test #'equal)))
618+
(candidate
619+
;; see #3498 typescript-language-server does not provide the
620+
;; proper insertText without resolving.
621+
(if (lsp-completion--find-workspace 'ts-ls)
622+
(lsp-completion--resolve candidate)
623+
candidate))
559624
((&plist 'lsp-completion-item item
560625
'lsp-completion-start-point start-point
561626
'lsp-completion-markers markers
@@ -564,12 +629,7 @@ Others: CANDIDATES"
564629
(text-properties-at 0 candidate))
565630
((&CompletionItem? :label :insert-text? :text-edit? :insert-text-format?
566631
:additional-text-edits? :insert-text-mode? :command?)
567-
;; see #3498 typescript-language-server does not provide the
568-
;; proper insertText without resolving.
569-
(if (and (lsp-completion--find-workspace 'ts-ls)
570-
(not resolved))
571-
(lsp-completion--resolve item)
572-
item)))
632+
item))
573633
(cond
574634
(text-edit?
575635
(apply #'delete-region markers)
@@ -597,7 +657,7 @@ Others: CANDIDATES"
597657
(point)))
598658

599659
(when lsp-completion-enable-additional-text-edit
600-
(if (or (get-text-property 0 'lsp-completion-resolved candidate)
660+
(if (or resolved
601661
(not (seq-empty-p additional-text-edits?)))
602662
(lsp--apply-text-edits additional-text-edits? 'completion)
603663
(-let [(callback cleanup-fn) (lsp--create-apply-text-edits-handlers)]
@@ -606,8 +666,7 @@ Others: CANDIDATES"
606666
(-compose callback #'lsp:completion-item-additional-text-edits?)
607667
cleanup-fn))))
608668

609-
(if (or (get-text-property 0 'lsp-completion-resolved candidate)
610-
command?)
669+
(if (or resolved command?)
611670
(when command? (lsp--execute-command command?))
612671
(lsp-completion--resolve-async
613672
item
@@ -705,44 +764,6 @@ The return is nil or in range of (0, inf)."
705764
(unless (zerop len)
706765
(/ score-numerator (1+ score-denominator) 1.0))))
707766

708-
(defun lsp-completion--fix-resolve-data (item)
709-
"Patch `CompletionItem' ITEM for rust-analyzer otherwise resolve will fail.
710-
See #2675"
711-
(let ((data (lsp:completion-item-data? item)))
712-
(when (lsp-member? data :import_for_trait_assoc_item)
713-
(unless (lsp-get data :import_for_trait_assoc_item)
714-
(lsp-put data :import_for_trait_assoc_item :json-false)))))
715-
716-
(defun lsp-completion--resolve (item)
717-
"Resolve completion ITEM."
718-
(cl-assert item nil "Completion item must not be nil")
719-
(lsp-completion--fix-resolve-data item)
720-
(or (ignore-errors
721-
(when (lsp-feature? "completionItem/resolve")
722-
(lsp-request "completionItem/resolve"
723-
(lsp-delete (lsp-copy item) :_emacsStartPoint))))
724-
item))
725-
726-
(defun lsp-completion--resolve-async (item callback &optional cleanup-fn)
727-
"Resolve completion ITEM asynchronously with CALLBACK.
728-
The CLEANUP-FN will be called to cleanup."
729-
(cl-assert item nil "Completion item must not be nil")
730-
(lsp-completion--fix-resolve-data item)
731-
(ignore-errors
732-
(if (lsp-feature? "completionItem/resolve")
733-
(lsp-request-async "completionItem/resolve"
734-
(lsp-delete (lsp-copy item) :_emacsStartPoint)
735-
(lambda (result)
736-
(funcall callback result)
737-
(when cleanup-fn (funcall cleanup-fn)))
738-
:error-handler (lambda (err)
739-
(when cleanup-fn (funcall cleanup-fn))
740-
(error (lsp:json-error-message err)))
741-
:cancel-handler cleanup-fn
742-
:mode 'alive)
743-
(funcall callback item)
744-
(when cleanup-fn (funcall cleanup-fn)))))
745-
746767

747768
;;;###autoload
748769
(defun lsp-completion--enable ()

lsp-mode.el

+3-1
Original file line numberDiff line numberDiff line change
@@ -3773,7 +3773,9 @@ disappearing, unset all the variables related to it."
37733773
. ((properties . ["documentation"
37743774
"detail"
37753775
"additionalTextEdits"
3776-
"command"])))
3776+
"command"
3777+
"insertTextFormat"
3778+
"insertTextMode"])))
37773779
(insertTextModeSupport . ((valueSet . [1 2])))))
37783780
(contextSupport . t)
37793781
(dynamicRegistration . t)))

0 commit comments

Comments
 (0)