I broke up with neovim....vim is my best friend now
This commit is contained in:
9
dot_vim/plugged/vim-vsnip/autoload/vital/_vsnip.vim
Normal file
9
dot_vim/plugged/vim-vsnip/autoload/vital/_vsnip.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
let s:_plugin_name = expand('<sfile>:t:r')
|
||||
|
||||
function! vital#{s:_plugin_name}#new() abort
|
||||
return vital#{s:_plugin_name[1:]}#new()
|
||||
endfunction
|
||||
|
||||
function! vital#{s:_plugin_name}#function(funcname) abort
|
||||
silent! return function(a:funcname)
|
||||
endfunction
|
||||
164
dot_vim/plugged/vim-vsnip/autoload/vital/_vsnip/VS/LSP/Diff.vim
Normal file
164
dot_vim/plugged/vim-vsnip/autoload/vital/_vsnip/VS/LSP/Diff.vim
Normal file
@@ -0,0 +1,164 @@
|
||||
" ___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#_vsnip#VS#LSP#Diff#import() abort', printf("return map({'try_enable_lua': '', 'compute': ''}, \"vital#_vsnip#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
"
|
||||
" compute
|
||||
"
|
||||
function! s:compute(old, new) abort
|
||||
let l:old = a:old
|
||||
let l:new = a:new
|
||||
|
||||
let l:old_len = len(l:old)
|
||||
let l:new_len = len(l:new)
|
||||
let l:min_len = min([l:old_len, l:new_len])
|
||||
|
||||
" empty -> empty
|
||||
if l:old_len == 0 && l:new_len == 0
|
||||
return {
|
||||
\ 'range': {
|
||||
\ 'start': {
|
||||
\ 'line': 0,
|
||||
\ 'character': 0,
|
||||
\ },
|
||||
\ 'end': {
|
||||
\ 'line': 0,
|
||||
\ 'character': 0,
|
||||
\ }
|
||||
\ },
|
||||
\ 'text': '',
|
||||
\ 'rangeLength': 0
|
||||
\ }
|
||||
" not empty -> empty
|
||||
elseif l:old_len != 0 && l:new_len == 0
|
||||
return {
|
||||
\ 'range': {
|
||||
\ 'start': {
|
||||
\ 'line': 0,
|
||||
\ 'character': 0,
|
||||
\ },
|
||||
\ 'end': {
|
||||
\ 'line': l:old_len - 1,
|
||||
\ 'character': strchars(l:old[-1]),
|
||||
\ }
|
||||
\ },
|
||||
\ 'text': '',
|
||||
\ 'rangeLength': strchars(join(l:old, "\n"))
|
||||
\ }
|
||||
" empty -> not empty
|
||||
elseif l:old_len == 0 && l:new_len != 0
|
||||
return {
|
||||
\ 'range': {
|
||||
\ 'start': {
|
||||
\ 'line': 0,
|
||||
\ 'character': 0,
|
||||
\ },
|
||||
\ 'end': {
|
||||
\ 'line': 0,
|
||||
\ 'character': 0,
|
||||
\ }
|
||||
\ },
|
||||
\ 'text': join(l:new, "\n"),
|
||||
\ 'rangeLength': 0
|
||||
\ }
|
||||
endif
|
||||
|
||||
if s:is_lua_enabled
|
||||
let [l:first_line, l:last_line] = luaeval('vital_vs_lsp_diff_search_line_region(_A[1], _A[2])', [l:old, l:new])
|
||||
else
|
||||
let l:first_line = 0
|
||||
while l:first_line < l:min_len - 1
|
||||
if l:old[l:first_line] !=# l:new[l:first_line]
|
||||
break
|
||||
endif
|
||||
let l:first_line += 1
|
||||
endwhile
|
||||
|
||||
let l:last_line = -1
|
||||
while l:last_line > -l:min_len + l:first_line
|
||||
if l:old[l:last_line] !=# l:new[l:last_line]
|
||||
break
|
||||
endif
|
||||
let l:last_line -= 1
|
||||
endwhile
|
||||
endif
|
||||
|
||||
let l:old_lines = l:old[l:first_line : l:last_line]
|
||||
let l:new_lines = l:new[l:first_line : l:last_line]
|
||||
let l:old_text = join(l:old_lines, "\n") . "\n"
|
||||
let l:new_text = join(l:new_lines, "\n") . "\n"
|
||||
let l:old_text_len = strchars(l:old_text)
|
||||
let l:new_text_len = strchars(l:new_text)
|
||||
let l:min_text_len = min([l:old_text_len, l:new_text_len])
|
||||
|
||||
let l:first_char = 0
|
||||
for l:first_char in range(0, l:min_text_len - 1)
|
||||
if strgetchar(l:old_text, l:first_char) != strgetchar(l:new_text, l:first_char)
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
let l:last_char = 0
|
||||
for l:last_char in range(0, -l:min_text_len + l:first_char, -1)
|
||||
if strgetchar(l:old_text, l:old_text_len + l:last_char - 1) != strgetchar(l:new_text, l:new_text_len + l:last_char - 1)
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
return {
|
||||
\ 'range': {
|
||||
\ 'start': {
|
||||
\ 'line': l:first_line,
|
||||
\ 'character': l:first_char,
|
||||
\ },
|
||||
\ 'end': {
|
||||
\ 'line': l:old_len + l:last_line,
|
||||
\ 'character': strchars(l:old_lines[-1]) + l:last_char + 1,
|
||||
\ }
|
||||
\ },
|
||||
\ 'text': strcharpart(l:new_text, l:first_char, l:new_text_len + l:last_char - l:first_char),
|
||||
\ 'rangeLength': l:old_text_len + l:last_char - l:first_char
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
function! s:try_enable_lua() abort
|
||||
lua <<EOF
|
||||
function vital_vs_lsp_diff_search_line_region(old, new)
|
||||
local old_len = #old
|
||||
local new_len = #new
|
||||
local min_len = math.min(#old, #new)
|
||||
|
||||
local first_line = 0
|
||||
while first_line < min_len - 1 do
|
||||
if old[first_line + 1] ~= new[first_line + 1] then
|
||||
break
|
||||
end
|
||||
first_line = first_line + 1
|
||||
end
|
||||
|
||||
local last_line = -1
|
||||
while last_line > -min_len + first_line do
|
||||
if old[(old_len + last_line) + 1] ~= new[(new_len + last_line) + 1] then
|
||||
break
|
||||
end
|
||||
last_line = last_line - 1
|
||||
end
|
||||
return { first_line, last_line }
|
||||
end
|
||||
EOF
|
||||
endfunction
|
||||
|
||||
let s:is_lua_enabled = v:false
|
||||
if has('nvim')
|
||||
try
|
||||
call s:try_enable_lua()
|
||||
let s:is_lua_enabled = v:true
|
||||
catch /.*/
|
||||
endtry
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
" ___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#_vsnip#VS#LSP#Position#import() abort', printf("return map({'cursor': '', 'vim_to_lsp': '', 'lsp_to_vim': ''}, \"vital#_vsnip#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
"
|
||||
" cursor
|
||||
"
|
||||
function! s:cursor() abort
|
||||
return s:vim_to_lsp('%', getpos('.')[1 : 3])
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vim_to_lsp
|
||||
"
|
||||
function! s:vim_to_lsp(expr, pos) abort
|
||||
let l:line = s:_get_buffer_line(a:expr, a:pos[0])
|
||||
if l:line is v:null
|
||||
return {
|
||||
\ 'line': a:pos[0] - 1,
|
||||
\ 'character': a:pos[1] - 1
|
||||
\ }
|
||||
endif
|
||||
|
||||
return {
|
||||
\ 'line': a:pos[0] - 1,
|
||||
\ 'character': strchars(strpart(l:line, 0, a:pos[1] - 1))
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
"
|
||||
" lsp_to_vim
|
||||
"
|
||||
function! s:lsp_to_vim(expr, position) abort
|
||||
let l:line = s:_get_buffer_line(a:expr, a:position.line + 1)
|
||||
if l:line is v:null
|
||||
return [a:position.line + 1, a:position.character + 1]
|
||||
endif
|
||||
return [a:position.line + 1, byteidx(l:line, a:position.character) + 1]
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _get_buffer_line
|
||||
"
|
||||
function! s:_get_buffer_line(expr, lnum) abort
|
||||
try
|
||||
let l:expr = bufnr(a:expr)
|
||||
catch /.*/
|
||||
let l:expr = a:expr
|
||||
endtry
|
||||
if bufloaded(l:expr)
|
||||
return get(getbufline(l:expr, a:lnum), 0, v:null)
|
||||
elseif filereadable(a:expr)
|
||||
return get(readfile(a:expr, '', a:lnum), 0, v:null)
|
||||
endif
|
||||
return v:null
|
||||
endfunction
|
||||
|
||||
@@ -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#_vsnip#VS#LSP#Text#import() abort', printf("return map({'normalize_eol': '', 'split_by_eol': ''}, \"vital#_vsnip#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
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
" ___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#_vsnip#VS#LSP#TextEdit#import() abort', printf("return map({'_vital_depends': '', 'apply': '', '_vital_loaded': ''}, \"vital#_vsnip#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')
|
||||
let s:Position = a:V.import('VS.LSP.Position')
|
||||
let s:Buffer = a:V.import('VS.Vim.Buffer')
|
||||
let s:Option = a:V.import('VS.Vim.Option')
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _vital_depends
|
||||
"
|
||||
function! s:_vital_depends() abort
|
||||
return ['VS.LSP.Text', 'VS.LSP.Position', 'VS.Vim.Buffer', 'VS.Vim.Option']
|
||||
endfunction
|
||||
|
||||
"
|
||||
" apply
|
||||
"
|
||||
function! s:apply(path, text_edits) abort
|
||||
let l:current_bufname = bufname('%')
|
||||
let l:current_position = s:Position.cursor()
|
||||
|
||||
let l:target_bufnr = s:_switch(a:path)
|
||||
call s:_substitute(l:target_bufnr, a:text_edits, l:current_position)
|
||||
let l:current_bufnr = s:_switch(l:current_bufname)
|
||||
|
||||
if l:current_bufnr == l:target_bufnr
|
||||
call cursor(s:Position.lsp_to_vim('%', l:current_position))
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _substitute
|
||||
"
|
||||
function! s:_substitute(bufnr, text_edits, current_position) abort
|
||||
try
|
||||
" Save state.
|
||||
let l:Restore = s:Option.define({
|
||||
\ 'foldenable': '0',
|
||||
\ })
|
||||
let l:view = winsaveview()
|
||||
|
||||
" Apply substitute.
|
||||
let [l:fixeol, l:text_edits] = s:_normalize(a:bufnr, a:text_edits)
|
||||
for l:text_edit in l:text_edits
|
||||
let l:start = s:Position.lsp_to_vim(a:bufnr, l:text_edit.range.start)
|
||||
let l:end = s:Position.lsp_to_vim(a:bufnr, l:text_edit.range.end)
|
||||
let l:text = s:Text.normalize_eol(l:text_edit.newText)
|
||||
execute printf('noautocmd keeppatterns keepjumps silent %ssubstitute/\%%%sl\%%%sc\_.\{-}\%%%sl\%%%sc/\=l:text/%se',
|
||||
\ l:start[0],
|
||||
\ l:start[0],
|
||||
\ l:start[1],
|
||||
\ l:end[0],
|
||||
\ l:end[1],
|
||||
\ &gdefault ? 'g' : ''
|
||||
\ )
|
||||
call s:_fix_cursor_position(a:current_position, l:text_edit, s:Text.split_by_eol(l:text))
|
||||
endfor
|
||||
|
||||
" Remove last empty line if fixeol enabled.
|
||||
if l:fixeol && getline('$') ==# ''
|
||||
noautocmd keeppatterns keepjumps silent $delete _
|
||||
endif
|
||||
catch /.*/
|
||||
echomsg string({ 'exception': v:exception, 'throwpoint': v:throwpoint })
|
||||
finally
|
||||
" Restore state.
|
||||
call l:Restore()
|
||||
call winrestview(l:view)
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _fix_cursor_position
|
||||
"
|
||||
function! s:_fix_cursor_position(position, text_edit, lines) abort
|
||||
let l:lines_len = len(a:lines)
|
||||
let l:range_len = (a:text_edit.range.end.line - a:text_edit.range.start.line) + 1
|
||||
|
||||
if a:text_edit.range.end.line < a:position.line
|
||||
let a:position.line += l:lines_len - l:range_len
|
||||
elseif a:text_edit.range.end.line == a:position.line && a:text_edit.range.end.character <= a:position.character
|
||||
let a:position.line += l:lines_len - l:range_len
|
||||
let a:position.character = strchars(a:lines[-1]) + (a:position.character - a:text_edit.range.end.character)
|
||||
if l:lines_len == 1
|
||||
let a:position.character += a:text_edit.range.start.character
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _normalize
|
||||
"
|
||||
function! s:_normalize(bufnr, text_edits) abort
|
||||
let l:text_edits = type(a:text_edits) == type([]) ? a:text_edits : [a:text_edits]
|
||||
let l:text_edits = s:_range(l:text_edits)
|
||||
let l:text_edits = sort(l:text_edits, function('s:_compare'))
|
||||
let l:text_edits = reverse(l:text_edits)
|
||||
return s:_fix_text_edits(a:bufnr, l:text_edits)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _range
|
||||
"
|
||||
function! s:_range(text_edits) abort
|
||||
let l:text_edits = []
|
||||
for l:text_edit in a:text_edits
|
||||
if type(l:text_edit) != type({})
|
||||
continue
|
||||
endif
|
||||
if l:text_edit.range.start.line > l:text_edit.range.end.line || (
|
||||
\ l:text_edit.range.start.line == l:text_edit.range.end.line &&
|
||||
\ l:text_edit.range.start.character > l:text_edit.range.end.character
|
||||
\ )
|
||||
let l:text_edit.range = { 'start': l:text_edit.range.end, 'end': l:text_edit.range.start }
|
||||
endif
|
||||
let l:text_edits += [l:text_edit]
|
||||
endfor
|
||||
return l:text_edits
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _compare
|
||||
"
|
||||
function! s:_compare(text_edit1, text_edit2) abort
|
||||
let l:diff = a:text_edit1.range.start.line - a:text_edit2.range.start.line
|
||||
if l:diff == 0
|
||||
return a:text_edit1.range.start.character - a:text_edit2.range.start.character
|
||||
endif
|
||||
return l:diff
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _fix_text_edits
|
||||
"
|
||||
function! s:_fix_text_edits(bufnr, text_edits) abort
|
||||
let l:max = s:Buffer.get_line_count(a:bufnr)
|
||||
|
||||
let l:fixeol = v:false
|
||||
let l:text_edits = []
|
||||
for l:text_edit in a:text_edits
|
||||
if l:max <= l:text_edit.range.start.line
|
||||
let l:text_edit.range.start.line = l:max - 1
|
||||
let l:text_edit.range.start.character = strchars(get(getbufline(a:bufnr, '$'), 0, ''))
|
||||
let l:text_edit.newText = "\n" . l:text_edit.newText
|
||||
let l:fixeol = &fixendofline && !&binary
|
||||
endif
|
||||
if l:max <= l:text_edit.range.end.line
|
||||
let l:text_edit.range.end.line = l:max - 1
|
||||
let l:text_edit.range.end.character = strchars(get(getbufline(a:bufnr, '$'), 0, ''))
|
||||
let l:fixeol = &fixendofline && !&binary
|
||||
endif
|
||||
call add(l:text_edits, l:text_edit)
|
||||
endfor
|
||||
|
||||
return [l:fixeol, l:text_edits]
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _switch
|
||||
"
|
||||
function! s:_switch(path) abort
|
||||
let l:curr = bufnr('%')
|
||||
let l:next = bufnr(a:path)
|
||||
if l:next >= 0
|
||||
if l:curr != l:next
|
||||
execute printf('noautocmd keepalt keepjumps %sbuffer!', bufnr(a:path))
|
||||
endif
|
||||
else
|
||||
execute printf('noautocmd keepalt keepjumps edit! %s', fnameescape(a:path))
|
||||
endif
|
||||
return bufnr('%')
|
||||
endfunction
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
" ___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#_vsnip#VS#Vim#Buffer#import() abort', printf("return map({'get_line_count': '', 'do': '', 'create': '', 'pseudo': '', 'ensure': '', 'load': ''}, \"vital#_vsnip#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
|
||||
badd `=a:expr`
|
||||
endif
|
||||
return bufnr(a:expr)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" 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,21 @@
|
||||
" ___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#_vsnip#VS#Vim#Option#import() abort', printf("return map({'define': ''}, \"vital#_vsnip#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
"
|
||||
" define
|
||||
"
|
||||
function! s:define(map) abort
|
||||
let l:old = {}
|
||||
for [l:key, l:value] in items(a:map)
|
||||
let l:old[l:key] = eval(printf('&%s', l:key))
|
||||
execute printf('let &%s = "%s"', l:key, l:value)
|
||||
endfor
|
||||
return { -> s:define(l:old) }
|
||||
endfunction
|
||||
|
||||
330
dot_vim/plugged/vim-vsnip/autoload/vital/vsnip.vim
Normal file
330
dot_vim/plugged/vim-vsnip/autoload/vital/vsnip.vim
Normal file
@@ -0,0 +1,330 @@
|
||||
let s:plugin_name = expand('<sfile>:t:r')
|
||||
let s:vital_base_dir = expand('<sfile>:h')
|
||||
let s:project_root = expand('<sfile>:h:h:h')
|
||||
let s:is_vital_vim = s:plugin_name is# 'vital'
|
||||
|
||||
let s:loaded = {}
|
||||
let s:cache_sid = {}
|
||||
|
||||
function! vital#{s:plugin_name}#new() abort
|
||||
return s:new(s:plugin_name)
|
||||
endfunction
|
||||
|
||||
function! vital#{s:plugin_name}#import(...) abort
|
||||
if !exists('s:V')
|
||||
let s:V = s:new(s:plugin_name)
|
||||
endif
|
||||
return call(s:V.import, a:000, s:V)
|
||||
endfunction
|
||||
|
||||
let s:Vital = {}
|
||||
|
||||
function! s:new(plugin_name) abort
|
||||
let base = deepcopy(s:Vital)
|
||||
let base._plugin_name = a:plugin_name
|
||||
return base
|
||||
endfunction
|
||||
|
||||
function! s:vital_files() abort
|
||||
if !exists('s:vital_files')
|
||||
let s:vital_files = map(
|
||||
\ s:is_vital_vim ? s:_global_vital_files() : s:_self_vital_files(),
|
||||
\ 'fnamemodify(v:val, ":p:gs?[\\\\/]?/?")')
|
||||
endif
|
||||
return copy(s:vital_files)
|
||||
endfunction
|
||||
let s:Vital.vital_files = function('s:vital_files')
|
||||
|
||||
function! s:import(name, ...) abort dict
|
||||
let target = {}
|
||||
let functions = []
|
||||
for a in a:000
|
||||
if type(a) == type({})
|
||||
let target = a
|
||||
elseif type(a) == type([])
|
||||
let functions = a
|
||||
endif
|
||||
unlet a
|
||||
endfor
|
||||
let module = self._import(a:name)
|
||||
if empty(functions)
|
||||
call extend(target, module, 'keep')
|
||||
else
|
||||
for f in functions
|
||||
if has_key(module, f) && !has_key(target, f)
|
||||
let target[f] = module[f]
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
return target
|
||||
endfunction
|
||||
let s:Vital.import = function('s:import')
|
||||
|
||||
function! s:load(...) abort dict
|
||||
for arg in a:000
|
||||
let [name; as] = type(arg) == type([]) ? arg[: 1] : [arg, arg]
|
||||
let target = split(join(as, ''), '\W\+')
|
||||
let dict = self
|
||||
let dict_type = type({})
|
||||
while !empty(target)
|
||||
let ns = remove(target, 0)
|
||||
if !has_key(dict, ns)
|
||||
let dict[ns] = {}
|
||||
endif
|
||||
if type(dict[ns]) == dict_type
|
||||
let dict = dict[ns]
|
||||
else
|
||||
unlet dict
|
||||
break
|
||||
endif
|
||||
endwhile
|
||||
if exists('dict')
|
||||
call extend(dict, self._import(name))
|
||||
endif
|
||||
unlet arg
|
||||
endfor
|
||||
return self
|
||||
endfunction
|
||||
let s:Vital.load = function('s:load')
|
||||
|
||||
function! s:unload() abort dict
|
||||
let s:loaded = {}
|
||||
let s:cache_sid = {}
|
||||
unlet! s:vital_files
|
||||
endfunction
|
||||
let s:Vital.unload = function('s:unload')
|
||||
|
||||
function! s:exists(name) abort dict
|
||||
if a:name !~# '\v^\u\w*%(\.\u\w*)*$'
|
||||
throw 'vital: Invalid module name: ' . a:name
|
||||
endif
|
||||
return s:_module_path(a:name) isnot# ''
|
||||
endfunction
|
||||
let s:Vital.exists = function('s:exists')
|
||||
|
||||
function! s:search(pattern) abort dict
|
||||
let paths = s:_extract_files(a:pattern, self.vital_files())
|
||||
let modules = sort(map(paths, 's:_file2module(v:val)'))
|
||||
return uniq(modules)
|
||||
endfunction
|
||||
let s:Vital.search = function('s:search')
|
||||
|
||||
function! s:plugin_name() abort dict
|
||||
return self._plugin_name
|
||||
endfunction
|
||||
let s:Vital.plugin_name = function('s:plugin_name')
|
||||
|
||||
function! s:_self_vital_files() abort
|
||||
let builtin = printf('%s/__%s__/', s:vital_base_dir, s:plugin_name)
|
||||
let installed = printf('%s/_%s/', s:vital_base_dir, s:plugin_name)
|
||||
let base = builtin . ',' . installed
|
||||
return split(globpath(base, '**/*.vim', 1), "\n")
|
||||
endfunction
|
||||
|
||||
function! s:_global_vital_files() abort
|
||||
let pattern = 'autoload/vital/__*__/**/*.vim'
|
||||
return split(globpath(&runtimepath, pattern, 1), "\n")
|
||||
endfunction
|
||||
|
||||
function! s:_extract_files(pattern, files) abort
|
||||
let tr = {'.': '/', '*': '[^/]*', '**': '.*'}
|
||||
let target = substitute(a:pattern, '\.\|\*\*\?', '\=tr[submatch(0)]', 'g')
|
||||
let regexp = printf('autoload/vital/[^/]\+/%s.vim$', target)
|
||||
return filter(a:files, 'v:val =~# regexp')
|
||||
endfunction
|
||||
|
||||
function! s:_file2module(file) abort
|
||||
let filename = fnamemodify(a:file, ':p:gs?[\\/]?/?')
|
||||
let tail = matchstr(filename, 'autoload/vital/_\w\+/\zs.*\ze\.vim$')
|
||||
return join(split(tail, '[\\/]\+'), '.')
|
||||
endfunction
|
||||
|
||||
" @param {string} name e.g. Data.List
|
||||
function! s:_import(name) abort dict
|
||||
if has_key(s:loaded, a:name)
|
||||
return copy(s:loaded[a:name])
|
||||
endif
|
||||
let module = self._get_module(a:name)
|
||||
if has_key(module, '_vital_created')
|
||||
call module._vital_created(module)
|
||||
endif
|
||||
let export_module = filter(copy(module), 'v:key =~# "^\\a"')
|
||||
" Cache module before calling module._vital_loaded() to avoid cyclic
|
||||
" dependences but remove the cache if module._vital_loaded() fails.
|
||||
" let s:loaded[a:name] = export_module
|
||||
let s:loaded[a:name] = export_module
|
||||
if has_key(module, '_vital_loaded')
|
||||
try
|
||||
call module._vital_loaded(vital#{s:plugin_name}#new())
|
||||
catch
|
||||
unlet s:loaded[a:name]
|
||||
throw 'vital: fail to call ._vital_loaded(): ' . v:exception . " from:\n" . s:_format_throwpoint(v:throwpoint)
|
||||
endtry
|
||||
endif
|
||||
return copy(s:loaded[a:name])
|
||||
endfunction
|
||||
let s:Vital._import = function('s:_import')
|
||||
|
||||
function! s:_format_throwpoint(throwpoint) abort
|
||||
let funcs = []
|
||||
let stack = matchstr(a:throwpoint, '^function \zs.*, .\{-} \d\+$')
|
||||
for line in split(stack, '\.\.')
|
||||
let m = matchlist(line, '^\(.\+\)\%(\[\(\d\+\)\]\|, .\{-} \(\d\+\)\)$')
|
||||
if !empty(m)
|
||||
let [name, lnum, lnum2] = m[1:3]
|
||||
if empty(lnum)
|
||||
let lnum = lnum2
|
||||
endif
|
||||
let info = s:_get_func_info(name)
|
||||
if !empty(info)
|
||||
let attrs = empty(info.attrs) ? '' : join([''] + info.attrs)
|
||||
let flnum = info.lnum == 0 ? '' : printf(' Line:%d', info.lnum + lnum)
|
||||
call add(funcs, printf('function %s(...)%s Line:%d (%s%s)',
|
||||
\ info.funcname, attrs, lnum, info.filename, flnum))
|
||||
continue
|
||||
endif
|
||||
endif
|
||||
" fallback when function information cannot be detected
|
||||
call add(funcs, line)
|
||||
endfor
|
||||
return join(funcs, "\n")
|
||||
endfunction
|
||||
|
||||
function! s:_get_func_info(name) abort
|
||||
let name = a:name
|
||||
if a:name =~# '^\d\+$' " is anonymous-function
|
||||
let name = printf('{%s}', a:name)
|
||||
elseif a:name =~# '^<lambda>\d\+$' " is lambda-function
|
||||
let name = printf("{'%s'}", a:name)
|
||||
endif
|
||||
if !exists('*' . name)
|
||||
return {}
|
||||
endif
|
||||
let body = execute(printf('verbose function %s', name))
|
||||
let lines = split(body, "\n")
|
||||
let signature = matchstr(lines[0], '^\s*\zs.*')
|
||||
let [_, file, lnum; __] = matchlist(lines[1],
|
||||
\ '^\t\%(Last set from\|.\{-}:\)\s*\zs\(.\{-}\)\%( \S\+ \(\d\+\)\)\?$')
|
||||
return {
|
||||
\ 'filename': substitute(file, '[/\\]\+', '/', 'g'),
|
||||
\ 'lnum': 0 + lnum,
|
||||
\ 'funcname': a:name,
|
||||
\ 'arguments': split(matchstr(signature, '(\zs.*\ze)'), '\s*,\s*'),
|
||||
\ 'attrs': filter(['dict', 'abort', 'range', 'closure'], 'signature =~# (").*" . v:val)'),
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
" s:_get_module() returns module object wihch has all script local functions.
|
||||
function! s:_get_module(name) abort dict
|
||||
let funcname = s:_import_func_name(self.plugin_name(), a:name)
|
||||
try
|
||||
return call(funcname, [])
|
||||
catch /^Vim\%((\a\+)\)\?:E117:/
|
||||
return s:_get_builtin_module(a:name)
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! s:_get_builtin_module(name) abort
|
||||
return s:sid2sfuncs(s:_module_sid(a:name))
|
||||
endfunction
|
||||
|
||||
if s:is_vital_vim
|
||||
" For vital.vim, we can use s:_get_builtin_module directly
|
||||
let s:Vital._get_module = function('s:_get_builtin_module')
|
||||
else
|
||||
let s:Vital._get_module = function('s:_get_module')
|
||||
endif
|
||||
|
||||
function! s:_import_func_name(plugin_name, module_name) abort
|
||||
return printf('vital#_%s#%s#import', a:plugin_name, s:_dot_to_sharp(a:module_name))
|
||||
endfunction
|
||||
|
||||
function! s:_module_sid(name) abort
|
||||
let path = s:_module_path(a:name)
|
||||
if !filereadable(path)
|
||||
throw 'vital: module not found: ' . a:name
|
||||
endif
|
||||
let vital_dir = s:is_vital_vim ? '__\w\+__' : printf('_\{1,2}%s\%%(__\)\?', s:plugin_name)
|
||||
let base = join([vital_dir, ''], '[/\\]\+')
|
||||
let p = base . substitute('' . a:name, '\.', '[/\\\\]\\+', 'g')
|
||||
let sid = s:_sid(path, p)
|
||||
if !sid
|
||||
call s:_source(path)
|
||||
let sid = s:_sid(path, p)
|
||||
if !sid
|
||||
throw printf('vital: cannot get <SID> from path: %s', path)
|
||||
endif
|
||||
endif
|
||||
return sid
|
||||
endfunction
|
||||
|
||||
function! s:_module_path(name) abort
|
||||
return get(s:_extract_files(a:name, s:vital_files()), 0, '')
|
||||
endfunction
|
||||
|
||||
function! s:_module_sid_base_dir() abort
|
||||
return s:is_vital_vim ? &rtp : s:project_root
|
||||
endfunction
|
||||
|
||||
function! s:_dot_to_sharp(name) abort
|
||||
return substitute(a:name, '\.', '#', 'g')
|
||||
endfunction
|
||||
|
||||
function! s:_source(path) abort
|
||||
execute 'source' fnameescape(a:path)
|
||||
endfunction
|
||||
|
||||
" @vimlint(EVL102, 1, l:_)
|
||||
" @vimlint(EVL102, 1, l:__)
|
||||
function! s:_sid(path, filter_pattern) abort
|
||||
let unified_path = s:_unify_path(a:path)
|
||||
if has_key(s:cache_sid, unified_path)
|
||||
return s:cache_sid[unified_path]
|
||||
endif
|
||||
for line in filter(split(execute(':scriptnames'), "\n"), 'v:val =~# a:filter_pattern')
|
||||
let [_, sid, path; __] = matchlist(line, '^\s*\(\d\+\):\s\+\(.\+\)\s*$')
|
||||
if s:_unify_path(path) is# unified_path
|
||||
let s:cache_sid[unified_path] = sid
|
||||
return s:cache_sid[unified_path]
|
||||
endif
|
||||
endfor
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
if filereadable(expand('<sfile>:r') . '.VIM') " is case-insensitive or not
|
||||
let s:_unify_path_cache = {}
|
||||
" resolve() is slow, so we cache results.
|
||||
" Note: On windows, vim can't expand path names from 8.3 formats.
|
||||
" So if getting full path via <sfile> and $HOME was set as 8.3 format,
|
||||
" vital load duplicated scripts. Below's :~ avoid this issue.
|
||||
function! s:_unify_path(path) abort
|
||||
if has_key(s:_unify_path_cache, a:path)
|
||||
return s:_unify_path_cache[a:path]
|
||||
endif
|
||||
let value = tolower(fnamemodify(resolve(fnamemodify(
|
||||
\ a:path, ':p')), ':~:gs?[\\/]?/?'))
|
||||
let s:_unify_path_cache[a:path] = value
|
||||
return value
|
||||
endfunction
|
||||
else
|
||||
function! s:_unify_path(path) abort
|
||||
return resolve(fnamemodify(a:path, ':p:gs?[\\/]?/?'))
|
||||
endfunction
|
||||
endif
|
||||
|
||||
" copied and modified from Vim.ScriptLocal
|
||||
let s:SNR = join(map(range(len("\<SNR>")), '"[\\x" . printf("%0x", char2nr("\<SNR>"[v:val])) . "]"'), '')
|
||||
function! s:sid2sfuncs(sid) abort
|
||||
let fs = split(execute(printf(':function /^%s%s_', s:SNR, a:sid)), "\n")
|
||||
let r = {}
|
||||
let pattern = printf('\m^function\s<SNR>%d_\zs\w\{-}\ze(', a:sid)
|
||||
for fname in map(fs, 'matchstr(v:val, pattern)')
|
||||
let r[fname] = function(s:_sfuncname(a:sid, fname))
|
||||
endfor
|
||||
return r
|
||||
endfunction
|
||||
|
||||
"" Return funcname of script local functions with SID
|
||||
function! s:_sfuncname(sid, funcname) abort
|
||||
return printf('<SNR>%s_%s', a:sid, a:funcname)
|
||||
endfunction
|
||||
6
dot_vim/plugged/vim-vsnip/autoload/vital/vsnip.vital
Normal file
6
dot_vim/plugged/vim-vsnip/autoload/vital/vsnip.vital
Normal file
@@ -0,0 +1,6 @@
|
||||
vsnip
|
||||
2755f0c8fbd3442bcb7f567832e4d1455b57f9a2
|
||||
|
||||
VS.LSP.TextEdit
|
||||
VS.LSP.Diff
|
||||
VS.LSP.Position
|
||||
243
dot_vim/plugged/vim-vsnip/autoload/vsnip.vim
Normal file
243
dot_vim/plugged/vim-vsnip/autoload/vsnip.vim
Normal file
@@ -0,0 +1,243 @@
|
||||
let s:Session = vsnip#session#import()
|
||||
let s:Snippet = vsnip#snippet#import()
|
||||
let s:TextEdit = vital#vsnip#import('VS.LSP.TextEdit')
|
||||
let s:Position = vital#vsnip#import('VS.LSP.Position')
|
||||
|
||||
let s:session = v:null
|
||||
let s:selected_text = ''
|
||||
|
||||
let g:vsnip#DeactivateOn = {}
|
||||
let g:vsnip#DeactivateOn.OutsideOfSnippet = 1
|
||||
let g:vsnip#DeactivateOn.OutsideOfCurrentTabstop = 2
|
||||
|
||||
"
|
||||
" vsnip#selected_text.
|
||||
"
|
||||
function! vsnip#selected_text(...) abort
|
||||
if len(a:000) == 1
|
||||
let s:selected_text = a:000[0]
|
||||
else
|
||||
return s:selected_text
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#available.
|
||||
"
|
||||
function! vsnip#available(...) abort
|
||||
let l:direction = get(a:000, 0, 1)
|
||||
return vsnip#expandable() || vsnip#jumpable(l:direction)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#expandable.
|
||||
"
|
||||
function! vsnip#expandable() abort
|
||||
return !empty(vsnip#get_context())
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#jumpable.
|
||||
"
|
||||
function! vsnip#jumpable(...) abort
|
||||
let l:direction = get(a:000, 0, 1)
|
||||
return !empty(s:session) && s:session.jumpable(l:direction)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#expand
|
||||
"
|
||||
function! vsnip#expand() abort
|
||||
let l:context = vsnip#get_context()
|
||||
if !empty(l:context)
|
||||
call s:TextEdit.apply(bufnr('%'), [{
|
||||
\ 'range': l:context.range,
|
||||
\ 'newText': ''
|
||||
\ }])
|
||||
call vsnip#anonymous(join(l:context.snippet.body, "\n"), {
|
||||
\ 'position': l:context.range.start
|
||||
\ })
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#anonymous.
|
||||
"
|
||||
function! vsnip#anonymous(text, ...) abort
|
||||
let l:option = get(a:000, 0, {})
|
||||
let l:prefix = get(l:option, 'prefix', v:null)
|
||||
let l:position = get(l:option, 'position', s:Position.cursor())
|
||||
|
||||
if l:prefix isnot# v:null
|
||||
let l:position.character -= strchars(l:prefix)
|
||||
call s:TextEdit.apply(bufnr('%'), [{
|
||||
\ 'range': {
|
||||
\ 'start': l:position,
|
||||
\ 'end': {
|
||||
\ 'line': l:position.line,
|
||||
\ 'character': l:position.character + strchars(l:prefix),
|
||||
\ },
|
||||
\ },
|
||||
\ 'newText': ''
|
||||
\ }])
|
||||
endif
|
||||
|
||||
let l:session = s:Session.new(bufnr('%'), l:position, a:text)
|
||||
|
||||
call vsnip#selected_text('')
|
||||
|
||||
if !empty(s:session)
|
||||
call s:session.flush_changes() " try to sync buffer content because vsnip#expand maybe remove prefix
|
||||
endif
|
||||
|
||||
if empty(s:session)
|
||||
let s:session = l:session
|
||||
call s:session.expand()
|
||||
else
|
||||
call s:session.merge(l:session)
|
||||
endif
|
||||
|
||||
doautocmd <nomodeline> User vsnip#expand
|
||||
|
||||
call s:session.refresh()
|
||||
call s:session.jump(1)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#get_session
|
||||
"
|
||||
function! vsnip#get_session() abort
|
||||
return s:session
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#deactivate
|
||||
"
|
||||
function! vsnip#deactivate() abort
|
||||
let s:session = {}
|
||||
endfunction
|
||||
|
||||
"
|
||||
" get_context.
|
||||
"
|
||||
function! vsnip#get_context() abort
|
||||
let l:offset = mode()[0] ==# 'i' ? 2 : 1
|
||||
let l:before_text = getline('.')[0 : col('.') - l:offset]
|
||||
let l:before_text_len = strchars(l:before_text)
|
||||
|
||||
if l:before_text_len == 0
|
||||
return {}
|
||||
endif
|
||||
|
||||
let l:sources = vsnip#source#find(bufnr('%'))
|
||||
|
||||
" Search prefix
|
||||
for l:source in l:sources
|
||||
for l:snippet in l:source
|
||||
for l:prefix in l:snippet.prefix
|
||||
let l:prefix_len = strchars(l:prefix)
|
||||
if strcharpart(l:before_text, l:before_text_len - l:prefix_len, l:prefix_len) !=# l:prefix
|
||||
continue
|
||||
endif
|
||||
if l:prefix =~# '^\h' && l:before_text !~# '\<\V' . escape(l:prefix, '\/?') . '\m$'
|
||||
continue
|
||||
endif
|
||||
return s:create_context(l:snippet, l:before_text_len, l:prefix_len)
|
||||
endfor
|
||||
endfor
|
||||
endfor
|
||||
|
||||
" Search prefix-alias
|
||||
for l:source in l:sources
|
||||
for l:snippet in l:source
|
||||
for l:prefix in l:snippet.prefix_alias
|
||||
let l:prefix_len = strchars(l:prefix)
|
||||
if strcharpart(l:before_text, l:before_text_len - l:prefix_len, l:prefix_len) !=# l:prefix
|
||||
continue
|
||||
endif
|
||||
if l:prefix =~# '^\h' && l:before_text !~# '\<\V' . escape(l:prefix, '\/?') . '\m$'
|
||||
continue
|
||||
endif
|
||||
return s:create_context(l:snippet, l:before_text_len, l:prefix_len)
|
||||
endfor
|
||||
endfor
|
||||
endfor
|
||||
|
||||
return {}
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#get_complete_items
|
||||
"
|
||||
function! vsnip#get_complete_items(bufnr) abort
|
||||
let l:uniq = {}
|
||||
let l:candidates = []
|
||||
|
||||
for l:source in vsnip#source#find(a:bufnr)
|
||||
for l:snippet in l:source
|
||||
for l:prefix in l:snippet.prefix
|
||||
if has_key(l:uniq, l:prefix)
|
||||
continue
|
||||
endif
|
||||
let l:uniq[l:prefix] = v:true
|
||||
|
||||
let l:menu = ''
|
||||
let l:menu .= '[v]'
|
||||
let l:menu .= ' '
|
||||
let l:menu .= (strlen(l:snippet.description) > 0 ? l:snippet.description : l:snippet.label)
|
||||
|
||||
call add(l:candidates, {
|
||||
\ 'word': l:prefix,
|
||||
\ 'abbr': l:prefix,
|
||||
\ 'kind': 'Snippet',
|
||||
\ 'menu': l:menu,
|
||||
\ 'dup': 1,
|
||||
\ 'user_data': json_encode({
|
||||
\ 'vsnip': {
|
||||
\ 'snippet': l:snippet.body
|
||||
\ }
|
||||
\ })
|
||||
\ })
|
||||
endfor
|
||||
endfor
|
||||
endfor
|
||||
|
||||
return l:candidates
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#decode
|
||||
"
|
||||
function! vsnip#to_string(text) abort
|
||||
let l:text = type(a:text) == type([]) ? join(a:text, "\n") : a:text
|
||||
return s:Snippet.new(s:Position.cursor(), l:text).text()
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#debug
|
||||
"
|
||||
function! vsnip#debug() abort
|
||||
if !empty(s:session)
|
||||
call s:session.snippet.debug()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"
|
||||
" create_context
|
||||
"
|
||||
function! s:create_context(snippet, before_text_len, prefix_len) abort
|
||||
let l:line = line('.') - 1
|
||||
return {
|
||||
\ 'range': {
|
||||
\ 'start': {
|
||||
\ 'line': l:line,
|
||||
\ 'character': a:before_text_len - a:prefix_len
|
||||
\ },
|
||||
\ 'end': {
|
||||
\ 'line': l:line,
|
||||
\ 'character': a:before_text_len
|
||||
\ }
|
||||
\ },
|
||||
\ 'snippet': a:snippet
|
||||
\ }
|
||||
endfunction
|
||||
61
dot_vim/plugged/vim-vsnip/autoload/vsnip/indent.vim
Normal file
61
dot_vim/plugged/vim-vsnip/autoload/vsnip/indent.vim
Normal file
@@ -0,0 +1,61 @@
|
||||
"
|
||||
" vsnip#indent#get_one_indent
|
||||
"
|
||||
function! vsnip#indent#get_one_indent() abort
|
||||
return !&expandtab ? "\t" : repeat(' ', &shiftwidth ? &shiftwidth : &tabstop)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#indent#get_base_indent
|
||||
"
|
||||
function! vsnip#indent#get_base_indent(text) abort
|
||||
return matchstr(a:text, '^\s*')
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#indent#adjust_snippet_body
|
||||
"
|
||||
function! vsnip#indent#adjust_snippet_body(line, text) abort
|
||||
let l:one_indent = vsnip#indent#get_one_indent()
|
||||
let l:base_indent = vsnip#indent#get_base_indent(a:line)
|
||||
let l:text = a:text
|
||||
if l:one_indent !=# "\t"
|
||||
while match(l:text, "\\%(^\\|\n\\)\\s*\\zs\\t") != -1
|
||||
let l:text = substitute(l:text, "\\%(^\\|\n\\)\\s*\\zs\\t", l:one_indent, 'g') " convert \t as one indent
|
||||
endwhile
|
||||
endif
|
||||
let l:text = substitute(l:text, "\n\\zs", l:base_indent, 'g') " add base_indent for all lines
|
||||
let l:text = substitute(l:text, "\n\\s*\\ze\n", "\n", 'g') " remove empty line's indent
|
||||
return l:text
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#indent#trim_base_indent
|
||||
"
|
||||
function! vsnip#indent#trim_base_indent(text) abort
|
||||
let l:is_char_wise = match(a:text, "\n$") == -1
|
||||
let l:text = substitute(a:text, "\n$", '', 'g')
|
||||
|
||||
let l:is_first_line = v:true
|
||||
let l:base_indent = ''
|
||||
for l:line in split(l:text, "\n", v:true)
|
||||
" Ignore the first line when the text created as char-wise.
|
||||
if l:is_char_wise && l:is_first_line
|
||||
let l:is_first_line = v:false
|
||||
continue
|
||||
endif
|
||||
|
||||
" Ignore empty line.
|
||||
if l:line ==# ''
|
||||
continue
|
||||
endif
|
||||
|
||||
" Detect most minimum base indent.
|
||||
let l:indent = matchstr(l:line, '^\s*')
|
||||
if l:base_indent ==# '' || strlen(l:indent) < strlen(l:base_indent)
|
||||
let l:base_indent = l:indent
|
||||
endif
|
||||
endfor
|
||||
return substitute(l:text, "\\%(^\\|\n\\)\\zs\\V" . l:base_indent, '', 'g')
|
||||
endfunction
|
||||
|
||||
223
dot_vim/plugged/vim-vsnip/autoload/vsnip/parser/combinator.vim
Normal file
223
dot_vim/plugged/vim-vsnip/autoload/vsnip/parser/combinator.vim
Normal file
@@ -0,0 +1,223 @@
|
||||
function! vsnip#parser#combinator#import() abort
|
||||
return {
|
||||
\ 'skip': function('s:skip'),
|
||||
\ 'token': function('s:token'),
|
||||
\ 'many': function('s:many'),
|
||||
\ 'or': function('s:or'),
|
||||
\ 'seq': function('s:seq'),
|
||||
\ 'pattern': function('s:pattern'),
|
||||
\ 'lazy': function('s:lazy'),
|
||||
\ 'option': function('s:option'),
|
||||
\ 'map': function('s:map')
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
"
|
||||
" string.
|
||||
"
|
||||
function! s:skip(stop, escape) abort
|
||||
let l:fn = {}
|
||||
let l:fn.stop = a:stop
|
||||
let l:fn.escape = a:escape
|
||||
function! l:fn.parse(text, pos) abort
|
||||
let l:pos = a:pos
|
||||
let l:value = ''
|
||||
|
||||
let l:len = strchars(a:text)
|
||||
while l:pos < l:len
|
||||
let l:char = s:getchar(a:text, l:pos)
|
||||
|
||||
" check escaped stop chars.
|
||||
if l:char ==# '\'
|
||||
let l:pos += 1
|
||||
let l:char = s:getchar(a:text, l:pos)
|
||||
if index(self.stop + self.escape + ['\'], l:char) == -1
|
||||
let l:value .= '\'
|
||||
continue " ignore invalid escape char.
|
||||
endif
|
||||
let l:pos += 1
|
||||
let l:value .= l:char
|
||||
continue
|
||||
endif
|
||||
|
||||
" check stop char.
|
||||
if index(self.stop, l:char) >= 0
|
||||
if a:pos != l:pos
|
||||
return [v:true, [strcharpart(a:text, a:pos, l:pos - a:pos), l:value], l:pos]
|
||||
else
|
||||
return [v:false, v:null, l:pos]
|
||||
endif
|
||||
endif
|
||||
|
||||
let l:value .= l:char
|
||||
let l:pos += 1
|
||||
endwhile
|
||||
|
||||
" everything was string.
|
||||
return [v:true, [strcharpart(a:text, a:pos), l:value], l:len]
|
||||
endfunction
|
||||
return l:fn
|
||||
endfunction
|
||||
|
||||
"
|
||||
" token.
|
||||
"
|
||||
function! s:token(token) abort
|
||||
let l:fn = {}
|
||||
let l:fn.token = a:token
|
||||
function! l:fn.parse(text, pos) abort
|
||||
let l:token_len = strchars(self.token)
|
||||
let l:value = strcharpart(a:text, a:pos, l:token_len)
|
||||
if l:value ==# self.token
|
||||
return [v:true, self.token, a:pos + l:token_len]
|
||||
endif
|
||||
return [v:false, v:null, a:pos]
|
||||
endfunction
|
||||
return l:fn
|
||||
endfunction
|
||||
|
||||
"
|
||||
" many.
|
||||
"
|
||||
function! s:many(parser) abort
|
||||
let l:fn = {}
|
||||
let l:fn.parser = a:parser
|
||||
function! l:fn.parse(text, pos) abort
|
||||
let l:pos = a:pos
|
||||
let l:values = []
|
||||
|
||||
let l:len = strchars(a:text)
|
||||
while l:pos < l:len
|
||||
let l:parsed = self.parser.parse(a:text, l:pos)
|
||||
if l:parsed[0]
|
||||
call add(l:values, l:parsed[1])
|
||||
let l:pos = l:parsed[2]
|
||||
else
|
||||
break
|
||||
endif
|
||||
endwhile
|
||||
if len(l:values) > 0
|
||||
return [v:true, l:values, l:pos]
|
||||
else
|
||||
return [v:false, v:null, l:pos]
|
||||
endif
|
||||
endfunction
|
||||
return l:fn
|
||||
endfunction
|
||||
|
||||
"
|
||||
" or.
|
||||
"
|
||||
function! s:or(...) abort
|
||||
let l:fn = {}
|
||||
let l:fn.parsers = a:000
|
||||
function! l:fn.parse(text, pos) abort
|
||||
for l:parser in self.parsers
|
||||
let l:parsed = l:parser.parse(a:text, a:pos)
|
||||
if l:parsed[0]
|
||||
return l:parsed
|
||||
endif
|
||||
endfor
|
||||
return [v:false, v:null, a:pos]
|
||||
endfunction
|
||||
return l:fn
|
||||
endfunction
|
||||
|
||||
"
|
||||
" seq.
|
||||
"
|
||||
function! s:seq(...) abort
|
||||
let l:fn = {}
|
||||
let l:fn.parsers = a:000
|
||||
function! l:fn.parse(text, pos) abort
|
||||
let l:pos = a:pos
|
||||
let l:values = []
|
||||
for l:parser in self.parsers
|
||||
let l:parsed = l:parser.parse(a:text, l:pos)
|
||||
if !l:parsed[0]
|
||||
return [v:false, v:null, a:pos]
|
||||
endif
|
||||
call add(l:values, l:parsed[1])
|
||||
let l:pos = l:parsed[2]
|
||||
endfor
|
||||
return [v:true, l:values, l:pos]
|
||||
endfunction
|
||||
return l:fn
|
||||
endfunction
|
||||
|
||||
"
|
||||
" lazy.
|
||||
"
|
||||
function! s:lazy(callback) abort
|
||||
let l:fn = {}
|
||||
let l:fn.callback = a:callback
|
||||
function! l:fn.parse(text, pos) abort
|
||||
if !has_key(self, 'parser')
|
||||
let self.parser = self.callback()
|
||||
endif
|
||||
return self.parser.parse(a:text, a:pos)
|
||||
endfunction
|
||||
return l:fn
|
||||
endfunction
|
||||
|
||||
"
|
||||
" pattern.
|
||||
"
|
||||
function! s:pattern(pattern) abort
|
||||
let l:fn = {}
|
||||
let l:fn.pattern = a:pattern[0] ==# '^' ? a:pattern : '^' . a:pattern
|
||||
function! l:fn.parse(text, pos) abort
|
||||
let l:text = strcharpart(a:text, a:pos)
|
||||
let l:matches = matchstrpos(l:text, self.pattern, 0, 1)
|
||||
if l:matches[0] !=# ''
|
||||
return [v:true, l:matches[0], a:pos + l:matches[2]]
|
||||
endif
|
||||
return [v:false, v:null, a:pos]
|
||||
endfunction
|
||||
return l:fn
|
||||
endfunction
|
||||
|
||||
"
|
||||
" map.
|
||||
"
|
||||
function! s:map(parser, callback) abort
|
||||
let l:fn = {}
|
||||
let l:fn.callback = a:callback
|
||||
let l:fn.parser = a:parser
|
||||
function! l:fn.parse(text, pos) abort
|
||||
let l:parsed = self.parser.parse(a:text, a:pos)
|
||||
if l:parsed[0]
|
||||
return [v:true, self.callback(l:parsed[1]), l:parsed[2]]
|
||||
endif
|
||||
return l:parsed
|
||||
endfunction
|
||||
return l:fn
|
||||
endfunction
|
||||
|
||||
"
|
||||
" option.
|
||||
"
|
||||
function! s:option(parser) abort
|
||||
let l:fn = {}
|
||||
let l:fn.parser = a:parser
|
||||
function! l:fn.parse(text, pos) abort
|
||||
let l:parsed = self.parser.parse(a:text, a:pos)
|
||||
if l:parsed[0]
|
||||
return l:parsed
|
||||
endif
|
||||
return [v:true, v:null, a:pos]
|
||||
endfunction
|
||||
return l:fn
|
||||
endfunction
|
||||
|
||||
"
|
||||
" getchar.
|
||||
"
|
||||
function! s:getchar(text, pos) abort
|
||||
let l:nr = strgetchar(a:text, a:pos)
|
||||
if l:nr != -1
|
||||
return nr2char(l:nr)
|
||||
endif
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
10
dot_vim/plugged/vim-vsnip/autoload/vsnip/range.vim
Normal file
10
dot_vim/plugged/vim-vsnip/autoload/vsnip/range.vim
Normal file
@@ -0,0 +1,10 @@
|
||||
"
|
||||
" vsnip#range#cover
|
||||
"
|
||||
function! vsnip#range#cover(whole_range, target_range) abort
|
||||
let l:cover = v:true
|
||||
let l:cover = l:cover && (a:whole_range.start.line < a:target_range.start.line || a:whole_range.start.line == a:target_range.start.line && a:whole_range.start.character <= a:target_range.start.character)
|
||||
let l:cover = l:cover && (a:target_range.end.line < a:whole_range.end.line || a:target_range.end.line == a:whole_range.end.line && a:target_range.end.character <= a:whole_range.end.character)
|
||||
return l:cover
|
||||
endfunction
|
||||
|
||||
260
dot_vim/plugged/vim-vsnip/autoload/vsnip/session.vim
Normal file
260
dot_vim/plugged/vim-vsnip/autoload/vsnip/session.vim
Normal file
@@ -0,0 +1,260 @@
|
||||
let s:Snippet = vsnip#snippet#import()
|
||||
let s:TextEdit = vital#vsnip#import('VS.LSP.TextEdit')
|
||||
let s:Position = vital#vsnip#import('VS.LSP.Position')
|
||||
let s:Diff = vital#vsnip#import('VS.LSP.Diff')
|
||||
|
||||
"
|
||||
" import.
|
||||
"
|
||||
function! vsnip#session#import() abort
|
||||
return s:Session
|
||||
endfunction
|
||||
|
||||
let s:Session = {}
|
||||
|
||||
"
|
||||
" new.
|
||||
"
|
||||
function! s:Session.new(bufnr, position, text) abort
|
||||
return extend(deepcopy(s:Session), {
|
||||
\ 'bufnr': a:bufnr,
|
||||
\ 'buffer': getbufline(a:bufnr, '^', '$'),
|
||||
\ 'timer_id': -1,
|
||||
\ 'changedtick': getbufvar(a:bufnr, 'changedtick', 0),
|
||||
\ 'snippet': s:Snippet.new(a:position, vsnip#indent#adjust_snippet_body(getline('.'), a:text)),
|
||||
\ 'tabstop': -1,
|
||||
\ 'changenr': changenr(),
|
||||
\ 'changenrs': {},
|
||||
\ })
|
||||
endfunction
|
||||
|
||||
"
|
||||
" expand.
|
||||
"
|
||||
function! s:Session.expand() abort
|
||||
" insert snippet.
|
||||
call s:TextEdit.apply(self.bufnr, [{
|
||||
\ 'range': {
|
||||
\ 'start': self.snippet.position,
|
||||
\ 'end': self.snippet.position
|
||||
\ },
|
||||
\ 'newText': self.snippet.text()
|
||||
\ }])
|
||||
call self.store(changenr())
|
||||
endfunction
|
||||
|
||||
"
|
||||
" merge.
|
||||
"
|
||||
function! s:Session.merge(session) abort
|
||||
call s:TextEdit.apply(self.bufnr, self.snippet.sync())
|
||||
call self.store(self.changenr)
|
||||
|
||||
call a:session.expand()
|
||||
call self.snippet.merge(self.tabstop, a:session.snippet)
|
||||
call self.snippet.insert(deepcopy(a:session.snippet.position), a:session.snippet.children)
|
||||
call s:TextEdit.apply(self.bufnr, self.snippet.sync())
|
||||
call self.store(changenr())
|
||||
endfunction
|
||||
|
||||
"
|
||||
" jumpable.
|
||||
"
|
||||
function! s:Session.jumpable(direction) abort
|
||||
if a:direction == 1
|
||||
let l:jumpable = !empty(self.snippet.get_next_jump_point(self.tabstop))
|
||||
else
|
||||
let l:jumpable = !empty(self.snippet.get_prev_jump_point(self.tabstop))
|
||||
endif
|
||||
return l:jumpable
|
||||
endfunction
|
||||
|
||||
"
|
||||
" jump.
|
||||
"
|
||||
function! s:Session.jump(direction) abort
|
||||
call self.flush_changes()
|
||||
|
||||
if a:direction == 1
|
||||
let l:jump_point = self.snippet.get_next_jump_point(self.tabstop)
|
||||
else
|
||||
let l:jump_point = self.snippet.get_prev_jump_point(self.tabstop)
|
||||
endif
|
||||
|
||||
if empty(l:jump_point)
|
||||
return
|
||||
endif
|
||||
|
||||
let self.tabstop = l:jump_point.placeholder.id
|
||||
|
||||
" choice.
|
||||
if len(l:jump_point.placeholder.choice) > 0
|
||||
call self.choice(l:jump_point)
|
||||
|
||||
" select.
|
||||
elseif l:jump_point.range.start.character != l:jump_point.range.end.character
|
||||
call self.select(l:jump_point)
|
||||
|
||||
" move.
|
||||
else
|
||||
call self.move(l:jump_point)
|
||||
endif
|
||||
|
||||
doautocmd <nomodeline> User vsnip#jump
|
||||
endfunction
|
||||
|
||||
"
|
||||
" choice.
|
||||
"
|
||||
function! s:Session.choice(jump_point) abort
|
||||
call self.move(a:jump_point)
|
||||
|
||||
let l:fn = {}
|
||||
let l:fn.jump_point = a:jump_point
|
||||
function! l:fn.next_tick() abort
|
||||
if mode()[0] ==# 'i'
|
||||
let l:pos = s:Position.lsp_to_vim('%', self.jump_point.range.start)
|
||||
call complete(l:pos[1], map(copy(self.jump_point.placeholder.choice), { k, v -> {
|
||||
\ 'word': v.escaped,
|
||||
\ 'abbr': v.escaped,
|
||||
\ 'menu': '[vsnip]',
|
||||
\ 'kind': 'Choice'
|
||||
\ } }))
|
||||
endif
|
||||
endfunction
|
||||
call timer_start(g:vsnip_choice_delay, { -> l:fn.next_tick() })
|
||||
endfunction
|
||||
|
||||
"
|
||||
" select.
|
||||
"
|
||||
" @NOTE: Must work even if virtualedit=all/onmore or not.
|
||||
"
|
||||
function! s:Session.select(jump_point) abort
|
||||
let l:start_pos = s:Position.lsp_to_vim('%', a:jump_point.range.start)
|
||||
let l:end_pos = s:Position.lsp_to_vim('%', a:jump_point.range.end)
|
||||
|
||||
let l:cmd = ''
|
||||
let l:cmd .= "\<Cmd>set virtualedit=onemore\<CR>"
|
||||
let l:cmd .= mode()[0] ==# 'i' ? "\<Esc>" : ''
|
||||
let l:cmd .= printf("\<Cmd>call cursor(%s, %s)\<CR>", l:start_pos[0], l:start_pos[1])
|
||||
let l:cmd .= 'v'
|
||||
let l:cmd .= printf("\<Cmd>call cursor(%s, %s)\<CR>%s", l:end_pos[0], l:end_pos[1], &selection ==# 'exclusive' ? '' : 'h')
|
||||
if get(g:, 'vsnip_test_mode', v:false)
|
||||
let l:cmd .= "\<Esc>gv"
|
||||
endif
|
||||
let l:cmd .= printf("\<Cmd>set virtualedit=%s\<CR>", &virtualedit)
|
||||
let l:cmd .= "\<C-g>"
|
||||
call feedkeys(l:cmd, 'ni')
|
||||
endfunction
|
||||
|
||||
"
|
||||
" move.
|
||||
"
|
||||
" @NOTE: Must work even if virtualedit=all/onmore or not.
|
||||
"
|
||||
function! s:Session.move(jump_point) abort
|
||||
let l:pos = s:Position.lsp_to_vim('%', a:jump_point.range.end)
|
||||
|
||||
call cursor(l:pos)
|
||||
|
||||
if mode()[0] ==# 'n'
|
||||
if l:pos[1] != getcurpos()[2]
|
||||
call feedkeys('a', 'ni')
|
||||
else
|
||||
call feedkeys('i', 'ni')
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"
|
||||
" refresh
|
||||
"
|
||||
function! s:Session.refresh() abort
|
||||
let self.buffer = getbufline(self.bufnr, '^', '$')
|
||||
let self.changedtick = getbufvar(self.bufnr, 'changedtick', 0)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" on_insert_leave
|
||||
"
|
||||
function! s:Session.on_insert_leave() abort
|
||||
call self.flush_changes()
|
||||
endfunction
|
||||
|
||||
"
|
||||
" on_text_changed
|
||||
"
|
||||
function! s:Session.on_text_changed() abort
|
||||
if self.bufnr != bufnr('%')
|
||||
return vsnip#deactivate()
|
||||
endif
|
||||
|
||||
let l:changenr = changenr()
|
||||
|
||||
" save state.
|
||||
if self.changenr != l:changenr
|
||||
call self.store(self.changenr)
|
||||
if has_key(self.changenrs, l:changenr)
|
||||
let self.tabstop = self.changenrs[l:changenr].tabstop
|
||||
let self.snippet = self.changenrs[l:changenr].snippet
|
||||
let self.changenr = l:changenr
|
||||
let self.buffer = getbufline(self.bufnr, '^', '$')
|
||||
return
|
||||
endif
|
||||
endif
|
||||
|
||||
if g:vsnip_sync_delay == 0
|
||||
call self.flush_changes()
|
||||
elseif g:vsnip_sync_delay > 0
|
||||
call timer_stop(self.timer_id)
|
||||
let self.timer_id = timer_start(g:vsnip_sync_delay, { -> self.flush_changes() }, { 'repeat': 1 })
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"
|
||||
" flush_changes
|
||||
"
|
||||
function! s:Session.flush_changes() abort
|
||||
let l:changedtick = getbufvar(self.bufnr, 'changedtick', 0)
|
||||
if self.changedtick == l:changedtick
|
||||
return
|
||||
endif
|
||||
let self.changedtick = l:changedtick
|
||||
|
||||
" compute diff.
|
||||
let l:buffer = getbufline(self.bufnr, '^', '$')
|
||||
let l:diff = s:Diff.compute(self.buffer, l:buffer)
|
||||
let self.buffer = l:buffer
|
||||
if l:diff.rangeLength == 0 && l:diff.text ==# ''
|
||||
return
|
||||
endif
|
||||
|
||||
" if follow succeeded, sync placeholders and write back to the buffer.
|
||||
if self.snippet.follow(self.tabstop, l:diff)
|
||||
try
|
||||
let l:text_edits = self.snippet.sync()
|
||||
if len(l:text_edits) > 0
|
||||
undojoin | call s:TextEdit.apply(self.bufnr, l:text_edits)
|
||||
endif
|
||||
call self.refresh()
|
||||
catch /.*/
|
||||
" TODO: More strict changenrs mangement.
|
||||
call vsnip#deactivate()
|
||||
endtry
|
||||
else
|
||||
call vsnip#deactivate()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"
|
||||
" save.
|
||||
"
|
||||
function! s:Session.store(changenr) abort
|
||||
let self.changenrs[a:changenr] = {
|
||||
\ 'tabstop': self.tabstop,
|
||||
\ 'snippet': deepcopy(self.snippet)
|
||||
\ }
|
||||
let self.changenr = a:changenr
|
||||
endfunction
|
||||
|
||||
557
dot_vim/plugged/vim-vsnip/autoload/vsnip/snippet.vim
Normal file
557
dot_vim/plugged/vim-vsnip/autoload/vsnip/snippet.vim
Normal file
@@ -0,0 +1,557 @@
|
||||
let s:max_tabstop = 1000000
|
||||
let s:Position = vital#vsnip#import('VS.LSP.Position')
|
||||
|
||||
"
|
||||
" import.
|
||||
"
|
||||
function! vsnip#snippet#import() abort
|
||||
return s:Snippet
|
||||
endfunction
|
||||
|
||||
let s:Snippet = {}
|
||||
|
||||
"
|
||||
" new.
|
||||
"
|
||||
function! s:Snippet.new(position, text) abort
|
||||
let l:pos = s:Position.lsp_to_vim('%', a:position)
|
||||
let l:snippet = extend(deepcopy(s:Snippet), {
|
||||
\ 'type': 'snippet',
|
||||
\ 'position': a:position,
|
||||
\ 'before_text': getline(l:pos[0])[0 : l:pos[1] - 2],
|
||||
\ 'children': vsnip#snippet#node#create_from_ast(
|
||||
\ vsnip#snippet#parser#parse(a:text)
|
||||
\ )
|
||||
\ })
|
||||
call l:snippet.init()
|
||||
call l:snippet.sync()
|
||||
return l:snippet
|
||||
endfunction
|
||||
|
||||
"
|
||||
" init.
|
||||
"
|
||||
" NOTE: Must not use the node range in this method.
|
||||
"
|
||||
function! s:Snippet.init() abort
|
||||
let l:fn = {}
|
||||
let l:fn.self = self
|
||||
let l:fn.group = {}
|
||||
let l:fn.variable_placeholder = {}
|
||||
let l:fn.has_final_tabstop = v:false
|
||||
function! l:fn.traverse(context) abort
|
||||
if a:context.node.type ==# 'placeholder'
|
||||
" Mark as follower placeholder.
|
||||
if !has_key(self.group, a:context.node.id)
|
||||
let self.group[a:context.node.id] = a:context.node
|
||||
else
|
||||
let a:context.node.follower = v:true
|
||||
endif
|
||||
|
||||
" Mark as having final tabstop
|
||||
if a:context.node.is_final
|
||||
let self.has_final_tabstop = v:true
|
||||
endif
|
||||
elseif a:context.node.type ==# 'variable'
|
||||
" TODO refactor
|
||||
" variable placeholder
|
||||
if a:context.node.unknown
|
||||
let a:context.node.type = 'placeholder'
|
||||
let a:context.node.choice = []
|
||||
|
||||
if !has_key(self.variable_placeholder, a:context.node.name)
|
||||
let self.variable_placeholder[a:context.node.name] = s:max_tabstop - (len(self.variable_placeholder) + 1)
|
||||
let a:context.node.id = self.variable_placeholder[a:context.node.name]
|
||||
let a:context.node.follower = v:false
|
||||
let a:context.node.children = empty(a:context.node.children) ? [vsnip#snippet#node#create_text(a:context.node.name)] : a:context.node.children
|
||||
let self.group[a:context.node.id] = a:context.node
|
||||
else
|
||||
let a:context.node.id = self.variable_placeholder[a:context.node.name]
|
||||
let a:context.node.follower = v:true
|
||||
let a:context.node.children = [vsnip#snippet#node#create_text(self.group[a:context.node.id].text())]
|
||||
endif
|
||||
else
|
||||
let l:text = a:context.node.resolve(a:context)
|
||||
let l:text = l:text is# v:null ? a:context.text : l:text
|
||||
let l:index = index(a:context.parent.children, a:context.node)
|
||||
call remove(a:context.parent.children, l:index)
|
||||
call insert(a:context.parent.children, vsnip#snippet#node#create_text(l:text), l:index)
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
call self.traverse(self, l:fn.traverse)
|
||||
|
||||
" Append ${MAX_TABSTOP} for the end of snippet.
|
||||
if !l:fn.has_final_tabstop && g:vsnip_append_final_tabstop
|
||||
let self.children += [vsnip#snippet#node#create_from_ast({
|
||||
\ 'type': 'placeholder',
|
||||
\ 'id': 0,
|
||||
\ 'choice': [],
|
||||
\ })]
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"
|
||||
" follow.
|
||||
"
|
||||
function! s:Snippet.follow(current_tabstop, diff) abort
|
||||
if !self.is_followable(a:current_tabstop, a:diff)
|
||||
return v:false
|
||||
endif
|
||||
|
||||
let a:diff.range = [
|
||||
\ self.position_to_offset(a:diff.range.start),
|
||||
\ self.position_to_offset(a:diff.range.end),
|
||||
\ ]
|
||||
|
||||
let l:fn = {}
|
||||
let l:fn.current_tabstop = a:current_tabstop
|
||||
let l:fn.diff = a:diff
|
||||
let l:fn.is_target_context_fixed = v:false
|
||||
let l:fn.target_context = v:null
|
||||
let l:fn.contexts = []
|
||||
function! l:fn.traverse(context) abort
|
||||
if self.diff.range[1] < a:context.range[0]
|
||||
return v:true
|
||||
endif
|
||||
if a:context.node.type !=# 'text'
|
||||
return
|
||||
endif
|
||||
|
||||
let l:included = v:false
|
||||
let l:included = l:included || a:context.range[0] <= self.diff.range[0] && self.diff.range[0] < a:context.range[1] " right
|
||||
let l:included = l:included || a:context.range[0] < self.diff.range[1] && self.diff.range[1] <= a:context.range[1] " left
|
||||
let l:included = l:included || self.diff.range[0] <= a:context.range[0] && a:context.range[1] <= self.diff.range[1] " middle
|
||||
if l:included
|
||||
if !self.is_target_context_fixed && (empty(self.target_context) && a:context.parent.type ==# 'placeholder' || get(a:context.parent, 'id', -1) == self.current_tabstop)
|
||||
let self.is_target_context_fixed = get(a:context.parent, 'id', -1) == self.current_tabstop
|
||||
let self.target_context = a:context
|
||||
endif
|
||||
call add(self.contexts, a:context)
|
||||
endif
|
||||
endfunction
|
||||
call self.traverse(self, l:fn.traverse)
|
||||
|
||||
if empty(l:fn.contexts)
|
||||
return v:false
|
||||
endif
|
||||
|
||||
let l:fn.target_context = empty(l:fn.target_context) ? l:fn.contexts[-1] : l:fn.target_context
|
||||
|
||||
let l:diff_text = a:diff.text
|
||||
for l:context in l:fn.contexts
|
||||
let l:diff_range = [max([a:diff.range[0], l:context.range[0]]), min([a:diff.range[1], l:context.range[1]])]
|
||||
let l:start = l:diff_range[0] - l:context.range[0]
|
||||
let l:end = l:diff_range[1] - l:context.range[0]
|
||||
|
||||
" Create patched new text.
|
||||
let l:new_text = strcharpart(l:context.text, 0, l:start)
|
||||
if l:fn.target_context is# l:context
|
||||
let l:new_text .= l:diff_text
|
||||
let l:followed = v:true
|
||||
endif
|
||||
let l:new_text .= strcharpart(l:context.text, l:end, l:context.length - l:end)
|
||||
|
||||
" Apply patched new text.
|
||||
let l:context.node.value = l:new_text
|
||||
endfor
|
||||
|
||||
" Squash nodes when the edit was unexpected
|
||||
let l:squashed = []
|
||||
for l:context in l:fn.contexts
|
||||
let l:squash_targets = l:context.parents + [l:context.node]
|
||||
for l:i in range(len(l:squash_targets) - 1, 1, -1)
|
||||
let l:node = l:squash_targets[l:i]
|
||||
let l:parent = l:squash_targets[l:i - 1]
|
||||
|
||||
let l:should_squash = v:false
|
||||
let l:should_squash = l:should_squash || get(l:node, 'follower', v:false)
|
||||
let l:should_squash = l:should_squash || get(l:parent, 'id', v:null) is# a:current_tabstop
|
||||
let l:should_squash = l:should_squash || l:context isnot# l:fn.target_context && strlen(l:node.text()) == 0
|
||||
if l:should_squash && index(l:squashed, l:node) == -1
|
||||
let l:index = index(l:parent.children, l:node)
|
||||
call remove(l:parent.children, l:index)
|
||||
call insert(l:parent.children, vsnip#snippet#node#create_text(l:node.text()), l:index)
|
||||
call add(l:squashed, l:node)
|
||||
endif
|
||||
endfor
|
||||
endfor
|
||||
|
||||
return v:true
|
||||
endfunction
|
||||
|
||||
"
|
||||
" sync.
|
||||
"
|
||||
function! s:Snippet.sync() abort
|
||||
let l:fn = {}
|
||||
let l:fn.new_texts = {}
|
||||
let l:fn.targets = []
|
||||
function! l:fn.traverse(context) abort
|
||||
if a:context.node.type ==# 'placeholder'
|
||||
if !has_key(self.new_texts, a:context.node.id)
|
||||
let self.new_texts[a:context.node.id] = a:context.text
|
||||
else
|
||||
if self.new_texts[a:context.node.id] !=# a:context.text
|
||||
call add(self.targets, {
|
||||
\ 'range': a:context.range,
|
||||
\ 'node': a:context.node,
|
||||
\ 'new_text': a:context.node.transform.text(self.new_texts[a:context.node.id]),
|
||||
\ })
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
call self.traverse(self, l:fn.traverse)
|
||||
|
||||
" Create text_edits.
|
||||
let l:text_edits = []
|
||||
for l:target in l:fn.targets
|
||||
call add(l:text_edits, {
|
||||
\ 'node': l:target.node,
|
||||
\ 'range': {
|
||||
\ 'start': self.offset_to_position(l:target.range[0]),
|
||||
\ 'end': self.offset_to_position(l:target.range[1]),
|
||||
\ },
|
||||
\ 'newText': l:target.new_text
|
||||
\ })
|
||||
endfor
|
||||
|
||||
" Sync placeholder text after created text_edits (the reason is to avoid using a modified range).
|
||||
for l:text_edit in l:text_edits
|
||||
let l:text_edit.node.children = [vsnip#snippet#node#create_text(l:text_edit.newText)]
|
||||
endfor
|
||||
|
||||
return l:text_edits
|
||||
endfunction
|
||||
|
||||
"
|
||||
" range.
|
||||
"
|
||||
function! s:Snippet.range() abort
|
||||
return {
|
||||
\ 'start': self.offset_to_position(0),
|
||||
\ 'end': self.offset_to_position(strchars(self.text()))
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
"
|
||||
" text.
|
||||
"
|
||||
function! s:Snippet.text() abort
|
||||
return join(map(copy(self.children), 'v:val.text()'), '')
|
||||
endfunction
|
||||
|
||||
"
|
||||
" is_followable.
|
||||
"
|
||||
function! s:Snippet.is_followable(current_tabstop, diff) abort
|
||||
if g:vsnip#DeactivateOn.OutsideOfSnippet == g:vsnip_deactivate_on
|
||||
return vsnip#range#cover(self.range(), a:diff.range)
|
||||
elseif g:vsnip#DeactivateOn.OutsideOfCurrentTabstop == g:vsnip_deactivate_on
|
||||
let l:context = self.get_placeholder_context_by_tabstop(a:current_tabstop)
|
||||
if empty(l:context)
|
||||
return v:false
|
||||
endif
|
||||
return vsnip#range#cover({
|
||||
\ 'start': self.offset_to_position(l:context.range[0]),
|
||||
\ 'end': self.offset_to_position(l:context.range[1]),
|
||||
\ }, a:diff.range)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"
|
||||
" get_placeholder_nodes
|
||||
"
|
||||
function! s:Snippet.get_placeholder_nodes() abort
|
||||
let l:fn = {}
|
||||
let l:fn.nodes = []
|
||||
function! l:fn.traverse(context) abort
|
||||
if a:context.node.type ==# 'placeholder'
|
||||
call add(self.nodes, a:context.node)
|
||||
endif
|
||||
endfunction
|
||||
call self.traverse(self, l:fn.traverse)
|
||||
|
||||
return sort(l:fn.nodes, { a, b -> a.id - b.id })
|
||||
endfunction
|
||||
|
||||
"
|
||||
" get_placeholder_context_by_tabstop
|
||||
"
|
||||
function! s:Snippet.get_placeholder_context_by_tabstop(current_tabstop) abort
|
||||
let l:fn = {}
|
||||
let l:fn.current_tabstop = a:current_tabstop
|
||||
let l:fn.context = v:null
|
||||
function! l:fn.traverse(context) abort
|
||||
if a:context.node.type ==# 'placeholder' && a:context.node.id == self.current_tabstop
|
||||
let self.context = a:context
|
||||
return v:true
|
||||
endif
|
||||
endfunction
|
||||
call self.traverse(self, l:fn.traverse)
|
||||
return l:fn.context
|
||||
endfunction
|
||||
|
||||
"
|
||||
" get_next_jump_point.
|
||||
"
|
||||
function! s:Snippet.get_next_jump_point(current_tabstop) abort
|
||||
let l:fn = {}
|
||||
let l:fn.current_tabstop = a:current_tabstop
|
||||
let l:fn.context = v:null
|
||||
function! l:fn.traverse(context) abort
|
||||
if a:context.node.type ==# 'placeholder' && self.current_tabstop < a:context.node.id
|
||||
if !empty(self.context) && self.context.node.id <= a:context.node.id
|
||||
return v:false
|
||||
endif
|
||||
|
||||
let self.context = copy(a:context)
|
||||
endif
|
||||
endfunction
|
||||
call self.traverse(self, l:fn.traverse)
|
||||
|
||||
let l:context = l:fn.context
|
||||
if empty(l:context)
|
||||
return {}
|
||||
endif
|
||||
|
||||
return {
|
||||
\ 'placeholder': l:context.node,
|
||||
\ 'range': {
|
||||
\ 'start': self.offset_to_position(l:context.range[0]),
|
||||
\ 'end': self.offset_to_position(l:context.range[1])
|
||||
\ }
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
"
|
||||
" get_prev_jump_point.
|
||||
"
|
||||
function! s:Snippet.get_prev_jump_point(current_tabstop) abort
|
||||
let l:fn = {}
|
||||
let l:fn.current_tabstop = a:current_tabstop
|
||||
let l:fn.context = v:null
|
||||
function! l:fn.traverse(context) abort
|
||||
if a:context.node.type ==# 'placeholder' && self.current_tabstop > a:context.node.id
|
||||
if !empty(self.context) && self.context.node.id >= a:context.node.id
|
||||
return v:false
|
||||
endif
|
||||
let self.context = copy(a:context)
|
||||
endif
|
||||
endfunction
|
||||
call self.traverse(self, l:fn.traverse)
|
||||
|
||||
let l:context = l:fn.context
|
||||
if empty(l:context)
|
||||
return {}
|
||||
endif
|
||||
|
||||
return {
|
||||
\ 'placeholder': l:context.node,
|
||||
\ 'range': {
|
||||
\ 'start': self.offset_to_position(l:context.range[0]),
|
||||
\ 'end': self.offset_to_position(l:context.range[1])
|
||||
\ }
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
"
|
||||
" normalize
|
||||
"
|
||||
" - merge adjacent text-nodes
|
||||
"
|
||||
function! s:Snippet.normalize() abort
|
||||
let l:fn = {}
|
||||
let l:fn.prev_context = v:null
|
||||
function! l:fn.traverse(context) abort
|
||||
if !empty(self.prev_context)
|
||||
if self.prev_context.node.type ==# 'text' && a:context.node.type ==# 'text' && self.prev_context.parent is# a:context.parent
|
||||
let a:context.node.value = self.prev_context.node.value . a:context.node.value
|
||||
call remove(self.prev_context.parent.children, index(self.prev_context.parent.children, self.prev_context.node))
|
||||
endif
|
||||
endif
|
||||
let self.prev_context = copy(a:context)
|
||||
endfunction
|
||||
call self.traverse(self, l:fn.traverse)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" merge
|
||||
"
|
||||
function! s:Snippet.merge(tabstop, snippet) abort
|
||||
" increase new snippet's tabstop by current snippet's current tabstop
|
||||
let l:offset = 1
|
||||
let l:tabstop_map = {}
|
||||
for l:node in a:snippet.get_placeholder_nodes()
|
||||
if !has_key(l:tabstop_map, l:node.id)
|
||||
let l:tabstop_map[l:node.id] = a:tabstop + l:offset
|
||||
endif
|
||||
let l:node.id = l:tabstop_map[l:node.id]
|
||||
let l:offset += 1
|
||||
endfor
|
||||
if empty(l:tabstop_map)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:tail = l:node
|
||||
|
||||
" re-assign current snippet's tabstop by new snippet's final tabstop
|
||||
let l:offset = 1
|
||||
let l:tabstop_map = {}
|
||||
for l:node in self.get_placeholder_nodes()
|
||||
if l:node.id > a:tabstop
|
||||
if !has_key(l:tabstop_map, l:node.id)
|
||||
let l:tabstop_map[l:node.id] = l:tail.id + l:offset
|
||||
endif
|
||||
let l:node.id = l:tabstop_map[l:node.id]
|
||||
let l:offset += 1
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
"
|
||||
" insert
|
||||
"
|
||||
function! s:Snippet.insert(position, nodes_to_insert) abort
|
||||
let l:offset = self.position_to_offset(a:position)
|
||||
|
||||
" Search target node for inserting nodes.
|
||||
let l:fn = {}
|
||||
let l:fn.offset = l:offset
|
||||
let l:fn.context = v:null
|
||||
function! l:fn.traverse(context) abort
|
||||
if a:context.range[0] <= self.offset && self.offset <= a:context.range[1] && a:context.node.type ==# 'text'
|
||||
" prefer more deeper node.
|
||||
if empty(self.context) || self.context.depth <= a:context.depth
|
||||
let self.context = copy(a:context)
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
call self.traverse(self, l:fn.traverse)
|
||||
|
||||
" This condition is unexpected normally
|
||||
let l:context = l:fn.context
|
||||
if empty(l:context)
|
||||
return
|
||||
endif
|
||||
|
||||
" Remove target text node
|
||||
let l:index = index(l:context.parent.children, l:context.node)
|
||||
call remove(l:context.parent.children, l:index)
|
||||
|
||||
" Should insert into existing text node when position is middle of node
|
||||
let l:nodes_to_insert = reverse(a:nodes_to_insert)
|
||||
if l:context.node.value !=# ''
|
||||
let l:off = l:offset - l:context.range[0]
|
||||
let l:before = vsnip#snippet#node#create_text(strcharpart(l:context.node.value, 0, l:off))
|
||||
let l:after = vsnip#snippet#node#create_text(strcharpart(l:context.node.value, l:off, strchars(l:context.node.value) - l:off))
|
||||
let l:nodes_to_insert = [l:after] + l:nodes_to_insert + [l:before]
|
||||
endif
|
||||
|
||||
" Insert nodes.
|
||||
for l:node in l:nodes_to_insert
|
||||
call insert(l:context.parent.children, l:node, l:index)
|
||||
endfor
|
||||
|
||||
call self.normalize()
|
||||
endfunction
|
||||
|
||||
"
|
||||
" offset_to_position.
|
||||
"
|
||||
" @param offset 0-based index for snippet text.
|
||||
" @return position buffer position
|
||||
"
|
||||
function! s:Snippet.offset_to_position(offset) abort
|
||||
let l:lines = split(strcharpart(self.text(), 0, a:offset), "\n", v:true)
|
||||
return {
|
||||
\ 'line': self.position.line + len(l:lines) - 1,
|
||||
\ 'character': strchars(l:lines[-1]) + (len(l:lines) == 1 ? self.position.character : 0),
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
"
|
||||
" position_to_offset.
|
||||
"
|
||||
" @param position buffer position
|
||||
" @return 0-based index for snippet text.
|
||||
"
|
||||
function! s:Snippet.position_to_offset(position) abort
|
||||
let l:line = a:position.line - self.position.line
|
||||
let l:char = a:position.character - (l:line == 0 ? self.position.character : 0)
|
||||
let l:lines = split(self.text(), "\n", v:true)[0 : l:line]
|
||||
let l:lines[-1] = strcharpart(l:lines[-1], 0, l:char)
|
||||
return strchars(join(l:lines, "\n"))
|
||||
endfunction
|
||||
|
||||
"
|
||||
" traverse.
|
||||
"
|
||||
function! s:Snippet.traverse(node, callback) abort
|
||||
let l:state = {
|
||||
\ 'offset': 0,
|
||||
\ 'before_text': self.before_text,
|
||||
\ }
|
||||
let l:context = {
|
||||
\ 'depth': 0,
|
||||
\ 'parent': v:null,
|
||||
\ 'parents': [],
|
||||
\ }
|
||||
call s:traverse(a:node, a:callback, l:state, l:context)
|
||||
endfunction
|
||||
function! s:traverse(node, callback, state, context) abort
|
||||
let l:text = ''
|
||||
let l:length = 0
|
||||
if a:node.type !=# 'snippet'
|
||||
let l:text = a:node.text()
|
||||
let l:length = strchars(l:text)
|
||||
if a:callback({
|
||||
\ 'node': a:node,
|
||||
\ 'text': l:text,
|
||||
\ 'length': l:length,
|
||||
\ 'parent': a:context.parent,
|
||||
\ 'parents': a:context.parents,
|
||||
\ 'depth': a:context.depth,
|
||||
\ 'offset': a:state.offset,
|
||||
\ 'before_text': a:state.before_text,
|
||||
\ 'range': [a:state.offset, a:state.offset + l:length],
|
||||
\ })
|
||||
return v:true
|
||||
endif
|
||||
endif
|
||||
|
||||
if len(a:node.children) > 0
|
||||
let l:next_context = {
|
||||
\ 'parent': a:node,
|
||||
\ 'parents': a:context.parents + [a:node],
|
||||
\ 'depth': len(a:context.parents) + 1,
|
||||
\ }
|
||||
for l:child in copy(a:node.children)
|
||||
if s:traverse(l:child, a:callback, a:state, l:next_context)
|
||||
return v:true
|
||||
endif
|
||||
endfor
|
||||
else
|
||||
let a:state.before_text .= l:text
|
||||
let a:state.offset += l:length
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"
|
||||
" debug
|
||||
"
|
||||
function! s:Snippet.debug() abort
|
||||
echomsg 'snippet.text()'
|
||||
for l:line in split(self.text(), "\n", v:true)
|
||||
echomsg string(l:line)
|
||||
endfor
|
||||
echomsg '-----'
|
||||
|
||||
let l:fn = {}
|
||||
function! l:fn.traverse(context) abort
|
||||
echomsg repeat(' ', a:context.depth - 1) . a:context.node.to_string()
|
||||
endfunction
|
||||
call self.traverse(self, l:fn.traverse)
|
||||
echomsg ' '
|
||||
endfunction
|
||||
43
dot_vim/plugged/vim-vsnip/autoload/vsnip/snippet/node.vim
Normal file
43
dot_vim/plugged/vim-vsnip/autoload/vsnip/snippet/node.vim
Normal file
@@ -0,0 +1,43 @@
|
||||
let s:Placeholder = vsnip#snippet#node#placeholder#import()
|
||||
let s:Variable = vsnip#snippet#node#variable#import()
|
||||
let s:Text = vsnip#snippet#node#text#import()
|
||||
let s:Transform = vsnip#snippet#node#transform#import()
|
||||
|
||||
"
|
||||
" vsnip#snippet#node#create_from_ast
|
||||
"
|
||||
function! vsnip#snippet#node#create_from_ast(ast) abort
|
||||
if type(a:ast) == type([])
|
||||
return map(a:ast, 'vsnip#snippet#node#create_from_ast(v:val)')
|
||||
endif
|
||||
|
||||
if a:ast.type ==# 'placeholder'
|
||||
return s:Placeholder.new(a:ast)
|
||||
endif
|
||||
if a:ast.type ==# 'variable'
|
||||
return s:Variable.new(a:ast)
|
||||
endif
|
||||
if a:ast.type ==# 'text'
|
||||
return s:Text.new(a:ast)
|
||||
endif
|
||||
|
||||
throw 'vsnip: invalid node type'
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#snippet#node#create_text
|
||||
"
|
||||
function! vsnip#snippet#node#create_text(text) abort
|
||||
return s:Text.new({
|
||||
\ 'type': 'text',
|
||||
\ 'raw': a:text,
|
||||
\ 'escaped': a:text
|
||||
\ })
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#snippet#node#create_transform
|
||||
"
|
||||
function! vsnip#snippet#node#create_transform(transform) abort
|
||||
return s:Transform.new(a:transform)
|
||||
endfunction
|
||||
@@ -0,0 +1,55 @@
|
||||
let s:max_tabstop = 1000000
|
||||
let s:uid = 0
|
||||
|
||||
function! vsnip#snippet#node#placeholder#import() abort
|
||||
return s:Placeholder
|
||||
endfunction
|
||||
|
||||
let s:Placeholder = {}
|
||||
|
||||
"
|
||||
" new.
|
||||
"
|
||||
function! s:Placeholder.new(ast) abort
|
||||
let s:uid += 1
|
||||
|
||||
let l:node = extend(deepcopy(s:Placeholder), {
|
||||
\ 'uid': s:uid,
|
||||
\ 'type': 'placeholder',
|
||||
\ 'id': a:ast.id,
|
||||
\ 'is_final': a:ast.id == 0,
|
||||
\ 'follower': v:false,
|
||||
\ 'choice': get(a:ast, 'choice', []),
|
||||
\ 'children': vsnip#snippet#node#create_from_ast(get(a:ast, 'children', [])),
|
||||
\ 'transform': vsnip#snippet#node#create_transform(get(a:ast, 'transform')),
|
||||
\ })
|
||||
|
||||
if l:node.is_final
|
||||
let l:node.id = s:max_tabstop
|
||||
endif
|
||||
|
||||
if len(l:node.children) == 0
|
||||
let l:node.children = [vsnip#snippet#node#create_text('')]
|
||||
endif
|
||||
|
||||
return l:node
|
||||
endfunction
|
||||
|
||||
"
|
||||
" text.
|
||||
"
|
||||
function! s:Placeholder.text() abort
|
||||
return join(map(copy(self.children), 'v:val.text()'), '')
|
||||
endfunction
|
||||
|
||||
"
|
||||
" to_string
|
||||
"
|
||||
function! s:Placeholder.to_string() abort
|
||||
return printf('%s(id=%s, follower=%s, choise=%s)',
|
||||
\ self.type,
|
||||
\ self.id,
|
||||
\ self.follower ? 'true' : 'false',
|
||||
\ self.choice
|
||||
\ )
|
||||
endfunction
|
||||
@@ -0,0 +1,38 @@
|
||||
let s:uid = 0
|
||||
|
||||
function! vsnip#snippet#node#text#import() abort
|
||||
return s:Text
|
||||
endfunction
|
||||
|
||||
let s:Text = {}
|
||||
|
||||
"
|
||||
" new.
|
||||
"
|
||||
function! s:Text.new(ast) abort
|
||||
let s:uid += 1
|
||||
|
||||
return extend(deepcopy(s:Text), {
|
||||
\ 'uid': s:uid,
|
||||
\ 'type': 'text',
|
||||
\ 'value': a:ast.escaped,
|
||||
\ 'children': [],
|
||||
\ })
|
||||
endfunction
|
||||
|
||||
"
|
||||
" text.
|
||||
"
|
||||
function! s:Text.text() abort
|
||||
return self.value
|
||||
endfunction
|
||||
|
||||
"
|
||||
" to_string
|
||||
"
|
||||
function! s:Text.to_string() abort
|
||||
return printf('%s(%s)',
|
||||
\ self.type,
|
||||
\ self.value
|
||||
\ )
|
||||
endfunction
|
||||
@@ -0,0 +1,112 @@
|
||||
function! vsnip#snippet#node#transform#import() abort
|
||||
return s:Transform
|
||||
endfunction
|
||||
|
||||
let s:Transform = {}
|
||||
|
||||
"
|
||||
" new.
|
||||
"
|
||||
function! s:Transform.new(ast) abort
|
||||
let l:transform = empty(a:ast) ? {} : a:ast
|
||||
|
||||
let l:node = extend(deepcopy(s:Transform), {
|
||||
\ 'type': 'transform',
|
||||
\ 'regex': get(l:transform, 'regex', v:null),
|
||||
\ 'replacements': get(l:transform, 'format', []),
|
||||
\ 'options': get(l:transform, 'option', []),
|
||||
\ })
|
||||
|
||||
let l:node.is_noop = l:node.regex is v:null
|
||||
|
||||
return l:node
|
||||
endfunction
|
||||
|
||||
"
|
||||
" text.
|
||||
"
|
||||
function! s:Transform.text(input_text) abort
|
||||
if empty(a:input_text) || self.is_noop
|
||||
return a:input_text
|
||||
endif
|
||||
|
||||
if self.regex.pattern !=# '(.*)'
|
||||
" TODO: fully support regex
|
||||
return a:input_text
|
||||
endif
|
||||
|
||||
let l:text = ''
|
||||
|
||||
for l:replacement in self.replacements
|
||||
if l:replacement.type ==# 'format'
|
||||
if l:replacement.modifier ==# '/capitalize'
|
||||
let l:text .= s:capitalize(a:input_text)
|
||||
elseif l:replacement.modifier ==# '/downcase'
|
||||
let l:text .= s:downcase(a:input_text)
|
||||
elseif l:replacement.modifier ==# '/upcase'
|
||||
let l:text .= s:upcase(a:input_text)
|
||||
elseif l:replacement.modifier ==# '/camelcase'
|
||||
let l:text .= s:camelcase(a:input_text)
|
||||
elseif l:replacement.modifier ==# '/pascalcase'
|
||||
let l:text .= s:capitalize(s:camelcase(a:input_text))
|
||||
endif
|
||||
elseif l:replacement.type ==# 'text'
|
||||
let l:text .= l:replacement.escaped
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:text
|
||||
endfunction
|
||||
|
||||
"
|
||||
" to_string
|
||||
"
|
||||
function! s:Transform.to_string() abort
|
||||
if self.is_noop
|
||||
return
|
||||
end
|
||||
|
||||
return printf('%s(regex=%s, total_replacements=%s, options=%s)',
|
||||
\ self.type,
|
||||
\ get(self.regex, 'pattern', ''),
|
||||
\ len(self.replacements),
|
||||
\ join(self.options, ''),
|
||||
\ )
|
||||
endfunction
|
||||
|
||||
"
|
||||
" upcase
|
||||
"
|
||||
function! s:upcase(word) abort
|
||||
let word = toupper(a:word)
|
||||
return word
|
||||
endfunction
|
||||
|
||||
"
|
||||
" downcase
|
||||
"
|
||||
function! s:downcase(word) abort
|
||||
let word = tolower(a:word)
|
||||
return word
|
||||
endfunction
|
||||
|
||||
"
|
||||
" capitalize
|
||||
"
|
||||
function! s:capitalize(word) abort
|
||||
let word = s:upcase(strpart(a:word, 0, 1)) . strpart(a:word, 1)
|
||||
return word
|
||||
endfunction
|
||||
|
||||
"
|
||||
" camelcase
|
||||
" @see https://github.com/tpope/vim-abolish/blob/3f0c8faa/plugin/abolish.vim#L111-L118
|
||||
"
|
||||
function! s:camelcase(word) abort
|
||||
let word = substitute(a:word, '-', '_', 'g')
|
||||
if word !~# '_' && word =~# '\l'
|
||||
return substitute(word,'^.','\l&','')
|
||||
else
|
||||
return substitute(word,'\C\(_\)\=\(.\)','\=submatch(1)==""?tolower(submatch(2)) : toupper(submatch(2))','g')
|
||||
endif
|
||||
endfunction
|
||||
@@ -0,0 +1,63 @@
|
||||
let s:uid = 0
|
||||
|
||||
"
|
||||
" vsnip#snippet#node#variable#import
|
||||
"
|
||||
function! vsnip#snippet#node#variable#import() abort
|
||||
return s:Variable
|
||||
endfunction
|
||||
|
||||
let s:Variable = {}
|
||||
|
||||
"
|
||||
" new.
|
||||
"
|
||||
function! s:Variable.new(ast) abort
|
||||
let s:uid += 1
|
||||
|
||||
let l:resolver = vsnip#variable#get(a:ast.name)
|
||||
return extend(deepcopy(s:Variable), {
|
||||
\ 'uid': s:uid,
|
||||
\ 'type': 'variable',
|
||||
\ 'name': a:ast.name,
|
||||
\ 'unknown': empty(l:resolver),
|
||||
\ 'resolver': l:resolver,
|
||||
\ 'children': vsnip#snippet#node#create_from_ast(get(a:ast, 'children', [])),
|
||||
\ 'transform': vsnip#snippet#node#create_transform(get(a:ast, 'transform')),
|
||||
\ })
|
||||
endfunction
|
||||
|
||||
"
|
||||
" text.
|
||||
"
|
||||
function! s:Variable.text() abort
|
||||
return self.transform.text(join(map(copy(self.children), 'v:val.text()'), ''))
|
||||
endfunction
|
||||
|
||||
"
|
||||
" resolve.
|
||||
"
|
||||
function! s:Variable.resolve(context) abort
|
||||
if !self.unknown
|
||||
let l:resolved = self.transform.text(self.resolver.func({ 'node': self }))
|
||||
if l:resolved isnot v:null
|
||||
" Fix indent when one variable returns multiple lines
|
||||
let l:base_indent = vsnip#indent#get_base_indent(split(a:context.before_text, "\n", v:true)[-1])
|
||||
return substitute(l:resolved, "\n\\zs", l:base_indent, 'g')
|
||||
endif
|
||||
endif
|
||||
return v:null
|
||||
endfunction
|
||||
|
||||
"
|
||||
" to_string
|
||||
"
|
||||
function! s:Variable.to_string() abort
|
||||
return printf('%s(name=%s, unknown=%s, text=%s)',
|
||||
\ self.type,
|
||||
\ self.name,
|
||||
\ self.unknown ? 'true' : 'false',
|
||||
\ self.text()
|
||||
\ )
|
||||
endfunction
|
||||
|
||||
212
dot_vim/plugged/vim-vsnip/autoload/vsnip/snippet/parser.vim
Normal file
212
dot_vim/plugged/vim-vsnip/autoload/vsnip/snippet/parser.vim
Normal file
@@ -0,0 +1,212 @@
|
||||
let s:Combinator = vsnip#parser#combinator#import()
|
||||
|
||||
"
|
||||
" vsnip#snippet#parser#parse.
|
||||
" @see https://github.com/Microsoft/language-server-protocol/blob/master/snippetSyntax.md
|
||||
"
|
||||
function! vsnip#snippet#parser#parse(text) abort
|
||||
if strlen(a:text) == 0
|
||||
return []
|
||||
endif
|
||||
|
||||
let l:parsed = s:parser.parse(a:text, 0)
|
||||
if !l:parsed[0]
|
||||
throw json_encode({ 'text': a:text, 'result': l:parsed })
|
||||
endif
|
||||
return l:parsed[1]
|
||||
endfunction
|
||||
|
||||
let s:skip = s:Combinator.skip
|
||||
let s:token = s:Combinator.token
|
||||
let s:many = s:Combinator.many
|
||||
let s:or = s:Combinator.or
|
||||
let s:seq = s:Combinator.seq
|
||||
let s:lazy = s:Combinator.lazy
|
||||
let s:option = s:Combinator.option
|
||||
let s:pattern = s:Combinator.pattern
|
||||
let s:map = s:Combinator.map
|
||||
|
||||
"
|
||||
" primitives.
|
||||
"
|
||||
let s:dollar = s:token('$')
|
||||
let s:open = s:token('{')
|
||||
let s:close = s:token('}')
|
||||
let s:colon = s:token(':')
|
||||
let s:slash = s:token('/')
|
||||
let s:comma = s:token(',')
|
||||
let s:pipe = s:token('|')
|
||||
let s:varname = s:pattern('[_[:alpha:]]\w*')
|
||||
let s:int = s:map(s:pattern('\d\+'), { value -> str2nr(value[0]) })
|
||||
let s:text = { stop, escape -> s:map(
|
||||
\ s:skip(stop, escape),
|
||||
\ { value -> {
|
||||
\ 'type': 'text',
|
||||
\ 'raw': value[0],
|
||||
\ 'escaped': value[1]
|
||||
\ }
|
||||
\ }) }
|
||||
let s:regex = s:map(s:text(['/'], []), { value -> {
|
||||
\ 'type': 'regex',
|
||||
\ 'pattern': value.raw
|
||||
\ } })
|
||||
|
||||
"
|
||||
" any (without text).
|
||||
"
|
||||
let s:any = s:or(
|
||||
\ s:lazy({ -> s:choice }),
|
||||
\ s:lazy({ -> s:variable }),
|
||||
\ s:lazy({ -> s:tabstop }),
|
||||
\ s:lazy({ -> s:placeholder }),
|
||||
\ )
|
||||
|
||||
"
|
||||
" format.
|
||||
"
|
||||
let s:format1 = s:map(s:seq(s:dollar, s:int), { value -> {
|
||||
\ 'type': 'format',
|
||||
\ 'id': value[1]
|
||||
\ } })
|
||||
let s:format2 = s:map(s:seq(s:dollar, s:open, s:int, s:close), { value -> {
|
||||
\ 'type': 'format',
|
||||
\ 'id': value[2]
|
||||
\ } })
|
||||
let s:format3 = s:map(
|
||||
\ s:seq(
|
||||
\ s:dollar,
|
||||
\ s:open,
|
||||
\ s:int,
|
||||
\ s:colon,
|
||||
\ s:or(
|
||||
\ s:token('/upcase'),
|
||||
\ s:token('/downcase'),
|
||||
\ s:token('/capitalize'),
|
||||
\ s:token('/camelcase'),
|
||||
\ s:token('/pascalcase'),
|
||||
\ s:token('+if'),
|
||||
\ s:token('?if:else'),
|
||||
\ s:token('-else'),
|
||||
\ s:token('else')
|
||||
\ ),
|
||||
\ s:close
|
||||
\ ), { value -> {
|
||||
\ 'type': 'format',
|
||||
\ 'id': value[2],
|
||||
\ 'modifier': value[4]
|
||||
\ } })
|
||||
let s:format = s:or(s:format1, s:format2, s:format3)
|
||||
|
||||
"
|
||||
" transform
|
||||
"
|
||||
let s:transform = s:map(s:seq(
|
||||
\ s:slash,
|
||||
\ s:regex,
|
||||
\ s:slash,
|
||||
\ s:many(s:or(s:format, s:text(['/', '$'], []))),
|
||||
\ s:slash,
|
||||
\ s:option(s:many(s:or(s:token('i'), s:token('g'))))
|
||||
\ ), { value -> {
|
||||
\ 'type': 'transform',
|
||||
\ 'regex': value[1],
|
||||
\ 'format': value[3],
|
||||
\ 'option': value[5]
|
||||
\ } })
|
||||
|
||||
"
|
||||
" variable
|
||||
"
|
||||
let s:variable1 = s:map(s:seq(s:dollar, s:varname), { value -> {
|
||||
\ 'type': 'variable',
|
||||
\ 'name': value[1],
|
||||
\ 'children': [],
|
||||
\ } })
|
||||
let s:variable2 = s:map(s:seq(s:dollar, s:open, s:varname, s:close), { value -> {
|
||||
\ 'type': 'variable',
|
||||
\ 'name': value[2],
|
||||
\ 'children': [],
|
||||
\ } })
|
||||
let s:variable3 = s:map(s:seq(
|
||||
\ s:dollar,
|
||||
\ s:open,
|
||||
\ s:varname,
|
||||
\ s:colon,
|
||||
\ s:many(s:or(s:any, s:text(['$', '}'], []))),
|
||||
\ s:close
|
||||
\ ), { value -> {
|
||||
\ 'type': 'variable',
|
||||
\ 'name': value[2],
|
||||
\ 'children': value[4]
|
||||
\ } })
|
||||
let s:variable4 = s:map(s:seq(s:dollar, s:open, s:varname, s:transform, s:close), { value -> {
|
||||
\ 'type': 'variable',
|
||||
\ 'name': value[2],
|
||||
\ 'transform': value[3],
|
||||
\ 'children': [],
|
||||
\ } })
|
||||
|
||||
let s:variable = s:or(s:variable1, s:variable2, s:variable3, s:variable4)
|
||||
|
||||
"
|
||||
" placeholder.
|
||||
"
|
||||
let s:placeholder = s:map(s:seq(
|
||||
\ s:dollar,
|
||||
\ s:open,
|
||||
\ s:int,
|
||||
\ s:colon,
|
||||
\ s:many(s:or(s:any, s:text(['$', '}'], []))),
|
||||
\ s:close
|
||||
\ ), { value -> {
|
||||
\ 'type': 'placeholder',
|
||||
\ 'id': value[2],
|
||||
\ 'children': value[4]
|
||||
\ } })
|
||||
|
||||
"
|
||||
" tabstop
|
||||
"
|
||||
let s:tabstop1 = s:map(s:seq(s:dollar, s:int), { value -> {
|
||||
\ 'type': 'placeholder',
|
||||
\ 'id': value[1],
|
||||
\ 'children': [],
|
||||
\ } })
|
||||
let s:tabstop2 = s:map(s:seq(s:dollar, s:open, s:int, s:option(s:colon), s:close), { value -> {
|
||||
\ 'type': 'placeholder',
|
||||
\ 'id': value[2],
|
||||
\ 'children': [],
|
||||
\ } })
|
||||
let s:tabstop3 = s:map(s:seq(s:dollar, s:open, s:int, s:transform, s:close), { value -> {
|
||||
\ 'type': 'placeholder',
|
||||
\ 'id': value[2],
|
||||
\ 'children': [],
|
||||
\ 'transform': value[3]
|
||||
\ } })
|
||||
let s:tabstop = s:or(s:tabstop1, s:tabstop2, s:tabstop3)
|
||||
|
||||
"
|
||||
" choice
|
||||
"
|
||||
let s:choice = s:map(s:seq(
|
||||
\ s:dollar,
|
||||
\ s:open,
|
||||
\ s:int,
|
||||
\ s:pipe,
|
||||
\ s:many(
|
||||
\ s:map(s:seq(s:text([',', '|'], []), s:option(s:comma)), { value -> value[0] }),
|
||||
\ ),
|
||||
\ s:pipe,
|
||||
\ s:close
|
||||
\ ), { value -> {
|
||||
\ 'type': 'placeholder',
|
||||
\ 'id': value[2],
|
||||
\ 'choice': value[4],
|
||||
\ 'children': [copy(value[4][0])],
|
||||
\ } })
|
||||
|
||||
"
|
||||
" parser.
|
||||
"
|
||||
let s:parser = s:many(s:or(s:any, s:text(['$'], ['}'])))
|
||||
|
||||
116
dot_vim/plugged/vim-vsnip/autoload/vsnip/source.vim
Normal file
116
dot_vim/plugged/vim-vsnip/autoload/vsnip/source.vim
Normal file
@@ -0,0 +1,116 @@
|
||||
"
|
||||
" vsnip#source#refresh.
|
||||
"
|
||||
function! vsnip#source#refresh(path) abort
|
||||
call vsnip#source#user_snippet#refresh(a:path)
|
||||
call vsnip#source#vscode#refresh(a:path)
|
||||
call vsnip#source#snipmate#refresh(a:path)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#source#find.
|
||||
"
|
||||
function! vsnip#source#find(bufnr) abort
|
||||
let l:sources = []
|
||||
let l:sources += vsnip#source#user_snippet#find(a:bufnr)
|
||||
let l:sources += vsnip#source#vscode#find(a:bufnr)
|
||||
let l:sources += vsnip#source#snipmate#find(a:bufnr)
|
||||
return l:sources
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#source#filetypes
|
||||
"
|
||||
function! vsnip#source#filetypes(bufnr) abort
|
||||
let l:filetype = getbufvar(a:bufnr, '&filetype', '')
|
||||
return split(l:filetype, '\.') + get(g:vsnip_filetypes, l:filetype, []) + ['global']
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#source#create.
|
||||
"
|
||||
function! vsnip#source#create(path) abort
|
||||
try
|
||||
let l:file = readfile(a:path)
|
||||
let l:file = type(l:file) == type([]) ? join(l:file, "\n") : l:file
|
||||
let l:file = iconv(l:file, 'utf-8', &encoding)
|
||||
let l:json = json_decode(l:file)
|
||||
|
||||
if type(l:json) != type({})
|
||||
throw printf('%s is not valid json.', a:path)
|
||||
endif
|
||||
catch /.*/
|
||||
let l:json = {}
|
||||
echohl ErrorMsg
|
||||
echomsg printf('[vsnip] Parsing error occurred on: %s', a:path)
|
||||
echohl None
|
||||
echomsg string({ 'exception': v:exception, 'throwpint': v:throwpoint })
|
||||
endtry
|
||||
|
||||
" @see https://github.com/microsoft/vscode/blob/0ba9f6631daec96a2b71eeb337e29f50dd21c7e1/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts#L216
|
||||
let l:source = []
|
||||
for [l:key, l:value] in items(l:json)
|
||||
if s:is_snippet(l:value)
|
||||
call add(l:source, s:format_snippet(l:key, l:value))
|
||||
else
|
||||
for [l:key, l:value_] in items(l:value)
|
||||
if s:is_snippet(l:value_)
|
||||
call add(l:source, s:format_snippet(l:key, l:value_))
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
endfor
|
||||
return sort(l:source, { a, b -> strlen(b.prefix[0]) - strlen(a.prefix[0]) })
|
||||
endfunction
|
||||
|
||||
"
|
||||
" format_snippet
|
||||
"
|
||||
function! s:format_snippet(label, snippet) abort
|
||||
let [l:prefixes, l:prefixes_alias] = vsnip#source#resolve_prefix(a:snippet.prefix)
|
||||
let l:description = get(a:snippet, 'description', '')
|
||||
|
||||
return {
|
||||
\ 'label': a:label,
|
||||
\ 'prefix': l:prefixes,
|
||||
\ 'prefix_alias': l:prefixes_alias,
|
||||
\ 'body': type(a:snippet.body) == type([]) ? a:snippet.body : [a:snippet.body],
|
||||
\ 'description': type(l:description) == type([]) ? join(l:description, '') : l:description,
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
"
|
||||
" is_snippet
|
||||
"
|
||||
function! s:is_snippet(snippet_or_source) abort
|
||||
return type(a:snippet_or_source) == type({}) && has_key(a:snippet_or_source, 'prefix') && has_key(a:snippet_or_source, 'body')
|
||||
endfunction
|
||||
|
||||
"
|
||||
" resolve_prefix.
|
||||
"
|
||||
function! vsnip#source#resolve_prefix(prefix) abort
|
||||
let l:prefixes = []
|
||||
let l:prefixes_alias = []
|
||||
|
||||
for l:prefix in type(a:prefix) == type([]) ? a:prefix : [a:prefix]
|
||||
" namspace.
|
||||
if strlen(g:vsnip_namespace) > 0
|
||||
call add(l:prefixes, g:vsnip_namespace . l:prefix)
|
||||
endif
|
||||
|
||||
" prefix.
|
||||
call add(l:prefixes, l:prefix)
|
||||
|
||||
" alias.
|
||||
if l:prefix =~# '^\h\w*\%(-\w\+\)\+$'
|
||||
call add(l:prefixes_alias, join(map(split(l:prefix, '-'), { i, v -> v[0] }), ''))
|
||||
endif
|
||||
endfor
|
||||
|
||||
return [
|
||||
\ sort(l:prefixes, { a, b -> strlen(b) - strlen(a) }),
|
||||
\ sort(l:prefixes_alias, { a, b -> strlen(b) - strlen(a) })
|
||||
\ ]
|
||||
endfunction
|
||||
|
||||
88
dot_vim/plugged/vim-vsnip/autoload/vsnip/source/snipmate.vim
Normal file
88
dot_vim/plugged/vim-vsnip/autoload/vsnip/source/snipmate.vim
Normal file
@@ -0,0 +1,88 @@
|
||||
let s:cache = {}
|
||||
|
||||
function! vsnip#source#snipmate#refresh(path) abort
|
||||
if has_key(s:cache, a:path)
|
||||
unlet s:cache[a:path]
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! vsnip#source#snipmate#find(bufnr) abort
|
||||
let filetypes = vsnip#source#filetypes(a:bufnr)
|
||||
return s:find(filetypes, a:bufnr)
|
||||
endfunction
|
||||
|
||||
function! s:find(filetypes, bufnr) abort
|
||||
let sources = []
|
||||
for path in s:get_source_paths(a:filetypes, a:bufnr)
|
||||
if !has_key(s:cache, path)
|
||||
let s:cache[path] = s:create(path, a:bufnr)
|
||||
endif
|
||||
call add(sources, s:cache[path])
|
||||
endfor
|
||||
return sources
|
||||
endfunction
|
||||
|
||||
function! s:get_source_paths(filetypes, bufnr) abort
|
||||
let paths = []
|
||||
for dir in s:get_source_dirs(a:bufnr)
|
||||
for filetype in a:filetypes
|
||||
let path = resolve(expand(printf('%s/%s.snippets', dir, filetype)))
|
||||
if has_key(s:cache, path) || filereadable(path)
|
||||
call add(paths, path)
|
||||
endif
|
||||
endfor
|
||||
endfor
|
||||
return paths
|
||||
endfunction
|
||||
|
||||
function! s:get_source_dirs(bufnr) abort
|
||||
let dirs = []
|
||||
let buf_dir = getbufvar(a:bufnr, 'vsnip_snippet_dir', '')
|
||||
if buf_dir !=# ''
|
||||
let dirs += [buf_dir]
|
||||
endif
|
||||
let dirs += getbufvar(a:bufnr, 'vsnip_snippet_dirs', [])
|
||||
let dirs += [g:vsnip_snippet_dir]
|
||||
let dirs += g:vsnip_snippet_dirs
|
||||
return dirs
|
||||
endfunction
|
||||
|
||||
function! s:create(path, bufnr) abort
|
||||
let file = readfile(a:path)
|
||||
let file = type(file) == v:t_list ? file : [file]
|
||||
call map(file, { _, f -> iconv(f, 'utf-8', &encoding) })
|
||||
let source = []
|
||||
let i = -1
|
||||
while i + 1 < len(file)
|
||||
let [i, line] = [i + 1, file[i + 1]]
|
||||
if line =~# '^\(#\|\s*$\)'
|
||||
" Comment, or blank line before snippets
|
||||
elseif line =~# '^extends\s\+\S'
|
||||
let filetypes = map(split(line[7:], ','), 'trim(v:val)')
|
||||
let source += flatten(s:find(filetypes, a:bufnr))
|
||||
elseif line =~# '^snippet\s\+\S' && i + 1 < len(file)
|
||||
let matched = matchlist(line, '^snippet\s\+\(\S\+\)\s*\(.*\)')
|
||||
let [prefix, description] = [matched[1], matched[2]]
|
||||
let body = []
|
||||
let indent = matchstr(file[i + 1], '^\s\+')
|
||||
while i + 1 < len(file) && file[i + 1] =~# '^\(' . indent . '\|\s*$\)'
|
||||
let [i, line] = [i + 1, file[i + 1]]
|
||||
call add(body, line[strlen(indent):])
|
||||
endwhile
|
||||
let [prefixes, prefixes_alias] = vsnip#source#resolve_prefix(prefix)
|
||||
call add(source, {
|
||||
\ 'label': prefix,
|
||||
\ 'prefix': prefixes,
|
||||
\ 'prefix_alias': prefixes_alias,
|
||||
\ 'body': body,
|
||||
\ 'description': description
|
||||
\ })
|
||||
else
|
||||
echohl ErrorMsg
|
||||
echomsg printf('[vsnip] Parsing error occurred on: %s#L%s', a:path, i + 1)
|
||||
echohl None
|
||||
break
|
||||
endif
|
||||
endwhile
|
||||
return sort(source, { a, b -> strlen(b.prefix[0]) - strlen(a.prefix[0]) })
|
||||
endfunction
|
||||
@@ -0,0 +1,69 @@
|
||||
let s:cache = {}
|
||||
|
||||
"
|
||||
" vsnip#source#user_snippet#find.
|
||||
"
|
||||
function! vsnip#source#user_snippet#find(bufnr) abort
|
||||
let l:sources = []
|
||||
for l:path in s:get_source_paths(a:bufnr)
|
||||
if !has_key(s:cache, l:path)
|
||||
let s:cache[l:path] = vsnip#source#create(l:path)
|
||||
endif
|
||||
call add(l:sources, s:cache[l:path])
|
||||
endfor
|
||||
return l:sources
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#source#user_snippet#refresh.
|
||||
"
|
||||
function! vsnip#source#user_snippet#refresh(path) abort
|
||||
if has_key(s:cache, a:path)
|
||||
unlet s:cache[a:path]
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:get_source_dirs(bufnr) abort
|
||||
let l:dirs = []
|
||||
let l:buf_dir = getbufvar(a:bufnr, 'vsnip_snippet_dir', v:null)
|
||||
if l:buf_dir isnot v:null
|
||||
let l:dirs += [l:buf_dir]
|
||||
endif
|
||||
let l:dirs += getbufvar(a:bufnr, 'vsnip_snippet_dirs', [])
|
||||
let l:dirs += [g:vsnip_snippet_dir]
|
||||
let l:dirs += g:vsnip_snippet_dirs
|
||||
return l:dirs
|
||||
endfunction
|
||||
|
||||
"
|
||||
" get_source_paths.
|
||||
"
|
||||
function! s:get_source_paths(bufnr) abort
|
||||
let l:filetypes = vsnip#source#filetypes(a:bufnr)
|
||||
|
||||
let l:paths = []
|
||||
for l:dir in s:get_source_dirs(a:bufnr)
|
||||
for l:filetype in l:filetypes
|
||||
let l:path = resolve(expand(printf('%s/%s.json', l:dir, l:filetype)))
|
||||
if has_key(s:cache, l:path) || filereadable(l:path)
|
||||
call add(l:paths, l:path)
|
||||
endif
|
||||
endfor
|
||||
endfor
|
||||
return l:paths
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#source#user_snippet#dirs
|
||||
"
|
||||
fun! vsnip#source#user_snippet#dirs(...) abort
|
||||
return s:get_source_dirs(a:0 ? a:1 : bufnr(''))
|
||||
endfun
|
||||
|
||||
"
|
||||
" vsnip#source#user_snippet#paths
|
||||
"
|
||||
fun! vsnip#source#user_snippet#paths(...) abort
|
||||
return s:get_source_paths(a:0 ? a:1 : bufnr(''))
|
||||
endfun
|
||||
|
||||
104
dot_vim/plugged/vim-vsnip/autoload/vsnip/source/vscode.vim
Normal file
104
dot_vim/plugged/vim-vsnip/autoload/vsnip/source/vscode.vim
Normal file
@@ -0,0 +1,104 @@
|
||||
let s:snippets = {}
|
||||
let s:runtimepaths = {}
|
||||
|
||||
"
|
||||
" vsnip#source#vscode#refresh.
|
||||
"
|
||||
function! vsnip#source#vscode#refresh(path) abort
|
||||
if has_key(s:snippets, a:path)
|
||||
unlet s:snippets[a:path]
|
||||
|
||||
for [l:rtp, l:v] in items(s:runtimepaths)
|
||||
if stridx(l:rtp, a:path) == 0
|
||||
unlet s:runtimepaths[l:rtp]
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#source#vscode#find.
|
||||
"
|
||||
function! vsnip#source#vscode#find(bufnr) abort
|
||||
return s:find(map(vsnip#source#filetypes(a:bufnr), 's:get_language(v:val)'))
|
||||
endfunction
|
||||
|
||||
"
|
||||
" find.
|
||||
"
|
||||
function! s:find(languages) abort
|
||||
" Load `package.json#contributes.snippets` if does not exists it's cache.
|
||||
let l:rtp_list = exists('*nvim_list_runtime_paths') ? nvim_list_runtime_paths() : split(&runtimepath, ',')
|
||||
for l:rtp in l:rtp_list
|
||||
if has_key(s:runtimepaths, l:rtp)
|
||||
continue
|
||||
endif
|
||||
let s:runtimepaths[l:rtp] = v:true
|
||||
|
||||
try
|
||||
let l:package_json = resolve(expand(l:rtp . '/package.json'))
|
||||
if !filereadable(l:package_json)
|
||||
continue
|
||||
endif
|
||||
let l:package_json = readfile(l:package_json)
|
||||
let l:package_json = type(l:package_json) == type([]) ? join(l:package_json, "\n") : l:package_json
|
||||
let l:package_json = iconv(l:package_json, 'utf-8', &encoding)
|
||||
let l:package_json = json_decode(l:package_json)
|
||||
|
||||
" if package.json has not `contributes.snippets` fields, skip it.
|
||||
if !has_key(l:package_json, 'contributes')
|
||||
\ || !has_key(l:package_json.contributes, 'snippets')
|
||||
continue
|
||||
endif
|
||||
|
||||
" Create source if does not exists it's cache.
|
||||
for l:snippet in l:package_json.contributes.snippets
|
||||
let l:path = resolve(expand(l:rtp . '/' . l:snippet.path))
|
||||
let l:languages = type(l:snippet.language) == type([]) ? l:snippet.language : [l:snippet.language]
|
||||
|
||||
" if already cached `snippets.json`, add new language.
|
||||
if has_key(s:snippets, l:path)
|
||||
for l:language in l:languages
|
||||
if index(s:snippets[l:path].languages, l:language) == -1
|
||||
call add(s:snippets[l:path].languages, l:language)
|
||||
endif
|
||||
endfor
|
||||
continue
|
||||
endif
|
||||
|
||||
" register new snippet.
|
||||
let s:snippets[l:path] = {
|
||||
\ 'languages': l:languages,
|
||||
\ }
|
||||
endfor
|
||||
catch /.*/
|
||||
endtry
|
||||
endfor
|
||||
|
||||
" filter by language.
|
||||
let l:sources = []
|
||||
for l:language in a:languages
|
||||
for [l:path, l:snippet] in items(s:snippets)
|
||||
if index(l:snippet.languages, l:language) >= 0
|
||||
if !has_key(l:snippet, 'source')
|
||||
let l:snippet.source = vsnip#source#create(l:path)
|
||||
end
|
||||
call add(l:sources, l:snippet.source)
|
||||
endif
|
||||
endfor
|
||||
endfor
|
||||
return l:sources
|
||||
endfunction
|
||||
|
||||
"
|
||||
" get_language.
|
||||
"
|
||||
function! s:get_language(filetype) abort
|
||||
return get({
|
||||
\ 'javascript.jsx': 'javascriptreact',
|
||||
\ 'typescript.tsx': 'typescriptreact',
|
||||
\ 'sh': 'shellscript',
|
||||
\ 'cs': 'csharp',
|
||||
\ }, a:filetype, a:filetype)
|
||||
endfunction
|
||||
|
||||
189
dot_vim/plugged/vim-vsnip/autoload/vsnip/variable.vim
Normal file
189
dot_vim/plugged/vim-vsnip/autoload/vsnip/variable.vim
Normal file
@@ -0,0 +1,189 @@
|
||||
let s:variables = {}
|
||||
|
||||
"
|
||||
" vsnip#variable#register
|
||||
"
|
||||
function! vsnip#variable#register(name, func, ...) abort
|
||||
let l:option = get(a:000, 0, {})
|
||||
let s:variables[a:name] = {
|
||||
\ 'func': a:func,
|
||||
\ 'once': get(l:option, 'once', v:false)
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
"
|
||||
" vsnip#variable#get
|
||||
"
|
||||
function! vsnip#variable#get(name) abort
|
||||
return get(s:variables, a:name, v:null)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" Register built-in variables.
|
||||
"
|
||||
" @see https://code.visualstudio.com/docs/editor/userdefinedsnippets#_variables
|
||||
"
|
||||
|
||||
function! s:TM_SELECTED_TEXT(context) abort
|
||||
let l:selected_text = vsnip#selected_text()
|
||||
if empty(l:selected_text)
|
||||
return v:null
|
||||
endif
|
||||
return vsnip#indent#trim_base_indent(l:selected_text)
|
||||
endfunction
|
||||
call vsnip#variable#register('TM_SELECTED_TEXT', function('s:TM_SELECTED_TEXT'))
|
||||
|
||||
function! s:TM_CURRENT_LINE(context) abort
|
||||
return getline('.')
|
||||
endfunction
|
||||
call vsnip#variable#register('TM_CURRENT_LINE', function('s:TM_CURRENT_LINE'))
|
||||
|
||||
function! s:TM_CURRENT_WORD(context) abort
|
||||
return v:null
|
||||
endfunction
|
||||
call vsnip#variable#register('TM_CURRENT_WORD', function('s:TM_CURRENT_WORD'))
|
||||
|
||||
function! s:TM_LINE_INDEX(context) abort
|
||||
return line('.') - 1
|
||||
endfunction
|
||||
call vsnip#variable#register('TM_LINE_INDEX', function('s:TM_LINE_INDEX'))
|
||||
|
||||
function! s:TM_LINE_NUMBER(context) abort
|
||||
return line('.')
|
||||
endfunction
|
||||
call vsnip#variable#register('TM_LINE_NUMBER', function('s:TM_LINE_NUMBER'))
|
||||
|
||||
function! s:TM_FILENAME(context) abort
|
||||
return expand('%:p:t')
|
||||
endfunction
|
||||
call vsnip#variable#register('TM_FILENAME', function('s:TM_FILENAME'))
|
||||
|
||||
function! s:TM_FILENAME_BASE(context) abort
|
||||
return substitute(expand('%:p:t'), '^\@<!\..*$', '', '')
|
||||
endfunction
|
||||
call vsnip#variable#register('TM_FILENAME_BASE', function('s:TM_FILENAME_BASE'))
|
||||
|
||||
function! s:TM_DIRECTORY(context) abort
|
||||
return expand('%:p:h:t')
|
||||
endfunction
|
||||
call vsnip#variable#register('TM_DIRECTORY', function('s:TM_DIRECTORY'))
|
||||
|
||||
function! s:TM_FILEPATH(context) abort
|
||||
return expand('%:p')
|
||||
endfunction
|
||||
call vsnip#variable#register('TM_FILEPATH', function('s:TM_FILEPATH'))
|
||||
|
||||
function! s:RELATIVE_FILEPATH(context) abort
|
||||
return expand('%')
|
||||
endfunction
|
||||
call vsnip#variable#register('RELATIVE_FILEPATH', function('s:RELATIVE_FILEPATH'))
|
||||
|
||||
function! s:CLIPBOARD(context) abort
|
||||
let l:clipboard = getreg(v:register)
|
||||
if empty(l:clipboard)
|
||||
return v:null
|
||||
endif
|
||||
return vsnip#indent#trim_base_indent(l:clipboard)
|
||||
endfunction
|
||||
call vsnip#variable#register('CLIPBOARD', function('s:CLIPBOARD'))
|
||||
|
||||
function! s:WORKSPACE_NAME(context) abort
|
||||
return v:null
|
||||
endfunction
|
||||
call vsnip#variable#register('WORKSPACE_NAME', function('s:WORKSPACE_NAME'))
|
||||
|
||||
function! s:CURRENT_YEAR(context) abort
|
||||
return strftime('%Y')
|
||||
endfunction
|
||||
call vsnip#variable#register('CURRENT_YEAR', function('s:CURRENT_YEAR'))
|
||||
|
||||
function! s:CURRENT_YEAR_SHORT(context) abort
|
||||
return strftime('%y')
|
||||
endfunction
|
||||
call vsnip#variable#register('CURRENT_YEAR_SHORT', function('s:CURRENT_YEAR_SHORT'))
|
||||
|
||||
function! s:CURRENT_MONTH(context) abort
|
||||
return strftime('%m')
|
||||
endfunction
|
||||
call vsnip#variable#register('CURRENT_MONTH', function('s:CURRENT_MONTH'))
|
||||
|
||||
function! s:CURRENT_MONTH_NAME(context) abort
|
||||
return strftime('%B')
|
||||
endfunction
|
||||
call vsnip#variable#register('CURRENT_MONTH_NAME', function('s:CURRENT_MONTH_NAME'))
|
||||
|
||||
function! s:CURRENT_MONTH_NAME_SHORT(context) abort
|
||||
return strftime('%b')
|
||||
endfunction
|
||||
call vsnip#variable#register('CURRENT_MONTH_NAME_SHORT', function('s:CURRENT_MONTH_NAME_SHORT'))
|
||||
|
||||
function! s:CURRENT_DATE(context) abort
|
||||
return strftime('%d')
|
||||
endfunction
|
||||
call vsnip#variable#register('CURRENT_DATE', function('s:CURRENT_DATE'))
|
||||
|
||||
function! s:CURRENT_DAY_NAME(context) abort
|
||||
return strftime('%A')
|
||||
endfunction
|
||||
call vsnip#variable#register('CURRENT_DAY_NAME', function('s:CURRENT_DAY_NAME'))
|
||||
|
||||
function! s:CURRENT_DAY_NAME_SHORT(context) abort
|
||||
return strftime('%a')
|
||||
endfunction
|
||||
call vsnip#variable#register('CURRENT_DAY_NAME_SHORT', function('s:CURRENT_DAY_NAME_SHORT'))
|
||||
|
||||
function! s:CURRENT_HOUR(context) abort
|
||||
return strftime('%H')
|
||||
endfunction
|
||||
call vsnip#variable#register('CURRENT_HOUR', function('s:CURRENT_HOUR'))
|
||||
|
||||
function! s:CURRENT_MINUTE(context) abort
|
||||
return strftime('%M')
|
||||
endfunction
|
||||
call vsnip#variable#register('CURRENT_MINUTE', function('s:CURRENT_MINUTE'))
|
||||
|
||||
function! s:CURRENT_SECOND(context) abort
|
||||
return strftime('%S')
|
||||
endfunction
|
||||
call vsnip#variable#register('CURRENT_SECOND', function('s:CURRENT_SECOND'))
|
||||
|
||||
function! s:CURRENT_SECONDS_UNIX(context) abort
|
||||
return localtime()
|
||||
endfunction
|
||||
call vsnip#variable#register('CURRENT_SECONDS_UNIX', function('s:CURRENT_SECONDS_UNIX'))
|
||||
|
||||
function! s:BLOCK_COMMENT_START(context) abort
|
||||
return split(&commentstring, '%s')[0]
|
||||
endfunction
|
||||
call vsnip#variable#register('BLOCK_COMMENT_START', function('s:BLOCK_COMMENT_START'))
|
||||
|
||||
function! s:BLOCK_COMMENT_END(context) abort
|
||||
let l:chars = split(&commentstring, '%s')
|
||||
let l:comment = len(l:chars) > 1 ? l:chars[1] : l:chars[0]
|
||||
return trim(l:comment)
|
||||
endfunction
|
||||
call vsnip#variable#register('BLOCK_COMMENT_END', function('s:BLOCK_COMMENT_END'))
|
||||
|
||||
function! s:LINE_COMMENT(context) abort
|
||||
let l:chars = split(&commentstring, '%s')
|
||||
let l:comment = &commentstring =~# '^/\*' ? '//' : substitute(&commentstring, '%s', '', 'g')
|
||||
return trim(l:comment)
|
||||
endfunction
|
||||
call vsnip#variable#register('LINE_COMMENT', function('s:LINE_COMMENT'))
|
||||
|
||||
function! s:VIM(context) abort
|
||||
let l:script = join(map(copy(a:context.node.children), 'v:val.text()'), '')
|
||||
try
|
||||
return eval(l:script)
|
||||
catch /.*/
|
||||
endtry
|
||||
return v:null
|
||||
endfunction
|
||||
call vsnip#variable#register('VIM', function('s:VIM'))
|
||||
|
||||
function! s:VSNIP_CAMELCASE_FILENAME(context) abort
|
||||
let l:basename = substitute(expand('%:p:t'), '^\@<!\..*$', '', '')
|
||||
return substitute(l:basename, '\(\%(\<\l\+\)\%(_\)\@=\)\|_\(\l\)', '\u\1\2', 'g')
|
||||
endfunction
|
||||
call vsnip#variable#register('VSNIP_CAMELCASE_FILENAME', function('s:VSNIP_CAMELCASE_FILENAME'))
|
||||
|
||||
Reference in New Issue
Block a user