Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitab6d69e

Browse files
committed
feat(lsp): completion support completitem/resolve when popup exist
support completeitem/resolve request to get documentation and showit in popup floating window when cot include popupFixes#29225
1 parent7c9b865 commitab6d69e

File tree

3 files changed

+299
-13
lines changed

3 files changed

+299
-13
lines changed

‎runtime/lua/vim/lsp/completion.lua‎

Lines changed: 231 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ local Context = {
6767
last_request_time=nil,--- @typeinteger?
6868
pending_requests= {},--- @typefunction[]
6969
isIncomplete=false,
70+
resolve_handler=nil,--- @typeCompletionResolver?
7071
}
7172

7273
--- @nodoc
@@ -84,6 +85,10 @@ function Context:reset()
8485
self.isIncomplete=false
8586
self.last_request_time=nil
8687
self:cancel_pending()
88+
ifself.resolve_handlerthen
89+
self.resolve_handler:cleanup()
90+
self.resolve_handler=nil
91+
end
8792
end
8893

8994
--- @typeuv.uv_timer_t?
@@ -105,7 +110,7 @@ end
105110

106111
--- @paramwindowinteger
107112
--- @paramwarmupinteger
108-
--- @returnfun(sample:number):number
113+
--- @returnfun(sample:integer):integer
109114
localfunctionexp_avg(window,warmup)
110115
localcount=0
111116
localsum=0
@@ -470,6 +475,217 @@ local function request(clients, bufnr, win, ctx, callback)
470475
end
471476
end
472477

478+
---@parambufnrinteger
479+
---@returnstring
480+
localfunctionget_augroup(bufnr)
481+
returnstring.format('nvim.lsp.completion_%d',bufnr)
482+
end
483+
484+
--- Updates the completion preview popup: configures conceal level, applies Treesitter or
485+
--- fallback syntax, and resizes height to fit content
486+
---
487+
--- @paramwinidinteger
488+
--- @parambufnrinteger
489+
--- @paramft?string
490+
localfunctionupdate_popup_window(winid,bufnr,ft)
491+
ifwinidandapi.nvim_win_is_valid(winid)andbufnrandapi.nvim_buf_is_valid(bufnr)then
492+
vim.wo[winid].conceallevel=2
493+
ifftthen
494+
localok=pcall(vim.treesitter.get_parser,bufnr,ft)
495+
ifokthen
496+
vim.treesitter.start(bufnr,vim.treesitter.language.get_lang(ft))
497+
else
498+
vim.bo[bufnr].filetype=ft
499+
vim.bo[bufnr].syntax='on'
500+
end
501+
end
502+
localall=api.nvim_win_text_height(winid, {}).all
503+
api.nvim_win_set_height(winid,all)
504+
end
505+
end
506+
507+
--- Handles the LSP completion item resolution process with debounce and timer management.
508+
--- This class resolves the completion item asynchronously and updates the documentation popup.
509+
---
510+
--- @nodoc
511+
--- @classCompletionResolver
512+
--- @fieldtimeruv.uv_timer_t?Timer used for debouncing
513+
--- @fieldrequest_idstable<integer,integer> Table tracking ongoing requests
514+
--- @fieldbufnrinteger?Buffer number for which the resolution is triggered
515+
--- @fieldwordstring?Word being completed
516+
--- @fieldlast_request_timeinteger?Last request timestamp
517+
--- @fielddoc_rtt_msinteger Last request timestamp
518+
--- @fielddoc_compute_new_averagefun(sample:integer):integer Last request timestamp
519+
localCompletionResolver= {}
520+
CompletionResolver.__index=CompletionResolver
521+
522+
--- Creates a new instance of `resolve_completion_item`.
523+
---
524+
--- @returnCompletionResolver
525+
functionCompletionResolver.new()
526+
localself=setmetatable({},CompletionResolver)
527+
self.timer=nil
528+
self.request_ids= {}
529+
self.bufnr=nil
530+
self.word=nil
531+
self.last_request_time=nil
532+
self.doc_rtt_ms=100
533+
self.doc_compute_new_average=exp_avg(10,5)
534+
returnself
535+
end
536+
537+
--- Calculates the debounce time for the next LSP request based on the last request time.
538+
--- @returninteger The time(in milliseconds)before the next request is made
539+
functionCompletionResolver:next_debounce_time()
540+
ifnotself.last_request_timethen
541+
returnself.doc_rtt_ms
542+
end
543+
localms_since_request= (vim.uv.hrtime()-self.last_request_time)*ns_to_ms
544+
returnmath.max((ms_since_request-self.doc_rtt_ms)*-1,0)
545+
end
546+
547+
--- Cancels any pending requests.
548+
functionCompletionResolver:cancel_pending_requests()
549+
forclient_id,request_idinpairs(self.request_ids)do
550+
localclient=vim.lsp.get_client_by_id(client_id)
551+
ifclientandclient.requestsandclient.requests[request_id]then
552+
client:cancel_request(request_id)
553+
end
554+
end
555+
self.request_ids= {}
556+
end
557+
558+
--- Cleans up the timer and cancels any ongoing requests.
559+
functionCompletionResolver:cleanup()
560+
ifself.timerandnotself.timer:is_closing()then
561+
self.timer:stop()
562+
self.timer:close()
563+
self.timer=nil
564+
end
565+
self:cancel_pending_requests()
566+
end
567+
568+
--- Checks if the completionItem/resolve request is valid by ensuring the buffer and word are valid.
569+
---
570+
--- @returnboolean,table Validity of the request and the completion info
571+
functionCompletionResolver:is_valid()
572+
localcmp_info=vim.fn.complete_info({'selected','completed'})
573+
returnvim.api.nvim_buf_is_valid(self.bufnr)
574+
andvim.api.nvim_get_current_buf()==self.bufnr
575+
andvim.startswith(vim.api.nvim_get_mode().mode,'i')
576+
andtonumber(vim.fn.pumvisible())==1
577+
and (vim.tbl_get(cmp_info,'completed','word')or'')==self.word,
578+
cmp_info
579+
end
580+
581+
--- Starts the resolution process for the completionItem/resolve.
582+
--- This includes starting a timer and making the LSP request after the debounce period.
583+
---
584+
--- @parambufnrinteger The buffer number where the request is triggered
585+
--- @paramparamtable The parameters for the LSP request
586+
--- @paramselected_wordstring The word being completed
587+
functionCompletionResolver:request(bufnr,param,selected_word)
588+
self:cleanup()
589+
590+
self.bufnr=bufnr
591+
self.word=selected_word
592+
localdebounce_time=self:next_debounce_time()
593+
594+
-- Create and start the timer
595+
self.timer=assert(vim.uv.new_timer())
596+
self.timer:start(
597+
debounce_time,
598+
0,
599+
vim.schedule_wrap(function()
600+
localvalid,cmp_info=self:is_valid()
601+
ifnotvalidthen
602+
self:cleanup()
603+
return
604+
end
605+
606+
-- Cancel any pending requests before sending a new one
607+
self:cancel_pending_requests()
608+
609+
localclient_id=vim.tbl_get(cmp_info.completed,'user_data','nvim','lsp','client_id')
610+
localclient=client_idandvim.lsp.get_client_by_id(client_id)
611+
ifnotclientthen
612+
return
613+
end
614+
615+
localstart_time=vim.uv.hrtime()
616+
self.last_request_time=start_time
617+
618+
localok,request_id=client:request('completionItem/resolve',param,function(err,result)
619+
localend_time=vim.uv.hrtime()
620+
localresponse_time= (end_time-start_time)*ns_to_ms
621+
self.doc_rtt_ms=self.doc_compute_new_average(response_time)
622+
623+
iferrornotresultornext(result)==nilthen
624+
iferrthen
625+
vim.notify(err.message,vim.log.levels.WARN)
626+
end
627+
return
628+
end
629+
630+
valid,cmp_info=self:is_valid()
631+
ifnotvalidthen
632+
return
633+
end
634+
635+
localvalue=vim.tbl_get(result,'documentation','value')
636+
ifnotvaluethen
637+
return
638+
end
639+
localwindata=vim.api.nvim__complete_set(cmp_info.selected, {
640+
info=value,
641+
})
642+
localkind=vim.tbl_get(result,'documentation','kind')
643+
update_popup_window(windata.winid,windata.bufnr,kind)
644+
end,bufnr)
645+
646+
ifokandrequest_idthen
647+
self.request_ids[client.id]=request_id
648+
end
649+
end)
650+
)
651+
end
652+
653+
--- Defines a CompleteChanged handler to request and display LSP completion item documentation
654+
--- via completionItem/resolve
655+
localfunctionon_completechanged(group,bufnr)
656+
api.nvim_create_autocmd('CompleteChanged', {
657+
group=group,
658+
buffer=bufnr,
659+
callback=function(args)
660+
localcompleted_item=vim.v.event.completed_itemor {}
661+
if (completed_item.infoor'')~=''then
662+
localdata=vim.fn.complete_info({'selected'})
663+
update_popup_window(data.preview_winid,data.preview_bufnr)
664+
return
665+
end
666+
667+
if
668+
#lsp.get_clients({
669+
id=vim.tbl_get(completed_item,'user_data','nvim','lsp','client_id'),
670+
method='completionItem/resolve',
671+
bufnr=args.buf,
672+
})==0
673+
then
674+
return
675+
end
676+
677+
-- Retrieve the raw LSP completionItem from completed_item as the parameter for
678+
-- the completionItem/resolve request
679+
localparam=vim.tbl_get(completed_item,'user_data','nvim','lsp','completion_item')
680+
ifparamthen
681+
Context.resolve_handler=Context.resolve_handlerorCompletionResolver.new()
682+
Context.resolve_handler:request(args.buf,param,completed_item.word)
683+
end
684+
end,
685+
desc='Request and display LSP completion item documentation via completionItem/resolve',
686+
})
687+
end
688+
473689
--- @parambufnrinteger
474690
--- @paramclientsvim.lsp.Client[]
475691
--- @paramctx?lsp.CompletionContext
@@ -554,6 +770,14 @@ local function trigger(bufnr, clients, ctx)
554770

555771
localstart_col= (server_start_boundaryorword_boundary)+1
556772
Context.cursor= {cursor_row,start_col }
773+
if#matches>0andvim.regex('\\<popup\\>'):match_str(vim.o.completeopt)then
774+
localgroup=get_augroup(bufnr)
775+
if
776+
#api.nvim_get_autocmds({buffer=bufnr,event='CompleteChanged',group=group })==0
777+
then
778+
on_completechanged(group,bufnr)
779+
end
780+
end
557781
vim.fn.complete(start_col,matches)
558782
end)
559783

@@ -587,7 +811,7 @@ local function on_insert_char_pre(handle)
587811
return
588812
end
589813

590-
localchar=api.nvim_get_vvar('char')
814+
localchar=vim.v.char
591815
localmatched_clients=handle.triggers[char]
592816
-- Discard pending trigger char, complete the "latest" one.
593817
-- Can happen if a mapping inputs multiple trigger chars simultaneously.
@@ -597,11 +821,10 @@ local function on_insert_char_pre(handle)
597821
completion_timer:start(25,0,function()
598822
reset_timer()
599823
vim.schedule(function()
600-
trigger(
601-
api.nvim_get_current_buf(),
602-
matched_clients,
603-
{triggerKind=protocol.CompletionTriggerKind.TriggerCharacter,triggerCharacter=char }
604-
)
824+
trigger(api.nvim_get_current_buf(),matched_clients, {
825+
triggerKind=protocol.CompletionTriggerKind.TriggerCharacter,
826+
triggerCharacter=char,
827+
})
605828
end)
606829
end)
607830
end
@@ -702,12 +925,6 @@ local function on_complete_done()
702925
end
703926
end
704927

705-
---@parambufnrinteger
706-
---@returnstring
707-
localfunctionget_augroup(bufnr)
708-
returnstring.format('nvim.lsp.completion_%d',bufnr)
709-
end
710-
711928
--- @inlinedoc
712929
--- @classvim.lsp.completion.BufferOpts
713930
--- @fieldautotrigger?boolean(default:false)When true,completion triggers automatically based on the server's `triggerCharacters`.
@@ -744,6 +961,7 @@ local function enable_completions(client_id, bufnr, opts)
744961
end
745962
end,
746963
})
964+
747965
ifopts.autotriggerthen
748966
api.nvim_create_autocmd('InsertCharPre', {
749967
group=group,

‎runtime/lua/vim/lsp/protocol.lua‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ function protocol.make_client_capabilities()
482482
properties= {
483483
'additionalTextEdits',
484484
'command',
485+
'documentation',
485486
},
486487
},
487488
tagSupport= {

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp