262 lines
7.7 KiB
VimL
262 lines
7.7 KiB
VimL
"=============================================================================
|
|
" FILE: util.vim
|
|
" AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
|
|
" License: MIT license
|
|
"=============================================================================
|
|
|
|
function! deoplete#util#set_default(var, val, ...) abort
|
|
if !exists(a:var) || type({a:var}) != type(a:val)
|
|
let alternate_var = get(a:000, 0, '')
|
|
|
|
let {a:var} = exists(alternate_var) ?
|
|
\ {alternate_var} : a:val
|
|
endif
|
|
endfunction
|
|
function! deoplete#util#set_pattern(variable, keys, pattern) abort
|
|
for key in split(a:keys, '\s*,\s*')
|
|
if !has_key(a:variable, key)
|
|
let a:variable[key] = a:pattern
|
|
endif
|
|
endfor
|
|
endfunction
|
|
function! deoplete#util#get_buffer_config(
|
|
\ filetype, buffer_var, user_var, default_var, ...) abort
|
|
let default_val = get(a:000, 0, '')
|
|
|
|
if exists(a:buffer_var)
|
|
return {a:buffer_var}
|
|
endif
|
|
|
|
let filetype = !has_key({a:user_var}, a:filetype)
|
|
\ && !has_key(eval(a:default_var), a:filetype) ? '_' : a:filetype
|
|
|
|
return get({a:user_var}, filetype,
|
|
\ get(eval(a:default_var), filetype, default_val))
|
|
endfunction
|
|
function! deoplete#util#get_simple_buffer_config(buffer_var, user_var) abort
|
|
return exists(a:buffer_var) ? {a:buffer_var} : {a:user_var}
|
|
endfunction
|
|
function! deoplete#util#print_error(string, ...) abort
|
|
let name = a:0 ? a:1 : 'deoplete'
|
|
echohl Error | echomsg printf('[%s] %s', name,
|
|
\ deoplete#util#string(a:string)) | echohl None
|
|
endfunction
|
|
function! deoplete#util#print_warning(string) abort
|
|
echohl WarningMsg | echomsg '[deoplete] '
|
|
\ . deoplete#util#string(a:string) | echohl None
|
|
endfunction
|
|
function! deoplete#util#print_debug(string) abort
|
|
echomsg '[deoplete] ' . deoplete#util#string(a:string)
|
|
endfunction
|
|
|
|
function! deoplete#util#convert2list(expr) abort
|
|
return type(a:expr) ==# v:t_list ? a:expr : [a:expr]
|
|
endfunction
|
|
function! deoplete#util#string(expr) abort
|
|
return type(a:expr) ==# v:t_string ? a:expr : string(a:expr)
|
|
endfunction
|
|
|
|
function! deoplete#util#get_input(event) abort
|
|
let mode = mode()
|
|
if a:event ==# 'InsertEnter'
|
|
let mode = 'i'
|
|
endif
|
|
let input = (mode ==# 'i' ? (col('.')-1) : col('.')) >= len(getline('.')) ?
|
|
\ getline('.') :
|
|
\ matchstr(getline('.'),
|
|
\ '^.*\%' . (mode ==# 'i' ? col('.') : col('.') - 1)
|
|
\ . 'c' . (mode ==# 'i' ? '' : '.'))
|
|
|
|
if input =~# '^.\{-}\ze\S\+$'
|
|
let complete_str = matchstr(input, '\S\+$')
|
|
let input = matchstr(input, '^.\{-}\ze\S\+$')
|
|
else
|
|
let complete_str = ''
|
|
endif
|
|
|
|
if a:event ==# 'InsertCharPre'
|
|
let complete_str .= v:char
|
|
endif
|
|
|
|
return input . complete_str
|
|
endfunction
|
|
function! deoplete#util#get_next_input(event) abort
|
|
return getline('.')[len(deoplete#util#get_input(a:event)) :]
|
|
endfunction
|
|
function! deoplete#util#get_prev_event() abort
|
|
return get(g:deoplete#_context, 'event', '')
|
|
endfunction
|
|
|
|
function! deoplete#util#vimoption2python(option) abort
|
|
return '[a-zA-Z' . s:vimoption2python(a:option) . ']'
|
|
endfunction
|
|
function! deoplete#util#vimoption2python_not(option) abort
|
|
return '[^a-zA-Z' . s:vimoption2python(a:option) . ']'
|
|
endfunction
|
|
function! s:vimoption2python(option) abort
|
|
let has_dash = 0
|
|
let patterns = []
|
|
for pattern in split(a:option, ',')
|
|
if pattern ==# ''
|
|
" ,
|
|
call add(patterns, ',')
|
|
elseif pattern ==# '\'
|
|
call add(patterns, '\\')
|
|
elseif pattern ==# '-'
|
|
let has_dash = 1
|
|
elseif pattern =~# '\d\+'
|
|
call add(patterns, substitute(pattern, '\d\+',
|
|
\ '\=nr2char(submatch(0))', 'g'))
|
|
else
|
|
call add(patterns, pattern)
|
|
endif
|
|
endfor
|
|
|
|
" Dash must be last.
|
|
if has_dash
|
|
call add(patterns, '-')
|
|
endif
|
|
|
|
return join(deoplete#util#uniq(patterns), '')
|
|
endfunction
|
|
|
|
function! deoplete#util#uniq(list) abort
|
|
let list = map(copy(a:list), '[v:val, v:val]')
|
|
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! deoplete#util#get_syn_names() abort
|
|
if col('$') >= 200
|
|
return []
|
|
endif
|
|
|
|
let names = []
|
|
try
|
|
" Note: synstack() seems broken in concealed text.
|
|
for id in synstack(line('.'), (mode() ==# 'i' ? col('.')-1 : col('.')))
|
|
let name = synIDattr(id, 'name')
|
|
call add(names, name)
|
|
if synIDattr(synIDtrans(id), 'name') !=# name
|
|
call add(names, synIDattr(synIDtrans(id), 'name'))
|
|
endif
|
|
endfor
|
|
catch
|
|
" Ignore error
|
|
endtry
|
|
return names
|
|
endfunction
|
|
|
|
function! deoplete#util#neovim_version() abort
|
|
redir => v
|
|
silent version
|
|
redir END
|
|
return split(v, '\n')[0]
|
|
endfunction
|
|
|
|
function! deoplete#util#has_yarp() abort
|
|
return !has('nvim') || get(g:, 'deoplete#enable_yarp', 0)
|
|
endfunction
|
|
|
|
function! deoplete#util#get_context_filetype(input, event) abort
|
|
if !exists('s:context_filetype')
|
|
let s:context_filetype = {}
|
|
|
|
" Force context_filetype call.
|
|
try
|
|
call context_filetype#get_filetype()
|
|
catch
|
|
" Ignore error
|
|
endtry
|
|
endif
|
|
|
|
if empty(s:context_filetype)
|
|
\ || s:context_filetype.prev_filetype !=# &filetype
|
|
\ || s:context_filetype.line != line('.')
|
|
\ || s:context_filetype.bufnr != bufnr('%')
|
|
\ || (a:input =~# '\W$' &&
|
|
\ substitute(a:input, '\s\zs\s\+$', '', '') !=#
|
|
\ substitute(s:context_filetype.input, '\s\zs\s\+$', '', ''))
|
|
\ || (a:input =~# '\w$' &&
|
|
\ substitute(a:input, '\w\+$', '', '') !=#
|
|
\ substitute(s:context_filetype.input, '\w\+$', '', ''))
|
|
\ || a:event ==# 'InsertEnter'
|
|
|
|
let s:context_filetype.line = line('.')
|
|
let s:context_filetype.bufnr = bufnr('%')
|
|
let s:context_filetype.input = a:input
|
|
let s:context_filetype.prev_filetype = &filetype
|
|
let s:context_filetype.filetype =
|
|
\ (exists('*context_filetype#get_filetype') ?
|
|
\ context_filetype#get_filetype() :
|
|
\ (&filetype ==# '' ? 'nothing' : &filetype))
|
|
let s:context_filetype.filetypes =
|
|
\ exists('*context_filetype#get_filetypes') ?
|
|
\ context_filetype#get_filetypes() :
|
|
\ &filetype ==# '' ? ['nothing'] :
|
|
\ deoplete#util#uniq([&filetype]
|
|
\ + split(&filetype, '\.'))
|
|
let s:context_filetype.same_filetypes =
|
|
\ exists('*context_filetype#get_same_filetypes') ?
|
|
\ context_filetype#get_same_filetypes() : []
|
|
endif
|
|
return [ s:context_filetype.filetype,
|
|
\ s:context_filetype.filetypes, s:context_filetype.same_filetypes]
|
|
endfunction
|
|
|
|
function! deoplete#util#rpcnotify(event, context) abort
|
|
if deoplete#init#_check_channel()
|
|
return ''
|
|
endif
|
|
call s:notify(a:event, a:context)
|
|
return ''
|
|
endfunction
|
|
|
|
function! s:notify(event, context) abort
|
|
let a:context['rpc'] = a:event
|
|
|
|
if deoplete#util#has_yarp()
|
|
if g:deoplete#_yarp.job_is_dead
|
|
return
|
|
endif
|
|
call g:deoplete#_yarp.notify(a:event, a:context)
|
|
else
|
|
call rpcnotify(g:deoplete#_channel_id, a:event, a:context)
|
|
endif
|
|
endfunction
|
|
|
|
" Compare versions. Return values is the distance between versions. Each
|
|
" version integer (from right to left) is an ascending power of 100.
|
|
"
|
|
" Example:
|
|
" '0.1.10' is (1 * 100) + 10, or 110.
|
|
" '1.2.3' is (1 * 10000) + (2 * 100) + 3, or 10203.
|
|
"
|
|
" Returns:
|
|
" <0 if a < b
|
|
" >0 if a > b
|
|
" 0 if versions are equal.
|
|
function! deoplete#util#versioncmp(a, b) abort
|
|
let a = map(split(a:a, '\.'), 'str2nr(v:val)')
|
|
let b = map(split(a:b, '\.'), 'str2nr(v:val)')
|
|
let l = min([len(a), len(b)])
|
|
let d = 0
|
|
|
|
" Only compare the parts that are common to both versions.
|
|
for i in range(l)
|
|
let d += (a[i] - b[i]) * pow(100, l - i - 1)
|
|
endfor
|
|
|
|
return d
|
|
endfunction
|