Add nvim floating window support (replaces #3314) (#3470)

* Add nvim floating window hover support
* Add configuration for float to replace preview
* preview#ShowFloating: qualify local variables
* Configure floating preview usecases individually

Also:
  * Extract floating preview to its own file.
  * Ignore 'stay_here' option. Moving into the floating preview window
    seems confusing at best.
  * Re-use existing floating preview window if it's still up.
  * Flush out floating preview documentation.

* Watch cursor position changes per window

Floating previews open a new window, so when that window is written to,
it moves briefly there at a different position than the original window.
This makes repeated positions detected when positions are tracked at a
s: level. Instead, we change the variable to window scoped, which only
fires a message if the cursor has changed from the last position in
*that window*.

* g:ale_floating_preview cleanup
* floating_preview: add ALEDetail tests
* Fix fecs test missing runtime call
* Add ALEHover floating preview tests

Co-authored-by: Jan-Grimo Sobez <jan-grimo.sobez@phys.chem.ethz.ch>
This commit is contained in:
Kevin Clark
2021-01-14 10:06:20 -08:00
committed by GitHub
parent 97ce2423b0
commit 39f393ef07
8 changed files with 330 additions and 7 deletions

View File

@@ -9,7 +9,6 @@ let g:ale_echo_delay = get(g:, 'ale_echo_delay', 10)
let g:ale_echo_msg_format = get(g:, 'ale_echo_msg_format', '%code: %%s')
let s:cursor_timer = -1
let s:last_pos = [0, 0, 0]
function! ale#cursor#TruncatedEcho(original_message) abort
let l:message = a:original_message
@@ -118,14 +117,18 @@ function! ale#cursor#EchoCursorWarningWithDelay() abort
let l:pos = getpos('.')[0:2]
if !exists('w:last_pos')
let w:last_pos = [0, 0, 0]
endif
" Check the current buffer, line, and column number against the last
" recorded position. If the position has actually changed, *then*
" we should echo something. Otherwise we can end up doing processing
" the echo message far too frequently.
if l:pos != s:last_pos
if l:pos != w:last_pos
let l:delay = ale#Var(l:buffer, 'echo_delay')
let s:last_pos = l:pos
let w:last_pos = l:pos
let s:cursor_timer = timer_start(
\ l:delay,
\ function('ale#cursor#EchoCursorWarning')
@@ -139,11 +142,16 @@ function! s:ShowCursorDetailForItem(loc, options) abort
let s:last_detailed_line = line('.')
let l:message = get(a:loc, 'detail', a:loc.text)
let l:lines = split(l:message, "\n")
call ale#preview#Show(l:lines, {'stay_here': l:stay_here})
" Clear the echo message if we manually displayed details.
if !l:stay_here
execute 'echo'
if g:ale_floating_preview || g:ale_detail_to_floating_preview
call ale#floating_preview#Show(l:lines)
else
call ale#preview#Show(l:lines, {'stay_here': l:stay_here})
" Clear the echo message if we manually displayed details.
if !l:stay_here
execute 'echo'
endif
endif
endfunction

View File

@@ -0,0 +1,91 @@
" Author: Jan-Grimo Sobez <jan-grimo.sobez@phys.chem.ethz.ch>
" Author: Kevin Clark <kevin.clark@gmail.com>
" Description: Floating preview window for showing whatever information in.
" Precondition: exists('*nvim_open_win')
function! ale#floating_preview#Show(lines, ...) abort
if !exists('*nvim_open_win')
execute 'echom ''Floating windows not supported in this vim instance.'''
return
endif
" Remove the close autocmd so it doesn't happen mid update
augroup ale_floating_preview_window
autocmd!
augroup END
let l:options = get(a:000, 0, {})
" Only create a new window if we need it
if !exists('w:preview') || index(nvim_list_wins(), w:preview['id']) is# -1
call s:Create(l:options)
else
call nvim_buf_set_option(w:preview['buffer'], 'modifiable', v:true)
endif
" Execute commands in window context
let l:parent_window = nvim_get_current_win()
call nvim_set_current_win(w:preview['id'])
for l:command in get(l:options, 'commands', [])
call execute(l:command)
endfor
call nvim_set_current_win(l:parent_window)
" Return to parent context on move
augroup ale_floating_preview_window
autocmd!
if g:ale_close_preview_on_insert
autocmd CursorMoved,TabLeave,WinLeave,InsertEnter <buffer> ++once call s:Close()
else
autocmd CursorMoved,TabLeave,WinLeave <buffer> ++once call s:Close()
endif
augroup END
let l:width = max(map(copy(a:lines), 'strdisplaywidth(v:val)'))
let l:height = min([len(a:lines), 10])
call nvim_win_set_width(w:preview['id'], l:width)
call nvim_win_set_height(w:preview['id'], l:height)
call nvim_buf_set_lines(w:preview['buffer'], 0, -1, v:false, a:lines)
call nvim_buf_set_option(w:preview['buffer'], 'modified', v:false)
call nvim_buf_set_option(w:preview['buffer'], 'modifiable', v:false)
endfunction
function! s:Create(options) abort
let l:buffer = nvim_create_buf(v:false, v:false)
let l:winid = nvim_open_win(l:buffer, v:false, {
\ 'relative': 'cursor',
\ 'row': 1,
\ 'col': 0,
\ 'width': 42,
\ 'height': 4,
\ 'style': 'minimal'
\ })
call nvim_buf_set_option(l:buffer, 'buftype', 'acwrite')
call nvim_buf_set_option(l:buffer, 'bufhidden', 'delete')
call nvim_buf_set_option(l:buffer, 'swapfile', v:false)
call nvim_buf_set_option(l:buffer, 'filetype', get(a:options, 'filetype', 'ale-preview'))
let w:preview = {'id': l:winid, 'buffer': l:buffer}
endfunction
function! s:Close() abort
if !exists('w:preview')
return
endif
call setbufvar(w:preview['buffer'], '&modified', 0)
if win_id2win(w:preview['id']) > 0
execute win_id2win(w:preview['id']).'wincmd c'
endif
unlet w:preview
endfunction

View File

@@ -46,6 +46,10 @@ function! ale#hover#HandleTSServerResponse(conn_id, response) abort
call balloon_show(a:response.body.displayString)
elseif get(l:options, 'truncated_echo', 0)
call ale#cursor#TruncatedEcho(split(a:response.body.displayString, "\n")[0])
elseif g:ale_hover_to_floating_preview || g:ale_floating_preview
call ale#floating_preview#Show(split(a:response.body.displayString, "\n"), {
\ 'filetype': 'ale-preview.message',
\})
elseif g:ale_hover_to_preview
call ale#preview#Show(split(a:response.body.displayString, "\n"), {
\ 'filetype': 'ale-preview.message',
@@ -226,6 +230,11 @@ function! ale#hover#HandleLSPResponse(conn_id, response) abort
call balloon_show(join(l:lines, "\n"))
elseif get(l:options, 'truncated_echo', 0)
call ale#cursor#TruncatedEcho(l:lines[0])
elseif g:ale_hover_to_floating_preview || g:ale_floating_preview
call ale#floating_preview#Show(l:lines, {
\ 'filetype': 'ale-preview.message',
\ 'commands': l:commands,
\})
elseif g:ale_hover_to_preview
call ale#preview#Show(l:lines, {
\ 'filetype': 'ale-preview.message',