summaryrefslogtreecommitdiffstats
path: root/powerline/bindings/vim/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'powerline/bindings/vim/__init__.py')
-rw-r--r--powerline/bindings/vim/__init__.py482
1 files changed, 482 insertions, 0 deletions
diff --git a/powerline/bindings/vim/__init__.py b/powerline/bindings/vim/__init__.py
new file mode 100644
index 0000000..b754c1f
--- /dev/null
+++ b/powerline/bindings/vim/__init__.py
@@ -0,0 +1,482 @@
+# vim:fileencoding=utf-8:noet
+from __future__ import (unicode_literals, division, absolute_import, print_function)
+
+import sys
+import codecs
+
+try:
+ import vim
+except ImportError:
+ vim = object()
+
+from powerline.lib.unicode import unicode
+
+
+if (
+ hasattr(vim, 'options')
+ and hasattr(vim, 'vvars')
+ and vim.vvars['version'] > 703
+):
+ if sys.version_info < (3,):
+ def get_vim_encoding():
+ return vim.options['encoding'] or 'ascii'
+ else:
+ def get_vim_encoding():
+ return vim.options['encoding'].decode('ascii') or 'ascii'
+elif hasattr(vim, 'eval'):
+ def get_vim_encoding():
+ return vim.eval('&encoding') or 'ascii'
+else:
+ def get_vim_encoding():
+ return 'utf-8'
+
+get_vim_encoding.__doc__ = (
+ '''Get encoding used for Vim strings
+
+ :return:
+ Value of ``&encoding``. If it is empty (i.e. Vim is compiled
+ without +multibyte) returns ``'ascii'``. When building documentation
+ outputs ``'utf-8'`` unconditionally.
+ '''
+)
+
+
+vim_encoding = get_vim_encoding()
+
+
+python_to_vim_types = {
+ unicode: (
+ lambda o: b'\'' + (o.translate({
+ ord('\''): '\'\'',
+ }).encode(vim_encoding)) + b'\''
+ ),
+ list: (
+ lambda o: b'[' + (
+ b','.join((python_to_vim(i) for i in o))
+ ) + b']'
+ ),
+ bytes: (lambda o: b'\'' + o.replace(b'\'', b'\'\'') + b'\''),
+ int: (str if str is bytes else (lambda o: unicode(o).encode('ascii'))),
+}
+python_to_vim_types[float] = python_to_vim_types[int]
+
+
+def python_to_vim(o):
+ return python_to_vim_types[type(o)](o)
+
+
+if sys.version_info < (3,):
+ def str_to_bytes(s):
+ return s
+
+ def unicode_eval(expr):
+ ret = vim.eval(expr)
+ return ret.decode(vim_encoding, 'powerline_vim_strtrans_error')
+else:
+ def str_to_bytes(s):
+ return s.encode(vim_encoding)
+
+ def unicode_eval(expr):
+ return vim.eval(expr)
+
+
+def safe_bytes_eval(expr):
+ return bytes(bytearray((
+ int(chunk) for chunk in (
+ vim.eval(
+ b'substitute(' + expr + b', ' +
+ b'\'^.*$\', \'\\=join(map(range(len(submatch(0))), ' +
+ b'"char2nr(submatch(0)[v:val])"))\', "")'
+ ).split()
+ )
+ )))
+
+
+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: getattr(vim, 'eval', None),
+ 'int': lambda expr: int(vim.eval(expr)),
+ 'bytes': eval_bytes,
+ 'unicode': eval_unicode,
+ }
+ rettype_eval['str'] = rettype_eval[None]
+
+ 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
+
+
+def vim_get_autoload_func(f, rettype=None):
+ func = vim_get_func(f)
+ if not func:
+ vim.command('runtime! ' + f.replace('#', '/')[:f.rindex('#')] + '.vim')
+ func = vim_get_func(f)
+ return func
+
+
+if hasattr(vim, 'Function'):
+ def vim_func_exists(f):
+ try:
+ vim.Function(f)
+ except ValueError:
+ return False
+ else:
+ return True
+else:
+ def vim_func_exists(f):
+ try:
+ return bool(int(vim.eval('exists("*{0}")'.format(f))))
+ except vim.error:
+ return False
+
+
+if type(vim) is object:
+ vim_get_func = lambda *args, **kwargs: None
+
+
+_getbufvar = vim_get_func('getbufvar')
+_vim_exists = vim_get_func('exists', rettype='int')
+
+
+# It may crash on some old vim versions and I do not remember in which patch
+# I fixed this crash.
+if hasattr(vim, 'vvars') and vim.vvars[str('version')] > 703:
+ _vim_to_python_types = {
+ getattr(vim, 'Dictionary', None) or type(vim.bindeval('{}')):
+ lambda value: dict((
+ (_vim_to_python(k), _vim_to_python(v))
+ for k, v in value.items()
+ )),
+ getattr(vim, 'List', None) or type(vim.bindeval('[]')):
+ lambda value: [_vim_to_python(item) for item in value],
+ getattr(vim, 'Function', None) or type(vim.bindeval('function("mode")')):
+ lambda _: None,
+ }
+
+ def vim_getvar(varname):
+ return _vim_to_python(vim.vars[str(varname)])
+
+ def bufvar_exists(buffer, varname):
+ buffer = buffer or vim.current.buffer
+ return varname in buffer.vars
+
+ def vim_getwinvar(segment_info, varname):
+ return _vim_to_python(segment_info['window'].vars[str(varname)])
+
+ def vim_global_exists(name):
+ try:
+ vim.vars[name]
+ except KeyError:
+ return False
+ else:
+ return True
+else:
+ _vim_to_python_types = {
+ dict: (lambda value: dict(((k, _vim_to_python(v)) for k, v in value.items()))),
+ list: (lambda value: [_vim_to_python(i) for i in value]),
+ }
+
+ def vim_getvar(varname):
+ varname = 'g:' + varname
+ if _vim_exists(varname):
+ return vim.eval(varname)
+ else:
+ raise KeyError(varname)
+
+ def bufvar_exists(buffer, varname):
+ if not buffer or buffer.number == vim.current.buffer.number:
+ return int(vim.eval('exists("b:{0}")'.format(varname)))
+ else:
+ return int(vim.eval(
+ 'has_key(getbufvar({0}, ""), {1})'.format(buffer.number, varname)
+ ))
+
+ def vim_getwinvar(segment_info, varname):
+ result = vim.eval('getwinvar({0}, "{1}")'.format(segment_info['winnr'], varname))
+ if result == '':
+ if not int(vim.eval('has_key(getwinvar({0}, ""), "{1}")'.format(segment_info['winnr'], varname))):
+ raise KeyError(varname)
+ return result
+
+ def vim_global_exists(name):
+ return int(vim.eval('exists("g:' + name + '")'))
+
+
+def vim_command_exists(name):
+ return _vim_exists(':' + name)
+
+
+if sys.version_info < (3,):
+ getbufvar = _getbufvar
+else:
+ _vim_to_python_types[bytes] = lambda value: value.decode(vim_encoding)
+
+ def getbufvar(*args):
+ return _vim_to_python(_getbufvar(*args))
+
+
+_id = lambda value: value
+
+
+def _vim_to_python(value):
+ return _vim_to_python_types.get(type(value), _id)(value)
+
+
+if hasattr(vim, 'options'):
+ def vim_getbufoption(info, option):
+ return _vim_to_python(info['buffer'].options[str(option)])
+
+ def vim_getoption(option):
+ return vim.options[str(option)]
+
+ def vim_setoption(option, value):
+ vim.options[str(option)] = value
+else:
+ def vim_getbufoption(info, option):
+ return getbufvar(info['bufnr'], '&' + option)
+
+ def vim_getoption(option):
+ return vim.eval('&g:' + option)
+
+ def vim_setoption(option, value):
+ vim.command('let &g:{option} = {value}'.format(
+ option=option, value=python_to_vim(value)))
+
+
+if hasattr(vim, 'tabpages'):
+ current_tabpage = lambda: vim.current.tabpage
+ list_tabpages = lambda: vim.tabpages
+
+ def list_tabpage_buffers_segment_info(segment_info):
+ return (
+ {'buffer': window.buffer, 'bufnr': window.buffer.number}
+ for window in segment_info['tabpage'].windows
+ )
+else:
+ class FalseObject(object):
+ @staticmethod
+ def __nonzero__():
+ return False
+
+ __bool__ = __nonzero__
+
+ def get_buffer(number):
+ for buffer in vim.buffers:
+ if buffer.number == number:
+ return buffer
+ raise KeyError(number)
+
+ class WindowVars(object):
+ __slots__ = ('tabnr', 'winnr')
+
+ def __init__(self, window):
+ self.tabnr = window.tabnr
+ self.winnr = window.number
+
+ def __getitem__(self, key):
+ has_key = vim.eval('has_key(gettabwinvar({0}, {1}, ""), "{2}")'.format(self.tabnr, self.winnr, key))
+ if has_key == '0':
+ raise KeyError
+ return vim.eval('gettabwinvar({0}, {1}, "{2}")'.format(self.tabnr, self.winnr, key))
+
+ def get(self, key, default=None):
+ try:
+ return self[key]
+ except KeyError:
+ return default
+
+ class Window(FalseObject):
+ __slots__ = ('tabnr', 'number', '_vars')
+
+ def __init__(self, tabnr, number):
+ self.tabnr = tabnr
+ self.number = number
+ self.vars = WindowVars(self)
+
+ @property
+ def buffer(self):
+ return get_buffer(int(vim.eval('tabpagebuflist({0})[{1}]'.format(self.tabnr, self.number - 1))))
+
+ class Tabpage(FalseObject):
+ __slots__ = ('number',)
+
+ def __init__(self, number):
+ self.number = number
+
+ def __eq__(self, tabpage):
+ if not isinstance(tabpage, Tabpage):
+ raise NotImplementedError
+ return self.number == tabpage.number
+
+ @property
+ def window(self):
+ return Window(self.number, int(vim.eval('tabpagewinnr({0})'.format(self.number))))
+
+ def _last_tab_nr():
+ return int(vim.eval('tabpagenr("$")'))
+
+ def current_tabpage():
+ return Tabpage(int(vim.eval('tabpagenr()')))
+
+ def list_tabpages():
+ return [Tabpage(nr) for nr in range(1, _last_tab_nr() + 1)]
+
+ class TabBufSegmentInfo(dict):
+ def __getitem__(self, key):
+ try:
+ return super(TabBufSegmentInfo, self).__getitem__(key)
+ except KeyError:
+ if key != 'buffer':
+ raise
+ else:
+ buffer = get_buffer(super(TabBufSegmentInfo, self).__getitem__('bufnr'))
+ self['buffer'] = buffer
+ return buffer
+
+ def list_tabpage_buffers_segment_info(segment_info):
+ return (
+ TabBufSegmentInfo(bufnr=int(bufnrstr))
+ for bufnrstr in vim.eval('tabpagebuflist({0})'.format(segment_info['tabnr']))
+ )
+
+
+class VimEnviron(object):
+ @staticmethod
+ def __getitem__(key):
+ return vim.eval('$' + key)
+
+ @staticmethod
+ def get(key, default=None):
+ return vim.eval('$' + key) or default
+
+ @staticmethod
+ def __setitem__(key, value):
+ return vim.command(
+ 'let ${0}="{1}"'.format(
+ key,
+ value.replace('"', '\\"')
+ .replace('\\', '\\\\')
+ .replace('\n', '\\n')
+ .replace('\0', '')
+ )
+ )
+
+
+if sys.version_info < (3,):
+ def buffer_name(segment_info):
+ return segment_info['buffer'].name
+else:
+ vim_bufname = vim_get_func('bufname', rettype='bytes')
+
+ def buffer_name(segment_info):
+ try:
+ name = segment_info['buffer'].name
+ except UnicodeDecodeError:
+ return vim_bufname(segment_info['bufnr'])
+ else:
+ return name.encode(segment_info['encoding']) if name else None
+
+
+vim_strtrans = vim_get_func('strtrans', rettype='unicode')
+
+
+def powerline_vim_strtrans_error(e):
+ if not isinstance(e, UnicodeDecodeError):
+ raise NotImplementedError
+ text = vim_strtrans(e.object[e.start:e.end])
+ return (text, e.end)
+
+
+codecs.register_error('powerline_vim_strtrans_error', powerline_vim_strtrans_error)
+
+
+did_autocmd = False
+buffer_caches = []
+
+
+def register_buffer_cache(cachedict):
+ global did_autocmd
+ global buffer_caches
+ from powerline.vim import get_default_pycmd, pycmd
+ if not did_autocmd:
+ import __main__
+ __main__.powerline_on_bwipe = on_bwipe
+ vim.command('augroup Powerline')
+ vim.command(' autocmd! BufWipeout * :{pycmd} powerline_on_bwipe()'.format(
+ pycmd=(pycmd or get_default_pycmd())))
+ vim.command('augroup END')
+ did_autocmd = True
+ buffer_caches.append(cachedict)
+ return cachedict
+
+
+def on_bwipe():
+ global buffer_caches
+ bufnr = int(vim.eval('expand("<abuf>")'))
+ for cachedict in buffer_caches:
+ cachedict.pop(bufnr, None)
+
+
+environ = VimEnviron()
+
+
+def create_ruby_dpowerline():
+ vim.command((
+ '''
+ ruby
+ if $powerline == nil
+ class Powerline
+ end
+ $powerline = Powerline.new
+ end
+ '''
+ ))