I broke up with neovim....vim is my best friend now

This commit is contained in:
LinlyBoi
2023-04-30 08:14:07 +03:00
parent 0d185449c5
commit 4a4a6b1e81
5245 changed files with 468325 additions and 25 deletions

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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(['$'], ['}'])))