Skip to content

Commit 572f84a

Browse files
committed
Reimplement hover window with floating window for Neovim 0.4.0 or later
1 parent 54c79a8 commit 572f84a

File tree

2 files changed

+104
-20
lines changed

2 files changed

+104
-20
lines changed

Diff for: autoload/LanguageClient.vim

+99
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ let s:TYPE = {
88
\ 'dict': type({}),
99
\ 'funcref': type(function('call'))
1010
\ }
11+
let s:FLOAT_WINDOW_AVAILABLE = has('nvim') && exists('*nvim_open_win')
1112

1213
function! s:AddPrefix(message) abort
1314
return '[LC] ' . a:message
@@ -261,6 +262,104 @@ function! s:GetVar(...) abort
261262
endif
262263
endfunction
263264

265+
function! s:CloseFloatingHover(bufname, opened) abort
266+
if getpos('.') == a:opened
267+
" Just after opening floating window, CursorMoved event is run.
268+
" To avoid closing floating window immediately, check the cursor
269+
" was really moved
270+
return
271+
endif
272+
autocmd! plugin-LC-neovim-close-hover
273+
let bufnr = bufnr(a:bufname)
274+
if bufnr == -1
275+
return
276+
endif
277+
let winnr = bufwinnr(bufnr)
278+
if winnr == -1
279+
return
280+
endif
281+
execute winnr . 'wincmd c'
282+
endfunction
283+
284+
" Open preview window. Window is open in:
285+
" - Floating window on Neovim (0.4.0 or later)
286+
" - Preview window on Neovim (0.3.0 or earlier) or Vim
287+
function! s:OpenHoverPreview(bufname, lines, filetype) abort
288+
" Use local variable since parameter is not modifiable
289+
let lines = a:lines
290+
291+
if s:FLOAT_WINDOW_AVAILABLE
292+
let pos = getpos('.')
293+
294+
" Unlike preview window, :pclose does not close window. Instead, close
295+
" hover window automatically when cursor is moved.
296+
let params = printf('"%s", %s', a:bufname, string(pos))
297+
augroup plugin-LC-neovim-close-hover
298+
execute 'autocmd CursorMoved,CursorMovedI,InsertEnter <buffer> call <SID>CloseFloatingHover(' . params . ')'
299+
augroup END
300+
301+
" Calculate width and height and give margin to lines
302+
let width = 0
303+
for index in range(len(lines))
304+
let line = ' ' . lines[index]
305+
let lw = strdisplaywidth(line)
306+
if lw > width
307+
let width = lw
308+
endif
309+
let lines[index] = line
310+
endfor
311+
312+
" Give margin
313+
let width += 1
314+
let lines = [''] + lines + ['']
315+
let height = len(lines)
316+
317+
" Calculate anchor
318+
" Prefer North, but if there is no space, fallback into South
319+
if pos[1] + height <= &lines
320+
let vert = 'N'
321+
let row = 1
322+
else
323+
let vert = 'S'
324+
let row = 0
325+
endif
326+
327+
" Prefer West, but if there is no space, fallback into East
328+
if pos[2] + width <= &columns
329+
let hor = 'W'
330+
let col = 0
331+
else
332+
let hor = 'E'
333+
let col = 1
334+
endif
335+
336+
call nvim_open_win(bufnr('%'), v:true, width, height, {
337+
\ 'relative': 'cursor',
338+
\ 'anchor': vert . hor,
339+
\ 'row': row,
340+
\ 'col': col,
341+
\ })
342+
343+
execute 'noswapfile edit!' a:bufname
344+
345+
setlocal winhl=Normal:CursorLine
346+
else
347+
execute 'silent! noswapfile pedit!' a:bufname
348+
wincmd P
349+
endif
350+
351+
setlocal buftype=nofile nobuflisted bufhidden=wipe nonumber norelativenumber signcolumn=no
352+
353+
if a:filetype isnot v:null
354+
let &filetype = a:filetype
355+
endif
356+
357+
call setline(1, lines)
358+
setlocal nomodified nomodifiable
359+
360+
wincmd p
361+
endfunction
362+
264363
let s:id = 1
265364
let s:handlers = {}
266365

Diff for: src/language_server_protocol.rs

+5-20
Original file line numberDiff line numberDiff line change
@@ -860,27 +860,12 @@ impl LanguageClient {
860860
D: ToDisplay + ?Sized,
861861
{
862862
let bufname = "__LanguageClient__";
863-
864-
let cmd = "silent! pedit! +setlocal\\ buftype=nofile\\ nobuflisted\\ noswapfile\\ nonumber";
865-
let cmd = if let Some(ref ft) = to_display.vim_filetype() {
866-
format!("{}\\ filetype={} {}", cmd, ft, bufname)
867-
} else {
868-
format!("{} {}", cmd, bufname)
869-
};
870-
self.vim()?.command(cmd)?;
871-
863+
let filetype = &to_display.vim_filetype();
872864
let lines = to_display.to_display();
873-
if self.get(|state| state.is_nvim)? {
874-
let bufnr: u64 = serde_json::from_value(self.vim()?.rpcclient.call("bufnr", bufname)?)?;
875-
self.vim()?
876-
.rpcclient
877-
.notify("nvim_buf_set_lines", json!([bufnr, 0, -1, 0, lines]))?;
878-
} else {
879-
self.vim()?
880-
.rpcclient
881-
.notify("setbufline", json!([bufname, 1, lines]))?;
882-
// TODO: removing existing bottom lines.
883-
}
865+
866+
self.vim()?
867+
.rpcclient
868+
.notify("s:OpenHoverPreview", json!([bufname, lines, filetype]))?;
884869

885870
Ok(())
886871
}

0 commit comments

Comments
 (0)