dotfiles/vim/plugins/deoplete.nvim/rplugin/python3/deoplete/util.py

309 lines
8.0 KiB
Python
Raw Normal View History

2018-04-05 13:06:54 +02:00
# ============================================================================
# FILE: util.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# License: MIT license
# ============================================================================
import os
import re
import sys
import glob
import traceback
import unicodedata
from importlib.machinery import SourceFileLoader
def get_buffer_config(context, filetype, buffer_var, user_var, default_var):
if buffer_var in context['bufvars']:
return context['bufvars'][buffer_var]
ft = filetype if (filetype in context['vars'][user_var] or
filetype in default_var) else '_'
default = default_var.get(ft, '')
return context['vars'][user_var].get(ft, default)
def get_simple_buffer_config(context, buffer_var, user_var):
return (context['bufvars'][buffer_var]
if buffer_var in context['bufvars']
else context['vars'][user_var])
def set_pattern(variable, keys, pattern):
for key in keys.split(','):
variable[key] = pattern
def set_list(vim, variable, keys, list):
return vim.call('deoplete#util#set_pattern', variable, keys, list)
def set_default(vim, var, val):
return vim.call('deoplete#util#set_default', var, val)
def convert2list(expr):
return (expr if isinstance(expr, list) else [expr])
def convert2candidates(l):
return ([{'word': x} for x in l]
if l and isinstance(l, list) and isinstance(l[0], str) else l)
def globruntime(runtimepath, path):
ret = []
for rtp in re.split(',', runtimepath):
ret += glob.glob(rtp + '/' + path)
return ret
def find_rplugins(context, source):
"""Search for base.py or *.py
Searches $VIMRUNTIME/*/rplugin/python3/deoplete/$source[s]/
"""
rtp = context.get('runtimepath', '').split(',')
if not rtp:
return
sources = (
os.path.join('rplugin/python3/deoplete', source, 'base.py'),
os.path.join('rplugin/python3/deoplete', source, '*.py'),
os.path.join('rplugin/python3/deoplete', source + 's', '*.py'),
os.path.join('rplugin/python3/deoplete', source, '*', '*.py'),
)
for src in sources:
for path in rtp:
yield from glob.iglob(os.path.join(path, src))
def import_plugin(path, source, classname):
"""Import Deoplete plugin source class.
If the class exists, add its directory to sys.path.
"""
name = os.path.splitext(os.path.basename(path))[0]
module_name = 'deoplete.%s.%s' % (source, name)
module = SourceFileLoader(module_name, path).load_module()
cls = getattr(module, classname, None)
if not cls:
return None
dirname = os.path.dirname(path)
if dirname not in sys.path:
sys.path.insert(0, dirname)
return cls
def debug(vim, expr):
if hasattr(vim, 'out_write'):
string = (expr if isinstance(expr, str) else str(expr))
return vim.out_write('[deoplete] ' + string + '\n')
else:
vim.call('deoplete#util#print_debug', expr)
def error(vim, expr):
if hasattr(vim, 'err_write'):
string = (expr if isinstance(expr, str) else str(expr))
return vim.err_write('[deoplete] ' + string + '\n')
else:
vim.call('deoplete#util#print_error', expr)
def error_tb(vim, msg):
lines = traceback.format_exc().splitlines()
lines += ['%s. Use :messages / see above for error details.' % msg]
if hasattr(vim, 'err_write'):
vim.err_write('[deoplete] %s\n' % '\n'.join(lines))
else:
for line in lines:
vim.call('deoplete#util#print_error', line)
def error_vim(vim, msg):
throwpoint = vim.eval('v:throwpoint')
if throwpoint != '':
error(vim, 'v:throwpoint = ' + throwpoint)
exception = vim.eval('v:exception')
if exception != '':
error(vim, 'v:exception = ' + exception)
error_tb(vim, msg)
def escape(expr):
return expr.replace("'", "''")
def charpos2bytepos(encoding, input, pos):
return len(bytes(input[: pos], encoding, errors='replace'))
def bytepos2charpos(encoding, input, pos):
return len(bytes(input, encoding, errors='replace')[: pos].decode(
encoding, errors='replace'))
def get_custom(custom, source_name, key, default):
custom_source = custom['source']
if source_name not in custom_source:
return get_custom(custom, '_', key, default)
elif key in custom_source[source_name]:
return custom_source[source_name][key]
elif key in custom_source['_']:
return custom_source['_'][key]
else:
return default
def get_syn_names(vim):
return vim.call('deoplete#util#get_syn_names')
def parse_file_pattern(f, pattern):
p = re.compile(pattern)
ret = []
for l in f:
ret += p.findall(l)
return list(set(ret))
def parse_buffer_pattern(b, pattern):
return list(set(re.compile(pattern).findall('\n'.join(b))))
def fuzzy_escape(string, camelcase):
# Escape string for python regexp.
p = re.sub(r'([a-zA-Z0-9_])', r'\1.*', re.escape(string))
if camelcase and re.search(r'[A-Z]', string):
p = re.sub(r'([a-z])', (lambda pat:
'['+pat.group(1)+pat.group(1).upper()+']'), p)
p = re.sub(r'([a-zA-Z0-9_])\.\*', r'\1[^\1]*', p)
return p
def load_external_module(file, module):
current = os.path.dirname(os.path.abspath(file))
module_dir = os.path.join(os.path.dirname(current), module)
if module_dir not in sys.path:
sys.path.insert(0, module_dir)
def truncate_skipping(string, max_width, footer, footer_len):
if not string:
return ''
if len(string) <= max_width/2:
return string
if strwidth(string) <= max_width:
return string
footer += string[
-len(truncate(string[::-1], footer_len)):]
return truncate(string, max_width - strwidth(footer)) + footer
def truncate(string, max_width):
if len(string) <= max_width/2:
return string
if strwidth(string) <= max_width:
return string
width = 0
ret = ''
for c in string:
wc = charwidth(c)
if width + wc > max_width:
break
ret += c
width += wc
return ret
def strwidth(string):
width = 0
for c in string:
width += charwidth(c)
return width
def charwidth(c):
wc = unicodedata.east_asian_width(c)
return 2 if wc == 'F' or wc == 'W' else 1
def expand(path):
return os.path.expanduser(os.path.expandvars(path))
def getlines(vim, start=1, end='$'):
if end == '$':
end = len(vim.current.buffer)
max_len = min([end - start, 5000])
lines = []
current = start
while current <= end:
lines += vim.call('getline', current, current + max_len)
current += max_len + 1
return lines
def binary_search_begin(l, prefix):
if not l:
return -1
if len(l) == 1:
return 0 if l[0]['word'].lower().startswith(prefix) else -1
s = 0
e = len(l)
prefix = prefix.lower()
while s < e:
index = int((s + e) / 2)
word = l[index]['word'].lower()
if word.startswith(prefix):
if (index - 1 < 0 or not
l[index-1]['word'].lower().startswith(prefix)):
return index
e = index
elif prefix < word:
e = index
else:
s = index + 1
return -1
def binary_search_end(l, prefix):
if not l:
return -1
if len(l) == 1:
return 0 if l[0]['word'].lower().startswith(prefix) else -1
s = 0
e = len(l)
prefix = prefix.lower()
while s < e:
index = int((s + e) / 2)
word = l[index]['word'].lower()
if word.startswith(prefix):
if ((index + 1) >= len(l) or not
l[index+1]['word'].lower().startswith(prefix)):
return index
s = index + 1
elif prefix < word:
e = index
else:
s = index + 1
return -1
def uniq_list_dict(l):
# Uniq list of dictionaries
ret = []
for d in l:
if d not in ret:
ret.append(d)
return ret