Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions autoload/lsp/ui/vim.vim
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
let s:Floatwin = lsp#ui#vim#floatwin#import()
let s:floatwin = s:Floatwin.new({
\ 'close_on': ['InsertEnter', 'CursorMoved']
\ })
let s:last_req_id = 0

function! s:not_supported(what) abort
Expand Down Expand Up @@ -505,17 +509,16 @@ function! s:handle_location(ctx, server, type, data) abort "ctx = {counter, list
else
let l:lines = readfile(fnameescape(l:loc['filename']))
if has_key(l:loc,'viewstart') " showing a locationLink
let l:view = l:lines[l:loc['viewstart'] : l:loc['viewend']]
call lsp#ui#vim#output#preview(a:server, l:view, {
\ 'statusline': ' LSP Peek ' . a:type,
\ 'filetype': &filetype
\ })
else " showing a location
call lsp#ui#vim#output#preview(a:server, l:lines, {
\ 'statusline': ' LSP Peek ' . a:type,
\ 'cursor': { 'line': l:loc['lnum'], 'col': l:loc['col'], 'align': g:lsp_peek_alignment },
\ 'filetype': &filetype
\ })
let l:lines = l:lines[l:loc['viewstart'] : l:loc['viewend']]
endif
let l:screenpos = lsp#ui#vim#floatwin#screenpos(line('.'), col('.'))
if s:floatwin.is_showing()
call s:floatwin.enter()
else
call s:floatwin.show(l:screenpos, lsp#utils#normalize_markup_content({
\ 'language': &filetype,
\ 'value': join(l:lines, "\n")
\ }))
endif
endif
endif
Expand Down
189 changes: 189 additions & 0 deletions autoload/lsp/ui/vim/floatwin.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
let s:floatwin_id = 0

let s:namespace = has('nvim') ? 'nvim' : 'vim'

"
" lsp#ui#vim#floatwin#screenpos
"
function! lsp#ui#vim#floatwin#screenpos(line, col) abort
let l:pos = getpos('.')
let l:scroll_x = (l:pos[2] + l:pos[3]) - wincol()
let l:scroll_y = l:pos[1] - winline()
let l:winpos = win_screenpos(win_getid())
return [l:winpos[0] + (a:line - l:scroll_y) - 1, l:winpos[1] + (a:col - l:scroll_x) - 1]
endfunction

"
" lsp#ui#vim#floatwin#import
"
function! lsp#ui#vim#floatwin#import() abort
return s:Floatwin
endfunction

let s:Floatwin = {}

"
" new
"
function! s:Floatwin.new(option) abort
let s:floatwin_id += 1
let l:bufname = printf('lsp_floatwin-%s.lsp_floatwin', s:floatwin_id)
let l:bufnr = bufnr(l:bufname, v:true)
call setbufvar(l:bufnr, '&buflisted', 0)
call setbufvar(l:bufnr, '&buftype', 'nofile')
call setbufvar(l:bufnr, '&filetype', 'lsp_floatwin')
return extend(deepcopy(s:Floatwin), {
\ 'id': s:floatwin_id,
\ 'bufnr': l:bufnr,
\ 'max_width': get(a:option, 'max_width', g:lsp_preview_max_width),
\ 'max_height': get(a:option, 'max_height', g:lsp_preview_max_height),
\ 'close_on': get(a:option, 'close_on', []),
\ 'screenpos': [0, 0],
\ 'contents': []
\ })
endfunction

"
" show_tooltip
"
function! s:Floatwin.show_tooltip(screenpos, contents) abort
let l:width = self.get_width(a:contents)
let l:height = self.get_height(a:contents)

let l:screenpos = copy(a:screenpos)
let l:screenpos[0] -= 1
let l:screenpos[1] -= 1

" fix height.
if l:screenpos[0] - l:height >= 0
let l:screenpos[0] -= l:height
else
let l:screenpos[0] += 1
endif

" fix width.
if &columns < l:screenpos[1] + l:width
let l:screenpos[1] -= l:screenpos[1] + l:width - &columns
endif

call self.show(l:screenpos, a:contents)
endfunction

"
" show
"
function! s:Floatwin.show(screenpos, contents) abort
let self.screenpos = a:screenpos
let self.contents = a:contents

" create lines.
let l:lines = []
for l:content in a:contents
let l:lines += l:content
endfor

" update bufvars.
call setbufvar(self.bufnr, 'lsp_floatwin_lines', l:lines)

" show or move
call lsp#ui#vim#floatwin#{s:namespace}#show(self)
call setwinvar(self.winid(), '&wrap', 1)
if g:lsp_hover_conceal
call setwinvar(self.winid(), '&conceallevel', 3)
endif

" write lines
call lsp#ui#vim#floatwin#{s:namespace}#write(self, l:lines)

" update syntax highlight.
if has('nvim') && LspFloatwinSyntaxShouldUpdate(self.bufnr)
call lsp#utils#windo(self.winid(), { -> LspFloatwinSyntaxUpdate() })
endif

call self.set_close_events()
endfunction

"
" hide
"
function! s:Floatwin.hide() abort
augroup printf('lsp#ui#vim#floatwin#hide_%s', self.id)
autocmd!
augroup END
call lsp#ui#vim#floatwin#{s:namespace}#hide(self)
endfunction

"
" enter
"
function! s:Floatwin.enter() abort
if g:lsp_preview_doubletap
call lsp#ui#vim#floatwin#{s:namespace}#enter(self)
endif
endfunction

"
" is_showing
"
function! s:Floatwin.is_showing() abort
return lsp#ui#vim#floatwin#{s:namespace}#is_showing(self)
endfunction

"
" winid
"
function! s:Floatwin.winid() abort
return lsp#ui#vim#floatwin#{s:namespace}#winid(self)
endfunction

"
" set_close_events
"
function! s:Floatwin.set_close_events() abort
let l:close_fn = printf('lsp_floatwin_close_%s', self.id)
let b:[l:close_fn] = { -> self.hide() }

if g:lsp_preview_autoclose
augroup printf('lsp#ui#vim#floatwin#hide_%s', self.id)
autocmd!
for l:event in self.close_on
execute printf('autocmd %s <buffer> call b:%s()', l:event, l:close_fn)
endfor
augroup END
endif
endfunction

"
" get_width
"
function! s:Floatwin.get_width(contents) abort
let l:width = 0
for l:content in a:contents
let l:width = max([l:width] + map(copy(l:content), { k, v -> strdisplaywidth(v) }))
endfor

if self.max_width != -1
return max([min([self.max_width, l:width]), 1])
endif
return max([l:width, 1])
endfunction

"
" get_height
"
function! s:Floatwin.get_height(contents) abort
let l:width = self.get_width(a:contents)

let l:height = len(a:contents) - 1
for l:content in a:contents
for l:line in l:content
let l:height += max([1, float2nr(ceil(strdisplaywidth(l:line) / str2float('' . l:width)))])
endfor
endfor

if self.max_height != -1
return max([min([self.max_height, l:height]), 1])
endif
return max([l:height, 1])
endfunction

78 changes: 78 additions & 0 deletions autoload/lsp/ui/vim/floatwin/nvim.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
"
" lsp#ui#vim#floatwin#nvim#show
"
function! lsp#ui#vim#floatwin#nvim#show(floatwin) abort
if lsp#ui#vim#floatwin#nvim#is_showing(a:floatwin)
call nvim_win_set_config(a:floatwin.nvim_window, s:get_config(a:floatwin))
else
let a:floatwin.nvim_window = nvim_open_win(a:floatwin.bufnr, v:false, s:get_config(a:floatwin))
endif
endfunction

"
" lsp#ui#vim#floatwin#nvim#hide
"
function! lsp#ui#vim#floatwin#nvim#hide(floatwin) abort
if lsp#ui#vim#floatwin#nvim#is_showing(a:floatwin)
call nvim_win_close(a:floatwin.nvim_window, v:true)
let a:floatwin.nvim_window = v:null
endif
endfunction

"
" lsp#ui#vim#floatwin#nvim#write
"
function! lsp#ui#vim#floatwin#nvim#write(floatwin, lines) abort
call nvim_buf_set_lines(a:floatwin.bufnr, 0, -1, v:true, a:lines)
endfunction

"
" lsp#ui#vim#floatwin#nvim#enter
"
function! lsp#ui#vim#floatwin#nvim#enter(floatwin) abort
if lsp#ui#vim#floatwin#nvim#is_showing(a:floatwin)
execute printf('%swincmd w', win_id2win(lsp#ui#vim#floatwin#nvim#winid(a:floatwin)))
endif
endfunction

"
" lsp#ui#vim#floatwin#nvim#is_showing
"
function! lsp#ui#vim#floatwin#nvim#is_showing(floatwin) abort
if !has_key(a:floatwin,'nvim_window') || a:floatwin.nvim_window is v:null
return v:false
endif

try
return nvim_win_get_number(a:floatwin.nvim_window) != -1
catch /.*/
let a:floatwin.nvim_window = v:null
endtry
return v:false
endfunction

"
" lsp#ui#vim#floatwin#nvim#winid
"
function! lsp#ui#vim#floatwin#nvim#winid(floatwin) abort
if lsp#ui#vim#floatwin#nvim#is_showing(a:floatwin)
return win_getid(nvim_win_get_number(a:floatwin.nvim_window))
endif
return -1
endfunction

"
" s:get_config
"
function! s:get_config(floatwin) abort
return {
\ 'relative': 'editor',
\ 'width': a:floatwin.get_width(a:floatwin.contents),
\ 'height': a:floatwin.get_height(a:floatwin.contents),
\ 'row': a:floatwin.screenpos[0],
\ 'col': a:floatwin.screenpos[1],
\ 'focusable': v:true,
\ 'style': 'minimal'
\ }
endfunction

83 changes: 83 additions & 0 deletions autoload/lsp/ui/vim/floatwin/vim.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
"
" lsp#ui#vim#floatwin#vim#show
"
function! lsp#ui#vim#floatwin#vim#show(floatwin) abort
if lsp#ui#vim#floatwin#vim#is_showing(a:floatwin)
call popup_move(a:floatwin.vim_winid, s:get_config(a:floatwin))
else
let a:floatwin.vim_winid = popup_create(a:floatwin.bufnr, s:get_config(a:floatwin))
endif
endfunction

"
" lsp#ui#vim#floatwin#vim#hide
"
function! lsp#ui#vim#floatwin#vim#hide(floatwin) abort
try
call popup_hide(a:floatwin.vim_winid)
catch /.*/
endtry
let a:floatwin.vim_winid = v:null
endfunction

"
" lsp#ui#vim#floatwin#vim#write
"
function! lsp#ui#vim#floatwin#vim#write(floatwin, lines) abort
call deletebufline(a:floatwin.bufnr, '^', '$')
for l:line in reverse(a:lines)
call appendbufline(a:floatwin.bufnr, 0, l:line)
endfor
call deletebufline(a:floatwin.bufnr, '$')
endfunction

"
" lsp#ui#vim#floatwin#vim#enter
"
function! lsp#ui#vim#floatwin#vim#enter(floatwin) abort
" noop
endfunction

"
" lsp#ui#vim#floatwin#vim#is_showing
"
function! lsp#ui#vim#floatwin#vim#is_showing(floatwin) abort
if !has_key(a:floatwin, 'vim_winid') || a:floatwin.vim_winid is v:null
return v:false
endif

if win_id2win(a:floatwin.vim_winid) == -1
let a:floatwin.vim_winid = v:null
return v:false
endif
return v:true
endfunction

"
" lsp#ui#vim#floatwin#vim#winid
"
function! lsp#ui#vim#floatwin#vim#winid(floatwin) abort
if lsp#ui#vim#floatwin#vim#is_showing(a:floatwin)
return a:floatwin.vim_winid
endif
return -1
endfunction

"
" s:get_config
"
function! s:get_config(floatwin) abort
return {
\ 'line': a:floatwin.screenpos[0] + 1,
\ 'col': a:floatwin.screenpos[1] + 1,
\ 'pos': 'topleft',
\ 'moved': [0, 100000],
\ 'scrollbar': 0,
\ 'maxwidth': a:floatwin.get_width(a:floatwin.contents),
\ 'maxheight': a:floatwin.get_height(a:floatwin.contents),
\ 'minwidth': a:floatwin.get_width(a:floatwin.contents),
\ 'minheight': a:floatwin.get_height(a:floatwin.contents),
\ 'tabpage': 0
\ }
endfunction

Loading