Fixed vim and zsh
This commit is contained in:
@ -0,0 +1,116 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not mofidify the code nor insert new lines before '" ___vital___'
|
||||
if v:version > 703 || v:version == 703 && has('patch1170')
|
||||
function! vital#_easymotion#Data#Dict#import() abort
|
||||
return map({'pick': '', 'clear': '', 'max_by': '', 'foldl': '', 'swap': '', 'omit': '', 'min_by': '', 'foldr': '', 'make_index': '', 'make': ''}, 'function("s:" . v:key)')
|
||||
endfunction
|
||||
else
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_easymotion#Data#Dict#import() abort', printf("return map({'pick': '', 'clear': '', 'max_by': '', 'foldl': '', 'swap': '', 'omit': '', 'min_by': '', 'foldr': '', 'make_index': '', 'make': ''}, \"function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
endif
|
||||
" ___vital___
|
||||
" Utilities for dictionary.
|
||||
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
" Makes a dict from keys and values
|
||||
function! s:make(keys, values, ...) abort
|
||||
let dict = {}
|
||||
let fill = a:0 ? a:1 : 0
|
||||
for i in range(len(a:keys))
|
||||
let key = type(a:keys[i]) == type('') ? a:keys[i] : string(a:keys[i])
|
||||
if key ==# ''
|
||||
throw "vital: Data.Dict: Can't use an empty string for key."
|
||||
endif
|
||||
let dict[key] = get(a:values, i, fill)
|
||||
endfor
|
||||
return dict
|
||||
endfunction
|
||||
|
||||
" Swaps keys and values
|
||||
function! s:swap(dict) abort
|
||||
return s:make(values(a:dict), keys(a:dict))
|
||||
endfunction
|
||||
|
||||
" Makes a index dict from a list
|
||||
function! s:make_index(list, ...) abort
|
||||
let value = a:0 ? a:1 : 1
|
||||
return s:make(a:list, [], value)
|
||||
endfunction
|
||||
|
||||
function! s:pick(dict, keys) abort
|
||||
let new_dict = {}
|
||||
for key in a:keys
|
||||
if has_key(a:dict, key)
|
||||
let new_dict[key] = a:dict[key]
|
||||
endif
|
||||
endfor
|
||||
return new_dict
|
||||
endfunction
|
||||
|
||||
function! s:omit(dict, keys) abort
|
||||
let new_dict = copy(a:dict)
|
||||
for key in a:keys
|
||||
if has_key(a:dict, key)
|
||||
call remove(new_dict, key)
|
||||
endif
|
||||
endfor
|
||||
return new_dict
|
||||
endfunction
|
||||
|
||||
function! s:clear(dict) abort
|
||||
for key in keys(a:dict)
|
||||
call remove(a:dict, key)
|
||||
endfor
|
||||
return a:dict
|
||||
endfunction
|
||||
|
||||
function! s:_max_by(dict, expr) abort
|
||||
let dict = s:swap(map(copy(a:dict), a:expr))
|
||||
let key = dict[max(keys(dict))]
|
||||
return [key, a:dict[key]]
|
||||
endfunction
|
||||
|
||||
function! s:max_by(dict, expr) abort
|
||||
if empty(a:dict)
|
||||
throw 'vital: Data.Dict: Empty dictionary'
|
||||
endif
|
||||
return s:_max_by(a:dict, a:expr)
|
||||
endfunction
|
||||
|
||||
function! s:min_by(dict, expr) abort
|
||||
if empty(a:dict)
|
||||
throw 'vital: Data.Dict: Empty dictionary'
|
||||
endif
|
||||
return s:_max_by(a:dict, '-(' . a:expr . ')')
|
||||
endfunction
|
||||
|
||||
function! s:_foldl(f, init, xs) abort
|
||||
let memo = a:init
|
||||
for [k, v] in a:xs
|
||||
let expr = substitute(a:f, 'v:key', string(k), 'g')
|
||||
let expr = substitute(expr, 'v:val', string(v), 'g')
|
||||
let expr = substitute(expr, 'v:memo', string(memo), 'g')
|
||||
unlet memo
|
||||
let memo = eval(expr)
|
||||
endfor
|
||||
return memo
|
||||
endfunction
|
||||
|
||||
function! s:foldl(f, init, dict) abort
|
||||
return s:_foldl(a:f, a:init, items(a:dict))
|
||||
endfunction
|
||||
|
||||
function! s:foldr(f, init, dict) abort
|
||||
return s:_foldl(a:f, a:init, reverse(items(a:dict)))
|
||||
endfunction
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
||||
|
||||
" vim:set et ts=2 sts=2 sw=2 tw=0:
|
@ -0,0 +1,457 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not mofidify the code nor insert new lines before '" ___vital___'
|
||||
if v:version > 703 || v:version == 703 && has('patch1170')
|
||||
function! vital#_easymotion#Data#List#import() abort
|
||||
return map({'combinations': '', 'and': '', 'sort_by': '', 'foldr1': '', 'sort': '', 'flatten': '', 'has_index': '', 'find_indices': '', 'any': '', 'unshift': '', 'span': '', 'pop': '', 'binary_search': '', 'uniq_by': '', 'or': '', 'all': '', 'zip': '', 'find_last_index': '', 'find': '', 'partition': '', 'map_accum': '', 'permutations': '', 'break': '', 'max_by': '', 'foldl': '', 'foldr': '', 'find_index': '', 'group_by': '', 'take_while': '', 'conj': '', 'push': '', 'char_range': '', 'cons': '', 'foldl1': '', 'intersect': '', 'concat': '', 'shift': '', 'clear': '', 'has_common_items': '', 'product': '', 'zip_fill': '', 'uniq': '', 'has': '', 'min_by': '', 'with_index': ''}, 'function("s:" . v:key)')
|
||||
endfunction
|
||||
else
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_easymotion#Data#List#import() abort', printf("return map({'combinations': '', 'and': '', 'sort_by': '', 'foldr1': '', 'sort': '', 'flatten': '', 'has_index': '', 'find_indices': '', 'any': '', 'unshift': '', 'span': '', 'pop': '', 'binary_search': '', 'uniq_by': '', 'or': '', 'all': '', 'zip': '', 'find_last_index': '', 'find': '', 'partition': '', 'map_accum': '', 'permutations': '', 'break': '', 'max_by': '', 'foldl': '', 'foldr': '', 'find_index': '', 'group_by': '', 'take_while': '', 'conj': '', 'push': '', 'char_range': '', 'cons': '', 'foldl1': '', 'intersect': '', 'concat': '', 'shift': '', 'clear': '', 'has_common_items': '', 'product': '', 'zip_fill': '', 'uniq': '', 'has': '', 'min_by': '', 'with_index': ''}, \"function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
endif
|
||||
" ___vital___
|
||||
" Utilities for list.
|
||||
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
function! s:pop(list) abort
|
||||
return remove(a:list, -1)
|
||||
endfunction
|
||||
|
||||
function! s:push(list, val) abort
|
||||
call add(a:list, a:val)
|
||||
return a:list
|
||||
endfunction
|
||||
|
||||
function! s:shift(list) abort
|
||||
return remove(a:list, 0)
|
||||
endfunction
|
||||
|
||||
function! s:unshift(list, val) abort
|
||||
return insert(a:list, a:val)
|
||||
endfunction
|
||||
|
||||
function! s:cons(x, xs) abort
|
||||
return [a:x] + a:xs
|
||||
endfunction
|
||||
|
||||
function! s:conj(xs, x) abort
|
||||
return a:xs + [a:x]
|
||||
endfunction
|
||||
|
||||
" Removes duplicates from a list.
|
||||
function! s:uniq(list) abort
|
||||
return s:uniq_by(a:list, 'v:val')
|
||||
endfunction
|
||||
|
||||
" Removes duplicates from a list.
|
||||
function! s:uniq_by(list, f) abort
|
||||
let list = map(copy(a:list), printf('[v:val, %s]', a:f))
|
||||
let i = 0
|
||||
let seen = {}
|
||||
while i < len(list)
|
||||
let key = string(list[i][1])
|
||||
if has_key(seen, key)
|
||||
call remove(list, i)
|
||||
else
|
||||
let seen[key] = 1
|
||||
let i += 1
|
||||
endif
|
||||
endwhile
|
||||
return map(list, 'v:val[0]')
|
||||
endfunction
|
||||
|
||||
function! s:clear(list) abort
|
||||
if !empty(a:list)
|
||||
unlet! a:list[0 : len(a:list) - 1]
|
||||
endif
|
||||
return a:list
|
||||
endfunction
|
||||
|
||||
" Concatenates a list of lists.
|
||||
" XXX: Should we verify the input?
|
||||
function! s:concat(list) abort
|
||||
let memo = []
|
||||
for Value in a:list
|
||||
let memo += Value
|
||||
endfor
|
||||
return memo
|
||||
endfunction
|
||||
|
||||
" Take each elements from lists to a new list.
|
||||
function! s:flatten(list, ...) abort
|
||||
let limit = a:0 > 0 ? a:1 : -1
|
||||
let memo = []
|
||||
if limit == 0
|
||||
return a:list
|
||||
endif
|
||||
let limit -= 1
|
||||
for Value in a:list
|
||||
let memo +=
|
||||
\ type(Value) == type([]) ?
|
||||
\ s:flatten(Value, limit) :
|
||||
\ [Value]
|
||||
unlet! Value
|
||||
endfor
|
||||
return memo
|
||||
endfunction
|
||||
|
||||
" Sorts a list with expression to compare each two values.
|
||||
" a:a and a:b can be used in {expr}.
|
||||
function! s:sort(list, expr) abort
|
||||
if type(a:expr) == type(function('function'))
|
||||
return sort(a:list, a:expr)
|
||||
endif
|
||||
let s:expr = a:expr
|
||||
return sort(a:list, 's:_compare')
|
||||
endfunction
|
||||
|
||||
function! s:_compare(a, b) abort
|
||||
return eval(s:expr)
|
||||
endfunction
|
||||
|
||||
" Sorts a list using a set of keys generated by mapping the values in the list
|
||||
" through the given expr.
|
||||
" v:val is used in {expr}
|
||||
function! s:sort_by(list, expr) abort
|
||||
let pairs = map(a:list, printf('[v:val, %s]', a:expr))
|
||||
return map(s:sort(pairs,
|
||||
\ 'a:a[1] ==# a:b[1] ? 0 : a:a[1] ># a:b[1] ? 1 : -1'), 'v:val[0]')
|
||||
endfunction
|
||||
|
||||
" Returns a maximum value in {list} through given {expr}.
|
||||
" Returns 0 if {list} is empty.
|
||||
" v:val is used in {expr}
|
||||
function! s:max_by(list, expr) abort
|
||||
if empty(a:list)
|
||||
return 0
|
||||
endif
|
||||
let list = map(copy(a:list), a:expr)
|
||||
return a:list[index(list, max(list))]
|
||||
endfunction
|
||||
|
||||
" Returns a minimum value in {list} through given {expr}.
|
||||
" Returns 0 if {list} is empty.
|
||||
" v:val is used in {expr}
|
||||
" FIXME: -0x80000000 == 0x80000000
|
||||
function! s:min_by(list, expr) abort
|
||||
return s:max_by(a:list, '-(' . a:expr . ')')
|
||||
endfunction
|
||||
|
||||
" Returns List of character sequence between [a:from, a:to]
|
||||
" e.g.: s:char_range('a', 'c') returns ['a', 'b', 'c']
|
||||
function! s:char_range(from, to) abort
|
||||
return map(
|
||||
\ range(char2nr(a:from), char2nr(a:to)),
|
||||
\ 'nr2char(v:val)'
|
||||
\)
|
||||
endfunction
|
||||
|
||||
" Returns true if a:list has a:value.
|
||||
" Returns false otherwise.
|
||||
function! s:has(list, value) abort
|
||||
return index(a:list, a:value) isnot -1
|
||||
endfunction
|
||||
|
||||
" Returns true if a:list[a:index] exists.
|
||||
" Returns false otherwise.
|
||||
" NOTE: Returns false when a:index is negative number.
|
||||
function! s:has_index(list, index) abort
|
||||
" Return true when negative index?
|
||||
" let index = a:index >= 0 ? a:index : len(a:list) + a:index
|
||||
return 0 <= a:index && a:index < len(a:list)
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Data.List.span
|
||||
function! s:span(f, xs) abort
|
||||
let border = len(a:xs)
|
||||
for i in range(len(a:xs))
|
||||
if !eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g'))
|
||||
let border = i
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
return border == 0 ? [[], copy(a:xs)] : [a:xs[: border - 1], a:xs[border :]]
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Data.List.break
|
||||
function! s:break(f, xs) abort
|
||||
return s:span(printf('!(%s)', a:f), a:xs)
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Data.List.takeWhile
|
||||
function! s:take_while(f, xs) abort
|
||||
return s:span(a:f, a:xs)[0]
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Data.List.partition
|
||||
function! s:partition(f, xs) abort
|
||||
return [filter(copy(a:xs), a:f), filter(copy(a:xs), '!(' . a:f . ')')]
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Prelude.all
|
||||
function! s:all(f, xs) abort
|
||||
return !s:any(printf('!(%s)', a:f), a:xs)
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Prelude.any
|
||||
function! s:any(f, xs) abort
|
||||
return !empty(filter(map(copy(a:xs), a:f), 'v:val'))
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Prelude.and
|
||||
function! s:and(xs) abort
|
||||
return s:all('v:val', a:xs)
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Prelude.or
|
||||
function! s:or(xs) abort
|
||||
return s:any('v:val', a:xs)
|
||||
endfunction
|
||||
|
||||
function! s:map_accum(expr, xs, init) abort
|
||||
let memo = []
|
||||
let init = a:init
|
||||
for x in a:xs
|
||||
let expr = substitute(a:expr, 'v:memo', init, 'g')
|
||||
let expr = substitute(expr, 'v:val', x, 'g')
|
||||
let [tmp, init] = eval(expr)
|
||||
call add(memo, tmp)
|
||||
endfor
|
||||
return memo
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Prelude.foldl
|
||||
function! s:foldl(f, init, xs) abort
|
||||
let memo = a:init
|
||||
for x in a:xs
|
||||
let expr = substitute(a:f, 'v:val', string(x), 'g')
|
||||
let expr = substitute(expr, 'v:memo', string(memo), 'g')
|
||||
unlet memo
|
||||
let memo = eval(expr)
|
||||
endfor
|
||||
return memo
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Prelude.foldl1
|
||||
function! s:foldl1(f, xs) abort
|
||||
if len(a:xs) == 0
|
||||
throw 'vital: Data.List: foldl1'
|
||||
endif
|
||||
return s:foldl(a:f, a:xs[0], a:xs[1:])
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Prelude.foldr
|
||||
function! s:foldr(f, init, xs) abort
|
||||
return s:foldl(a:f, a:init, reverse(copy(a:xs)))
|
||||
endfunction
|
||||
|
||||
" similar to Haskell's Prelude.fold11
|
||||
function! s:foldr1(f, xs) abort
|
||||
if len(a:xs) == 0
|
||||
throw 'vital: Data.List: foldr1'
|
||||
endif
|
||||
return s:foldr(a:f, a:xs[-1], a:xs[0:-2])
|
||||
endfunction
|
||||
|
||||
" similar to python's zip()
|
||||
function! s:zip(...) abort
|
||||
return map(range(min(map(copy(a:000), 'len(v:val)'))), "map(copy(a:000), 'v:val['.v:val.']')")
|
||||
endfunction
|
||||
|
||||
" similar to zip(), but goes until the longer one.
|
||||
function! s:zip_fill(xs, ys, filler) abort
|
||||
if empty(a:xs) && empty(a:ys)
|
||||
return []
|
||||
elseif empty(a:ys)
|
||||
return s:cons([a:xs[0], a:filler], s:zip_fill(a:xs[1 :], [], a:filler))
|
||||
elseif empty(a:xs)
|
||||
return s:cons([a:filler, a:ys[0]], s:zip_fill([], a:ys[1 :], a:filler))
|
||||
else
|
||||
return s:cons([a:xs[0], a:ys[0]], s:zip_fill(a:xs[1 :], a:ys[1: ], a:filler))
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Inspired by Ruby's with_index method.
|
||||
function! s:with_index(list, ...) abort
|
||||
let base = a:0 > 0 ? a:1 : 0
|
||||
return map(copy(a:list), '[v:val, v:key + base]')
|
||||
endfunction
|
||||
|
||||
" similar to Ruby's detect or Haskell's find.
|
||||
function! s:find(list, default, f) abort
|
||||
for x in a:list
|
||||
if eval(substitute(a:f, 'v:val', string(x), 'g'))
|
||||
return x
|
||||
endif
|
||||
endfor
|
||||
return a:default
|
||||
endfunction
|
||||
|
||||
" Returns the index of the first element which satisfies the given expr.
|
||||
function! s:find_index(xs, f, ...) abort
|
||||
let len = len(a:xs)
|
||||
let start = a:0 > 0 ? (a:1 < 0 ? len + a:1 : a:1) : 0
|
||||
let default = a:0 > 1 ? a:2 : -1
|
||||
if start >=# len || start < 0
|
||||
return default
|
||||
endif
|
||||
for i in range(start, len - 1)
|
||||
if eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g'))
|
||||
return i
|
||||
endif
|
||||
endfor
|
||||
return default
|
||||
endfunction
|
||||
|
||||
" Returns the index of the last element which satisfies the given expr.
|
||||
function! s:find_last_index(xs, f, ...) abort
|
||||
let len = len(a:xs)
|
||||
let start = a:0 > 0 ? (a:1 < 0 ? len + a:1 : a:1) : len - 1
|
||||
let default = a:0 > 1 ? a:2 : -1
|
||||
if start >=# len || start < 0
|
||||
return default
|
||||
endif
|
||||
for i in range(start, 0, -1)
|
||||
if eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g'))
|
||||
return i
|
||||
endif
|
||||
endfor
|
||||
return default
|
||||
endfunction
|
||||
|
||||
" Similar to find_index but returns the list of indices satisfying the given expr.
|
||||
function! s:find_indices(xs, f, ...) abort
|
||||
let len = len(a:xs)
|
||||
let start = a:0 > 0 ? (a:1 < 0 ? len + a:1 : a:1) : 0
|
||||
let result = []
|
||||
if start >=# len || start < 0
|
||||
return result
|
||||
endif
|
||||
for i in range(start, len - 1)
|
||||
if eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g'))
|
||||
call add(result, i)
|
||||
endif
|
||||
endfor
|
||||
return result
|
||||
endfunction
|
||||
|
||||
" Return non-zero if a:list1 and a:list2 have any common item(s).
|
||||
" Return zero otherwise.
|
||||
function! s:has_common_items(list1, list2) abort
|
||||
return !empty(filter(copy(a:list1), 'index(a:list2, v:val) isnot -1'))
|
||||
endfunction
|
||||
|
||||
function! s:intersect(list1, list2) abort
|
||||
let items = []
|
||||
" for funcref
|
||||
for X in a:list1
|
||||
if index(a:list2, X) != -1 && index(items, X) == -1
|
||||
let items += [X]
|
||||
endif
|
||||
endfor
|
||||
return items
|
||||
endfunction
|
||||
|
||||
" similar to Ruby's group_by.
|
||||
function! s:group_by(xs, f) abort
|
||||
let result = {}
|
||||
let list = map(copy(a:xs), printf('[v:val, %s]', a:f))
|
||||
for x in list
|
||||
let Val = x[0]
|
||||
let key = type(x[1]) !=# type('') ? string(x[1]) : x[1]
|
||||
if has_key(result, key)
|
||||
call add(result[key], Val)
|
||||
else
|
||||
let result[key] = [Val]
|
||||
endif
|
||||
unlet Val
|
||||
endfor
|
||||
return result
|
||||
endfunction
|
||||
|
||||
function! s:_default_compare(a, b) abort
|
||||
return a:a <# a:b ? -1 : a:a ># a:b ? 1 : 0
|
||||
endfunction
|
||||
|
||||
function! s:binary_search(list, value, ...) abort
|
||||
let Predicate = a:0 >= 1 ? a:1 : 's:_default_compare'
|
||||
let dic = a:0 >= 2 ? a:2 : {}
|
||||
let start = 0
|
||||
let end = len(a:list) - 1
|
||||
|
||||
while 1
|
||||
if start > end
|
||||
return -1
|
||||
endif
|
||||
|
||||
let middle = (start + end) / 2
|
||||
|
||||
let compared = call(Predicate, [a:value, a:list[middle]], dic)
|
||||
|
||||
if compared < 0
|
||||
let end = middle - 1
|
||||
elseif compared > 0
|
||||
let start = middle + 1
|
||||
else
|
||||
return middle
|
||||
endif
|
||||
endwhile
|
||||
endfunction
|
||||
|
||||
function! s:product(lists) abort
|
||||
let result = [[]]
|
||||
for pool in a:lists
|
||||
let tmp = []
|
||||
for x in result
|
||||
let tmp += map(copy(pool), 'x + [v:val]')
|
||||
endfor
|
||||
let result = tmp
|
||||
endfor
|
||||
return result
|
||||
endfunction
|
||||
|
||||
function! s:permutations(list, ...) abort
|
||||
if a:0 > 1
|
||||
throw 'vital: Data.List: too many arguments'
|
||||
endif
|
||||
let r = a:0 == 1 ? a:1 : len(a:list)
|
||||
if r > len(a:list)
|
||||
return []
|
||||
elseif r < 0
|
||||
throw 'vital: Data.List: {r} must be non-negative integer'
|
||||
endif
|
||||
let n = len(a:list)
|
||||
let result = []
|
||||
for indices in s:product(map(range(r), 'range(n)'))
|
||||
if len(s:uniq(indices)) == r
|
||||
call add(result, map(indices, 'a:list[v:val]'))
|
||||
endif
|
||||
endfor
|
||||
return result
|
||||
endfunction
|
||||
|
||||
function! s:combinations(list, r) abort
|
||||
if a:r > len(a:list)
|
||||
return []
|
||||
elseif a:r < 0
|
||||
throw 'vital: Data:List: {r} must be non-negative integer'
|
||||
endif
|
||||
let n = len(a:list)
|
||||
let result = []
|
||||
for indices in s:permutations(range(n), a:r)
|
||||
if s:sort(copy(indices), 'a:a - a:b') == indices
|
||||
call add(result, map(indices, 'a:list[v:val]'))
|
||||
endif
|
||||
endfor
|
||||
return result
|
||||
endfunction
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
||||
|
||||
" vim:set et ts=2 sts=2 sw=2 tw=0:
|
@ -0,0 +1,284 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not mofidify the code nor insert new lines before '" ___vital___'
|
||||
if v:version > 703 || v:version == 703 && has('patch1170')
|
||||
function! vital#_easymotion#Data#Set#import() abort
|
||||
return map({'set': '', 'frozenset': ''}, 'function("s:" . v:key)')
|
||||
endfunction
|
||||
else
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_easymotion#Data#Set#import() abort', printf("return map({'set': '', 'frozenset': ''}, \"function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
endif
|
||||
" ___vital___
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
let s:TRUE = !0
|
||||
let s:FALSE = 0
|
||||
|
||||
function! s:set(...) abort
|
||||
return call(s:set._new, a:000, s:set)
|
||||
endfunction
|
||||
|
||||
function! s:frozenset(...) abort
|
||||
return call(s:frozenset._new, a:000, s:frozenset)
|
||||
endfunction
|
||||
|
||||
function! s:_hash_func(x) abort
|
||||
return a:x
|
||||
endfunction
|
||||
|
||||
let s:_base_set = {
|
||||
\ '_is_set' : s:TRUE,
|
||||
\ '_data' : {},
|
||||
\ '_hash_func' : function('s:_hash_func')
|
||||
\ }
|
||||
|
||||
function! s:_base_set._new(...) abort
|
||||
let obj = deepcopy(self)
|
||||
let xs = get(a:, 1, [])
|
||||
let obj._hash_func = get(a:, 2, obj._hash_func)
|
||||
call obj._set_data(xs)
|
||||
return obj
|
||||
endfunction
|
||||
|
||||
"" Return the union of two sets as a new set.
|
||||
" (I.e. all elements that are in either set.)
|
||||
function! s:_base_set.union(t) abort
|
||||
let r = deepcopy(self)
|
||||
call r._update(a:t)
|
||||
return r
|
||||
endfunction
|
||||
let s:_base_set.or = s:_base_set.union
|
||||
|
||||
"" Return the intersection of two sets as a new set.
|
||||
" (I.e. all elements that are in both sets.)
|
||||
function! s:_base_set.intersection(t) abort
|
||||
let t = self._to_set(a:t)
|
||||
let [little, big] = self.len() <= t.len() ? [self, t] : [t, self]
|
||||
return self._new(filter(copy(big.to_list()), 'little.in(v:val)'))
|
||||
endfunction
|
||||
let s:_base_set.and = s:_base_set.intersection
|
||||
|
||||
"" Return the symmetric difference of two sets as a new set.
|
||||
" (I.e. all elements that are in exactly one of the sets.)
|
||||
function! s:_base_set.symmetric_difference(t) abort
|
||||
let t = self._to_set(a:t)
|
||||
return self._new(filter(copy(self.to_list()), '!t.in(v:val)')
|
||||
\ + filter(copy(t.to_list()), '!self.in(v:val)'))
|
||||
endfunction
|
||||
let s:_base_set.xor = s:_base_set.symmetric_difference
|
||||
|
||||
"" Return the difference of two sets as a new Set.
|
||||
function! s:_base_set.difference(t) abort
|
||||
let t = self._to_set(a:t)
|
||||
return self._new(filter(copy(self.to_list()), '!t.in(v:val)'))
|
||||
endfunction
|
||||
let s:_base_set.sub = s:_base_set.difference
|
||||
|
||||
"" Report whether another set contains this set.
|
||||
function! s:_base_set.issubset(t) abort
|
||||
let t = self._to_set(a:t)
|
||||
return self.len() > t.len() ? s:FALSE
|
||||
\ : empty(filter(copy(self.to_list()), '!t.in(v:val)'))
|
||||
endfunction
|
||||
|
||||
"" Report whether this set contains another set.
|
||||
function! s:_base_set.issuperset(t) abort
|
||||
let t = self._to_set(a:t)
|
||||
return self.len() < t.len() ? s:FALSE
|
||||
\ : empty(filter(copy(t.to_list()), '!self.in(v:val)'))
|
||||
endfunction
|
||||
|
||||
" less than equal & greater than equal
|
||||
let s:_base_set.le = s:_base_set.issubset
|
||||
let s:_base_set.ge = s:_base_set.issuperset
|
||||
|
||||
" less than
|
||||
function! s:_base_set.lt(t) abort
|
||||
let t = self._to_set(a:t)
|
||||
return self.len() < t.len() && self.issubset(t)
|
||||
endfunction
|
||||
|
||||
" greater than
|
||||
function! s:_base_set.gt(t) abort
|
||||
let t = self._to_set(a:t)
|
||||
return self.len() > t.len() && self.issuperset(t)
|
||||
endfunction
|
||||
|
||||
function! s:_base_set.len() abort
|
||||
return len(self._data)
|
||||
endfunction
|
||||
|
||||
function! s:_base_set.to_list() abort
|
||||
return values(self._data)
|
||||
endfunction
|
||||
|
||||
function! s:_base_set._update(xs) abort
|
||||
for X in (s:_is_set(a:xs) ? a:xs.to_list() : a:xs)
|
||||
call self._add(X)
|
||||
unlet X
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! s:_base_set._add(x) abort
|
||||
let key = self._hash(a:x)
|
||||
if !has_key(self._data, key)
|
||||
let self._data[key] = a:x
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Report whether an element is a member of a set.
|
||||
function! s:_base_set.in(x) abort
|
||||
return has_key(self._data, self._hash(a:x))
|
||||
endfunction
|
||||
|
||||
function! s:_base_set._to_set(x) abort
|
||||
return s:_is_set(a:x) ? a:x : self._new(a:x)
|
||||
endfunction
|
||||
|
||||
function! s:_base_set._clear() abort
|
||||
let self._data = {}
|
||||
endfunction
|
||||
|
||||
function! s:_base_set._set_data(xs) abort
|
||||
call self._clear()
|
||||
call self._update(a:xs)
|
||||
endfunction
|
||||
|
||||
function! s:_base_set._hash(x) abort
|
||||
return string(self._hash_func(a:x))
|
||||
endfunction
|
||||
|
||||
" frozenset: Immutable set class.
|
||||
|
||||
let s:frozenset = deepcopy(s:_base_set)
|
||||
|
||||
" Set: Mutable set class.
|
||||
|
||||
let s:set = deepcopy(s:_base_set)
|
||||
|
||||
" Update a set with the union of itself and another.
|
||||
function! s:set.update(iterable) abort
|
||||
call self._update(a:iterable)
|
||||
endfunction
|
||||
|
||||
" Update a set with the union of itself and another.
|
||||
function! s:set.ior(t) abort
|
||||
call self.update(a:t)
|
||||
return self
|
||||
endfunction
|
||||
|
||||
" Update a set with the intersection of itself and another.
|
||||
function! s:set.intersection_update(t) abort
|
||||
let r = self.and(a:t).to_list()
|
||||
call self.clear()
|
||||
call self.update(r)
|
||||
endfunction
|
||||
|
||||
" Update a set with the intersection of itself and another.
|
||||
function! s:set.iand(t) abort
|
||||
call self.intersection_update(a:t)
|
||||
return self
|
||||
endfunction
|
||||
|
||||
" Update a set with the symmetric difference of itself and another.
|
||||
function! s:set.symmetric_difference_update(t) abort
|
||||
let t = self._to_set(a:t)
|
||||
if self is t
|
||||
call self.clear()
|
||||
return
|
||||
endif
|
||||
for X in t.to_list()
|
||||
if self.in(X)
|
||||
call self.remove(X)
|
||||
else
|
||||
call self._add(X)
|
||||
endif
|
||||
unlet X
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
" Update a set with the symmetric difference of itself and another.
|
||||
function! s:set.ixor(t) abort
|
||||
call self.symmetric_difference_update(a:t)
|
||||
return self
|
||||
endfunction
|
||||
|
||||
" Remove all elements of another set from this set.
|
||||
function! s:set.difference_update(t) abort
|
||||
let t = self._to_set(a:t)
|
||||
if self is t
|
||||
call self.clear()
|
||||
return
|
||||
endif
|
||||
for X in filter(t.to_list(), 'self.in(v:val)')
|
||||
call self.remove(X)
|
||||
unlet X
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
" Remove all elements of another set from this set.
|
||||
function! s:set.isub(t) abort
|
||||
call self.difference_update(a:t)
|
||||
return self
|
||||
endfunction
|
||||
|
||||
" Remove all elements from this set.
|
||||
function! s:set.clear() abort
|
||||
call self._clear()
|
||||
endfunction
|
||||
|
||||
"" Add an element to a set.
|
||||
" This has no effect if the element is already present.
|
||||
function! s:set.add(x) abort
|
||||
return self._add(a:x)
|
||||
endfunction
|
||||
|
||||
"" Remove an element from a set; it must be a member.
|
||||
" If the element is not a member, throw Exception.
|
||||
function! s:set.remove(e) abort
|
||||
try
|
||||
unlet self._data[self._hash(a:e)]
|
||||
catch /^Vim\%((\a\+)\)\?:E716/
|
||||
call s:_throw('the element is not a member')
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
"" Remove an element from a set if it is a member.
|
||||
" If the element is not a member, do nothing.
|
||||
function! s:set.discard(e) abort
|
||||
try
|
||||
call self.remove(a:e)
|
||||
catch /vital: Data.Set: the element is not a member/
|
||||
" Do nothing
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
" Remove and return an arbitrary set element.
|
||||
function! s:set.pop() abort
|
||||
try
|
||||
let k = keys(self._data)[0]
|
||||
catch /^Vim\%((\a\+)\)\?:E684/
|
||||
call s:_throw('set is empty')
|
||||
endtry
|
||||
let v = self._data[k]
|
||||
unlet self._data[k]
|
||||
return v
|
||||
endfunction
|
||||
|
||||
" Helper:
|
||||
|
||||
function! s:_is_set(x) abort
|
||||
return type(a:x) is type({}) && get(a:x, '_is_set', s:FALSE)
|
||||
endfunction
|
||||
|
||||
function! s:_throw(message) abort
|
||||
throw 'vital: Data.Set: ' . a:message
|
||||
endfunction
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
Reference in New Issue
Block a user