189 lines
5.6 KiB
Python
189 lines
5.6 KiB
Python
# vim:fileencoding=utf-8:noet
|
||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||
|
||
import sys
|
||
|
||
import vim
|
||
|
||
from powerline.bindings.vim import vim_get_func, vim_getoption, environ, current_tabpage, get_vim_encoding
|
||
from powerline.renderer import Renderer
|
||
from powerline.colorscheme import ATTR_BOLD, ATTR_ITALIC, ATTR_UNDERLINE
|
||
from powerline.theme import Theme
|
||
from powerline.lib.unicode import unichr, register_strwidth_error
|
||
|
||
|
||
vim_mode = vim_get_func('mode', rettype='unicode')
|
||
if int(vim.eval('v:version')) >= 702:
|
||
_vim_mode = vim_mode
|
||
vim_mode = lambda: _vim_mode(1)
|
||
|
||
mode_translations = {
|
||
unichr(ord('V') - 0x40): '^V',
|
||
unichr(ord('S') - 0x40): '^S',
|
||
}
|
||
|
||
|
||
class VimRenderer(Renderer):
|
||
'''Powerline vim segment renderer.'''
|
||
|
||
character_translations = Renderer.character_translations.copy()
|
||
character_translations[ord('%')] = '%%'
|
||
|
||
segment_info = Renderer.segment_info.copy()
|
||
segment_info.update(environ=environ)
|
||
|
||
def __init__(self, *args, **kwargs):
|
||
if not hasattr(vim, 'strwidth'):
|
||
# Hope nobody want to change this at runtime
|
||
if vim.eval('&ambiwidth') == 'double':
|
||
kwargs = dict(**kwargs)
|
||
kwargs['ambigious'] = 2
|
||
super(VimRenderer, self).__init__(*args, **kwargs)
|
||
self.hl_groups = {}
|
||
self.prev_highlight = None
|
||
self.strwidth_error_name = register_strwidth_error(self.strwidth)
|
||
self.encoding = get_vim_encoding()
|
||
|
||
def shutdown(self):
|
||
self.theme.shutdown()
|
||
for match in self.local_themes.values():
|
||
if 'theme' in match:
|
||
match['theme'].shutdown()
|
||
|
||
def add_local_theme(self, matcher, theme):
|
||
if matcher in self.local_themes:
|
||
raise KeyError('There is already a local theme with given matcher')
|
||
self.local_themes[matcher] = theme
|
||
|
||
def get_matched_theme(self, match):
|
||
try:
|
||
return match['theme']
|
||
except KeyError:
|
||
match['theme'] = Theme(theme_config=match['config'], main_theme_config=self.theme_config, **self.theme_kwargs)
|
||
return match['theme']
|
||
|
||
def get_theme(self, matcher_info):
|
||
if matcher_info is None:
|
||
return self.get_matched_theme(self.local_themes[None])
|
||
for matcher in self.local_themes.keys():
|
||
if matcher and matcher(matcher_info):
|
||
return self.get_matched_theme(self.local_themes[matcher])
|
||
else:
|
||
return self.theme
|
||
|
||
if hasattr(vim, 'strwidth'):
|
||
if sys.version_info < (3,):
|
||
def strwidth(self, string):
|
||
# Does not work with tabs, but neither is strwidth from default
|
||
# renderer
|
||
return vim.strwidth(string.encode(self.encoding, 'replace'))
|
||
else:
|
||
@staticmethod
|
||
def strwidth(string):
|
||
return vim.strwidth(string)
|
||
|
||
def get_segment_info(self, segment_info, mode):
|
||
return segment_info or self.segment_info
|
||
|
||
def render(self, window=None, window_id=None, winnr=None, is_tabline=False):
|
||
'''Render all segments.'''
|
||
segment_info = self.segment_info.copy()
|
||
|
||
if window is vim.current.window:
|
||
mode = vim_mode()
|
||
mode = mode_translations.get(mode, mode)
|
||
else:
|
||
mode = 'nc'
|
||
|
||
segment_info.update(
|
||
window=window,
|
||
mode=mode,
|
||
window_id=window_id,
|
||
winnr=winnr,
|
||
buffer=window.buffer,
|
||
tabpage=current_tabpage(),
|
||
encoding=self.encoding,
|
||
)
|
||
segment_info['tabnr'] = segment_info['tabpage'].number
|
||
segment_info['bufnr'] = segment_info['buffer'].number
|
||
if is_tabline:
|
||
winwidth = int(vim_getoption('columns'))
|
||
else:
|
||
winwidth = segment_info['window'].width
|
||
|
||
statusline = super(VimRenderer, self).render(
|
||
mode=mode,
|
||
width=winwidth,
|
||
segment_info=segment_info,
|
||
matcher_info=(None if is_tabline else segment_info),
|
||
)
|
||
statusline = statusline.encode(self.encoding, self.strwidth_error_name)
|
||
return statusline
|
||
|
||
def reset_highlight(self):
|
||
self.hl_groups.clear()
|
||
|
||
def hlstyle(self, fg=None, bg=None, attrs=None):
|
||
'''Highlight a segment.
|
||
|
||
If an argument is None, the argument is ignored. If an argument is
|
||
False, the argument is reset to the terminal defaults. If an argument
|
||
is a valid color or attribute, it’s added to the vim highlight group.
|
||
'''
|
||
# In order not to hit E541 two consequent identical highlighting
|
||
# specifiers may be squashed into one.
|
||
attrs = attrs or 0 # Normalize `attrs`
|
||
if (fg, bg, attrs) == self.prev_highlight:
|
||
return ''
|
||
self.prev_highlight = (fg, bg, attrs)
|
||
|
||
# We don’t need to explicitly reset attributes in vim, so skip those
|
||
# calls
|
||
if not attrs and not bg and not fg:
|
||
return ''
|
||
|
||
if not (fg, bg, attrs) in self.hl_groups:
|
||
hl_group = {
|
||
'ctermfg': 'NONE',
|
||
'guifg': None,
|
||
'ctermbg': 'NONE',
|
||
'guibg': None,
|
||
'attrs': ['NONE'],
|
||
'name': '',
|
||
}
|
||
if fg is not None and fg is not False:
|
||
hl_group['ctermfg'] = fg[0]
|
||
hl_group['guifg'] = fg[1]
|
||
if bg is not None and bg is not False:
|
||
hl_group['ctermbg'] = bg[0]
|
||
hl_group['guibg'] = bg[1]
|
||
if attrs:
|
||
hl_group['attrs'] = []
|
||
if attrs & ATTR_BOLD:
|
||
hl_group['attrs'].append('bold')
|
||
if attrs & ATTR_ITALIC:
|
||
hl_group['attrs'].append('italic')
|
||
if attrs & ATTR_UNDERLINE:
|
||
hl_group['attrs'].append('underline')
|
||
hl_group['name'] = (
|
||
'Pl_'
|
||
+ str(hl_group['ctermfg']) + '_'
|
||
+ str(hl_group['guifg']) + '_'
|
||
+ str(hl_group['ctermbg']) + '_'
|
||
+ str(hl_group['guibg']) + '_'
|
||
+ ''.join(hl_group['attrs'])
|
||
)
|
||
self.hl_groups[(fg, bg, attrs)] = hl_group
|
||
vim.command('hi {group} ctermfg={ctermfg} guifg={guifg} guibg={guibg} ctermbg={ctermbg} cterm={attrs} gui={attrs}'.format(
|
||
group=hl_group['name'],
|
||
ctermfg=hl_group['ctermfg'],
|
||
guifg='#{0:06x}'.format(hl_group['guifg']) if hl_group['guifg'] is not None else 'NONE',
|
||
ctermbg=hl_group['ctermbg'],
|
||
guibg='#{0:06x}'.format(hl_group['guibg']) if hl_group['guibg'] is not None else 'NONE',
|
||
attrs=','.join(hl_group['attrs']),
|
||
))
|
||
return '%#' + self.hl_groups[(fg, bg, attrs)]['name'] + '#'
|
||
|
||
|
||
renderer = VimRenderer
|