Skip to content

Commit 5a93f51

Browse files
committed
Introduce floatwin/popupwin compatible layer
1 parent 45d5bff commit 5a93f51

File tree

10 files changed

+636
-71
lines changed

10 files changed

+636
-71
lines changed

autoload/lsp/ui/vim.vim

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
let s:Floatwin = lsp#ui#vim#floatwin#import()
2+
let s:floatwin = s:Floatwin.new({
3+
\ 'close_on': ['InsertEnter', 'CursorMoved']
4+
\ })
15
let s:last_req_id = 0
26

37
function! s:not_supported(what) abort
@@ -506,16 +510,17 @@ function! s:handle_location(ctx, server, type, data) abort "ctx = {counter, list
506510
let l:lines = readfile(fnameescape(l:loc['filename']))
507511
if has_key(l:loc,'viewstart') " showing a locationLink
508512
let l:view = l:lines[l:loc['viewstart'] : l:loc['viewend']]
509-
call lsp#ui#vim#output#preview(a:server, l:view, {
510-
\ 'statusline': ' LSP Peek ' . a:type,
511-
\ 'filetype': &filetype
512-
\ })
513+
let l:screenpos = lsp#ui#vim#floatwin#screenpos(line('.'), col('.'))
514+
call s:floatwin.show(l:screenpos, lsp#utils#normalize_markup_content({
515+
\ 'language': &filetype,
516+
\ 'value': join(l:view, "\n")
517+
\ }))
513518
else " showing a location
514-
call lsp#ui#vim#output#preview(a:server, l:lines, {
515-
\ 'statusline': ' LSP Peek ' . a:type,
516-
\ 'cursor': { 'line': l:loc['lnum'], 'col': l:loc['col'], 'align': g:lsp_peek_alignment },
517-
\ 'filetype': &filetype
518-
\ })
519+
let l:screenpos = lsp#ui#vim#floatwin#screenpos(line('.'), col('.'))
520+
call s:floatwin.show(l:screenpos, lsp#utils#normalize_markup_content({
521+
\ 'language': &filetype,
522+
\ 'value': join(l:lines, "\n")
523+
\ }))
519524
endif
520525
endif
521526
endif

autoload/lsp/ui/vim/floatwin.vim

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
let s:floatwin_id = 0
2+
3+
let s:namespace = has('nvim') ? 'nvim' : 'vim'
4+
5+
"
6+
" lsp#ui#vim#floatwin#screenpos
7+
"
8+
function! lsp#ui#vim#floatwin#screenpos(line, col) abort
9+
let l:pos = getpos('.')
10+
let l:scroll_x = (l:pos[2] + l:pos[3]) - wincol()
11+
let l:scroll_y = l:pos[1] - winline()
12+
let l:winpos = win_screenpos(win_getid())
13+
return [l:winpos[0] + (a:line - l:scroll_y) - 1, l:winpos[1] + (a:col - l:scroll_x) - 1]
14+
endfunction
15+
16+
"
17+
" lsp#ui#vim#floatwin#import
18+
"
19+
function! lsp#ui#vim#floatwin#import() abort
20+
return s:Floatwin
21+
endfunction
22+
23+
let s:Floatwin = {}
24+
25+
"
26+
" new
27+
"
28+
function! s:Floatwin.new(option) abort
29+
let s:floatwin_id += 1
30+
let l:bufname = printf('lsp_floatwin-%s.lsp_floatwin', s:floatwin_id)
31+
let l:bufnr = bufnr(l:bufname, v:true)
32+
call setbufvar(l:bufnr, '&buflisted', 0)
33+
call setbufvar(l:bufnr, '&buftype', 'nofile')
34+
call setbufvar(l:bufnr, '&filetype', 'lsp_floatwin')
35+
return extend(deepcopy(s:Floatwin), {
36+
\ 'id': s:floatwin_id,
37+
\ 'bufnr': l:bufnr,
38+
\ 'max_width': get(a:option, 'max_width', &columns / 3),
39+
\ 'max_height': get(a:option, 'max_height', &lines / 2),
40+
\ 'close_on': get(a:option, 'close_on', []),
41+
\ 'screenpos': [0, 0],
42+
\ 'contents': []
43+
\ })
44+
endfunction
45+
46+
"
47+
" show_tooltip
48+
"
49+
function! s:Floatwin.show_tooltip(screenpos, contents) abort
50+
let l:width = self.get_width(a:contents)
51+
let l:height = self.get_height(a:contents)
52+
53+
let l:screenpos = copy(a:screenpos)
54+
let l:screenpos[0] -= 1
55+
let l:screenpos[1] -= 1
56+
57+
" fix height.
58+
if l:screenpos[0] - l:height >= 0
59+
let l:screenpos[0] -= l:height
60+
else
61+
let l:screenpos[0] += 1
62+
endif
63+
64+
" fix width.
65+
if &columns < l:screenpos[1] + l:width
66+
let l:screenpos[1] -= l:screenpos[1] + l:width - &columns
67+
endif
68+
69+
call self.show(l:screenpos, a:contents)
70+
endfunction
71+
72+
"
73+
" show
74+
"
75+
function! s:Floatwin.show(screenpos, contents) abort
76+
let self.screenpos = a:screenpos
77+
let self.contents = a:contents
78+
79+
" create lines.
80+
let l:lines = []
81+
for l:content in a:contents
82+
let l:lines += l:content
83+
endfor
84+
85+
" update bufvars.
86+
call setbufvar(self.bufnr, 'lsp_floatwin_lines', l:lines)
87+
88+
" show or move
89+
call lsp#ui#vim#floatwin#{s:namespace}#show(self)
90+
call setwinvar(self.winid(), '&wrap', 1)
91+
call setwinvar(self.winid(), '&conceallevel', 3)
92+
93+
" write lines
94+
call lsp#ui#vim#floatwin#{s:namespace}#write(self, l:lines)
95+
96+
" update syntax highlight.
97+
if has('nvim') && LspFloatwinSyntaxShouldUpdate(self.bufnr)
98+
call lsp#utils#windo(self.winid(), { -> LspFloatwinSyntaxUpdate() })
99+
endif
100+
101+
call self.set_close_events()
102+
endfunction
103+
104+
"
105+
" hide
106+
"
107+
function! s:Floatwin.hide() abort
108+
augroup printf('lsp#ui#vim#floatwin#hide_%s', self.id)
109+
autocmd!
110+
augroup END
111+
call lsp#ui#vim#floatwin#{s:namespace}#hide(self)
112+
endfunction
113+
114+
"
115+
" enter
116+
"
117+
function! s:Floatwin.enter() abort
118+
call lsp#ui#vim#floatwin#{s:namespace}#enter(self)
119+
endfunction
120+
121+
"
122+
" is_showing
123+
"
124+
function! s:Floatwin.is_showing() abort
125+
return lsp#ui#vim#floatwin#{s:namespace}#is_showing(self)
126+
endfunction
127+
128+
"
129+
" winid
130+
"
131+
function! s:Floatwin.winid() abort
132+
return lsp#ui#vim#floatwin#{s:namespace}#winid(self)
133+
endfunction
134+
135+
"
136+
" set_close_events
137+
"
138+
function! s:Floatwin.set_close_events() abort
139+
let l:close_fn = printf('lsp_floatwin_close_%s', self.id)
140+
let b:[l:close_fn] = { -> self.hide() }
141+
142+
augroup printf('lsp#ui#vim#floatwin#hide_%s', self.id)
143+
autocmd!
144+
for l:event in self.close_on
145+
execute printf('autocmd %s <buffer> call b:%s()', l:event, l:close_fn)
146+
endfor
147+
augroup END
148+
endfunction
149+
150+
"
151+
" get_width
152+
"
153+
function! s:Floatwin.get_width(contents) abort
154+
let l:width = 0
155+
for l:content in a:contents
156+
let l:width = max([l:width] + map(copy(l:content), { k, v -> strdisplaywidth(v) }))
157+
endfor
158+
159+
if self.max_width != -1
160+
return max([min([self.max_width, l:width]), 1])
161+
endif
162+
return max([l:width, 1])
163+
endfunction
164+
165+
"
166+
" get_height
167+
"
168+
function! s:Floatwin.get_height(contents) abort
169+
let l:width = self.get_width(a:contents)
170+
171+
let l:height = len(a:contents) - 1
172+
for l:content in a:contents
173+
for l:line in l:content
174+
let l:height += max([1, float2nr(ceil(strdisplaywidth(l:line) / str2float('' . l:width)))])
175+
endfor
176+
endfor
177+
178+
if self.max_height != -1
179+
return max([min([self.max_height, l:height]), 1])
180+
endif
181+
return max([l:height, 1])
182+
endfunction
183+

autoload/lsp/ui/vim/floatwin/nvim.vim

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
"
2+
" lsp#ui#vim#floatwin#nvim#show
3+
"
4+
function! lsp#ui#vim#floatwin#nvim#show(floatwin) abort
5+
if lsp#ui#vim#floatwin#nvim#is_showing(a:floatwin)
6+
call nvim_win_set_config(a:floatwin.nvim_window, s:get_config(a:floatwin))
7+
else
8+
let a:floatwin.nvim_window = nvim_open_win(a:floatwin.bufnr, v:false, s:get_config(a:floatwin))
9+
endif
10+
endfunction
11+
12+
"
13+
" lsp#ui#vim#floatwin#nvim#hide
14+
"
15+
function! lsp#ui#vim#floatwin#nvim#hide(floatwin) abort
16+
if lsp#ui#vim#floatwin#nvim#is_showing(a:floatwin)
17+
call nvim_win_close(a:floatwin.nvim_window, v:true)
18+
let a:floatwin.nvim_window = v:null
19+
endif
20+
endfunction
21+
22+
"
23+
" lsp#ui#vim#floatwin#nvim#write
24+
"
25+
function! lsp#ui#vim#floatwin#nvim#write(floatwin, lines) abort
26+
call nvim_buf_set_lines(a:floatwin.bufnr, 0, -1, v:true, a:lines)
27+
endfunction
28+
29+
"
30+
" lsp#ui#vim#floatwin#nvim#enter
31+
"
32+
function! lsp#ui#vim#floatwin#nvim#enter(floatwin) abort
33+
if lsp#ui#vim#floatwin#nvim#is_showing(a:floatwin)
34+
execute printf('%swincmd w', win_id2win(lsp#ui#vim#floatwin#nvim#winid(a:floatwin)))
35+
endif
36+
endfunction
37+
38+
"
39+
" lsp#ui#vim#floatwin#nvim#is_showing
40+
"
41+
function! lsp#ui#vim#floatwin#nvim#is_showing(floatwin) abort
42+
if !has_key(a:floatwin,'nvim_window') || a:floatwin.nvim_window is v:null
43+
return v:false
44+
endif
45+
46+
try
47+
return nvim_win_get_number(a:floatwin.nvim_window) != -1
48+
catch /.*/
49+
let a:floatwin.nvim_window = v:null
50+
endtry
51+
return v:false
52+
endfunction
53+
54+
"
55+
" lsp#ui#vim#floatwin#nvim#winid
56+
"
57+
function! lsp#ui#vim#floatwin#nvim#winid(floatwin) abort
58+
if lsp#ui#vim#floatwin#nvim#is_showing(a:floatwin)
59+
return win_getid(nvim_win_get_number(a:floatwin.nvim_window))
60+
endif
61+
return -1
62+
endfunction
63+
64+
"
65+
" s:get_config
66+
"
67+
function! s:get_config(floatwin) abort
68+
return {
69+
\ 'relative': 'editor',
70+
\ 'width': a:floatwin.get_width(a:floatwin.contents),
71+
\ 'height': a:floatwin.get_height(a:floatwin.contents),
72+
\ 'row': a:floatwin.screenpos[0],
73+
\ 'col': a:floatwin.screenpos[1],
74+
\ 'focusable': v:true,
75+
\ 'style': 'minimal'
76+
\ }
77+
endfunction
78+

autoload/lsp/ui/vim/floatwin/vim.vim

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
"
2+
" lsp#ui#vim#floatwin#vim#show
3+
"
4+
function! lsp#ui#vim#floatwin#vim#show(floatwin) abort
5+
if lsp#ui#vim#floatwin#vim#is_showing(a:floatwin)
6+
call popup_move(a:floatwin.vim_winid, s:get_config(a:floatwin))
7+
else
8+
let a:floatwin.vim_winid = popup_create(a:floatwin.bufnr, s:get_config(a:floatwin))
9+
endif
10+
endfunction
11+
12+
"
13+
" lsp#ui#vim#floatwin#vim#hide
14+
"
15+
function! lsp#ui#vim#floatwin#vim#hide(floatwin) abort
16+
try
17+
call popup_hide(a:floatwin.vim_winid)
18+
catch /.*/
19+
endtry
20+
let a:floatwin.vim_winid = v:null
21+
endfunction
22+
23+
"
24+
" lsp#ui#vim#floatwin#vim#write
25+
"
26+
function! lsp#ui#vim#floatwin#vim#write(floatwin, lines) abort
27+
call deletebufline(a:floatwin.bufnr, '^', '$')
28+
for l:line in reverse(a:lines)
29+
call appendbufline(a:floatwin.bufnr, 0, l:line)
30+
endfor
31+
call deletebufline(a:floatwin.bufnr, '$')
32+
endfunction
33+
34+
"
35+
" lsp#ui#vim#floatwin#vim#enter
36+
"
37+
function! lsp#ui#vim#floatwin#vim#enter(floatwin) abort
38+
" noop
39+
endfunction
40+
41+
"
42+
" lsp#ui#vim#floatwin#vim#is_showing
43+
"
44+
function! lsp#ui#vim#floatwin#vim#is_showing(floatwin) abort
45+
if !has_key(a:floatwin, 'vim_winid') || a:floatwin.vim_winid is v:null
46+
return v:false
47+
endif
48+
49+
if win_id2win(a:floatwin.vim_winid) == -1
50+
let a:floatwin.vim_winid = v:null
51+
return v:false
52+
endif
53+
return v:true
54+
endfunction
55+
56+
"
57+
" lsp#ui#vim#floatwin#vim#winid
58+
"
59+
function! lsp#ui#vim#floatwin#vim#winid(floatwin) abort
60+
if lsp#ui#vim#floatwin#vim#is_showing(a:floatwin)
61+
return a:floatwin.vim_winid
62+
endif
63+
return -1
64+
endfunction
65+
66+
"
67+
" s:get_config
68+
"
69+
function! s:get_config(floatwin) abort
70+
return {
71+
\ 'line': a:floatwin.screenpos[0] + 1,
72+
\ 'col': a:floatwin.screenpos[1] + 1,
73+
\ 'pos': 'topleft',
74+
\ 'moved': [0, 100000],
75+
\ 'scrollbar': 0,
76+
\ 'maxwidth': a:floatwin.get_width(a:floatwin.contents),
77+
\ 'maxheight': a:floatwin.get_height(a:floatwin.contents),
78+
\ 'minwidth': a:floatwin.get_width(a:floatwin.contents),
79+
\ 'minheight': a:floatwin.get_height(a:floatwin.contents),
80+
\ 'tabpage': 0
81+
\ }
82+
endfunction
83+

0 commit comments

Comments
 (0)