--- /dev/null
+" ___vital___
+" NOTE: lines between '" ___vital___' is generated by :Vitalize.
+" Do not modify the code nor insert new lines before '" ___vital___'
+function! s:_SID() abort
+ return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
+endfunction
+execute join(['function! vital#_lsp#VS#Vim#Window#import() abort', printf("return map({'info': '', 'do': '', 'is_floating': '', 'find': '', 'scroll': '', 'screenpos': ''}, \"vital#_lsp#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
+delfunction s:_SID
+" ___vital___
+let s:Do = { -> {} }
+
+"
+" do
+"
+function! s:do(winid, func) abort
+ let l:curr_winid = win_getid()
+ if l:curr_winid == a:winid
+ call a:func()
+ return
+ endif
+
+ if !has('nvim') && exists('*win_execute')
+ let s:Do = a:func
+ try
+ noautocmd keepalt keepjumps call win_execute(a:winid, 'call s:Do()')
+ catch /.*/
+ echomsg string({ 'exception': v:exception, 'throwpoint': v:throwpoint })
+ endtry
+ unlet s:Do
+ return
+ endif
+
+ noautocmd keepalt keepjumps call win_gotoid(a:winid)
+ try
+ call a:func()
+ catch /.*/
+ echomsg string({ 'exception': v:exception, 'throwpoint': v:throwpoint })
+ endtry
+ noautocmd keepalt keepjumps call win_gotoid(l:curr_winid)
+endfunction
+
+"
+" info
+"
+if has('nvim')
+ function! s:info(winid) abort
+ let l:info = getwininfo(a:winid)[0]
+
+ if s:is_floating(a:winid)
+ let l:config = nvim_win_get_config(a:winid)
+ let l:config.border = get(l:config, 'border', 'none')
+ if type(l:config.border) !=# type([])
+ if index(['rounded', 'single', 'double', 'solid'], l:config.border) >= 0
+ let l:width_off = 2
+ let l:height_off = 2
+ elseif l:config.border ==# 'shadow'
+ let l:width_off = 1
+ let l:height_off = 1
+ else
+ let l:width_off = 0
+ let l:height_off = 0
+ endif
+ else
+ let l:has_top = v:false
+ let l:has_top = l:has_top || get(l:config.border, 0, '') !=# ''
+ let l:has_top = l:has_top || get(l:config.border, 1, '') !=# ''
+ let l:has_top = l:has_top || get(l:config.border, 2, '') !=# ''
+ let l:has_right = v:false
+ let l:has_right = l:has_right || get(l:config.border, 2, '') !=# ''
+ let l:has_right = l:has_right || get(l:config.border, 3, '') !=# ''
+ let l:has_right = l:has_right || get(l:config.border, 4, '') !=# ''
+ let l:has_bottom = v:false
+ let l:has_bottom = l:has_bottom || get(l:config.border, 4, '') !=# ''
+ let l:has_bottom = l:has_bottom || get(l:config.border, 5, '') !=# ''
+ let l:has_bottom = l:has_bottom || get(l:config.border, 6, '') !=# ''
+ let l:has_left = v:false
+ let l:has_left = l:has_left || get(l:config.border, 6, '') !=# ''
+ let l:has_left = l:has_left || get(l:config.border, 7, '') !=# ''
+ let l:has_left = l:has_left || get(l:config.border, 0, '') !=# ''
+
+ let l:width_off = (l:has_left ? 1 : 0) + (l:has_right ? 1 : 0)
+ let l:height_off = (l:has_top ? 1 : 0) + (l:has_bottom ? 1 : 0)
+ endif
+ let l:left = get(l:config, '')
+ let l:info.core_width = l:config.width - l:width_off
+ let l:info.core_height = l:config.height - l:height_off
+ else
+ let l:info.core_width = l:info.width
+ let l:info.core_height = l:info.height
+ endif
+
+ return {
+ \ 'width': l:info.width,
+ \ 'height': l:info.height,
+ \ 'core_width': l:info.core_width,
+ \ 'core_height': l:info.core_height,
+ \ 'topline': l:info.topline,
+ \ }
+ endfunction
+else
+ function! s:info(winid) abort
+ if s:is_floating(a:winid)
+ let l:info = popup_getpos(a:winid)
+ return {
+ \ 'width': l:info.width,
+ \ 'height': l:info.height,
+ \ 'core_width': l:info.core_width,
+ \ 'core_height': l:info.core_height,
+ \ 'topline': l:info.firstline
+ \ }
+ endif
+
+ let l:ctx = {}
+ let l:ctx.info = {}
+ function! l:ctx.callback() abort
+ let self.info.width = winwidth(0)
+ let self.info.height = winheight(0)
+ let self.info.core_width = self.info.width
+ let self.info.core_height = self.info.height
+ let self.info.topline = line('w0')
+ endfunction
+ call s:do(a:winid, { -> l:ctx.callback() })
+ return l:ctx.info
+ endfunction
+endif
+
+"
+" find
+"
+function! s:find(callback) abort
+ let l:winids = []
+ let l:winids += map(range(1, tabpagewinnr(tabpagenr(), '$')), 'win_getid(v:val)')
+ let l:winids += s:_get_visible_popup_winids()
+ return filter(l:winids, 'a:callback(v:val)')
+endfunction
+
+"
+" is_floating
+"
+if has('nvim')
+ function! s:is_floating(winid) abort
+ let l:config = nvim_win_get_config(a:winid)
+ return empty(l:config) || !empty(get(l:config, 'relative', ''))
+ endfunction
+else
+ function! s:is_floating(winid) abort
+ return winheight(a:winid) != -1 && win_id2win(a:winid) == 0
+ endfunction
+endif
+
+"
+" scroll
+"
+function! s:scroll(winid, topline) abort
+ let l:ctx = {}
+ function! l:ctx.callback(winid, topline) abort
+ let l:wininfo = s:info(a:winid)
+ let l:topline = a:topline
+ let l:topline = min([l:topline, line('$') - l:wininfo.core_height + 1])
+ let l:topline = max([l:topline, 1])
+
+ if l:topline == l:wininfo.topline
+ return
+ endif
+
+ if !has('nvim') && s:is_floating(a:winid)
+ call popup_setoptions(a:winid, {
+ \ 'firstline': l:topline,
+ \ })
+ else
+ let l:delta = l:topline - l:wininfo.topline
+ let l:key = l:delta > 0 ? "\<C-e>" : "\<C-y>"
+ execute printf('noautocmd silent normal! %s', repeat(l:key, abs(l:delta)))
+ endif
+ endfunction
+ call s:do(a:winid, { -> l:ctx.callback(a:winid, a:topline) })
+endfunction
+
+"
+" screenpos
+"
+" @param {[number, number]} pos - position on the current buffer.
+"
+function! s:screenpos(pos) abort
+ let l:y = a:pos[0]
+ let l:x = a:pos[1] + get(a:pos, 2, 0)
+
+ let l:view = winsaveview()
+ let l:scroll_x = l:view.leftcol
+ let l:scroll_y = l:view.topline
+
+ let l:winpos = win_screenpos(win_getid())
+ let l:y = l:winpos[0] + l:y - l:scroll_y
+ let l:x = l:winpos[1] + l:x - l:scroll_x
+ return [l:y, l:x + (wincol() - virtcol('.')) - 1]
+endfunction
+
+"
+" _get_visible_popup_winids
+"
+function! s:_get_visible_popup_winids() abort
+ if !exists('*popup_list')
+ return []
+ endif
+ return filter(popup_list(), 'popup_getpos(v:val).visible')
+endfunction
+