@@ -11,6 +11,9 @@ let s:TYPE = {
1111let s: FLOAT_WINDOW_AVAILABLE = exists (' *nvim_open_win' )
1212let s: POPUP_WINDOW_AVAILABLE = exists (' *popup_atcursor' )
1313
14+ " timers to control throttling
15+ let s: timers = {}
16+
1417function ! s: AddPrefix (message) abort
1518 return ' [LC] ' . a: message
1619endfunction
@@ -426,7 +429,9 @@ endfunction
426429" - Floating window on Neovim (0.4.0 or later)
427430" - popup window on vim (8.2 or later)
428431" - Preview window on Neovim (0.3.0 or earlier) or Vim
429- function ! s: OpenHoverPreview (bufname , lines , filetype ) abort
432+ "
433+ " Receives two optional arguments which are the X and Y position
434+ function ! s: OpenHoverPreview (bufname , lines , filetype , ... ) abort
430435 " Use local variable since parameter is not modifiable
431436 let lines = a: lines
432437 let bufnr = bufnr (' %' )
@@ -492,8 +497,15 @@ function! s:OpenHoverPreview(bufname, lines, filetype) abort
492497 let col = 1
493498 endif
494499
500+ let relative = ' cursor'
501+ let col = get (a: 000 , 0 , col )
502+ let row = get (a: 000 , 1 , row)
503+ if get (a: 000 , 0 , v: null ) isnot v: null && get (a: 000 , 1 , v: null ) isnot v: null
504+ let relative = ' win'
505+ endif
506+
495507 let s: float_win_id = nvim_open_win (bufnr , v: true , {
496- \ ' relative' : ' cursor ' ,
508+ \ ' relative' : relative ,
497509 \ ' anchor' : vert . hor ,
498510 \ ' row' : row,
499511 \ ' col' : col ,
@@ -507,7 +519,12 @@ function! s:OpenHoverPreview(bufname, lines, filetype) abort
507519 let float_win_highlight = s: GetVar (' LanguageClient_floatingHoverHighlight' , ' Normal:CursorLine' )
508520 execute printf (' setlocal winhl=%s' , float_win_highlight)
509521 elseif display_approach == # ' popup_win'
510- let pop_win_id = popup_atcursor (a: lines , {})
522+ let l: padding = [1 , 1 , 1 , 1 ]
523+ if get (a: 000 , 0 , v: null ) isnot v: null && get (a: 000 , 1 , v: null ) isnot v: null
524+ let pop_win_id = popup_create (a: lines , { ' line' : get (a: 000 , 1 ) + 1 , ' col' : get (a: 000 , 0 ) + 1 , ' padding' : l: padding })
525+ else
526+ let pop_win_id = popup_atcursor (a: lines , { ' padding' : l: padding })
527+ endif
511528 call setbufvar (winbufnr (pop_win_id), ' &filetype' , a: filetype )
512529 elseif display_approach == # ' preview'
513530 execute ' silent! noswapfile pedit!' a: bufname
@@ -525,7 +542,7 @@ function! s:OpenHoverPreview(bufname, lines, filetype) abort
525542
526543 call setline (1 , lines )
527544 " trigger refresh on plasticboy/vim-markdown
528- normal ! i
545+ doautocmd InsertLeave
529546 setlocal nomodified nomodifiable
530547
531548 wincmd p
@@ -1053,7 +1070,7 @@ function! LanguageClient#completionItem_resolve(completion_item, ...) abort
10531070 \ ' completionItem' : a: completion_item ,
10541071 \ ' handle' : s: IsFalse (l: Callback )
10551072 \ }
1056- call extend (l: params , get (a: 000 , 0 , {}))
1073+ call extend (l: params , get (a: 000 , 0 , {})) " extend with pumpos params
10571074 return LanguageClient#Call (' completionItem/resolve' , l: params , l: Callback )
10581075endfunction
10591076
@@ -1281,8 +1298,12 @@ function! LanguageClient#handleCursorMoved() abort
12811298endfunction
12821299
12831300function ! LanguageClient#handleCompleteDone () abort
1301+ " close any hovers that may have been opened for example for completion
1302+ " item documentation.
1303+ call s: ClosePopups ()
1304+
12841305 let user_data = get (v: completed_item , ' user_data' , ' ' )
1285- if user_data == # ' '
1306+ if len ( user_data) == # 0
12861307 return
12871308 endif
12881309
@@ -1643,4 +1664,90 @@ function! LanguageClient#debugInfo(...) abort
16431664 return LanguageClient#Call (' languageClient/debugInfo' , l: params , l: Callback )
16441665endfunction
16451666
1667+ function ! s: ClosePopups (... ) abort
1668+ if s: ShouldUseFloatWindow ()
1669+ call s: CloseFloatingHover ()
1670+ elseif exists (' *popup_clear' ) && s: GetVar (' LanguageClient_usePopupHover' , v: true )
1671+ call popup_clear ()
1672+ else
1673+ :pclose
1674+ endif
1675+ endfunction
1676+
1677+ " receives the v:event from the CompleteChanged autocmd
1678+ function ! LanguageClient#handleCompleteChanged (event ) abort
1679+ " this timer is just to stop textlock from locking our changes
1680+ call timer_start (0 , funcref (' s:ClosePopups' ))
1681+
1682+ if has_key (s: timers , ' LanguageClient#handleCompleteChanged' )
1683+ call timer_stop (s: timers [' LanguageClient#handleCompleteChanged' ])
1684+ endif
1685+
1686+ function ! Debounced (event ) abort
1687+ let l: user_data = get (v: completed_item , ' user_data' , ' ' )
1688+ if len (l: user_data ) == # 0
1689+ return
1690+ endif
1691+
1692+ if type (l: user_data ) == # v: t_string
1693+ let l: user_data = json_decode (l: user_data )
1694+ endif
1695+
1696+ let l: completed_item = {}
1697+
1698+ " LCN completion items
1699+ if has_key (l: user_data , ' lspitem' )
1700+ let l: completed_item = l: user_data [' lspitem' ]
1701+ endif
1702+
1703+ " NCM2 completion items
1704+ if has_key (l: user_data , ' ncm2_lspitem' )
1705+ let l: completed_item = l: user_data [' ncm2_lspitem' ]
1706+ endif
1707+
1708+ if l: completed_item == # {}
1709+ return
1710+ endif
1711+
1712+ if has_key (l: completed_item , ' documentation' )
1713+ call s: ShowCompletionItemDocumentation (l: completed_item [' documentation' ], a: event )
1714+ else
1715+ call LanguageClient#completionItem_resolve (l: completed_item , { ' pumpos' : a: event })
1716+ endif
1717+ endfunction
1718+
1719+ let s: timers [' LanguageClient#handleCompleteChanged' ] = timer_start (100 , { - > Debounced (a: event ) })
1720+ endfunction
1721+
1722+ function ! s: ShowCompletionItemDocumentation (doc, completion_event) abort
1723+ let l: kind = ' text'
1724+
1725+ " some servers send a dictionary with kind and value whereas others just
1726+ " send the value
1727+ if type (a: doc ) is s: TYPE .dict
1728+ let l: lines = split (a: doc [' value' ], " \n " )
1729+ if has_key (a: doc , ' kind' )
1730+ let l: kind = a: doc [' kind' ]
1731+ endif
1732+ else
1733+ let l: lines = split (a: doc , " \n " )
1734+ endif
1735+
1736+ if len (l: lines ) == # 0
1737+ return
1738+ endif
1739+
1740+ for l: line in l: lines
1741+ let l: line = ' ' . l: line . ' '
1742+ endfor
1743+
1744+ let l: pos = a: completion_event
1745+ if exists (' *pum_getpos' )
1746+ " favor pum_getpos output if available
1747+ let l: pos = pum_getpos ()
1748+ endif
1749+ let l: x_pos = l: pos [' width' ] + l: pos [' col' ] + 1
1750+ call s: OpenHoverPreview (' CompletionItemDocumentation' , l: lines , l: kind , l: x_pos , l: pos [' row' ])
1751+ endfunction
1752+
16461753let g: LanguageClient_loaded = s: Launch ()
0 commit comments