I broke up with neovim....vim is my best friend now
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
" ___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#LSP#MarkupContent#import() abort', printf("return map({'_vital_depends': '', 'normalize': '', '_vital_loaded': ''}, \"vital#_lsp#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
"
|
||||
" _vital_loaded
|
||||
"
|
||||
function! s:_vital_loaded(V) abort
|
||||
let s:Text = a:V.import('VS.LSP.Text')
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _vital_depends
|
||||
"
|
||||
function! s:_vital_depends() abort
|
||||
return ['VS.LSP.Text']
|
||||
endfunction
|
||||
|
||||
"
|
||||
" normalize
|
||||
"
|
||||
function! s:normalize(markup_content, ...) abort
|
||||
let l:option = get(a:000, 0, {})
|
||||
let l:option.compact = get(l:option, 'compact', v:true)
|
||||
|
||||
let l:normalized = ''
|
||||
if type(a:markup_content) == type('')
|
||||
let l:normalized = a:markup_content
|
||||
elseif type(a:markup_content) == type([])
|
||||
let l:normalized = join(a:markup_content, "\n")
|
||||
elseif type(a:markup_content) == type({})
|
||||
let l:normalized = a:markup_content.value
|
||||
if has_key(a:markup_content, 'language')
|
||||
let l:normalized = join([
|
||||
\ '```' . a:markup_content.language,
|
||||
\ l:normalized,
|
||||
\ '```'
|
||||
\ ], "\n")
|
||||
endif
|
||||
endif
|
||||
let l:normalized = s:Text.normalize_eol(l:normalized)
|
||||
let l:normalized = s:_format(l:normalized, l:option.compact)
|
||||
return l:normalized
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _format
|
||||
"
|
||||
function! s:_format(string, compact) abort
|
||||
let l:string = a:string
|
||||
if a:compact
|
||||
let l:string = substitute(l:string, "\\%(\\s\\|\n\\)*```\\s*\\(\\w\\+\\)\\%(\\s\\|\n\\)\\+", "\n\n```\\1 ", 'g')
|
||||
let l:string = substitute(l:string, "\\%(\\s\\|\n\\)\\+```\\%(\\s*\\%(\\%$\\|\n\\)\\)\\+", " ```\n\n", 'g')
|
||||
else
|
||||
let l:string = substitute(l:string, "```\n\\zs\\%(\\s\\|\n\\)\\+", "", 'g')
|
||||
endif
|
||||
let l:string = substitute(l:string, "\\%^\\%(\\s\\|\n\\)*", '', 'g')
|
||||
let l:string = substitute(l:string, "\\%(\\s\\|\n\\)*\\%$", '', 'g')
|
||||
return l:string
|
||||
endfunction
|
||||
|
||||
23
dot_vim/plugged/vim-lsp/autoload/vital/_lsp/VS/LSP/Text.vim
Normal file
23
dot_vim/plugged/vim-lsp/autoload/vital/_lsp/VS/LSP/Text.vim
Normal file
@@ -0,0 +1,23 @@
|
||||
" ___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#LSP#Text#import() abort', printf("return map({'normalize_eol': '', 'split_by_eol': ''}, \"vital#_lsp#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
"
|
||||
" normalize_eol
|
||||
"
|
||||
function! s:normalize_eol(text) abort
|
||||
return substitute(a:text, "\r\n\\|\r", "\n", 'g')
|
||||
endfunction
|
||||
|
||||
"
|
||||
" split_by_eol
|
||||
"
|
||||
function! s:split_by_eol(text) abort
|
||||
return split(a:text, "\r\n\\|\r\\|\n", v:true)
|
||||
endfunction
|
||||
|
||||
140
dot_vim/plugged/vim-lsp/autoload/vital/_lsp/VS/Vim/Buffer.vim
Normal file
140
dot_vim/plugged/vim-lsp/autoload/vital/_lsp/VS/Vim/Buffer.vim
Normal file
@@ -0,0 +1,140 @@
|
||||
" ___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#Buffer#import() abort', printf("return map({'add': '', 'do': '', 'create': '', 'get_line_count': '', 'pseudo': '', 'ensure': '', 'load': ''}, \"vital#_lsp#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
let s:Do = { -> {} }
|
||||
|
||||
let g:___VS_Vim_Buffer_id = get(g:, '___VS_Vim_Buffer_id', 0)
|
||||
|
||||
"
|
||||
" get_line_count
|
||||
"
|
||||
if exists('*nvim_buf_line_count')
|
||||
function! s:get_line_count(bufnr) abort
|
||||
return nvim_buf_line_count(a:bufnr)
|
||||
endfunction
|
||||
elseif has('patch-8.2.0019')
|
||||
function! s:get_line_count(bufnr) abort
|
||||
return getbufinfo(a:bufnr)[0].linecount
|
||||
endfunction
|
||||
else
|
||||
function! s:get_line_count(bufnr) abort
|
||||
if bufnr('%') == bufnr(a:bufnr)
|
||||
return line('$')
|
||||
endif
|
||||
return len(getbufline(a:bufnr, '^', '$'))
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" create
|
||||
"
|
||||
function! s:create(...) abort
|
||||
let g:___VS_Vim_Buffer_id += 1
|
||||
let l:bufname = printf('VS.Vim.Buffer: %s: %s',
|
||||
\ g:___VS_Vim_Buffer_id,
|
||||
\ get(a:000, 0, 'VS.Vim.Buffer.Default')
|
||||
\ )
|
||||
return s:load(l:bufname)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" ensure
|
||||
"
|
||||
function! s:ensure(expr) abort
|
||||
if !bufexists(a:expr)
|
||||
if type(a:expr) == type(0)
|
||||
throw printf('VS.Vim.Buffer: `%s` is not valid expr.', a:expr)
|
||||
endif
|
||||
call s:add(a:expr)
|
||||
endif
|
||||
return bufnr(a:expr)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" add
|
||||
"
|
||||
if exists('*bufadd')
|
||||
function! s:add(name) abort
|
||||
let l:bufnr = bufadd(a:name)
|
||||
call setbufvar(l:bufnr, '&buflisted', 1)
|
||||
endfunction
|
||||
else
|
||||
function! s:add(name) abort
|
||||
badd `=a:name`
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" load
|
||||
"
|
||||
if exists('*bufload')
|
||||
function! s:load(expr) abort
|
||||
let l:bufnr = s:ensure(a:expr)
|
||||
if !bufloaded(l:bufnr)
|
||||
call bufload(l:bufnr)
|
||||
endif
|
||||
return l:bufnr
|
||||
endfunction
|
||||
else
|
||||
function! s:load(expr) abort
|
||||
let l:curr_bufnr = bufnr('%')
|
||||
try
|
||||
let l:bufnr = s:ensure(a:expr)
|
||||
execute printf('keepalt keepjumps silent %sbuffer', l:bufnr)
|
||||
catch /.*/
|
||||
echomsg string({ 'exception': v:exception, 'throwpoint': v:throwpoint })
|
||||
finally
|
||||
execute printf('noautocmd keepalt keepjumps silent %sbuffer', l:curr_bufnr)
|
||||
endtry
|
||||
return l:bufnr
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" do
|
||||
"
|
||||
function! s:do(bufnr, func) abort
|
||||
let l:curr_bufnr = bufnr('%')
|
||||
if l:curr_bufnr == a:bufnr
|
||||
call a:func()
|
||||
return
|
||||
endif
|
||||
|
||||
try
|
||||
execute printf('noautocmd keepalt keepjumps silent %sbuffer', a:bufnr)
|
||||
call a:func()
|
||||
catch /.*/
|
||||
echomsg string({ 'exception': v:exception, 'throwpoint': v:throwpoint })
|
||||
finally
|
||||
execute printf('noautocmd keepalt keepjumps silent %sbuffer', l:curr_bufnr)
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
"
|
||||
" pseudo
|
||||
"
|
||||
function! s:pseudo(filepath) abort
|
||||
if !filereadable(a:filepath)
|
||||
throw printf('VS.Vim.Buffer: `%s` is not valid filepath.', a:filepath)
|
||||
endif
|
||||
|
||||
" create pseudo buffer
|
||||
let l:bufname = printf('VSVimBufferPseudo://%s', a:filepath)
|
||||
if bufexists(l:bufname)
|
||||
return s:ensure(l:bufname)
|
||||
endif
|
||||
|
||||
let l:bufnr = s:ensure(l:bufname)
|
||||
let l:group = printf('VS_Vim_Buffer_pseudo:%s', l:bufnr)
|
||||
execute printf('augroup %s', l:group)
|
||||
execute printf('autocmd BufReadCmd <buffer=%s> call setline(1, readfile(bufname("%")[20 : -1])) | try | filetype detect | catch /.*/ | endtry | augroup %s | autocmd! | augroup END', l:bufnr, l:group)
|
||||
augroup END
|
||||
return l:bufnr
|
||||
endfunction
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
" ___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#Syntax#Markdown#import() abort', printf("return map({'apply': ''}, \"vital#_lsp#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
"
|
||||
" apply
|
||||
"
|
||||
" TODO: Refactor
|
||||
"
|
||||
function! s:apply(...) abort
|
||||
let l:args = get(a:000, 0, {})
|
||||
let l:text = has_key(l:args, 'text') ? l:args.text : getbufline('%', 1, '$')
|
||||
let l:text = type(l:text) == v:t_list ? join(l:text, "\n") : l:text
|
||||
|
||||
call s:_execute('syntax sync clear')
|
||||
if !exists('b:___VS_Vim_Syntax_Markdown')
|
||||
" Avoid automatic highlighting by built-in runtime syntax.
|
||||
if !has_key(g:, 'markdown_fenced_languages')
|
||||
call s:_execute('runtime! syntax/markdown.vim')
|
||||
else
|
||||
let l:markdown_fenced_languages = g:markdown_fenced_languages
|
||||
unlet g:markdown_fenced_languages
|
||||
call s:_execute('runtime! syntax/markdown.vim')
|
||||
let g:markdown_fenced_languages = l:markdown_fenced_languages
|
||||
endif
|
||||
|
||||
" Remove markdownCodeBlock because we support it manually.
|
||||
call s:_clear('markdownCodeBlock') " runtime
|
||||
call s:_clear('mkdCode') " plasticboy/vim-markdown
|
||||
|
||||
" Modify markdownCode (`codes...`)
|
||||
call s:_clear('markdownCode')
|
||||
syntax region markdownCode matchgroup=Conceal start=/\%(``\)\@!`/ matchgroup=Conceal end=/\%(``\)\@!`/ containedin=TOP keepend concealends
|
||||
|
||||
" Modify markdownEscape (_bold\_text_) @see nvim's syntax/lsp_markdown.vim
|
||||
call s:_clear('markdownEscape')
|
||||
syntax region markdownEscape matchgroup=markdownEscape start=/\\\ze[\\\x60*{}\[\]()#+\-,.!_>~|"$%&'\/:;<=?@^ ]/ end=/./ containedin=ALL keepend oneline concealends
|
||||
|
||||
" Add syntax for basic html entities.
|
||||
syntax match vital_vs_vim_syntax_markdown_entities_lt /</ containedin=ALL conceal cchar=<
|
||||
syntax match vital_vs_vim_syntax_markdown_entities_gt />/ containedin=ALL conceal cchar=>
|
||||
syntax match vital_vs_vim_syntax_markdown_entities_amp /&/ containedin=ALL conceal cchar=&
|
||||
syntax match vital_vs_vim_syntax_markdown_entities_quot /"/ containedin=ALL conceal cchar="
|
||||
syntax match vital_vs_vim_syntax_markdown_entities_nbsp / / containedin=ALL conceal cchar=
|
||||
|
||||
let b:___VS_Vim_Syntax_Markdown = {}
|
||||
let b:___VS_Vim_Syntax_Markdown.marks = {}
|
||||
let b:___VS_Vim_Syntax_Markdown.filetypes = {}
|
||||
endif
|
||||
|
||||
for [l:mark, l:filetype] in items(s:_get_filetype_map(l:text))
|
||||
try
|
||||
let l:mark_group = substitute(toupper(l:mark), '\.', '_', 'g')
|
||||
if has_key(b:___VS_Vim_Syntax_Markdown.marks, l:mark_group)
|
||||
continue
|
||||
endif
|
||||
let b:___VS_Vim_Syntax_Markdown.marks[l:mark_group] = v:true
|
||||
|
||||
let l:filetype_group = substitute(toupper(l:filetype), '\.', '_', 'g')
|
||||
if !has_key(b:___VS_Vim_Syntax_Markdown.filetypes, l:filetype_group)
|
||||
call s:_execute('syntax include @%s syntax/%s.vim', l:filetype_group, l:filetype)
|
||||
let b:___VS_Vim_Syntax_Markdown.filetypes[l:filetype_group] = v:true
|
||||
endif
|
||||
|
||||
call s:_execute('syntax region %s matchgroup=Conceal start=/%s/ matchgroup=Conceal end=/%s/ contains=@%s containedin=TOP keepend concealends',
|
||||
\ l:mark_group,
|
||||
\ printf('```\s*%s\s*', l:mark),
|
||||
\ '```\s*\%(' . "\n" . '\|$\)',
|
||||
\ l:filetype_group
|
||||
\ )
|
||||
catch /.*/
|
||||
unsilent echomsg printf('Fail to apply "syntax/%s.vim". Add "let g:markdown_fenced_languages = ["%s=$FILETYPE"]" to enable syntax', l:filetype, l:filetype)
|
||||
endtry
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _clear
|
||||
"
|
||||
function! s:_clear(group) abort
|
||||
try
|
||||
execute printf('silent! syntax clear %s', a:group)
|
||||
catch /.*/
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _execute
|
||||
"
|
||||
function! s:_execute(command, ...) abort
|
||||
let b:current_syntax = ''
|
||||
unlet b:current_syntax
|
||||
|
||||
let g:main_syntax = ''
|
||||
unlet g:main_syntax
|
||||
|
||||
execute call('printf', [a:command] + a:000)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _get_filetype_map
|
||||
"
|
||||
function! s:_get_filetype_map(text) abort
|
||||
let l:filetype_map = {}
|
||||
for l:mark in s:_find_marks(a:text)
|
||||
let l:filetype_map[l:mark] = s:_get_filetype_from_mark(l:mark)
|
||||
endfor
|
||||
return l:filetype_map
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _find_marks
|
||||
"
|
||||
function! s:_find_marks(text) abort
|
||||
let l:marks = {}
|
||||
|
||||
" find from buffer contents.
|
||||
let l:text = a:text
|
||||
let l:pos = 0
|
||||
while 1
|
||||
let l:match = matchstrpos(l:text, '```\s*\zs\w\+', l:pos, 1)
|
||||
if empty(l:match[0])
|
||||
break
|
||||
endif
|
||||
let l:marks[l:match[0]] = v:true
|
||||
let l:pos = l:match[2]
|
||||
endwhile
|
||||
|
||||
return keys(l:marks)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _get_filetype_from_mark
|
||||
"
|
||||
function! s:_get_filetype_from_mark(mark) abort
|
||||
for l:config in get(g:, 'markdown_fenced_languages', [])
|
||||
if l:config !~# '='
|
||||
if l:config ==# a:mark
|
||||
return a:mark
|
||||
endif
|
||||
else
|
||||
let l:config = split(l:config, '=')
|
||||
if l:config[0] ==# a:mark
|
||||
return l:config[1]
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
return a:mark
|
||||
endfunction
|
||||
|
||||
157
dot_vim/plugged/vim-lsp/autoload/vital/_lsp/VS/Vim/Window.vim
Normal file
157
dot_vim/plugged/vim-lsp/autoload/vital/_lsp/VS/Vim/Window.vim
Normal file
@@ -0,0 +1,157 @@
|
||||
" ___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]
|
||||
return {
|
||||
\ 'width': l:info.width,
|
||||
\ 'height': l:info.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,
|
||||
\ '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.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.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
|
||||
|
||||
@@ -0,0 +1,515 @@
|
||||
" ___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#FloatingWindow#import() abort', printf("return map({'_vital_depends': '', 'is_available': '', 'new': '', '_vital_loaded': ''}, \"vital#_lsp#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
"
|
||||
" _vital_loaded
|
||||
"
|
||||
function! s:_vital_loaded(V) abort
|
||||
let s:Window = a:V.import('VS.Vim.Window')
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _vital_depends
|
||||
"
|
||||
function! s:_vital_depends() abort
|
||||
return ['VS.Vim.Window']
|
||||
endfunction
|
||||
|
||||
"
|
||||
" managed floating windows.
|
||||
"
|
||||
let s:floating_windows = {}
|
||||
|
||||
"
|
||||
" is_available
|
||||
"
|
||||
function! s:is_available() abort
|
||||
if has('nvim')
|
||||
return v:true
|
||||
endif
|
||||
return exists('*popup_create') && exists('*popup_close') && exists('*popup_move') && exists('*popup_getpos')
|
||||
endfunction
|
||||
|
||||
"
|
||||
" new
|
||||
"
|
||||
function! s:new(...) abort
|
||||
call s:_init()
|
||||
|
||||
return s:FloatingWindow.new(get(a:000, 0, {}))
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _notify_opened
|
||||
"
|
||||
" @param {number} winid
|
||||
" @param {VS.Vim.Window.FloatingWindow} floating_window
|
||||
"
|
||||
function! s:_notify_opened(winid, floating_window) abort
|
||||
let s:floating_windows[a:winid] = a:floating_window
|
||||
call a:floating_window._on_opened()
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _notify_closed
|
||||
"
|
||||
function! s:_notify_closed() abort
|
||||
for [l:winid, l:floating_window] in items(s:floating_windows)
|
||||
if winheight(l:winid) == -1
|
||||
call l:floating_window._on_closed()
|
||||
unlet s:floating_windows[l:winid]
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
let s:FloatingWindow = {}
|
||||
|
||||
"
|
||||
" new
|
||||
"
|
||||
" @param {function?} args.on_opened
|
||||
" @param {function?} args.on_closed
|
||||
"
|
||||
function! s:FloatingWindow.new(args) abort
|
||||
return extend(deepcopy(s:FloatingWindow), {
|
||||
\ '_winid': v:null,
|
||||
\ '_bufnr': v:null,
|
||||
\ '_vars': {},
|
||||
\ '_on_opened': get(a:args, 'on_opened', { -> {} }),
|
||||
\ '_on_closed': get(a:args, 'on_closed', { -> {} }),
|
||||
\ })
|
||||
endfunction
|
||||
|
||||
"
|
||||
" get_size
|
||||
"
|
||||
" @param {number?} args.minwidth
|
||||
" @param {number?} args.maxwidth
|
||||
" @param {number?} args.minheight
|
||||
" @param {number?} args.maxheight
|
||||
" @param {boolean?} args.wrap
|
||||
"
|
||||
function! s:FloatingWindow.get_size(args) abort
|
||||
if self._bufnr is# v:null
|
||||
throw 'VS.Vim.Window.FloatingWindow: Failed to detect bufnr.'
|
||||
endif
|
||||
|
||||
let l:maxwidth = get(a:args, 'maxwidth', -1)
|
||||
let l:minwidth = get(a:args, 'minwidth', -1)
|
||||
let l:maxheight = get(a:args, 'maxheight', -1)
|
||||
let l:minheight = get(a:args, 'minheight', -1)
|
||||
let l:lines = getbufline(self._bufnr, '^', '$')
|
||||
|
||||
" width
|
||||
let l:width = 0
|
||||
for l:line in l:lines
|
||||
let l:width = max([l:width, strdisplaywidth(l:line)])
|
||||
endfor
|
||||
|
||||
let l:width = l:minwidth == -1 ? l:width : max([l:minwidth, l:width])
|
||||
let l:width = l:maxwidth == -1 ? l:width : min([l:maxwidth, l:width])
|
||||
|
||||
" height
|
||||
if get(a:args, 'wrap', get(self._vars, '&wrap', 0))
|
||||
let l:height = 0
|
||||
for l:line in l:lines
|
||||
let l:height += max([1, float2nr(ceil(strdisplaywidth(l:line) / str2float('' . l:width)))])
|
||||
endfor
|
||||
else
|
||||
let l:height = len(l:lines)
|
||||
endif
|
||||
let l:height = l:minheight == -1 ? l:height : max([l:minheight, l:height])
|
||||
let l:height = l:maxheight == -1 ? l:height : min([l:maxheight, l:height])
|
||||
|
||||
return {
|
||||
\ 'width': max([1, l:width]),
|
||||
\ 'height': max([1, l:height]),
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
"
|
||||
" set_bufnr
|
||||
"
|
||||
" @param {number} bufnr
|
||||
"
|
||||
function! s:FloatingWindow.set_bufnr(bufnr) abort
|
||||
let self._bufnr = a:bufnr
|
||||
endfunction
|
||||
|
||||
"
|
||||
" get_bufnr
|
||||
"
|
||||
function! s:FloatingWindow.get_bufnr() abort
|
||||
return self._bufnr
|
||||
endfunction
|
||||
|
||||
"
|
||||
" get_winid
|
||||
"
|
||||
function! s:FloatingWindow.get_winid() abort
|
||||
if self.is_visible()
|
||||
return self._winid
|
||||
endif
|
||||
return v:null
|
||||
endfunction
|
||||
|
||||
"
|
||||
" info
|
||||
"
|
||||
function! s:FloatingWindow.info() abort
|
||||
if self.is_visible()
|
||||
return s:_info(self._winid)
|
||||
endif
|
||||
return v:null
|
||||
endfunction
|
||||
|
||||
"
|
||||
" set_var
|
||||
"
|
||||
" @param {string} key
|
||||
" @param {unknown} value
|
||||
"
|
||||
function! s:FloatingWindow.set_var(key, value) abort
|
||||
let self._vars[a:key] = a:value
|
||||
if self.is_visible()
|
||||
call setwinvar(self._winid, a:key, a:value)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"
|
||||
" get_var
|
||||
"
|
||||
" @param {string} key
|
||||
"
|
||||
function! s:FloatingWindow.get_var(key) abort
|
||||
return self._vars[a:key]
|
||||
endfunction
|
||||
|
||||
"
|
||||
" open
|
||||
"
|
||||
" @param {number} args.row 0-based indexing
|
||||
" @param {number} args.col 0-based indexing
|
||||
" @param {number} args.width
|
||||
" @param {number} args.height
|
||||
" @param {boolean|[string]?} args.border - boolean, or list of characters
|
||||
" clockwise from top-left (same as nvim_open_win() in neovim)
|
||||
" @param {number?} args.topline
|
||||
" @param {string?} args.origin - topleft/topright/botleft/botright
|
||||
"
|
||||
function! s:FloatingWindow.open(args) abort
|
||||
let l:style = {
|
||||
\ 'row': a:args.row,
|
||||
\ 'col': a:args.col,
|
||||
\ 'width': a:args.width,
|
||||
\ 'height': a:args.height,
|
||||
\ 'border': get(a:args, 'border', v:false),
|
||||
\ 'topline': get(a:args, 'topline', 1),
|
||||
\ 'origin': get(a:args, 'origin', 'topleft'),
|
||||
\ }
|
||||
|
||||
let l:will_move = self.is_visible()
|
||||
if l:will_move
|
||||
let self._winid = s:_move(self, self._winid, self._bufnr, l:style)
|
||||
else
|
||||
let self._winid = s:_open(self._bufnr, l:style, { -> self._on_closed() })
|
||||
endif
|
||||
for [l:key, l:value] in items(self._vars)
|
||||
call setwinvar(self._winid, l:key, l:value)
|
||||
endfor
|
||||
if !l:will_move
|
||||
call s:_notify_opened(self._winid, self)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"
|
||||
" close
|
||||
"
|
||||
function! s:FloatingWindow.close() abort
|
||||
if self.is_visible()
|
||||
call s:_close(self._winid)
|
||||
endif
|
||||
let self._winid = v:null
|
||||
endfunction
|
||||
|
||||
"
|
||||
" enter
|
||||
"
|
||||
function! s:FloatingWindow.enter() abort
|
||||
call s:_enter(self._winid)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" is_visible
|
||||
"
|
||||
function! s:FloatingWindow.is_visible() abort
|
||||
return s:_exists(self._winid) ? v:true : v:false
|
||||
endfunction
|
||||
|
||||
"
|
||||
" open
|
||||
"
|
||||
if has('nvim')
|
||||
function! s:_open(bufnr, style, callback) abort
|
||||
let l:winid = nvim_open_win(a:bufnr, v:false, s:_style(a:style))
|
||||
call s:Window.scroll(l:winid, a:style.topline)
|
||||
return l:winid
|
||||
endfunction
|
||||
else
|
||||
function! s:_open(bufnr, style, callback) abort
|
||||
return popup_create(a:bufnr, extend(s:_style(a:style), {
|
||||
\ 'callback': a:callback,
|
||||
\ }, 'force'))
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" close
|
||||
"
|
||||
if has('nvim')
|
||||
function! s:_close(winid) abort
|
||||
call nvim_win_close(a:winid, v:true)
|
||||
call s:_notify_closed()
|
||||
endfunction
|
||||
else
|
||||
function! s:_close(winid) abort
|
||||
call popup_close(a:winid)
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" move
|
||||
"
|
||||
if has('nvim')
|
||||
function! s:_move(self, winid, bufnr, style) abort
|
||||
call nvim_win_set_config(a:winid, s:_style(a:style))
|
||||
if a:bufnr != nvim_win_get_buf(a:winid)
|
||||
call nvim_win_set_buf(a:winid, a:bufnr)
|
||||
endif
|
||||
call s:Window.scroll(a:winid, a:style.topline)
|
||||
return a:winid
|
||||
endfunction
|
||||
else
|
||||
function! s:_move(self, winid, bufnr, style) abort
|
||||
" vim's popup window can't change bufnr so open new popup in here.
|
||||
if a:bufnr != winbufnr(a:winid)
|
||||
let l:On_closed = a:self._on_closed
|
||||
let a:self._on_closed = { -> {} }
|
||||
call s:_close(a:winid)
|
||||
let a:self._on_closed = l:On_closed
|
||||
return s:_open(a:bufnr, a:style, { -> a:self._on_closed() })
|
||||
endif
|
||||
let l:style = s:_style(a:style)
|
||||
call popup_move(a:winid, l:style)
|
||||
call popup_setoptions(a:winid, l:style)
|
||||
return a:winid
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" enter
|
||||
"
|
||||
if has('nvim')
|
||||
function! s:_enter(winid) abort
|
||||
call win_gotoid(a:winid)
|
||||
endfunction
|
||||
else
|
||||
function! s:_enter(winid) abort
|
||||
" not supported.
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" exists
|
||||
"
|
||||
if has('nvim')
|
||||
function! s:_exists(winid) abort
|
||||
try
|
||||
return type(a:winid) == type(0) && nvim_win_is_valid(a:winid) && nvim_win_get_number(a:winid) != -1
|
||||
catch /.*/
|
||||
return v:false
|
||||
endtry
|
||||
endfunction
|
||||
else
|
||||
function! s:_exists(winid) abort
|
||||
return type(a:winid) == type(0) && winheight(a:winid) != -1
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" info
|
||||
"
|
||||
if has('nvim')
|
||||
function! s:_info(winid) abort
|
||||
let l:info = getwininfo(a:winid)[0]
|
||||
return {
|
||||
\ 'row': l:info.winrow,
|
||||
\ 'col': l:info.wincol,
|
||||
\ 'width': l:info.width,
|
||||
\ 'height': l:info.height,
|
||||
\ 'topline': l:info.topline,
|
||||
\ }
|
||||
endfunction
|
||||
else
|
||||
function! s:_info(winid) abort
|
||||
let l:pos = popup_getpos(a:winid)
|
||||
return {
|
||||
\ 'row': l:pos.core_line,
|
||||
\ 'col': l:pos.core_col,
|
||||
\ 'width': l:pos.core_width,
|
||||
\ 'height': l:pos.core_height,
|
||||
\ 'topline': l:pos.firstline,
|
||||
\ }
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" style
|
||||
"
|
||||
if has('nvim')
|
||||
function! s:_style(style) abort
|
||||
let l:style = s:_resolve_origin(a:style)
|
||||
let l:style = s:_resolve_border(l:style)
|
||||
let l:style = {
|
||||
\ 'relative': 'editor',
|
||||
\ 'row': l:style.row - 1,
|
||||
\ 'col': l:style.col - 1,
|
||||
\ 'width': l:style.width,
|
||||
\ 'height': l:style.height,
|
||||
\ 'focusable': v:true,
|
||||
\ 'style': 'minimal',
|
||||
\ 'border': has_key(l:style, 'border') ? l:style.border : 'none',
|
||||
\ }
|
||||
if !exists('*win_execute') " We can't detect neovim features via patch version so we try it by function existence.
|
||||
unlet l:style.border
|
||||
endif
|
||||
return l:style
|
||||
endfunction
|
||||
else
|
||||
function! s:_style(style) abort
|
||||
let l:style = s:_resolve_origin(a:style)
|
||||
let l:style = s:_resolve_border(l:style)
|
||||
return {
|
||||
\ 'line': l:style.row,
|
||||
\ 'col': l:style.col,
|
||||
\ 'pos': 'topleft',
|
||||
\ 'wrap': v:false,
|
||||
\ 'moved': [0, 0, 0],
|
||||
\ 'scrollbar': 0,
|
||||
\ 'maxwidth': l:style.width,
|
||||
\ 'maxheight': l:style.height,
|
||||
\ 'minwidth': l:style.width,
|
||||
\ 'minheight': l:style.height,
|
||||
\ 'tabpage': 0,
|
||||
\ 'firstline': l:style.topline,
|
||||
\ 'padding': [0, 0, 0, 0],
|
||||
\ 'border': has_key(l:style, 'border') ? [1, 1, 1, 1] : [0, 0, 0, 0],
|
||||
\ 'borderchars': get(l:style, 'border', []),
|
||||
\ 'fixed': v:true,
|
||||
\ }
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" _resolve_origin
|
||||
"
|
||||
function! s:_resolve_origin(style) abort
|
||||
if index(['topleft', 'topright', 'bottomleft', 'bottomright', 'topcenter', 'bottomcenter'], a:style.origin) == -1
|
||||
let a:style.origin = 'topleft'
|
||||
endif
|
||||
|
||||
if a:style.origin ==# 'topleft'
|
||||
let a:style.col = a:style.col
|
||||
let a:style.row = a:style.row
|
||||
elseif a:style.origin ==# 'topright'
|
||||
let a:style.col = a:style.col - (a:style.width - 1)
|
||||
let a:style.row = a:style.row
|
||||
elseif a:style.origin ==# 'bottomleft'
|
||||
let a:style.col = a:style.col
|
||||
let a:style.row = a:style.row - (a:style.height - 1)
|
||||
elseif a:style.origin ==# 'bottomright'
|
||||
let a:style.col = a:style.col - (a:style.width - 1)
|
||||
let a:style.row = a:style.row - (a:style.height - 1)
|
||||
elseif a:style.origin ==# 'topcenter'
|
||||
let a:style.col = a:style.col - float2nr(a:style.width / 2)
|
||||
let a:style.row = a:style.row
|
||||
elseif a:style.origin ==# 'bottomcenter'
|
||||
let a:style.col = a:style.col - float2nr(a:style.width / 2)
|
||||
let a:style.row = a:style.row - (a:style.height - 1)
|
||||
elseif a:style.origin ==# 'centercenter'
|
||||
let a:style.col = a:style.col - float2nr(a:style.width / 2)
|
||||
let a:style.row = a:style.row - float2nr(a:style.height / 2)
|
||||
endif
|
||||
return a:style
|
||||
endfunction
|
||||
|
||||
if has('nvim')
|
||||
function! s:_resolve_border(style) abort
|
||||
let l:border = get(a:style, 'border', v:null)
|
||||
if !empty(l:border)
|
||||
if type(l:border) != type([])
|
||||
if &ambiwidth ==# 'single'
|
||||
let a:style.border = ['┌', '─', '┐', '│', '┘', '─', '└', '│']
|
||||
else
|
||||
let a:style.border = ['+', '-', '+', '|', '+', '-', '+', '|']
|
||||
endif
|
||||
endif
|
||||
elseif has_key(a:style, 'border')
|
||||
unlet a:style.border
|
||||
endif
|
||||
return a:style
|
||||
endfunction
|
||||
else
|
||||
function! s:_resolve_border(style) abort
|
||||
let l:border = get(a:style, 'border', v:null)
|
||||
if !empty(get(a:style, 'border', v:null))
|
||||
if type(l:border) != type([])
|
||||
if &ambiwidth ==# 'single'
|
||||
let a:style.border = ['─', '│', '─', '│', '┌', '┐', '┘', '└']
|
||||
else
|
||||
let a:style.border = ['-', '|', '-', '|', '+', '+', '+', '+']
|
||||
endif
|
||||
else
|
||||
" Emulate nvim behavior for lists of 1/2/4 elements
|
||||
let l:topleft = l:border[0]
|
||||
let l:top = get(l:border, 1, l:topleft)
|
||||
let l:topright = get(l:border, 2, l:topleft)
|
||||
let l:right = get(l:border, 3, l:top)
|
||||
let l:bottomright = get(l:border, 4, l:topleft)
|
||||
let l:bottom = get(l:border, 5, l:top)
|
||||
let l:bottomleft = get(l:border, 6, l:topright)
|
||||
let l:left = get(l:border, 7, l:right)
|
||||
let a:style.border = [
|
||||
\ l:top, l:right, l:bottom, l:left,
|
||||
\ l:topleft, l:topright, l:bottomright, l:bottomleft,
|
||||
\ ]
|
||||
endif
|
||||
elseif has_key(a:style, 'border')
|
||||
unlet a:style.border
|
||||
endif
|
||||
return a:style
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" init
|
||||
"
|
||||
let s:has_init = v:false
|
||||
let s:filepath = expand('<sfile>:p')
|
||||
function! s:_init() abort
|
||||
if s:has_init || !has('nvim')
|
||||
return
|
||||
endif
|
||||
let s:has_init = v:true
|
||||
execute printf('augroup VS_Vim_Window_FloatingWindow:%s', s:filepath)
|
||||
autocmd!
|
||||
autocmd WinEnter * call <SID>_notify_closed()
|
||||
augroup END
|
||||
endfunction
|
||||
|
||||
Reference in New Issue
Block a user