mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-01-24 05:30:07 +08:00
324 lines
8.4 KiB
VimL
324 lines
8.4 KiB
VimL
|
let s:t_number = type(0)
|
||
|
let s:t_string = type('')
|
||
|
|
||
|
function! s:_vital_loaded(V) abort
|
||
|
let s:Guard = a:V.import('Vim.Guard')
|
||
|
let s:List = a:V.import('Data.List')
|
||
|
let s:String = a:V.import('Data.String')
|
||
|
endfunction
|
||
|
|
||
|
function! s:_vital_depends() abort
|
||
|
return ['Vim.Guard', 'Data.List', 'Data.String']
|
||
|
endfunction
|
||
|
|
||
|
function! s:_vital_created(module) abort
|
||
|
" build pattern for parsing arguments
|
||
|
let single_quote = '''\zs[^'']\+\ze'''
|
||
|
let double_quote = '"\zs[^"]\+\ze"'
|
||
|
let bare_strings = '\%(\\\s\|[^ ''"]\)\+'
|
||
|
let s:PARSE_PATTERN = printf(
|
||
|
\ '\%%(%s\)*\zs\%%(\s\+\|$\)\ze',
|
||
|
\ join([single_quote, double_quote, bare_strings], '\|')
|
||
|
\)
|
||
|
let s:NORM_PATTERN = '^\%("\zs.*\ze"\|''\zs.*\ze''\|.*\)$'
|
||
|
endfunction
|
||
|
|
||
|
function! s:parse(cmdline) abort
|
||
|
return s:norm(split(a:cmdline, s:PARSE_PATTERN))
|
||
|
endfunction
|
||
|
|
||
|
function! s:norm(terms) abort
|
||
|
return map(copy(a:terms), 's:_norm_term(v:val)')
|
||
|
endfunction
|
||
|
|
||
|
function! s:new(...) abort
|
||
|
if a:0 > 0
|
||
|
let init = type(a:1) == s:t_string ? s:parse(a:1) : s:norm(a:1)
|
||
|
else
|
||
|
let init = []
|
||
|
endif
|
||
|
let args = copy(s:args)
|
||
|
let args.raw = init
|
||
|
return args
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Private --------------------------------------------------------------------
|
||
|
function! s:_norm_term(term) abort
|
||
|
let m = matchlist(a:term, '^\(-\w\|--\S\+=\)\(.\+\)')
|
||
|
if empty(m)
|
||
|
return matchstr(a:term, s:NORM_PATTERN)
|
||
|
endif
|
||
|
return m[1] . matchstr(m[2], s:NORM_PATTERN)
|
||
|
endfunction
|
||
|
|
||
|
function! s:_parse_term(term) abort
|
||
|
let m = matchlist(a:term, '^\(-\w\|--\S\+=\)\(.\+\)')
|
||
|
if empty(m)
|
||
|
return a:term =~# '^--\?\S\+' ? [a:term, 1] : ['', a:term]
|
||
|
else
|
||
|
return [substitute(m[1], '=$', '', ''), m[2]]
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
function! s:_build_term(key, value) abort
|
||
|
if type(a:value) == s:t_number
|
||
|
return a:value == 0 ? '' : a:key
|
||
|
elseif empty(a:key) || a:key =~# '^-\w$'
|
||
|
return a:key . a:value
|
||
|
else
|
||
|
return a:key . '=' . a:value
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
function! s:_build_pattern(query) abort
|
||
|
let patterns = split(a:query, '|')
|
||
|
call map(patterns, 's:String.escape_pattern(v:val)')
|
||
|
call map(patterns, 'v:val =~# ''^--\S\+'' ? v:val . ''\%(=\|$\)'' : v:val')
|
||
|
return printf('^\%%(%s\)', join(patterns, '\|'))
|
||
|
endfunction
|
||
|
|
||
|
function! s:_is_query(query) abort
|
||
|
return a:query =~# '^--\?\S\+\%(|--\?\S\+\)*$'
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Instance -------------------------------------------------------------------
|
||
|
let s:args = {}
|
||
|
|
||
|
function! s:_index(pattern) abort dict
|
||
|
let guard = s:Guard.store(['&l:iskeyword'])
|
||
|
try
|
||
|
setlocal iskeyword&
|
||
|
let indices = range(0, len(self.raw)-1)
|
||
|
for index in indices
|
||
|
let term = self.raw[index]
|
||
|
if term ==# '--'
|
||
|
return -1
|
||
|
elseif term =~# a:pattern
|
||
|
return index
|
||
|
endif
|
||
|
endfor
|
||
|
return -1
|
||
|
finally
|
||
|
call guard.restore()
|
||
|
endtry
|
||
|
endfunction
|
||
|
|
||
|
function! s:_has(pattern) abort dict
|
||
|
return call('s:_index', [a:pattern], self) != -1
|
||
|
endfunction
|
||
|
|
||
|
function! s:_get(pattern, default) abort dict
|
||
|
let index = call('s:_index', [a:pattern], self)
|
||
|
if index == -1
|
||
|
return a:default
|
||
|
endif
|
||
|
return self.raw[index]
|
||
|
endfunction
|
||
|
|
||
|
function! s:_pop(pattern, default) abort dict
|
||
|
let index = call('s:_index', [a:pattern], self)
|
||
|
if index == -1
|
||
|
return a:default
|
||
|
endif
|
||
|
return remove(self.raw, index)
|
||
|
endfunction
|
||
|
|
||
|
function! s:_set(pattern, term) abort dict
|
||
|
let index = call('s:_index', [a:pattern], self)
|
||
|
if index == -1
|
||
|
let tail = index(self.raw, '--')
|
||
|
let tail = tail == -1 ? len(self.raw) : tail
|
||
|
call insert(self.raw, a:term, tail)
|
||
|
else
|
||
|
let self.raw[index] = a:term
|
||
|
endif
|
||
|
return self
|
||
|
endfunction
|
||
|
|
||
|
function! s:_index_o(query) abort dict
|
||
|
return call('s:_index', [s:_build_pattern(a:query)], self)
|
||
|
endfunction
|
||
|
|
||
|
function! s:_has_o(query) abort dict
|
||
|
return call('s:_has', [s:_build_pattern(a:query)], self)
|
||
|
endfunction
|
||
|
|
||
|
function! s:_get_o(query, default) abort dict
|
||
|
let index = call('s:_index_o', [a:query], self)
|
||
|
if index == -1
|
||
|
return a:default
|
||
|
endif
|
||
|
return s:_parse_term(self.raw[index])[1]
|
||
|
endfunction
|
||
|
|
||
|
function! s:_pop_o(query, default) abort dict
|
||
|
let index = call('s:_index_o', [a:query], self)
|
||
|
if index == -1
|
||
|
return a:default
|
||
|
endif
|
||
|
return s:_parse_term(remove(self.raw, index))[1]
|
||
|
endfunction
|
||
|
|
||
|
function! s:_set_o(query, value) abort dict
|
||
|
let index = call('s:_index_o', [a:query], self)
|
||
|
if index == -1
|
||
|
let tail = index(self.raw, '--')
|
||
|
let tail = tail == -1 ? len(self.raw) : tail
|
||
|
let term = s:_build_term(split(a:query, '|')[-1], a:value)
|
||
|
call insert(self.raw, term, tail)
|
||
|
else
|
||
|
let term = s:_build_term(s:_parse_term(self.raw[index])[0], a:value)
|
||
|
let self.raw[index] = term
|
||
|
endif
|
||
|
return self
|
||
|
endfunction
|
||
|
|
||
|
function! s:_index_p(query) abort dict
|
||
|
if a:query < 0
|
||
|
throw 'vital: Argument: {query} (n-th) requires to be positive.'
|
||
|
endif
|
||
|
let indices = range(0, len(self.raw)-1)
|
||
|
let pattern = '^--\?\w\+'
|
||
|
let counter = 0
|
||
|
for index in indices
|
||
|
let term = self.raw[index]
|
||
|
if term ==# '--'
|
||
|
return -1
|
||
|
elseif term !~# pattern
|
||
|
let counter += 1
|
||
|
if counter == a:query + 1
|
||
|
return index
|
||
|
endif
|
||
|
endif
|
||
|
endfor
|
||
|
return -1
|
||
|
endfunction
|
||
|
|
||
|
function! s:_has_p(query) abort dict
|
||
|
return call('s:_index_p', [a:query], self) != -1
|
||
|
endfunction
|
||
|
|
||
|
function! s:_get_p(query, ...) abort dict
|
||
|
let default = get(a:000, 0, '')
|
||
|
let index = call('s:_index_p', [a:query], self)
|
||
|
if index == -1
|
||
|
return default
|
||
|
endif
|
||
|
return self.raw[index]
|
||
|
endfunction
|
||
|
|
||
|
function! s:_pop_p(query, ...) abort dict
|
||
|
let default = get(a:000, 0, '')
|
||
|
let index = call('s:_index_p', [a:query], self)
|
||
|
if index == -1
|
||
|
return default
|
||
|
endif
|
||
|
return remove(self.raw, index)
|
||
|
endfunction
|
||
|
|
||
|
function! s:_set_p(query, value) abort dict
|
||
|
let index = call('s:_index_p', [a:query], self)
|
||
|
if index == -1
|
||
|
let tail = index(self.raw, '--')
|
||
|
let tail = tail == -1 ? len(self.raw) : tail
|
||
|
let n = (a:query + 1) - len(filter(
|
||
|
\ self.raw[:tail-1],
|
||
|
\ 'v:val !~# ''^--\?\w\+'''
|
||
|
\))
|
||
|
call extend(self.raw, repeat([''], n), tail)
|
||
|
let self.raw[tail - 1 + n] = a:value
|
||
|
else
|
||
|
let self.raw[index] = a:value
|
||
|
endif
|
||
|
let self.raw = s:List.flatten(self.raw)
|
||
|
return self
|
||
|
endfunction
|
||
|
|
||
|
function! s:args.hash() abort
|
||
|
return sha256(string(self.raw))
|
||
|
endfunction
|
||
|
|
||
|
function! s:args.lock() abort
|
||
|
lockvar self
|
||
|
return self
|
||
|
endfunction
|
||
|
|
||
|
function! s:args.clone() abort
|
||
|
let args = deepcopy(self)
|
||
|
lockvar 1 args
|
||
|
return args
|
||
|
endfunction
|
||
|
|
||
|
function! s:args.index(query) abort
|
||
|
return type(a:query) == s:t_string
|
||
|
\ ? s:_is_query(a:query)
|
||
|
\ ? call('s:_index_o', [a:query], self)
|
||
|
\ : call('s:_index', [a:query], self)
|
||
|
\ : call('s:_index_p', [a:query], self)
|
||
|
endfunction
|
||
|
|
||
|
function! s:args.has(query, ...) abort
|
||
|
return type(a:query) == s:t_string
|
||
|
\ ? s:_is_query(a:query)
|
||
|
\ ? call('s:_has_o', [a:query], self)
|
||
|
\ : call('s:_has', [a:query], self)
|
||
|
\ : call('s:_has_p', [a:query], self)
|
||
|
endfunction
|
||
|
|
||
|
function! s:args.get(query, ...) abort
|
||
|
return type(a:query) == s:t_string
|
||
|
\ ? s:_is_query(a:query)
|
||
|
\ ? call('s:_get_o', [a:query, get(a:000, 0, 0)], self)
|
||
|
\ : call('s:_get', [a:query, get(a:000, 0, '')], self)
|
||
|
\ : call('s:_get_p', [a:query, get(a:000, 0, '')], self)
|
||
|
endfunction
|
||
|
|
||
|
function! s:args.pop(query, ...) abort
|
||
|
return type(a:query) == s:t_string
|
||
|
\ ? s:_is_query(a:query)
|
||
|
\ ? call('s:_pop_o', [a:query, get(a:000, 0, 0)], self)
|
||
|
\ : call('s:_pop', [a:query, get(a:000, 0, '')], self)
|
||
|
\ : call('s:_pop_p', [a:query, get(a:000, 0, '')], self)
|
||
|
endfunction
|
||
|
|
||
|
function! s:args.set(query, value) abort
|
||
|
return type(a:query) == s:t_string
|
||
|
\ ? s:_is_query(a:query)
|
||
|
\ ? call('s:_set_o', [a:query, a:value], self)
|
||
|
\ : call('s:_set', [a:query, a:value], self)
|
||
|
\ : call('s:_set_p', [a:query, a:value], self)
|
||
|
endfunction
|
||
|
|
||
|
function! s:args.split() abort
|
||
|
let tail = index(self.raw, '--')
|
||
|
if tail == -1
|
||
|
return [copy(self.raw), []]
|
||
|
elseif tail == 0
|
||
|
return [[], self.raw[1:]]
|
||
|
else
|
||
|
return [self.raw[:tail-1], self.raw[tail+1:]]
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
function! s:args.effective(...) abort
|
||
|
if a:0 == 0
|
||
|
return self.split()[0]
|
||
|
else
|
||
|
let residual = self.residual()
|
||
|
let self.raw = empty(residual) ? a:1 : a:1 + ['--'] + residual
|
||
|
return self
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
function! s:args.residual(...) abort
|
||
|
if a:0 == 0
|
||
|
return self.split()[1]
|
||
|
else
|
||
|
let effective = self.effective()
|
||
|
let self.raw = effective + ['--'] + a:1
|
||
|
return self
|
||
|
endif
|
||
|
endfunction
|