]> git.madduck.net Git - etc/vim.git/blob - autoload/lsp/internal/diagnostics/float.vim

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Squashed '.vim/bundle/vim-lsp/' content from commit 04428c92
[etc/vim.git] / autoload / lsp / internal / diagnostics / float.vim
1 " internal state for whether it is enabled or not to avoid multiple subscriptions
2 let s:enabled = 0
3
4 let s:Markdown = vital#lsp#import('VS.Vim.Syntax.Markdown')
5 let s:MarkupContent = vital#lsp#import('VS.LSP.MarkupContent')
6 let s:FloatingWindow = vital#lsp#import('VS.Vim.Window.FloatingWindow')
7 let s:Window = vital#lsp#import('VS.Vim.Window')
8 let s:Buffer = vital#lsp#import('VS.Vim.Buffer')
9
10 function! lsp#internal#diagnostics#float#_enable() abort
11     " don't even bother registering if the feature is disabled
12     if !lsp#ui#vim#output#float_supported() | return | endif
13     if !g:lsp_diagnostics_float_cursor | return | endif 
14
15     if s:enabled | return | endif
16     let s:enabled = 1
17
18     let s:Dispose = lsp#callbag#pipe(
19         \ lsp#callbag#merge(
20         \   lsp#callbag#fromEvent(['CursorMoved', 'CursorHold']),
21         \   lsp#callbag#pipe(
22         \       lsp#callbag#fromEvent(['InsertEnter']),
23         \       lsp#callbag#filter({_->!g:lsp_diagnostics_float_insert_mode_enabled}),
24         \       lsp#callbag#tap({_->s:hide_float()}),
25         \   )
26         \ ),
27         \ lsp#callbag#filter({_->g:lsp_diagnostics_float_cursor}),
28         \ lsp#callbag#tap({_->s:hide_float()}),
29         \ lsp#callbag#debounceTime(g:lsp_diagnostics_float_delay),
30         \ lsp#callbag#map({_->{'bufnr': bufnr('%'), 'curpos': getcurpos()[0:2], 'changedtick': b:changedtick }}),
31         \ lsp#callbag#distinctUntilChanged({a,b -> a['bufnr'] == b['bufnr'] && a['curpos'] == b['curpos'] && a['changedtick'] == b['changedtick']}),
32         \ lsp#callbag#filter({_->mode() is# 'n'}),
33         \ lsp#callbag#filter({_->getbufvar(bufnr('%'), '&buftype') !=# 'terminal' }),
34         \ lsp#callbag#map({_->lsp#internal#diagnostics#under_cursor#get_diagnostic()}),
35         \ lsp#callbag#subscribe({x->s:show_float(x)}),
36         \ )
37 endfunction
38
39 function! lsp#internal#diagnostics#float#_disable() abort
40     if !s:enabled | return | endif
41     if exists('s:Dispose')
42         call s:Dispose()
43         unlet s:Dispose
44     endif
45     let s:enabled = 0
46 endfunction
47
48 function! s:show_float(diagnostic) abort
49     let l:doc_win = s:get_doc_win()
50     if !empty(a:diagnostic) && has_key(a:diagnostic, 'message')
51         " Update contents. 
52         call deletebufline(l:doc_win.get_bufnr(), 1, '$')
53         call setbufline(l:doc_win.get_bufnr(), 1, lsp#utils#_split_by_eol(a:diagnostic['message']))
54
55         " Compute size. 
56         if g:lsp_float_max_width >= 1
57             let l:maxwidth = g:lsp_float_max_width
58         elseif g:lsp_float_max_width == 0
59             let l:maxwidth = &columns
60         else
61             let l:maxwidth = float2nr(&columns * 0.4)
62         endif
63         let l:size = l:doc_win.get_size({
64         \   'maxwidth': l:maxwidth,
65         \   'maxheight': float2nr(&lines * 0.4),
66         \ })
67
68         " Compute position.
69         let l:pos = s:compute_position(l:size)
70
71         " Open window. 
72         call l:doc_win.open({
73         \   'row': l:pos[0],
74         \   'col': l:pos[1],
75         \   'width': l:size.width,
76         \   'height': l:size.height,
77         \   'border': v:true,
78         \   'topline': 1,
79         \ })
80     else
81         call s:hide_float()
82     endif
83 endfunction
84
85 function! s:hide_float() abort
86     let l:doc_win = s:get_doc_win()
87     call l:doc_win.close()
88 endfunction
89
90 function! s:get_doc_win() abort
91     if exists('s:doc_win')
92         return s:doc_win
93     endif
94
95     let s:doc_win = s:FloatingWindow.new({
96     \   'on_opened': { -> execute('doautocmd <nomodeline> User lsp_float_opened') },
97     \   'on_closed': { -> execute('doautocmd <nomodeline> User lsp_float_closed') }
98     \ })
99     call s:doc_win.set_var('&wrap', 1)
100     call s:doc_win.set_var('&conceallevel', 2)
101     noautocmd silent let l:bufnr = s:Buffer.create()
102     call s:doc_win.set_bufnr(l:bufnr)
103     call setbufvar(s:doc_win.get_bufnr(), '&buftype', 'nofile')
104     call setbufvar(s:doc_win.get_bufnr(), '&bufhidden', 'hide')
105     call setbufvar(s:doc_win.get_bufnr(), '&buflisted', 0)
106     call setbufvar(s:doc_win.get_bufnr(), '&swapfile', 0)
107     return s:doc_win
108 endfunction
109
110 function! s:compute_position(size) abort
111     let l:pos = screenpos(0, line('.'), col('.'))
112     if l:pos.row == 0 && l:pos.col == 0
113         let l:pos = {'curscol': screencol(), 'row': screenrow()}
114     endif
115     let l:pos = [l:pos.row + 1, l:pos.curscol + 1]
116     if l:pos[0] + a:size.height > &lines
117         let l:pos[0] = l:pos[0] - a:size.height - 3
118     endif
119     if l:pos[1] + a:size.width > &columns
120         let l:pos[1] = l:pos[1] - a:size.width - 3
121     endif
122     return l:pos
123 endfunction