231 lines
7.2 KiB
VimL
231 lines
7.2 KiB
VimL
" Author: Jan-Grimo Sobez <jan-grimo.sobez@phys.chem.ethz.ch>
|
|
" Author: Kevin Clark <kevin.clark@gmail.com>
|
|
" Author: D. Ben Knoble <ben.knoble+github@gmail.com>
|
|
" Author: Shaun Duncan <shaun.duncan@gmail.com>
|
|
" Description: Floating preview window for showing whatever information in.
|
|
|
|
" Precondition: exists('*nvim_open_win') || has('popupwin')
|
|
|
|
function! ale#floating_preview#Show(lines, ...) abort
|
|
if !exists('*nvim_open_win') && !has('popupwin')
|
|
" no-custom-checks
|
|
echom 'Floating windows not supported in this vim instance.'
|
|
|
|
return
|
|
endif
|
|
|
|
let l:options = get(a:000, 0, {})
|
|
|
|
if has('nvim')
|
|
call s:NvimShow(a:lines, l:options)
|
|
else
|
|
call s:VimShow(a:lines, l:options)
|
|
endif
|
|
endfunction
|
|
|
|
function! s:NvimShow(lines, options) abort
|
|
" Remove the close autocmd so it doesn't happen mid update
|
|
augroup ale_floating_preview_window
|
|
autocmd!
|
|
augroup END
|
|
|
|
" Only create a new window if we need it
|
|
if !exists('w:preview') || index(nvim_list_wins(), w:preview['id']) is# -1
|
|
call s:NvimCreate(a: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(a: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:NvimClose()
|
|
else
|
|
autocmd CursorMoved,TabLeave,WinLeave <buffer> ++once call s:NvimClose()
|
|
endif
|
|
augroup END
|
|
|
|
let [l:lines, l:width, l:height] = s:NvimPrepareWindowContent(a:lines)
|
|
|
|
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, l: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:VimShow(lines, options) abort
|
|
if g:ale_close_preview_on_insert
|
|
" Remove the close autocmd so it doesn't happen mid update
|
|
silent! autocmd! ale_floating_preview_window
|
|
endif
|
|
|
|
" Only create a new window if we need it
|
|
if !exists('w:preview') || index(popup_list(), w:preview['id']) is# -1
|
|
call s:VimCreate(a:options)
|
|
endif
|
|
|
|
" Execute commands in window context
|
|
for l:command in get(a:options, 'commands', [])
|
|
call win_execute(w:preview['id'], l:command)
|
|
endfor
|
|
|
|
call popup_settext(w:preview['id'], a:lines)
|
|
|
|
if g:ale_close_preview_on_insert
|
|
augroup ale_floating_preview_window
|
|
autocmd!
|
|
autocmd InsertEnter * ++once call s:VimClose()
|
|
augroup END
|
|
endif
|
|
endfunction
|
|
|
|
function! s:NvimPrepareWindowContent(lines) abort
|
|
let l:max_height = 10
|
|
|
|
let l:width = max(map(copy(a:lines), 'strdisplaywidth(v:val)'))
|
|
let l:height = min([len(a:lines), l:max_height])
|
|
|
|
if empty(g:ale_floating_window_border)
|
|
return [a:lines, l:width, l:height]
|
|
endif
|
|
|
|
" Add the size of borders
|
|
let l:width += 2
|
|
let l:height += 2
|
|
|
|
let l:left = get(g:ale_floating_window_border, 0, '|')
|
|
let l:top = get(g:ale_floating_window_border, 1, '-')
|
|
let l:top_left = get(g:ale_floating_window_border, 2, '+')
|
|
let l:top_right = get(g:ale_floating_window_border, 3, '+')
|
|
let l:bottom_right = get(g:ale_floating_window_border, 4, '+')
|
|
let l:bottom_left = get(g:ale_floating_window_border, 5, '+')
|
|
let l:right = get(g:ale_floating_window_border, 6, l:left)
|
|
let l:bottom = get(g:ale_floating_window_border, 7, l:top)
|
|
|
|
let l:lines = [l:top_left . repeat(l:top, l:width - 2) . l:top_right]
|
|
|
|
for l:line in a:lines
|
|
let l:line_width = strchars(l:line)
|
|
let l:lines = add(l:lines, l:left . l:line . repeat(' ', l:width - l:line_width - 2). l:right)
|
|
endfor
|
|
|
|
" Truncate the lines
|
|
if len(l:lines) > l:max_height + 1
|
|
let l:lines = l:lines[0:l:max_height]
|
|
endif
|
|
|
|
let l:lines = add(l:lines, l:bottom_left . repeat(l:bottom, l:width - 2) . l:bottom_right)
|
|
|
|
return [l:lines, l:width, l:height]
|
|
endfunction
|
|
|
|
function! s:NvimCreate(options) abort
|
|
let l:popup_opts = extend({
|
|
\ 'relative': 'cursor',
|
|
\ 'row': 1,
|
|
\ 'col': 0,
|
|
\ 'width': 42,
|
|
\ 'height': 4,
|
|
\ 'style': 'minimal'
|
|
\ }, s:GetPopupOpts())
|
|
|
|
let l:buffer = nvim_create_buf(v:false, v:false)
|
|
let l:winid = nvim_open_win(l:buffer, v:false, l:popup_opts)
|
|
|
|
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:VimCreate(options) abort
|
|
" default options
|
|
let l:popup_opts = extend({
|
|
\ 'line': 'cursor+1',
|
|
\ 'col': 'cursor',
|
|
\ 'drag': v:true,
|
|
\ 'resize': v:true,
|
|
\ 'close': 'button',
|
|
\ 'padding': [0, 1, 0, 1],
|
|
\ 'border': [],
|
|
\ 'borderchars': empty(g:ale_floating_window_border) ? [' '] : [
|
|
\ get(g:ale_floating_window_border, 1, '-'),
|
|
\ get(g:ale_floating_window_border, 6, '|'),
|
|
\ get(g:ale_floating_window_border, 7, '-'),
|
|
\ get(g:ale_floating_window_border, 0, '|'),
|
|
\ get(g:ale_floating_window_border, 2, '+'),
|
|
\ get(g:ale_floating_window_border, 3, '+'),
|
|
\ get(g:ale_floating_window_border, 4, '+'),
|
|
\ get(g:ale_floating_window_border, 5, '+'),
|
|
\ ],
|
|
\ 'moved': 'any',
|
|
\ }, s:GetPopupOpts())
|
|
|
|
let l:popup_id = popup_create([], l:popup_opts)
|
|
call setbufvar(winbufnr(l:popup_id), '&filetype', get(a:options, 'filetype', 'ale-preview'))
|
|
let w:preview = {'id': l:popup_id}
|
|
endfunction
|
|
|
|
function! s:NvimClose() abort
|
|
let l:mode = mode()
|
|
let l:restore_visual = l:mode is# 'v' || l:mode is# 'V' || l:mode is# "\<C-V>"
|
|
|
|
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
|
|
|
|
if l:restore_visual
|
|
normal! gv
|
|
endif
|
|
endfunction
|
|
|
|
function! s:VimClose() abort
|
|
if !exists('w:preview')
|
|
return
|
|
endif
|
|
|
|
call popup_close(w:preview['id'])
|
|
unlet w:preview
|
|
endfunction
|
|
|
|
" get either the results of a function callback or dictionary for popup overrides
|
|
function! s:GetPopupOpts() abort
|
|
if exists('g:ale_floating_preview_popup_opts')
|
|
let l:ref = g:ale_floating_preview_popup_opts
|
|
|
|
if type(l:ref) is# v:t_dict
|
|
return l:ref
|
|
elseif type(l:ref) is# v:t_string
|
|
try
|
|
return function(l:ref)()
|
|
catch /E700/
|
|
endtry
|
|
endif
|
|
endif
|
|
|
|
return {}
|
|
endfunction
|