Upgrade vital, add Data.String
This commit is contained in:
		
							parent
							
								
									48689a972d
								
							
						
					
					
						commit
						4fcaf4221f
					
				@ -1,4 +1,4 @@
 | 
			
		||||
function! vital#of(name)
 | 
			
		||||
function! vital#of(name) abort
 | 
			
		||||
  let files = globpath(&runtimepath, 'autoload/vital/' . a:name . '.vital')
 | 
			
		||||
  let file = split(files, "\n")
 | 
			
		||||
  if empty(file)
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,12 @@
 | 
			
		||||
let s:self_version = expand('<sfile>:t:r')
 | 
			
		||||
let s:self_file = expand('<sfile>')
 | 
			
		||||
 | 
			
		||||
" Note: The extra argument to globpath() was added in Patch 7.2.051.
 | 
			
		||||
let s:globpath_third_arg = v:version > 702 || v:version == 702 && has('patch51')
 | 
			
		||||
 | 
			
		||||
let s:loaded = {}
 | 
			
		||||
 | 
			
		||||
function! s:import(name, ...)
 | 
			
		||||
function! s:import(name, ...) abort
 | 
			
		||||
  let target = {}
 | 
			
		||||
  let functions = []
 | 
			
		||||
  for a in a:000
 | 
			
		||||
@ -29,7 +30,7 @@ function! s:import(name, ...)
 | 
			
		||||
  return target
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:load(...) dict
 | 
			
		||||
function! s:load(...) dict abort
 | 
			
		||||
  for arg in a:000
 | 
			
		||||
    let [name; as] = type(arg) == type([]) ? arg[: 1] : [arg, arg]
 | 
			
		||||
    let target = split(join(as, ''), '\W\+')
 | 
			
		||||
@ -55,24 +56,45 @@ function! s:load(...) dict
 | 
			
		||||
  return self
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:unload()
 | 
			
		||||
function! s:unload() abort
 | 
			
		||||
  let s:loaded = {}
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:exists(name)
 | 
			
		||||
function! s:exists(name) abort
 | 
			
		||||
  return s:_get_module_path(a:name) !=# ''
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:search(pattern)
 | 
			
		||||
  let target = substitute(a:pattern, '\.', '/', 'g')
 | 
			
		||||
  let tailpath = printf('autoload/vital/%s/%s.vim', s:self_version, target)
 | 
			
		||||
 | 
			
		||||
  let paths = s:_runtime_files(tailpath)
 | 
			
		||||
function! s:search(pattern) abort
 | 
			
		||||
  let paths = s:_vital_files(a:pattern)
 | 
			
		||||
  let modules = sort(map(paths, 's:_file2module(v:val)'))
 | 
			
		||||
  return s:_uniq(modules)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:_import(name)
 | 
			
		||||
function! s:expand_modules(entry, all) abort
 | 
			
		||||
  if type(a:entry) == type([])
 | 
			
		||||
    let candidates = s:_concat(map(copy(a:entry), 's:search(v:val)'))
 | 
			
		||||
    if empty(candidates)
 | 
			
		||||
      throw printf('vital: Any of module %s is not found', string(a:entry))
 | 
			
		||||
    endif
 | 
			
		||||
    if eval(join(map(copy(candidates), 'has_key(a:all, v:val)'), '+'))
 | 
			
		||||
      let modules = []
 | 
			
		||||
    else
 | 
			
		||||
      let modules = [candidates[0]]
 | 
			
		||||
    endif
 | 
			
		||||
  else
 | 
			
		||||
    let modules = s:search(a:entry)
 | 
			
		||||
    if empty(modules)
 | 
			
		||||
      throw printf('vital: Module %s is not found', a:entry)
 | 
			
		||||
    endif
 | 
			
		||||
  endif
 | 
			
		||||
  call filter(modules, '!has_key(a:all, v:val)')
 | 
			
		||||
  for module in modules
 | 
			
		||||
    let a:all[module] = 1
 | 
			
		||||
  endfor
 | 
			
		||||
  return modules
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:_import(name) abort
 | 
			
		||||
  if type(a:name) == type(0)
 | 
			
		||||
    return s:_build_module(a:name)
 | 
			
		||||
  endif
 | 
			
		||||
@ -80,7 +102,7 @@ function! s:_import(name)
 | 
			
		||||
  if path ==# ''
 | 
			
		||||
    throw 'vital: module not found: ' . a:name
 | 
			
		||||
  endif
 | 
			
		||||
  let sid = get(s:_scripts(), path, 0)
 | 
			
		||||
  let sid = s:_get_sid_by_script(path)
 | 
			
		||||
  if !sid
 | 
			
		||||
    try
 | 
			
		||||
      execute 'source' fnameescape(path)
 | 
			
		||||
@ -90,84 +112,105 @@ function! s:_import(name)
 | 
			
		||||
      " Ignore.
 | 
			
		||||
    endtry
 | 
			
		||||
 | 
			
		||||
    let sid = s:_scripts()[path]
 | 
			
		||||
    let sid = s:_get_sid_by_script(path)
 | 
			
		||||
  endif
 | 
			
		||||
  return s:_build_module(sid)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:_get_module_path(name)
 | 
			
		||||
function! s:_get_module_path(name) abort
 | 
			
		||||
  if s:_is_absolute_path(a:name) && filereadable(a:name)
 | 
			
		||||
    return s:_unify_path(a:name)
 | 
			
		||||
    return a:name
 | 
			
		||||
  endif
 | 
			
		||||
  if a:name ==# ''
 | 
			
		||||
    let tailpath = printf('autoload/vital/%s.vim', s:self_version)
 | 
			
		||||
    let paths = [s:self_file]
 | 
			
		||||
  elseif a:name =~# '\v^\u\w*%(\.\u\w*)*$'
 | 
			
		||||
    let target = substitute(a:name, '\W\+', '/', 'g')
 | 
			
		||||
    let tailpath = printf('autoload/vital/%s/%s.vim', s:self_version, target)
 | 
			
		||||
    let paths = s:_vital_files(a:name)
 | 
			
		||||
  else
 | 
			
		||||
    throw 'vital: Invalid module name: ' . a:name
 | 
			
		||||
  endif
 | 
			
		||||
 | 
			
		||||
  let paths = s:_runtime_files(tailpath)
 | 
			
		||||
  call filter(paths, 'filereadable(v:val)')
 | 
			
		||||
  call filter(paths, 'filereadable(expand(v:val, 1))')
 | 
			
		||||
  let path = get(paths, 0, '')
 | 
			
		||||
  return path !=# '' ? s:_unify_path(path) : ''
 | 
			
		||||
  return path !=# '' ? path : ''
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:_scripts()
 | 
			
		||||
  let scripts = {}
 | 
			
		||||
function! s:_get_sid_by_script(path) abort
 | 
			
		||||
  let path = s:_unify_path(a:path)
 | 
			
		||||
  for line in filter(split(s:_redir('scriptnames'), "\n"),
 | 
			
		||||
  \                  'stridx(v:val, s:self_version) > 0')
 | 
			
		||||
    let list = matchlist(line, '^\s*\(\d\+\):\s\+\(.\+\)\s*$')
 | 
			
		||||
    if !empty(list)
 | 
			
		||||
      let scripts[s:_unify_path(list[2])] = list[1] - 0
 | 
			
		||||
    if !empty(list) && s:_unify_path(list[2]) ==# path
 | 
			
		||||
      return list[1] - 0
 | 
			
		||||
    endif
 | 
			
		||||
  endfor
 | 
			
		||||
  return scripts
 | 
			
		||||
  return 0
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:_file2module(file)
 | 
			
		||||
  let filename = s:_unify_path(a:file)
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
if filereadable(expand('<sfile>:r') . '.VIM')
 | 
			
		||||
  function! s:_unify_path(path)
 | 
			
		||||
    " 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.
 | 
			
		||||
    return tolower(fnamemodify(resolve(fnamemodify(
 | 
			
		||||
    \              a:path, ':p:gs?[\\/]\+?/?')), ':~'))
 | 
			
		||||
  " resolve() is slow, so we cache results.
 | 
			
		||||
  let s:_unify_path_cache = {}
 | 
			
		||||
  " 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)
 | 
			
		||||
    return resolve(fnamemodify(a:path, ':p:gs?[\\/]\+?/?'))
 | 
			
		||||
  function! s:_unify_path(path) abort
 | 
			
		||||
    return resolve(fnamemodify(a:path, ':p:gs?[\\/]?/?'))
 | 
			
		||||
  endfunction
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
if s:globpath_third_arg
 | 
			
		||||
  function! s:_runtime_files(path)
 | 
			
		||||
  function! s:_runtime_files(path) abort
 | 
			
		||||
    return split(globpath(&runtimepath, a:path, 1), "\n")
 | 
			
		||||
  endfunction
 | 
			
		||||
else
 | 
			
		||||
  function! s:_runtime_files(path)
 | 
			
		||||
  function! s:_runtime_files(path) abort
 | 
			
		||||
    return split(globpath(&runtimepath, a:path), "\n")
 | 
			
		||||
  endfunction
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
let s:_vital_files_cache_runtimepath = ''
 | 
			
		||||
let s:_vital_files_cache = []
 | 
			
		||||
function! s:_vital_files(pattern) abort
 | 
			
		||||
  if s:_vital_files_cache_runtimepath !=# &runtimepath
 | 
			
		||||
    let path = printf('autoload/vital/%s/**/*.vim', s:self_version)
 | 
			
		||||
    let s:_vital_files_cache = s:_runtime_files(path)
 | 
			
		||||
    let mod = ':p:gs?[\\/]\+?/?'
 | 
			
		||||
    call map(s:_vital_files_cache, 'fnamemodify(v:val, mod)')
 | 
			
		||||
    let s:_vital_files_cache_runtimepath = &runtimepath
 | 
			
		||||
  endif
 | 
			
		||||
  let target = substitute(a:pattern, '\.', '/', 'g')
 | 
			
		||||
  let target = substitute(target, '\*', '[^/]*', 'g')
 | 
			
		||||
  let regexp = printf('autoload/vital/%s/%s.vim', s:self_version, target)
 | 
			
		||||
  return filter(copy(s:_vital_files_cache), 'v:val =~# regexp')
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" Copy from System.Filepath
 | 
			
		||||
if has('win16') || has('win32') || has('win64')
 | 
			
		||||
  function! s:_is_absolute_path(path)
 | 
			
		||||
  function! s:_is_absolute_path(path) abort
 | 
			
		||||
    return a:path =~? '^[a-z]:[/\\]'
 | 
			
		||||
  endfunction
 | 
			
		||||
else
 | 
			
		||||
  function! s:_is_absolute_path(path)
 | 
			
		||||
  function! s:_is_absolute_path(path) abort
 | 
			
		||||
    return a:path[0] ==# '/'
 | 
			
		||||
  endfunction
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
function! s:_build_module(sid)
 | 
			
		||||
function! s:_build_module(sid) abort
 | 
			
		||||
  if has_key(s:loaded, a:sid)
 | 
			
		||||
    return copy(s:loaded[a:sid])
 | 
			
		||||
  endif
 | 
			
		||||
@ -181,7 +224,11 @@ function! s:_build_module(sid)
 | 
			
		||||
  if has_key(module, '_vital_loaded')
 | 
			
		||||
    let V = vital#{s:self_version}#new()
 | 
			
		||||
    if has_key(module, '_vital_depends')
 | 
			
		||||
      call call(V.load, module._vital_depends(), V)
 | 
			
		||||
      let all = {}
 | 
			
		||||
      let modules =
 | 
			
		||||
      \     s:_concat(map(module._vital_depends(),
 | 
			
		||||
      \                   's:expand_modules(v:val, all)'))
 | 
			
		||||
      call call(V.load, modules, V)
 | 
			
		||||
    endif
 | 
			
		||||
    try
 | 
			
		||||
      call module._vital_loaded(V)
 | 
			
		||||
@ -197,13 +244,13 @@ function! s:_build_module(sid)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
if exists('+regexpengine')
 | 
			
		||||
  function! s:_get_functions(sid)
 | 
			
		||||
  function! s:_get_functions(sid) abort
 | 
			
		||||
    let funcs = s:_redir(printf("function /\\%%#=2^\<SNR>%d_", a:sid))
 | 
			
		||||
    let map_pat = '<SNR>' . a:sid . '_\zs\w\+'
 | 
			
		||||
    return map(split(funcs, "\n"), 'matchstr(v:val, map_pat)')
 | 
			
		||||
  endfunction
 | 
			
		||||
else
 | 
			
		||||
  function! s:_get_functions(sid)
 | 
			
		||||
  function! s:_get_functions(sid) abort
 | 
			
		||||
    let prefix = '<SNR>' . a:sid . '_'
 | 
			
		||||
    let funcs = s:_redir('function')
 | 
			
		||||
    let filter_pat = '^\s*function ' . prefix
 | 
			
		||||
@ -215,11 +262,11 @@ else
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
if exists('*uniq')
 | 
			
		||||
  function! s:_uniq(list)
 | 
			
		||||
  function! s:_uniq(list) abort
 | 
			
		||||
    return uniq(a:list)
 | 
			
		||||
  endfunction
 | 
			
		||||
else
 | 
			
		||||
  function! s:_uniq(list)
 | 
			
		||||
  function! s:_uniq(list) abort
 | 
			
		||||
    let i = len(a:list) - 1
 | 
			
		||||
    while 0 < i
 | 
			
		||||
      if a:list[i] ==# a:list[i - 1]
 | 
			
		||||
@ -233,7 +280,15 @@ else
 | 
			
		||||
  endfunction
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
function! s:_redir(cmd)
 | 
			
		||||
function! s:_concat(lists) abort
 | 
			
		||||
  let result_list = []
 | 
			
		||||
  for list in a:lists
 | 
			
		||||
    let result_list += list
 | 
			
		||||
  endfor
 | 
			
		||||
  return result_list
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:_redir(cmd) abort
 | 
			
		||||
  let [save_verbose, save_verbosefile] = [&verbose, &verbosefile]
 | 
			
		||||
  set verbose=0 verbosefile=
 | 
			
		||||
  redir => res
 | 
			
		||||
@ -243,6 +298,6 @@ function! s:_redir(cmd)
 | 
			
		||||
  return res
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! vital#{s:self_version}#new()
 | 
			
		||||
function! vital#{s:self_version}#new() abort
 | 
			
		||||
  return s:_import('')
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
@ -3,38 +3,38 @@
 | 
			
		||||
let s:save_cpo = &cpo
 | 
			
		||||
set cpo&vim
 | 
			
		||||
 | 
			
		||||
function! s:pop(list)
 | 
			
		||||
function! s:pop(list) abort
 | 
			
		||||
  return remove(a:list, -1)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:push(list, val)
 | 
			
		||||
function! s:push(list, val) abort
 | 
			
		||||
  call add(a:list, a:val)
 | 
			
		||||
  return a:list
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:shift(list)
 | 
			
		||||
function! s:shift(list) abort
 | 
			
		||||
  return remove(a:list, 0)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:unshift(list, val)
 | 
			
		||||
function! s:unshift(list, val) abort
 | 
			
		||||
  return insert(a:list, a:val)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:cons(x, xs)
 | 
			
		||||
function! s:cons(x, xs) abort
 | 
			
		||||
  return [a:x] + a:xs
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:conj(xs, x)
 | 
			
		||||
function! s:conj(xs, x) abort
 | 
			
		||||
  return a:xs + [a:x]
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" Removes duplicates from a list.
 | 
			
		||||
function! s:uniq(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)
 | 
			
		||||
function! s:uniq_by(list, f) abort
 | 
			
		||||
  let list = map(copy(a:list), printf('[v:val, %s]', a:f))
 | 
			
		||||
  let i = 0
 | 
			
		||||
  let seen = {}
 | 
			
		||||
@ -50,7 +50,7 @@ function! s:uniq_by(list, f)
 | 
			
		||||
  return map(list, 'v:val[0]')
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:clear(list)
 | 
			
		||||
function! s:clear(list) abort
 | 
			
		||||
  if !empty(a:list)
 | 
			
		||||
    unlet! a:list[0 : len(a:list) - 1]
 | 
			
		||||
  endif
 | 
			
		||||
@ -59,7 +59,7 @@ endfunction
 | 
			
		||||
 | 
			
		||||
" Concatenates a list of lists.
 | 
			
		||||
" XXX: Should we verify the input?
 | 
			
		||||
function! s:concat(list)
 | 
			
		||||
function! s:concat(list) abort
 | 
			
		||||
  let memo = []
 | 
			
		||||
  for Value in a:list
 | 
			
		||||
    let memo += Value
 | 
			
		||||
@ -68,7 +68,7 @@ function! s:concat(list)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" Take each elements from lists to a new list.
 | 
			
		||||
function! s:flatten(list, ...)
 | 
			
		||||
function! s:flatten(list, ...) abort
 | 
			
		||||
  let limit = a:0 > 0 ? a:1 : -1
 | 
			
		||||
  let memo = []
 | 
			
		||||
  if limit == 0
 | 
			
		||||
@ -87,7 +87,7 @@ 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)
 | 
			
		||||
function! s:sort(list, expr) abort
 | 
			
		||||
  if type(a:expr) == type(function('function'))
 | 
			
		||||
    return sort(a:list, a:expr)
 | 
			
		||||
  endif
 | 
			
		||||
@ -95,14 +95,14 @@ function! s:sort(list, expr)
 | 
			
		||||
  return sort(a:list, 's:_compare')
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:_compare(a, b)
 | 
			
		||||
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)
 | 
			
		||||
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]')
 | 
			
		||||
@ -111,7 +111,7 @@ 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)
 | 
			
		||||
function! s:max_by(list, expr) abort
 | 
			
		||||
  if empty(a:list)
 | 
			
		||||
    return 0
 | 
			
		||||
  endif
 | 
			
		||||
@ -123,13 +123,13 @@ endfunction
 | 
			
		||||
" Returns 0 if {list} is empty.
 | 
			
		||||
" v:val is used in {expr}
 | 
			
		||||
" FIXME: -0x80000000 == 0x80000000
 | 
			
		||||
function! s:min_by(list, expr)
 | 
			
		||||
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)
 | 
			
		||||
function! s:char_range(from, to) abort
 | 
			
		||||
  return map(
 | 
			
		||||
  \   range(char2nr(a:from), char2nr(a:to)),
 | 
			
		||||
  \   'nr2char(v:val)'
 | 
			
		||||
@ -138,21 +138,21 @@ endfunction
 | 
			
		||||
 | 
			
		||||
" Returns true if a:list has a:value.
 | 
			
		||||
" Returns false otherwise.
 | 
			
		||||
function! s:has(list, value)
 | 
			
		||||
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)
 | 
			
		||||
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)
 | 
			
		||||
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'))
 | 
			
		||||
@ -164,41 +164,41 @@ function! s:span(f, xs)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" similar to Haskell's Data.List.break
 | 
			
		||||
function! s:break(f, xs)
 | 
			
		||||
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)
 | 
			
		||||
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)
 | 
			
		||||
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)
 | 
			
		||||
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)
 | 
			
		||||
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)
 | 
			
		||||
function! s:and(xs) abort
 | 
			
		||||
  return s:all('v:val', a:xs)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" similar to Haskell's Prelude.or
 | 
			
		||||
function! s:or(xs)
 | 
			
		||||
function! s:or(xs) abort
 | 
			
		||||
  return s:any('v:val', a:xs)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:map_accum(expr, xs, init)
 | 
			
		||||
function! s:map_accum(expr, xs, init) abort
 | 
			
		||||
  let memo = []
 | 
			
		||||
  let init = a:init
 | 
			
		||||
  for x in a:xs
 | 
			
		||||
@ -211,7 +211,7 @@ function! s:map_accum(expr, xs, init)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" similar to Haskell's Prelude.foldl
 | 
			
		||||
function! s:foldl(f, init, xs)
 | 
			
		||||
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')
 | 
			
		||||
@ -223,7 +223,7 @@ function! s:foldl(f, init, xs)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" similar to Haskell's Prelude.foldl1
 | 
			
		||||
function! s:foldl1(f, xs)
 | 
			
		||||
function! s:foldl1(f, xs) abort
 | 
			
		||||
  if len(a:xs) == 0
 | 
			
		||||
    throw 'foldl1'
 | 
			
		||||
  endif
 | 
			
		||||
@ -231,12 +231,12 @@ function! s:foldl1(f, xs)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" similar to Haskell's Prelude.foldr
 | 
			
		||||
function! s:foldr(f, init, xs)
 | 
			
		||||
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)
 | 
			
		||||
function! s:foldr1(f, xs) abort
 | 
			
		||||
  if len(a:xs) == 0
 | 
			
		||||
    throw 'foldr1'
 | 
			
		||||
  endif
 | 
			
		||||
@ -244,12 +244,12 @@ function! s:foldr1(f, xs)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" similar to python's zip()
 | 
			
		||||
function! 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)
 | 
			
		||||
function! s:zip_fill(xs, ys, filler) abort
 | 
			
		||||
  if empty(a:xs) && empty(a:ys)
 | 
			
		||||
    return []
 | 
			
		||||
  elseif empty(a:ys)
 | 
			
		||||
@ -262,14 +262,13 @@ function! s:zip_fill(xs, ys, filler)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" Inspired by Ruby's with_index method.
 | 
			
		||||
function! s:with_index(list, ...)
 | 
			
		||||
function! s:with_index(list, ...) abort
 | 
			
		||||
  let base = a:0 > 0 ? a:1 : 0
 | 
			
		||||
  return s:zip(a:list, range(base, len(a:list)+base-1))
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" similar to Ruby's detect or Haskell's find.
 | 
			
		||||
" TODO spec and doc
 | 
			
		||||
function! s:find(list, default, f)
 | 
			
		||||
function! s:find(list, default, f) abort
 | 
			
		||||
  for x in a:list
 | 
			
		||||
    if eval(substitute(a:f, 'v:val', string(x), 'g'))
 | 
			
		||||
      return x
 | 
			
		||||
@ -278,12 +277,165 @@ function! s:find(list, default, f)
 | 
			
		||||
  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)
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										551
									
								
								autoload/vital/_neosnippet/Data/String.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										551
									
								
								autoload/vital/_neosnippet/Data/String.vim
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,551 @@
 | 
			
		||||
" Utilities for string.
 | 
			
		||||
 | 
			
		||||
let s:save_cpo = &cpo
 | 
			
		||||
set cpo&vim
 | 
			
		||||
 | 
			
		||||
function! s:_vital_loaded(V) abort
 | 
			
		||||
  let s:V = a:V
 | 
			
		||||
  let s:P = s:V.import('Prelude')
 | 
			
		||||
  let s:L = s:V.import('Data.List')
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:_vital_depends() abort
 | 
			
		||||
  return ['Prelude', 'Data.List']
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" Substitute a:from => a:to by string.
 | 
			
		||||
" To substitute by pattern, use substitute() instead.
 | 
			
		||||
function! s:replace(str, from, to) abort
 | 
			
		||||
  return s:_replace(a:str, a:from, a:to, 'g')
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" Substitute a:from => a:to only once.
 | 
			
		||||
" cf. s:replace()
 | 
			
		||||
function! s:replace_first(str, from, to) abort
 | 
			
		||||
  return s:_replace(a:str, a:from, a:to, '')
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" implement of replace() and replace_first()
 | 
			
		||||
function! s:_replace(str, from, to, flags) abort
 | 
			
		||||
  return substitute(a:str, '\V'.escape(a:from, '\'), escape(a:to, '\'), a:flags)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:scan(str, pattern) abort
 | 
			
		||||
  let list = []
 | 
			
		||||
  call substitute(a:str, a:pattern, '\=add(list, submatch(0)) == [] ? "" : ""', 'g')
 | 
			
		||||
  return list
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:reverse(str) abort
 | 
			
		||||
  return join(reverse(split(a:str, '.\zs')), '')
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:common_head(strs) abort
 | 
			
		||||
  if empty(a:strs)
 | 
			
		||||
    return ''
 | 
			
		||||
  endif
 | 
			
		||||
  let len = len(a:strs)
 | 
			
		||||
  if len == 1
 | 
			
		||||
    return a:strs[0]
 | 
			
		||||
  endif
 | 
			
		||||
  let strs = len == 2 ? a:strs : sort(copy(a:strs))
 | 
			
		||||
  let pat = substitute(strs[0], '.', '\="[" . escape(submatch(0), "^\\") . "]"', 'g')
 | 
			
		||||
  return pat == '' ? '' : matchstr(strs[-1], '\C^\%[' . pat . ']')
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" Split to two elements of List. ([left, right])
 | 
			
		||||
" e.g.: s:split3('neocomplcache', 'compl') returns ['neo', 'compl', 'cache']
 | 
			
		||||
function! s:split_leftright(expr, pattern) abort
 | 
			
		||||
  let [left, _, right] = s:split3(a:expr, a:pattern)
 | 
			
		||||
  return [left, right]
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:split3(expr, pattern) abort
 | 
			
		||||
  let ERROR = ['', '', '']
 | 
			
		||||
  if a:expr ==# '' || a:pattern ==# ''
 | 
			
		||||
    return ERROR
 | 
			
		||||
  endif
 | 
			
		||||
  let begin = match(a:expr, a:pattern)
 | 
			
		||||
  if begin is -1
 | 
			
		||||
    return ERROR
 | 
			
		||||
  endif
 | 
			
		||||
  let end   = matchend(a:expr, a:pattern)
 | 
			
		||||
  let left  = begin <=# 0 ? '' : a:expr[: begin - 1]
 | 
			
		||||
  let right = a:expr[end :]
 | 
			
		||||
  return [left, a:expr[begin : end-1], right]
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" Slices into strings determines the number of substrings.
 | 
			
		||||
" e.g.: s:nsplit("neo compl cache", 2, '\s') returns ['neo', 'compl cache']
 | 
			
		||||
function! s:nsplit(expr, n, ...) abort
 | 
			
		||||
  let pattern = get(a:000, 0, '\s')
 | 
			
		||||
  let keepempty = get(a:000, 1, 1)
 | 
			
		||||
  let ret = []
 | 
			
		||||
  let expr = a:expr
 | 
			
		||||
  if a:n <= 1
 | 
			
		||||
    return [expr]
 | 
			
		||||
  endif
 | 
			
		||||
  while 1
 | 
			
		||||
    let pos = match(expr, pattern)
 | 
			
		||||
    if pos == -1
 | 
			
		||||
      if expr !~ pattern || keepempty
 | 
			
		||||
        call add(ret, expr)
 | 
			
		||||
      endif
 | 
			
		||||
      break
 | 
			
		||||
    elseif pos >= 0
 | 
			
		||||
      let left = pos > 0 ? expr[:pos-1] : ''
 | 
			
		||||
      if pos > 0 || keepempty
 | 
			
		||||
        call add(ret, left)
 | 
			
		||||
      endif
 | 
			
		||||
      let ml = len(matchstr(expr, pattern))
 | 
			
		||||
      if pos == 0 && ml == 0
 | 
			
		||||
        let pos = 1
 | 
			
		||||
      endif
 | 
			
		||||
      let expr = expr[pos+ml :]
 | 
			
		||||
    endif
 | 
			
		||||
    if len(expr) == 0
 | 
			
		||||
      break
 | 
			
		||||
    endif
 | 
			
		||||
    if len(ret) == a:n - 1
 | 
			
		||||
      call add(ret, expr)
 | 
			
		||||
      break
 | 
			
		||||
    endif
 | 
			
		||||
  endwhile
 | 
			
		||||
  return ret
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" Returns the number of character in a:str.
 | 
			
		||||
" NOTE: This returns proper value
 | 
			
		||||
" even if a:str contains multibyte character(s).
 | 
			
		||||
" s:strchars(str) {{{
 | 
			
		||||
if exists('*strchars')
 | 
			
		||||
  function! s:strchars(str) abort
 | 
			
		||||
    return strchars(a:str)
 | 
			
		||||
  endfunction
 | 
			
		||||
else
 | 
			
		||||
  function! s:strchars(str) abort
 | 
			
		||||
    return strlen(substitute(copy(a:str), '.', 'x', 'g'))
 | 
			
		||||
  endfunction
 | 
			
		||||
endif "}}}
 | 
			
		||||
 | 
			
		||||
" Returns the bool of contains any multibyte character in s:str
 | 
			
		||||
function! s:contains_multibyte(str) abort "{{{
 | 
			
		||||
  return strlen(a:str) != s:strchars(a:str)
 | 
			
		||||
endfunction "}}}
 | 
			
		||||
 | 
			
		||||
" Remove last character from a:str.
 | 
			
		||||
" NOTE: This returns proper value
 | 
			
		||||
" even if a:str contains multibyte character(s).
 | 
			
		||||
function! s:chop(str) abort "{{{
 | 
			
		||||
  return substitute(a:str, '.$', '', '')
 | 
			
		||||
endfunction "}}}
 | 
			
		||||
 | 
			
		||||
" Remove last \r,\n,\r\n from a:str.
 | 
			
		||||
function! s:chomp(str) abort "{{{
 | 
			
		||||
  return substitute(a:str, '\%(\r\n\|[\r\n]\)$', '', '')
 | 
			
		||||
endfunction "}}}
 | 
			
		||||
 | 
			
		||||
" wrap() and its internal functions
 | 
			
		||||
" * _split_by_wcswidth_once()
 | 
			
		||||
" * _split_by_wcswidth()
 | 
			
		||||
" * _concat()
 | 
			
		||||
" * wrap()
 | 
			
		||||
"
 | 
			
		||||
" NOTE _concat() is just a copy of Data.List.concat().
 | 
			
		||||
" FIXME don't repeat yourself
 | 
			
		||||
function! s:_split_by_wcswidth_once(body, x) abort
 | 
			
		||||
  let fst = s:P.strwidthpart(a:body, a:x)
 | 
			
		||||
  let snd = s:P.strwidthpart_reverse(a:body, s:P.wcswidth(a:body) - s:P.wcswidth(fst))
 | 
			
		||||
  return [fst, snd]
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:_split_by_wcswidth(body, x) abort
 | 
			
		||||
  let memo = []
 | 
			
		||||
  let body = a:body
 | 
			
		||||
  while s:P.wcswidth(body) > a:x
 | 
			
		||||
    let [tmp, body] = s:_split_by_wcswidth_once(body, a:x)
 | 
			
		||||
    call add(memo, tmp)
 | 
			
		||||
  endwhile
 | 
			
		||||
  call add(memo, body)
 | 
			
		||||
  return memo
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:trim(str) abort
 | 
			
		||||
  return matchstr(a:str,'^\s*\zs.\{-}\ze\s*$')
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:wrap(str,...) abort
 | 
			
		||||
  let _columns = a:0 > 0 ? a:1 : &columns
 | 
			
		||||
  return s:L.concat(
 | 
			
		||||
        \ map(split(a:str, '\r\n\|[\r\n]'), 's:_split_by_wcswidth(v:val, _columns - 1)'))
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:nr2byte(nr) abort
 | 
			
		||||
  if a:nr < 0x80
 | 
			
		||||
    return nr2char(a:nr)
 | 
			
		||||
  elseif a:nr < 0x800
 | 
			
		||||
    return nr2char(a:nr/64+192).nr2char(a:nr%64+128)
 | 
			
		||||
  else
 | 
			
		||||
    return nr2char(a:nr/4096%16+224).nr2char(a:nr/64%64+128).nr2char(a:nr%64+128)
 | 
			
		||||
  endif
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:nr2enc_char(charcode) abort
 | 
			
		||||
  if &encoding == 'utf-8'
 | 
			
		||||
    return nr2char(a:charcode)
 | 
			
		||||
  endif
 | 
			
		||||
  let char = s:nr2byte(a:charcode)
 | 
			
		||||
  if strlen(char) > 1
 | 
			
		||||
    let char = strtrans(iconv(char, 'utf-8', &encoding))
 | 
			
		||||
  endif
 | 
			
		||||
  return char
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:nr2hex(nr) abort
 | 
			
		||||
  let n = a:nr
 | 
			
		||||
  let r = ""
 | 
			
		||||
  while n
 | 
			
		||||
    let r = '0123456789ABCDEF'[n % 16] . r
 | 
			
		||||
    let n = n / 16
 | 
			
		||||
  endwhile
 | 
			
		||||
  return r
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" If a ==# b, returns -1.
 | 
			
		||||
" If a !=# b, returns first index of different character.
 | 
			
		||||
function! s:diffidx(a, b) abort
 | 
			
		||||
  return a:a ==# a:b ? -1 : strlen(s:common_head([a:a, a:b]))
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:substitute_last(expr, pat, sub) abort
 | 
			
		||||
  return substitute(a:expr, printf('.*\zs%s', a:pat), a:sub, '')
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:dstring(expr) abort
 | 
			
		||||
  let x = substitute(string(a:expr), "^'\\|'$", '', 'g')
 | 
			
		||||
  let x = substitute(x, "''", "'", 'g')
 | 
			
		||||
  return printf('"%s"', escape(x, '"'))
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:lines(str) abort
 | 
			
		||||
  return split(a:str, '\r\?\n')
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:_pad_with_char(str, left, right, char) abort
 | 
			
		||||
  return repeat(a:char, a:left). a:str. repeat(a:char, a:right)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:pad_left(str, width, ...) abort
 | 
			
		||||
  let char = get(a:, 1, ' ')
 | 
			
		||||
  if strdisplaywidth(char) != 1
 | 
			
		||||
    throw "vital: Data.String: Can't use non-half-width characters for padding."
 | 
			
		||||
  endif
 | 
			
		||||
  let left = max([0, a:width - strdisplaywidth(a:str)])
 | 
			
		||||
  return s:_pad_with_char(a:str, left, 0, char)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:pad_right(str, width, ...) abort
 | 
			
		||||
  let char = get(a:, 1, ' ')
 | 
			
		||||
  if strdisplaywidth(char) != 1
 | 
			
		||||
    throw "vital: Data.String: Can't use non-half-width characters for padding."
 | 
			
		||||
  endif
 | 
			
		||||
  let right = max([0, a:width - strdisplaywidth(a:str)])
 | 
			
		||||
  return s:_pad_with_char(a:str, 0, right, char)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:pad_both_sides(str, width, ...) abort
 | 
			
		||||
  let char = get(a:, 1, ' ')
 | 
			
		||||
  if strdisplaywidth(char) != 1
 | 
			
		||||
    throw "vital: Data.String: Can't use non-half-width characters for padding."
 | 
			
		||||
  endif
 | 
			
		||||
  let space = max([0, a:width - strdisplaywidth(a:str)])
 | 
			
		||||
  let left = space / 2
 | 
			
		||||
  let right = space - left
 | 
			
		||||
  return s:_pad_with_char(a:str, left, right, char)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:pad_between_letters(str, width, ...) abort
 | 
			
		||||
  let char = get(a:, 1, ' ')
 | 
			
		||||
  if strdisplaywidth(char) != 1
 | 
			
		||||
    throw "vital: Data.String: Can't use non-half-width characters for padding."
 | 
			
		||||
  endif
 | 
			
		||||
  let letters = split(a:str, '\zs')
 | 
			
		||||
  let each_width = a:width / len(letters)
 | 
			
		||||
  let str = join(map(letters, 's:pad_both_sides(v:val, each_width, char)'), '')
 | 
			
		||||
  if a:width - strdisplaywidth(str) > 0
 | 
			
		||||
    return char. s:pad_both_sides(str, a:width - 1, char)
 | 
			
		||||
  endif
 | 
			
		||||
  return str
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:justify_equal_spacing(str, width, ...) abort
 | 
			
		||||
  let char = get(a:, 1, ' ')
 | 
			
		||||
  if strdisplaywidth(char) != 1
 | 
			
		||||
    throw "vital: Data.String: Can't use non-half-width characters for padding."
 | 
			
		||||
  endif
 | 
			
		||||
  let letters = split(a:str, '\zs')
 | 
			
		||||
  let first_letter = letters[0]
 | 
			
		||||
  " {width w/o the first letter} / {length w/o the first letter}
 | 
			
		||||
  let each_width = (a:width - strdisplaywidth(first_letter)) / (len(letters) - 1)
 | 
			
		||||
  let remainder = (a:width - strdisplaywidth(first_letter)) % (len(letters) - 1)
 | 
			
		||||
  return first_letter. join(s:L.concat([
 | 
			
		||||
\     map(letters[1:remainder], 's:pad_left(v:val, each_width + 1, char)'),
 | 
			
		||||
\     map(letters[remainder + 1:], 's:pad_left(v:val, each_width, char)')
 | 
			
		||||
\   ]), '')
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:levenshtein_distance(str1, str2) abort
 | 
			
		||||
  let letters1 = split(a:str1, '\zs')
 | 
			
		||||
  let letters2 = split(a:str2, '\zs')
 | 
			
		||||
  let length1 = len(letters1)
 | 
			
		||||
  let length2 = len(letters2)
 | 
			
		||||
  let distances = map(range(1, length1 + 1), 'map(range(1, length2 + 1), "0")')
 | 
			
		||||
 | 
			
		||||
  for i1 in range(0, length1)
 | 
			
		||||
    let distances[i1][0] = i1
 | 
			
		||||
  endfor
 | 
			
		||||
  for i2 in range(0, length2)
 | 
			
		||||
    let distances[0][i2] = i2
 | 
			
		||||
  endfor
 | 
			
		||||
 | 
			
		||||
  for i1 in range(1, length1)
 | 
			
		||||
    for i2 in range(1, length2)
 | 
			
		||||
      let cost = (letters1[i1 - 1] ==# letters2[i2 - 1]) ? 0 : 1
 | 
			
		||||
 | 
			
		||||
      let distances[i1][i2] = min([
 | 
			
		||||
      \ distances[i1 - 1][i2    ] + 1,
 | 
			
		||||
      \ distances[i1    ][i2 - 1] + 1,
 | 
			
		||||
      \ distances[i1 - 1][i2 - 1] + cost,
 | 
			
		||||
      \])
 | 
			
		||||
    endfor
 | 
			
		||||
  endfor
 | 
			
		||||
 | 
			
		||||
  return distances[length1][length2]
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:padding_by_displaywidth(expr, width, float) abort
 | 
			
		||||
  let padding_char = ' '
 | 
			
		||||
  let n = a:width - strdisplaywidth(a:expr)
 | 
			
		||||
  if n <= 0
 | 
			
		||||
    let n = 0
 | 
			
		||||
  endif
 | 
			
		||||
  if a:float < 0
 | 
			
		||||
    return a:expr . repeat(padding_char, n)
 | 
			
		||||
  elseif 0 < a:float
 | 
			
		||||
    return repeat(padding_char, n) . a:expr
 | 
			
		||||
  else
 | 
			
		||||
    if n % 2 is 0
 | 
			
		||||
      return repeat(padding_char, n / 2) . a:expr . repeat(padding_char, n / 2)
 | 
			
		||||
    else
 | 
			
		||||
      return repeat(padding_char, (n - 1) / 2) . a:expr . repeat(padding_char, (n - 1) / 2) . padding_char
 | 
			
		||||
    endif
 | 
			
		||||
  endif
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:split_by_displaywidth(expr, width, float, is_wrap) abort
 | 
			
		||||
  if a:width is 0
 | 
			
		||||
    return ['']
 | 
			
		||||
  endif
 | 
			
		||||
 | 
			
		||||
  let lines = []
 | 
			
		||||
 | 
			
		||||
  let cs = split(a:expr, '\zs')
 | 
			
		||||
  let cs_index = 0
 | 
			
		||||
 | 
			
		||||
  let text = ''
 | 
			
		||||
  while cs_index < len(cs)
 | 
			
		||||
    if cs[cs_index] is "\n"
 | 
			
		||||
      let text = s:padding_by_displaywidth(text, a:width, a:float)
 | 
			
		||||
      let lines += [text]
 | 
			
		||||
      let text = ''
 | 
			
		||||
    else
 | 
			
		||||
      let w = strdisplaywidth(text . cs[cs_index])
 | 
			
		||||
 | 
			
		||||
      if w < a:width
 | 
			
		||||
        let text .= cs[cs_index]
 | 
			
		||||
      elseif a:width < w
 | 
			
		||||
        let text = s:padding_by_displaywidth(text, a:width, a:float)
 | 
			
		||||
      else
 | 
			
		||||
        let text .= cs[cs_index]
 | 
			
		||||
      endif
 | 
			
		||||
 | 
			
		||||
      if a:width <= w
 | 
			
		||||
        let lines += [text]
 | 
			
		||||
        let text = ''
 | 
			
		||||
        if a:is_wrap
 | 
			
		||||
          if a:width < w
 | 
			
		||||
            if a:width < strdisplaywidth(cs[cs_index])
 | 
			
		||||
              while get(cs, cs_index, "\n") isnot "\n"
 | 
			
		||||
                let cs_index += 1
 | 
			
		||||
              endwhile
 | 
			
		||||
              continue
 | 
			
		||||
            else
 | 
			
		||||
              let text = cs[cs_index]
 | 
			
		||||
            endif
 | 
			
		||||
          endif
 | 
			
		||||
        else
 | 
			
		||||
          while get(cs, cs_index, "\n") isnot "\n"
 | 
			
		||||
            let cs_index += 1
 | 
			
		||||
          endwhile
 | 
			
		||||
          continue
 | 
			
		||||
        endif
 | 
			
		||||
      endif
 | 
			
		||||
 | 
			
		||||
    endif
 | 
			
		||||
    let cs_index += 1
 | 
			
		||||
  endwhile
 | 
			
		||||
 | 
			
		||||
  if !empty(text)
 | 
			
		||||
    let lines += [ s:padding_by_displaywidth(text, a:width, a:float) ]
 | 
			
		||||
  endif
 | 
			
		||||
 | 
			
		||||
  return lines
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:hash(str) abort
 | 
			
		||||
  if exists('*sha256')
 | 
			
		||||
    return sha256(a:str)
 | 
			
		||||
  else
 | 
			
		||||
    " This gives up sha256ing but just adds up char with index.
 | 
			
		||||
    let sum = 0
 | 
			
		||||
    for i in range(len(a:str))
 | 
			
		||||
      let sum += char2nr(a:str[i]) * (i + 1)
 | 
			
		||||
    endfor
 | 
			
		||||
 | 
			
		||||
    return printf('%x', sum)
 | 
			
		||||
  endif
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:truncate(str, width) abort
 | 
			
		||||
  " Original function is from mattn.
 | 
			
		||||
  " http://github.com/mattn/googlereader-vim/tree/master
 | 
			
		||||
 | 
			
		||||
  if a:str =~# '^[\x00-\x7f]*$'
 | 
			
		||||
    return len(a:str) < a:width ?
 | 
			
		||||
          \ printf('%-'.a:width.'s', a:str) : strpart(a:str, 0, a:width)
 | 
			
		||||
  endif
 | 
			
		||||
 | 
			
		||||
  let ret = a:str
 | 
			
		||||
  let width = s:wcswidth(a:str)
 | 
			
		||||
  if width > a:width
 | 
			
		||||
    let ret = s:strwidthpart(ret, a:width)
 | 
			
		||||
    let width = s:wcswidth(ret)
 | 
			
		||||
  endif
 | 
			
		||||
 | 
			
		||||
  if width < a:width
 | 
			
		||||
    let ret .= repeat(' ', a:width - width)
 | 
			
		||||
  endif
 | 
			
		||||
 | 
			
		||||
  return ret
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:truncate_skipping(str, max, footer_width, separator) abort
 | 
			
		||||
  let width = s:wcswidth(a:str)
 | 
			
		||||
  if width <= a:max
 | 
			
		||||
    let ret = a:str
 | 
			
		||||
  else
 | 
			
		||||
    let header_width = a:max - s:wcswidth(a:separator) - a:footer_width
 | 
			
		||||
    let ret = s:strwidthpart(a:str, header_width) . a:separator
 | 
			
		||||
          \ . s:strwidthpart_reverse(a:str, a:footer_width)
 | 
			
		||||
  endif
 | 
			
		||||
  return s:truncate(ret, a:max)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:strwidthpart(str, width) abort
 | 
			
		||||
  if a:width <= 0
 | 
			
		||||
    return ''
 | 
			
		||||
  endif
 | 
			
		||||
  let strarr = split(a:str, '\zs')
 | 
			
		||||
  let width = s:wcswidth(a:str)
 | 
			
		||||
  let index = len(strarr)
 | 
			
		||||
  let diff = (index + 1) / 2
 | 
			
		||||
  let rightindex = index - 1
 | 
			
		||||
  while width > a:width
 | 
			
		||||
    let index = max([rightindex - diff + 1, 0])
 | 
			
		||||
    let partwidth = s:wcswidth(join(strarr[(index):(rightindex)], ''))
 | 
			
		||||
    if width - partwidth >= a:width || diff <= 1
 | 
			
		||||
      let width -= partwidth
 | 
			
		||||
      let rightindex = index - 1
 | 
			
		||||
    endif
 | 
			
		||||
    if diff > 1
 | 
			
		||||
      let diff = diff / 2
 | 
			
		||||
    endif
 | 
			
		||||
  endwhile
 | 
			
		||||
  return index ? join(strarr[:index - 1], '') : ''
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:strwidthpart_reverse(str, width) abort
 | 
			
		||||
  if a:width <= 0
 | 
			
		||||
    return ''
 | 
			
		||||
  endif
 | 
			
		||||
  let strarr = split(a:str, '\zs')
 | 
			
		||||
  let width = s:wcswidth(a:str)
 | 
			
		||||
  let strlen = len(strarr)
 | 
			
		||||
  let diff = (strlen + 1) / 2
 | 
			
		||||
  let leftindex = 0
 | 
			
		||||
  let index = -1
 | 
			
		||||
  while width > a:width
 | 
			
		||||
    let index = min([leftindex + diff, strlen]) - 1
 | 
			
		||||
    let partwidth = s:wcswidth(join(strarr[(leftindex):(index)], ''))
 | 
			
		||||
    if width - partwidth >= a:width || diff <= 1
 | 
			
		||||
      let width -= partwidth
 | 
			
		||||
      let leftindex = index + 1
 | 
			
		||||
    endif
 | 
			
		||||
    if diff > 1
 | 
			
		||||
      let diff = diff / 2
 | 
			
		||||
    endif
 | 
			
		||||
  endwhile
 | 
			
		||||
  return index < strlen ? join(strarr[(index + 1):], '') : ''
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
if v:version >= 703
 | 
			
		||||
  " Use builtin function.
 | 
			
		||||
  function! s:wcswidth(str) abort
 | 
			
		||||
    return strwidth(a:str)
 | 
			
		||||
  endfunction
 | 
			
		||||
else
 | 
			
		||||
  function! s:wcswidth(str) abort
 | 
			
		||||
    if a:str =~# '^[\x00-\x7f]*$'
 | 
			
		||||
      return strlen(a:str)
 | 
			
		||||
    endif
 | 
			
		||||
    let mx_first = '^\(.\)'
 | 
			
		||||
    let str = a:str
 | 
			
		||||
    let width = 0
 | 
			
		||||
    while 1
 | 
			
		||||
      let ucs = char2nr(substitute(str, mx_first, '\1', ''))
 | 
			
		||||
      if ucs == 0
 | 
			
		||||
        break
 | 
			
		||||
      endif
 | 
			
		||||
      let width += s:_wcwidth(ucs)
 | 
			
		||||
      let str = substitute(str, mx_first, '', '')
 | 
			
		||||
    endwhile
 | 
			
		||||
    return width
 | 
			
		||||
  endfunction
 | 
			
		||||
 | 
			
		||||
  " UTF-8 only.
 | 
			
		||||
  function! s:_wcwidth(ucs) abort
 | 
			
		||||
    let ucs = a:ucs
 | 
			
		||||
    if (ucs >= 0x1100
 | 
			
		||||
          \  && (ucs <= 0x115f
 | 
			
		||||
          \  || ucs == 0x2329
 | 
			
		||||
          \  || ucs == 0x232a
 | 
			
		||||
          \  || (ucs >= 0x2e80 && ucs <= 0xa4cf
 | 
			
		||||
          \      && ucs != 0x303f)
 | 
			
		||||
          \  || (ucs >= 0xac00 && ucs <= 0xd7a3)
 | 
			
		||||
          \  || (ucs >= 0xf900 && ucs <= 0xfaff)
 | 
			
		||||
          \  || (ucs >= 0xfe30 && ucs <= 0xfe6f)
 | 
			
		||||
          \  || (ucs >= 0xff00 && ucs <= 0xff60)
 | 
			
		||||
          \  || (ucs >= 0xffe0 && ucs <= 0xffe6)
 | 
			
		||||
          \  || (ucs >= 0x20000 && ucs <= 0x2fffd)
 | 
			
		||||
          \  || (ucs >= 0x30000 && ucs <= 0x3fffd)
 | 
			
		||||
          \  ))
 | 
			
		||||
      return 2
 | 
			
		||||
    endif
 | 
			
		||||
    return 1
 | 
			
		||||
  endfunction
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
let &cpo = s:save_cpo
 | 
			
		||||
unlet s:save_cpo
 | 
			
		||||
 | 
			
		||||
" vim:set et ts=2 sts=2 sw=2 tw=0:
 | 
			
		||||
@ -3,17 +3,17 @@ set cpo&vim
 | 
			
		||||
 | 
			
		||||
if v:version ># 703 ||
 | 
			
		||||
\  (v:version is 703 && has('patch465'))
 | 
			
		||||
  function! s:glob(expr)
 | 
			
		||||
  function! s:glob(expr) abort
 | 
			
		||||
    return glob(a:expr, 1, 1)
 | 
			
		||||
  endfunction
 | 
			
		||||
else
 | 
			
		||||
  function! s:glob(expr)
 | 
			
		||||
  function! s:glob(expr) abort
 | 
			
		||||
    let R = glob(a:expr, 1)
 | 
			
		||||
    return split(R, '\n')
 | 
			
		||||
  endfunction
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
function! s:globpath(path, expr)
 | 
			
		||||
function! s:globpath(path, expr) abort
 | 
			
		||||
  let R = globpath(a:path, a:expr, 1)
 | 
			
		||||
  return split(R, '\n')
 | 
			
		||||
endfunction
 | 
			
		||||
@ -36,44 +36,41 @@ let [
 | 
			
		||||
" This doesn't match to anything.
 | 
			
		||||
 | 
			
		||||
" Number or Float
 | 
			
		||||
function! s:is_numeric(Value)
 | 
			
		||||
function! s:is_numeric(Value) abort
 | 
			
		||||
  let _ = type(a:Value)
 | 
			
		||||
  return _ ==# s:__TYPE_NUMBER
 | 
			
		||||
  \   || _ ==# s:__TYPE_FLOAT
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" Number
 | 
			
		||||
function! s:is_number(Value)
 | 
			
		||||
function! s:is_number(Value) abort
 | 
			
		||||
  return type(a:Value) ==# s:__TYPE_NUMBER
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" Float
 | 
			
		||||
function! s:is_float(Value)
 | 
			
		||||
function! s:is_float(Value) abort
 | 
			
		||||
  return type(a:Value) ==# s:__TYPE_FLOAT
 | 
			
		||||
endfunction
 | 
			
		||||
" String
 | 
			
		||||
function! s:is_string(Value)
 | 
			
		||||
function! s:is_string(Value) abort
 | 
			
		||||
  return type(a:Value) ==# s:__TYPE_STRING
 | 
			
		||||
endfunction
 | 
			
		||||
" Funcref
 | 
			
		||||
function! s:is_funcref(Value)
 | 
			
		||||
function! s:is_funcref(Value) abort
 | 
			
		||||
  return type(a:Value) ==# s:__TYPE_FUNCREF
 | 
			
		||||
endfunction
 | 
			
		||||
" List
 | 
			
		||||
function! s:is_list(Value)
 | 
			
		||||
function! s:is_list(Value) abort
 | 
			
		||||
  return type(a:Value) ==# s:__TYPE_LIST
 | 
			
		||||
endfunction
 | 
			
		||||
" Dictionary
 | 
			
		||||
function! s:is_dict(Value)
 | 
			
		||||
function! s:is_dict(Value) abort
 | 
			
		||||
  return type(a:Value) ==# s:__TYPE_DICT
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:truncate_smart(str, max, footer_width, separator)
 | 
			
		||||
  echoerr 'Prelude.truncate_smart() is obsolete. Use its truncate_skipping() instead; they are equivalent.'
 | 
			
		||||
  return s:truncate_skipping(a:str, a:max, a:footer_width, a:separator)
 | 
			
		||||
endfunction
 | 
			
		||||
function! s:truncate_skipping(str, max, footer_width, separator) abort
 | 
			
		||||
  call s:_warn_deprecated("truncate_skipping", "Data.String.truncate_skipping")
 | 
			
		||||
 | 
			
		||||
function! s:truncate_skipping(str, max, footer_width, separator)
 | 
			
		||||
  let width = s:wcswidth(a:str)
 | 
			
		||||
  if width <= a:max
 | 
			
		||||
    let ret = a:str
 | 
			
		||||
@ -86,10 +83,12 @@ function! s:truncate_skipping(str, max, footer_width, separator)
 | 
			
		||||
  return s:truncate(ret, a:max)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:truncate(str, width)
 | 
			
		||||
function! s:truncate(str, width) abort
 | 
			
		||||
  " Original function is from mattn.
 | 
			
		||||
  " http://github.com/mattn/googlereader-vim/tree/master
 | 
			
		||||
 | 
			
		||||
  call s:_warn_deprecated("truncate", "Data.String.truncate")
 | 
			
		||||
 | 
			
		||||
  if a:str =~# '^[\x00-\x7f]*$'
 | 
			
		||||
    return len(a:str) < a:width ?
 | 
			
		||||
          \ printf('%-'.a:width.'s', a:str) : strpart(a:str, 0, a:width)
 | 
			
		||||
@ -109,7 +108,9 @@ function! s:truncate(str, width)
 | 
			
		||||
  return ret
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:strwidthpart(str, width)
 | 
			
		||||
function! s:strwidthpart(str, width) abort
 | 
			
		||||
  call s:_warn_deprecated("strwidthpart", "Data.String.strwidthpart")
 | 
			
		||||
 | 
			
		||||
  if a:width <= 0
 | 
			
		||||
    return ''
 | 
			
		||||
  endif
 | 
			
		||||
@ -123,7 +124,9 @@ function! s:strwidthpart(str, width)
 | 
			
		||||
 | 
			
		||||
  return ret
 | 
			
		||||
endfunction
 | 
			
		||||
function! s:strwidthpart_reverse(str, width)
 | 
			
		||||
function! s:strwidthpart_reverse(str, width) abort
 | 
			
		||||
  call s:_warn_deprecated("strwidthpart_reverse", "Data.String.strwidthpart_reverse")
 | 
			
		||||
 | 
			
		||||
  if a:width <= 0
 | 
			
		||||
    return ''
 | 
			
		||||
  endif
 | 
			
		||||
@ -140,11 +143,14 @@ endfunction
 | 
			
		||||
 | 
			
		||||
if v:version >= 703
 | 
			
		||||
  " Use builtin function.
 | 
			
		||||
  function! s:wcswidth(str)
 | 
			
		||||
  function! s:wcswidth(str) abort
 | 
			
		||||
    call s:_warn_deprecated("wcswidth", "Data.String.wcswidth")
 | 
			
		||||
    return strwidth(a:str)
 | 
			
		||||
  endfunction
 | 
			
		||||
else
 | 
			
		||||
  function! s:wcswidth(str)
 | 
			
		||||
  function! s:wcswidth(str) abort
 | 
			
		||||
    call s:_warn_deprecated("wcswidth", "Data.String.wcswidth")
 | 
			
		||||
 | 
			
		||||
    if a:str =~# '^[\x00-\x7f]*$'
 | 
			
		||||
      return strlen(a:str)
 | 
			
		||||
    end
 | 
			
		||||
@ -164,7 +170,7 @@ else
 | 
			
		||||
  endfunction
 | 
			
		||||
 | 
			
		||||
  " UTF-8 only.
 | 
			
		||||
  function! s:_wcwidth(ucs)
 | 
			
		||||
  function! s:_wcwidth(ucs) abort
 | 
			
		||||
    let ucs = a:ucs
 | 
			
		||||
    if (ucs >= 0x1100
 | 
			
		||||
          \  && (ucs <= 0x115f
 | 
			
		||||
@ -193,54 +199,58 @@ let s:is_mac = !s:is_windows && !s:is_cygwin
 | 
			
		||||
      \   (!isdirectory('/proc') && executable('sw_vers')))
 | 
			
		||||
let s:is_unix = has('unix')
 | 
			
		||||
 | 
			
		||||
function! s:is_windows()
 | 
			
		||||
function! s:is_windows() abort
 | 
			
		||||
  return s:is_windows
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:is_cygwin()
 | 
			
		||||
function! s:is_cygwin() abort
 | 
			
		||||
  return s:is_cygwin
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:is_mac()
 | 
			
		||||
function! s:is_mac() abort
 | 
			
		||||
  return s:is_mac
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:is_unix()
 | 
			
		||||
function! s:is_unix() abort
 | 
			
		||||
  return s:is_unix
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:_deprecated2(fname)
 | 
			
		||||
  echomsg printf("Vital.Prelude.%s is deprecated!",
 | 
			
		||||
        \ a:fname)
 | 
			
		||||
function! s:_warn_deprecated(name, alternative) abort
 | 
			
		||||
  try
 | 
			
		||||
    echohl Error
 | 
			
		||||
    echomsg "Prelude." . a:name . " is deprecated!  Please use " . a:alternative . " instead."
 | 
			
		||||
  finally
 | 
			
		||||
    echohl None
 | 
			
		||||
  endtry
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:smart_execute_command(action, word)
 | 
			
		||||
function! s:smart_execute_command(action, word) abort
 | 
			
		||||
  execute a:action . ' ' . (a:word == '' ? '' : '`=a:word`')
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:escape_file_searching(buffer_name)
 | 
			
		||||
function! s:escape_file_searching(buffer_name) abort
 | 
			
		||||
  return escape(a:buffer_name, '*[]?{}, ')
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:escape_pattern(str)
 | 
			
		||||
function! s:escape_pattern(str) abort
 | 
			
		||||
  return escape(a:str, '~"\.^$[]*')
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:getchar(...)
 | 
			
		||||
function! s:getchar(...) abort
 | 
			
		||||
  let c = call('getchar', a:000)
 | 
			
		||||
  return type(c) == type(0) ? nr2char(c) : c
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:getchar_safe(...)
 | 
			
		||||
function! s:getchar_safe(...) abort
 | 
			
		||||
  let c = s:input_helper('getchar', a:000)
 | 
			
		||||
  return type(c) == type("") ? c : nr2char(c)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:input_safe(...)
 | 
			
		||||
function! s:input_safe(...) abort
 | 
			
		||||
  return s:input_helper('input', a:000)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:input_helper(funcname, args)
 | 
			
		||||
function! s:input_helper(funcname, args) abort
 | 
			
		||||
  let success = 0
 | 
			
		||||
  if inputsave() !=# success
 | 
			
		||||
    throw 'inputsave() failed'
 | 
			
		||||
@ -254,31 +264,21 @@ function! s:input_helper(funcname, args)
 | 
			
		||||
  endtry
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:set_default(var, val)
 | 
			
		||||
function! s:set_default(var, val) abort
 | 
			
		||||
  if !exists(a:var) || type({a:var}) != type(a:val)
 | 
			
		||||
    let {a:var} = a:val
 | 
			
		||||
  endif
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:set_dictionary_helper(variable, keys, pattern)
 | 
			
		||||
  call s:_deprecated2('set_dictionary_helper')
 | 
			
		||||
 | 
			
		||||
  for key in split(a:keys, '\s*,\s*')
 | 
			
		||||
    if !has_key(a:variable, key)
 | 
			
		||||
      let a:variable[key] = a:pattern
 | 
			
		||||
    endif
 | 
			
		||||
  endfor
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:substitute_path_separator(path)
 | 
			
		||||
function! s:substitute_path_separator(path) abort
 | 
			
		||||
  return s:is_windows ? substitute(a:path, '\\', '/', 'g') : a:path
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:path2directory(path)
 | 
			
		||||
function! s:path2directory(path) abort
 | 
			
		||||
  return s:substitute_path_separator(isdirectory(a:path) ? a:path : fnamemodify(a:path, ':p:h'))
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:_path2project_directory_git(path)
 | 
			
		||||
function! s:_path2project_directory_git(path) abort
 | 
			
		||||
  let parent = a:path
 | 
			
		||||
 | 
			
		||||
  while 1
 | 
			
		||||
@ -294,7 +294,7 @@ function! s:_path2project_directory_git(path)
 | 
			
		||||
  endwhile
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:_path2project_directory_svn(path)
 | 
			
		||||
function! s:_path2project_directory_svn(path) abort
 | 
			
		||||
  let search_directory = a:path
 | 
			
		||||
  let directory = ''
 | 
			
		||||
 | 
			
		||||
@ -319,7 +319,7 @@ function! s:_path2project_directory_svn(path)
 | 
			
		||||
  return directory
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:_path2project_directory_others(vcs, path)
 | 
			
		||||
function! s:_path2project_directory_others(vcs, path) abort
 | 
			
		||||
  let vcs = a:vcs
 | 
			
		||||
  let search_directory = a:path
 | 
			
		||||
 | 
			
		||||
@ -331,7 +331,7 @@ function! s:_path2project_directory_others(vcs, path)
 | 
			
		||||
  return fnamemodify(d, ':p:h:h')
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:path2project_directory(path, ...)
 | 
			
		||||
function! s:path2project_directory(path, ...) abort
 | 
			
		||||
  let is_allow_empty = get(a:000, 0, 0)
 | 
			
		||||
  let search_directory = s:path2directory(a:path)
 | 
			
		||||
  let directory = ''
 | 
			
		||||
 | 
			
		||||
@ -12,6 +12,14 @@ set cpo&vim
 | 
			
		||||
" Because these variables are used when this script file is loaded.
 | 
			
		||||
let s:is_windows = has('win16') || has('win32') || has('win64') || has('win95')
 | 
			
		||||
let s:is_unix = has('unix')
 | 
			
		||||
" As of 7.4.122, the system()'s 1st argument is converted internally by Vim.
 | 
			
		||||
" Note that Patch 7.4.122 does not convert system()'s 2nd argument and
 | 
			
		||||
" return-value. We must convert them manually.
 | 
			
		||||
let s:need_trans = v:version < 704 || (v:version == 704 && !has('patch122'))
 | 
			
		||||
 | 
			
		||||
let s:TYPE_DICT = type({})
 | 
			
		||||
let s:TYPE_LIST = type([])
 | 
			
		||||
let s:TYPE_STRING = type("")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
" Execute program in the background from Vim.
 | 
			
		||||
@ -28,17 +36,17 @@ let s:is_unix = has('unix')
 | 
			
		||||
"
 | 
			
		||||
" Unix:
 | 
			
		||||
" using :! , execute program in the background by shell.
 | 
			
		||||
function! s:spawn(expr, ...)
 | 
			
		||||
function! s:spawn(expr, ...) abort
 | 
			
		||||
  let shellslash = 0
 | 
			
		||||
  if s:is_windows
 | 
			
		||||
    let shellslash = &l:shellslash
 | 
			
		||||
    setlocal noshellslash
 | 
			
		||||
  endif
 | 
			
		||||
  try
 | 
			
		||||
    if type(a:expr) is type([])
 | 
			
		||||
    if type(a:expr) is s:TYPE_LIST
 | 
			
		||||
      let special = 1
 | 
			
		||||
      let cmdline = join(map(a:expr, 'shellescape(v:val, special)'), ' ')
 | 
			
		||||
    elseif type(a:expr) is type("")
 | 
			
		||||
    elseif type(a:expr) is s:TYPE_STRING
 | 
			
		||||
      let cmdline = a:expr
 | 
			
		||||
      if a:0 && a:1
 | 
			
		||||
        " for :! command
 | 
			
		||||
@ -61,7 +69,7 @@ function! s:spawn(expr, ...)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" iconv() wrapper for safety.
 | 
			
		||||
function! s:iconv(expr, from, to)
 | 
			
		||||
function! s:iconv(expr, from, to) abort
 | 
			
		||||
  if a:from == '' || a:to == '' || a:from ==? a:to
 | 
			
		||||
    return a:expr
 | 
			
		||||
  endif
 | 
			
		||||
@ -70,7 +78,7 @@ function! s:iconv(expr, from, to)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
" Check vimproc.
 | 
			
		||||
function! s:has_vimproc()
 | 
			
		||||
function! s:has_vimproc() abort
 | 
			
		||||
  if !exists('s:exists_vimproc')
 | 
			
		||||
    try
 | 
			
		||||
      call vimproc#version()
 | 
			
		||||
@ -88,21 +96,20 @@ endfunction
 | 
			
		||||
"     use_vimproc: bool,
 | 
			
		||||
"     input: string,
 | 
			
		||||
"     timeout: bool,
 | 
			
		||||
"     background: bool,
 | 
			
		||||
"   }
 | 
			
		||||
function! s:system(str, ...)
 | 
			
		||||
  if type(a:str) is type([])
 | 
			
		||||
    let command = join(map(copy(a:str), 's:shellescape(v:val)'), ' ')
 | 
			
		||||
  elseif type(a:str) is type("")
 | 
			
		||||
    let command = a:str
 | 
			
		||||
  else
 | 
			
		||||
    throw 'Process.system(): invalid argument (value type:'.type(a:str).')'
 | 
			
		||||
  endif
 | 
			
		||||
  let command = s:iconv(command, &encoding, 'char')
 | 
			
		||||
function! s:system(str, ...) abort
 | 
			
		||||
  " Process optional arguments at first
 | 
			
		||||
  " because use_vimproc is required later
 | 
			
		||||
  " for a:str argument.
 | 
			
		||||
  let input = ''
 | 
			
		||||
  let use_vimproc = s:has_vimproc()
 | 
			
		||||
  let args = [command]
 | 
			
		||||
  let background = 0
 | 
			
		||||
  let args = []
 | 
			
		||||
  if a:0 ==# 1
 | 
			
		||||
    if type(a:1) is type({})
 | 
			
		||||
    " {command} [, {dict}]
 | 
			
		||||
    " a:1 = {dict}
 | 
			
		||||
    if type(a:1) is s:TYPE_DICT
 | 
			
		||||
      if has_key(a:1, 'use_vimproc')
 | 
			
		||||
        let use_vimproc = a:1.use_vimproc
 | 
			
		||||
      endif
 | 
			
		||||
@ -113,31 +120,56 @@ function! s:system(str, ...)
 | 
			
		||||
        " ignores timeout unless you have vimproc.
 | 
			
		||||
        let args += [a:1.timeout]
 | 
			
		||||
      endif
 | 
			
		||||
      if has_key(a:1, 'background')
 | 
			
		||||
        let background = a:1.background
 | 
			
		||||
      endif
 | 
			
		||||
    elseif type(a:1) is s:TYPE_STRING
 | 
			
		||||
      let args += [s:iconv(a:1, &encoding, 'char')]
 | 
			
		||||
    else
 | 
			
		||||
      throw 'Process.system(): invalid argument (value type:'.type(a:1).')'
 | 
			
		||||
    endif
 | 
			
		||||
  elseif a:0 >= 2
 | 
			
		||||
    " {command} [, {input} [, {timeout}]]
 | 
			
		||||
    " a:000 = [{input} [, {timeout}]]
 | 
			
		||||
    let [input; rest] = a:000
 | 
			
		||||
    let input = s:iconv(a:1, &encoding, 'char')
 | 
			
		||||
    let input   = s:iconv(input, &encoding, 'char')
 | 
			
		||||
    let args += [input] + rest
 | 
			
		||||
  endif
 | 
			
		||||
 | 
			
		||||
  " Process a:str argument.
 | 
			
		||||
  if type(a:str) is s:TYPE_LIST
 | 
			
		||||
    let expr = use_vimproc ? '"''" . v:val . "''"' : 's:shellescape(v:val)'
 | 
			
		||||
    let command = join(map(copy(a:str), expr), ' ')
 | 
			
		||||
  elseif type(a:str) is s:TYPE_STRING
 | 
			
		||||
    let command = a:str
 | 
			
		||||
  else
 | 
			
		||||
    throw 'Process.system(): invalid argument (value type:'.type(a:str).')'
 | 
			
		||||
  endif
 | 
			
		||||
  if s:need_trans
 | 
			
		||||
    let command = s:iconv(command, &encoding, 'char')
 | 
			
		||||
  endif
 | 
			
		||||
  let args = [command] + args
 | 
			
		||||
  if background && (use_vimproc || !s:is_windows)
 | 
			
		||||
    let args[0] = args[0] . ' &'
 | 
			
		||||
  endif
 | 
			
		||||
 | 
			
		||||
  let funcname = use_vimproc ? 'vimproc#system' : 'system'
 | 
			
		||||
  let output = call(funcname, args)
 | 
			
		||||
  let output = s:iconv(output, 'char', &encoding)
 | 
			
		||||
 | 
			
		||||
  return output
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:get_last_status()
 | 
			
		||||
function! s:get_last_status() abort
 | 
			
		||||
  return s:has_vimproc() ?
 | 
			
		||||
        \ vimproc#get_last_status() : v:shell_error
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
if s:is_windows
 | 
			
		||||
  function! s:shellescape(command)
 | 
			
		||||
  function! s:shellescape(command) abort
 | 
			
		||||
    return substitute(a:command, '[&()[\]{}^=;!''+,`~]', '^\0', 'g')
 | 
			
		||||
  endfunction
 | 
			
		||||
else
 | 
			
		||||
  function! s:shellescape(...)
 | 
			
		||||
  function! s:shellescape(...) abort
 | 
			
		||||
    return call('shellescape', a:000)
 | 
			
		||||
  endfunction
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
@ -3,37 +3,46 @@
 | 
			
		||||
let s:save_cpo = &cpo
 | 
			
		||||
set cpo&vim
 | 
			
		||||
 | 
			
		||||
function! s:getfilename(cache_dir, filename)
 | 
			
		||||
function! s:_vital_loaded(V) abort
 | 
			
		||||
  let s:V = a:V
 | 
			
		||||
  let s:S = s:V.import('Data.String')
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:_vital_depends() abort
 | 
			
		||||
  return ['Data.String']
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:getfilename(cache_dir, filename) abort
 | 
			
		||||
  return s:_encode_name(a:cache_dir, a:filename)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:filereadable(cache_dir, filename)
 | 
			
		||||
function! s:filereadable(cache_dir, filename) abort
 | 
			
		||||
  let cache_name = s:_encode_name(a:cache_dir, a:filename)
 | 
			
		||||
  return filereadable(cache_name)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:readfile(cache_dir, filename)
 | 
			
		||||
function! s:readfile(cache_dir, filename) abort
 | 
			
		||||
  let cache_name = s:_encode_name(a:cache_dir, a:filename)
 | 
			
		||||
  return filereadable(cache_name) ? readfile(cache_name) : []
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:writefile(cache_dir, filename, list)
 | 
			
		||||
function! s:writefile(cache_dir, filename, list) abort
 | 
			
		||||
  let cache_name = s:_encode_name(a:cache_dir, a:filename)
 | 
			
		||||
 | 
			
		||||
  call writefile(a:list, cache_name)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:delete(cache_dir, filename)
 | 
			
		||||
function! s:delete(cache_dir, filename) abort
 | 
			
		||||
  echoerr 'System.Cache.delete() is obsolete. Use its deletefile() instead.'
 | 
			
		||||
  return call('s:deletefile', a:cache_dir, a:filename)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:deletefile(cache_dir, filename)
 | 
			
		||||
function! s:deletefile(cache_dir, filename) abort
 | 
			
		||||
  let cache_name = s:_encode_name(a:cache_dir, a:filename)
 | 
			
		||||
  return delete(cache_name)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:_encode_name(cache_dir, filename)
 | 
			
		||||
function! s:_encode_name(cache_dir, filename) abort
 | 
			
		||||
  " Check cache directory.
 | 
			
		||||
  if !isdirectory(a:cache_dir)
 | 
			
		||||
    call mkdir(a:cache_dir, 'p')
 | 
			
		||||
@ -46,7 +55,7 @@ function! s:_encode_name(cache_dir, filename)
 | 
			
		||||
  return cache_dir . s:_create_hash(cache_dir, a:filename)
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:check_old_cache(cache_dir, filename)
 | 
			
		||||
function! s:check_old_cache(cache_dir, filename) abort
 | 
			
		||||
  " Check old cache file.
 | 
			
		||||
  let cache_name = s:_encode_name(a:cache_dir, a:filename)
 | 
			
		||||
  let ret = getftime(cache_name) == -1
 | 
			
		||||
@ -59,20 +68,12 @@ function! s:check_old_cache(cache_dir, filename)
 | 
			
		||||
  return ret
 | 
			
		||||
endfunction
 | 
			
		||||
 | 
			
		||||
function! s:_create_hash(dir, str)
 | 
			
		||||
function! s:_create_hash(dir, str) abort
 | 
			
		||||
  if len(a:dir) + len(a:str) < 150
 | 
			
		||||
    let hash = substitute(substitute(
 | 
			
		||||
          \ a:str, ':', '=-', 'g'), '[/\\]', '=+', 'g')
 | 
			
		||||
  elseif exists('*sha256')
 | 
			
		||||
    let hash = sha256(a:str)
 | 
			
		||||
  else
 | 
			
		||||
    " Use simple hash.
 | 
			
		||||
    let sum = 0
 | 
			
		||||
    for i in range(len(a:str))
 | 
			
		||||
      let sum += char2nr(a:str[i]) * (i + 1)
 | 
			
		||||
    endfor
 | 
			
		||||
 | 
			
		||||
    let hash = printf('%x', sum)
 | 
			
		||||
    let hash = s:S.hash(a:str)
 | 
			
		||||
  endif
 | 
			
		||||
 | 
			
		||||
  return hash
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,8 @@
 | 
			
		||||
neosnippet
 | 
			
		||||
d3554a5
 | 
			
		||||
1c73bcc
 | 
			
		||||
 | 
			
		||||
Prelude
 | 
			
		||||
Data.List
 | 
			
		||||
Process
 | 
			
		||||
System.Cache
 | 
			
		||||
Data.String
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user