Make vim_get_func handle rettype argument better

As usual it was not working well in Python-3
This commit is contained in:
ZyX 2014-09-14 15:53:29 +04:00
parent 80db7df959
commit af170eca13
3 changed files with 76 additions and 36 deletions

View File

@ -34,37 +34,23 @@ def python_to_vim(o):
return python_to_vim_types[type(o)](o) return python_to_vim_types[type(o)](o)
if hasattr(vim, 'bindeval'): if sys.version_info < (3,):
def vim_get_func(f, rettype=None): def str_to_bytes(s):
'''Return a vim function binding.''' return s
try:
func = vim.bindeval('function("' + f + '")') def unicode_eval(expr):
if sys.version_info >= (3,) and rettype is str: ret = vim.eval(expr)
return (lambda *args, **kwargs: func(*args, **kwargs).decode( return ret.decode(vim_encoding, 'powerline_vim_strtrans_error')
vim_encoding, errors='powerline_vim_strtrans_error'))
return func
except vim.error:
return None
else: else:
class VimFunc(object): def str_to_bytes(s):
'''Evaluate a vim function using vim.eval(). return s.encode(vim_encoding)
This is a fallback class for older vim versions. def unicode_eval(expr):
''' return vim.eval(expr)
__slots__ = ('f', 'rettype')
def __init__(self, f, rettype=None):
self.f = f.encode('utf-8')
self.rettype = rettype
def __call__(self, *args): def safe_bytes_eval(expr):
expr = self.f + b'(' + (b','.join(( return bytes(bytearray((
python_to_vim(o) for o in args
))) + b')'
try:
r = vim.eval(expr)
except UnicodeDecodeError:
r = bytes(bytearray((
int(chunk) for chunk in ( int(chunk) for chunk in (
vim.eval( vim.eval(
b'substitute(' + expr + b', ' + b'substitute(' + expr + b', ' +
@ -73,9 +59,67 @@ else:
).split() ).split()
) )
))) )))
if self.rettype:
return self.rettype(r)
return r def eval_bytes(expr):
try:
return str_to_bytes(vim.eval(expr))
except UnicodeDecodeError:
return safe_bytes_eval(expr)
def eval_unicode(expr):
try:
return unicode_eval(expr)
except UnicodeDecodeError:
return safe_bytes_eval(expr).decode(vim_encoding, 'powerline_vim_strtrans_error')
if hasattr(vim, 'bindeval'):
rettype_func = {
None: lambda f: f,
'unicode': (
lambda f: (
lambda *args, **kwargs: (
f(*args, **kwargs).decode(
vim_encoding, 'powerline_vim_strtrans_error'
))))
}
rettype_func['int'] = rettype_func['bytes'] = rettype_func[None]
rettype_func['str'] = rettype_func['bytes'] if str is bytes else rettype_func['unicode']
def vim_get_func(f, rettype=None):
'''Return a vim function binding.'''
try:
func = vim.bindeval('function("' + f + '")')
except vim.error:
return None
else:
return rettype_func[rettype](func)
else:
rettype_eval = {
None: vim.eval,
'int': lambda expr: int(vim.eval(expr)),
'str': vim.eval,
'bytes': eval_bytes,
'unicode': eval_unicode,
}
class VimFunc(object):
'''Evaluate a vim function using vim.eval().
This is a fallback class for older vim versions.
'''
__slots__ = ('f', 'eval')
def __init__(self, f, rettype=None):
self.f = f.encode('utf-8')
self.eval = rettype_eval[rettype]
def __call__(self, *args):
return self.eval(self.f + b'(' + (b','.join((
python_to_vim(o) for o in args
))) + b')')
vim_get_func = VimFunc vim_get_func = VimFunc
@ -110,7 +154,7 @@ else:
list: (lambda value: [_vim_to_python(i) for i in value]), list: (lambda value: [_vim_to_python(i) for i in value]),
} }
_vim_exists = vim_get_func('exists', rettype=int) _vim_exists = vim_get_func('exists', rettype='int')
def vim_getvar(varname): def vim_getvar(varname):
varname = 'g:' + varname varname = 'g:' + varname
@ -295,7 +339,7 @@ if sys.version_info < (3,):
def buffer_name(segment_info): def buffer_name(segment_info):
return segment_info['buffer'].name return segment_info['buffer'].name
else: else:
vim_bufname = vim_get_func('bufname') vim_bufname = vim_get_func('bufname', rettype='bytes')
def buffer_name(segment_info): def buffer_name(segment_info):
try: try:
@ -306,15 +350,13 @@ else:
return name.encode(segment_info['encoding']) if name else None return name.encode(segment_info['encoding']) if name else None
vim_strtrans = vim_get_func('strtrans') vim_strtrans = vim_get_func('strtrans', rettype='unicode')
def powerline_vim_strtrans_error(e): def powerline_vim_strtrans_error(e):
if not isinstance(e, UnicodeDecodeError): if not isinstance(e, UnicodeDecodeError):
raise NotImplementedError raise NotImplementedError
# Assuming &encoding is utf-8 strtrans should not return anything but ASCII text = vim_strtrans(e.object[e.start:e.end])
# under current circumstances
text = vim_strtrans(e.object[e.start:e.end]).decode()
return (text, e.end) return (text, e.end)

View File

@ -12,7 +12,7 @@ from powerline.theme import Theme
from powerline.lib.unicode import unichr, register_strwidth_error from powerline.lib.unicode import unichr, register_strwidth_error
vim_mode = vim_get_func('mode', rettype=str) vim_mode = vim_get_func('mode', rettype='unicode')
if int(vim.eval('v:version')) >= 702: if int(vim.eval('v:version')) >= 702:
_vim_mode = vim_mode _vim_mode = vim_mode
vim_mode = lambda: _vim_mode(1) vim_mode = lambda: _vim_mode(1)

View File

@ -28,13 +28,11 @@ except ImportError:
vim_funcs = { vim_funcs = {
'virtcol': vim_get_func('virtcol', rettype=int), 'virtcol': vim_get_func('virtcol', rettype='int'),
'getpos': vim_get_func('getpos'), 'getpos': vim_get_func('getpos'),
'fnamemodify': vim_get_func('fnamemodify'), 'fnamemodify': vim_get_func('fnamemodify', rettype='bytes'),
'expand': vim_get_func('expand'), 'line2byte': vim_get_func('line2byte', rettype='int'),
'bufnr': vim_get_func('bufnr', rettype=int), 'line': vim_get_func('line', rettype='int'),
'line2byte': vim_get_func('line2byte', rettype=int),
'line': vim_get_func('line', rettype=int),
} }
vim_modes = { vim_modes = {