mirror of
https://github.com/prabirshrestha/vim-lsp.git
synced 2026-09-28 17:12:29 +02:00
Current event handling seems somewhat confusing. It is good to document the intent, in order to be able to asses if the code is doing what is intended. Co-authored-by: mattn <mattn.jp@gmail.com>
149 lines
5.5 KiB
VimL
149 lines
5.5 KiB
VimL
" internal state for whether it is enabled or not to avoid multiple subscriptions
|
|
let s:enabled = 0
|
|
|
|
let s:Markdown = vital#lsp#import('VS.Vim.Syntax.Markdown')
|
|
let s:MarkupContent = vital#lsp#import('VS.LSP.MarkupContent')
|
|
let s:FloatingWindow = vital#lsp#import('VS.Vim.Window.FloatingWindow')
|
|
let s:Window = vital#lsp#import('VS.Vim.Window')
|
|
let s:Buffer = vital#lsp#import('VS.Vim.Buffer')
|
|
|
|
function! lsp#internal#diagnostics#float#_enable() abort
|
|
" don't even bother registering if the feature is disabled
|
|
if !lsp#ui#vim#output#float_supported() | return | endif
|
|
if !g:lsp_diagnostics_float_cursor | return | endif
|
|
|
|
if s:enabled | return | endif
|
|
let s:enabled = 1
|
|
|
|
" CursorMoved - Movement in normal or insert mode is expected to hide the
|
|
" float and, potentially, show it later after a delay of
|
|
" 'g:lsp_diagnostics_float_delay'. So we always call 'hide_float()' for
|
|
" this event, and may call 'show_float()' later.
|
|
"
|
|
" CursorHold - If the cursor did not move long enough in the normal mode, we
|
|
" want to hide the float. So we want to call 'hide_float()'. Because of
|
|
" the 'curpos' check, 'show_float()' is not going to be called, but we could
|
|
" be more explicit and just not call it at all.
|
|
"
|
|
" InsertEnter - If insert mode is entered and we do not show floats in the
|
|
" insert mode (g:lsp_diagnostics_float_insert_mode_enabled) we want to hide
|
|
" the cursor. Similar to |CursorHold| we do not show the float due to the
|
|
" "mode() is# 'n'" check, but it seems more like an accident than the
|
|
" intended action.
|
|
let s:Dispose = lsp#callbag#pipe(
|
|
\ lsp#callbag#merge(
|
|
\ lsp#callbag#fromEvent(['CursorMoved']),
|
|
\ lsp#callbag#pipe(
|
|
\ lsp#callbag#fromEvent(['InsertEnter']),
|
|
\ lsp#callbag#filter({_->!g:lsp_diagnostics_float_insert_mode_enabled}),
|
|
\ lsp#callbag#tap({_->s:hide_float()}),
|
|
\ )
|
|
\ ),
|
|
\ lsp#callbag#filter({_->g:lsp_diagnostics_float_cursor}),
|
|
\ lsp#callbag#tap({_->s:hide_float()}),
|
|
\ lsp#callbag#map({_->{
|
|
\ 'bufnr': bufnr('%'),
|
|
\ 'curpos': getcurpos()[0:2],
|
|
\ 'changedtick': b:changedtick
|
|
\ }}),
|
|
\ lsp#callbag#debounceTime(g:lsp_diagnostics_float_delay),
|
|
\ lsp#callbag#distinctUntilChanged({a,b ->
|
|
\ a['bufnr'] == b['bufnr']
|
|
\ && a['curpos'] == b['curpos']
|
|
\ && a['changedtick'] == b['changedtick']
|
|
\ }),
|
|
\ lsp#callbag#filter({_->mode() is# 'n'}),
|
|
\ lsp#callbag#filter({_->getbufvar(bufnr('%'), '&buftype') !=# 'terminal' }),
|
|
\ lsp#callbag#map({_->lsp#internal#diagnostics#under_cursor#get_diagnostic()}),
|
|
\ lsp#callbag#subscribe({x->s:show_float(x)}),
|
|
\ )
|
|
endfunction
|
|
|
|
function! lsp#internal#diagnostics#float#_disable() abort
|
|
if !s:enabled | return | endif
|
|
if exists('s:Dispose')
|
|
call s:Dispose()
|
|
unlet s:Dispose
|
|
endif
|
|
let s:enabled = 0
|
|
endfunction
|
|
|
|
function! s:show_float(diagnostic) abort
|
|
let l:doc_win = s:get_doc_win()
|
|
if !empty(a:diagnostic) && has_key(a:diagnostic, 'message')
|
|
" Update contents.
|
|
call deletebufline(l:doc_win.get_bufnr(), 1, '$')
|
|
call setbufline(l:doc_win.get_bufnr(), 1, lsp#utils#_split_by_eol(a:diagnostic['message']))
|
|
|
|
" Compute size.
|
|
if g:lsp_float_max_width >= 1
|
|
let l:maxwidth = g:lsp_float_max_width
|
|
elseif g:lsp_float_max_width == 0
|
|
let l:maxwidth = &columns
|
|
else
|
|
let l:maxwidth = float2nr(&columns * 0.4)
|
|
endif
|
|
let l:size = l:doc_win.get_size({
|
|
\ 'maxwidth': l:maxwidth,
|
|
\ 'maxheight': float2nr(&lines * 0.4),
|
|
\ })
|
|
|
|
" Compute position.
|
|
let l:pos = s:compute_position(l:size)
|
|
|
|
" Open window.
|
|
call l:doc_win.open({
|
|
\ 'row': l:pos[0],
|
|
\ 'col': l:pos[1],
|
|
\ 'width': l:size.width,
|
|
\ 'height': l:size.height,
|
|
\ 'border': v:true,
|
|
\ 'topline': 1,
|
|
\ })
|
|
else
|
|
call s:hide_float()
|
|
endif
|
|
endfunction
|
|
|
|
function! s:hide_float() abort
|
|
let l:doc_win = s:get_doc_win()
|
|
call l:doc_win.close()
|
|
endfunction
|
|
|
|
function! s:get_doc_win() abort
|
|
if exists('s:doc_win')
|
|
return s:doc_win
|
|
endif
|
|
|
|
let s:doc_win = s:FloatingWindow.new({
|
|
\ 'on_opened': { -> execute('doautocmd <nomodeline> User lsp_float_opened') },
|
|
\ 'on_closed': { -> execute('doautocmd <nomodeline> User lsp_float_closed') }
|
|
\ })
|
|
call s:doc_win.set_var('&wrap', 1)
|
|
call s:doc_win.set_var('&conceallevel', 2)
|
|
noautocmd silent let l:bufnr = s:Buffer.create()
|
|
call s:doc_win.set_bufnr(l:bufnr)
|
|
call setbufvar(s:doc_win.get_bufnr(), '&buftype', 'nofile')
|
|
call setbufvar(s:doc_win.get_bufnr(), '&bufhidden', 'hide')
|
|
call setbufvar(s:doc_win.get_bufnr(), '&buflisted', 0)
|
|
call setbufvar(s:doc_win.get_bufnr(), '&swapfile', 0)
|
|
call setbufvar(s:doc_win.get_bufnr(), '&modifiable', 1)
|
|
call setbufvar(s:doc_win.get_bufnr(), '&readonly', 0)
|
|
return s:doc_win
|
|
endfunction
|
|
|
|
function! s:compute_position(size) abort
|
|
let l:pos = screenpos(0, line('.'), col('.'))
|
|
if l:pos.row == 0 && l:pos.col == 0
|
|
let l:pos = {'curscol': screencol(), 'row': screenrow()}
|
|
endif
|
|
let l:pos = [l:pos.row + 1, l:pos.curscol + 1]
|
|
if l:pos[0] + a:size.height > &lines
|
|
let l:pos[0] = l:pos[0] - a:size.height - 3
|
|
endif
|
|
if l:pos[1] + a:size.width > &columns
|
|
let l:pos[1] = l:pos[1] - a:size.width - 3
|
|
endif
|
|
return l:pos
|
|
endfunction
|