Remove non-current window caching
API changes done: - memoize additional_key function now accepts all function arguments - get_theme now receives matcher_info - render now receives segment_info and matcher_info, but segments and themes were removed - due to very different ways of obtaining column information col_current splitted back to col_current and virtcol_current. The former should be false in case of horizontal scrollbind (when &scrollopt contains hor) - added requires_segment_info decorator for convenience Other changes: - removed all vim function calls that were possible to remove - removed direct vim.eval calls
This commit is contained in:
parent
cc83d741ff
commit
d638f1d6ea
|
@ -46,3 +46,5 @@ except AttributeError:
|
|||
return r
|
||||
|
||||
vim_get_func = VimFunc
|
||||
|
||||
getbufvar = vim_get_func('getbufvar')
|
||||
|
|
|
@ -36,7 +36,7 @@ catch
|
|||
finish
|
||||
endtry
|
||||
endtry
|
||||
exec s:powerline_pycmd 'powerline = Powerline("vim")'
|
||||
exec s:powerline_pycmd 'powerline = Powerline("vim", segment_info={})'
|
||||
|
||||
if exists('*'. s:powerline_pyeval)
|
||||
let s:pyeval = function(s:powerline_pyeval)
|
||||
|
|
|
@ -87,11 +87,12 @@
|
|||
"align": "r"
|
||||
},
|
||||
{
|
||||
"name": "col_current",
|
||||
"name": "virtcol_current",
|
||||
"draw_divider": false,
|
||||
"priority": 30,
|
||||
"before": ":",
|
||||
"width": 3,
|
||||
"highlight_group": ["col_current"],
|
||||
"align": "l"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -16,7 +16,7 @@ class memoize(object):
|
|||
@wraps(func)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if self.additional_key:
|
||||
key = (func.__name__, args, tuple(kwargs.items()), self.additional_key())
|
||||
key = (func.__name__, args, tuple(kwargs.items()), self.additional_key(*args, **kwargs))
|
||||
else:
|
||||
key = (func.__name__, args, tuple(kwargs.items()))
|
||||
cached = self._cache.get(key, None)
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import vim
|
||||
import os
|
||||
from powerline.bindings.vim import getbufvar
|
||||
|
||||
|
||||
def help():
|
||||
return bool(int(vim.eval('&buftype is# "help"')))
|
||||
def help(matcher_info):
|
||||
return getbufvar(matcher_info['bufnr'], '&buftype') == 'help'
|
||||
|
||||
|
||||
def cmdwin():
|
||||
return bool(int(vim.eval('bufname("%") is# "[Command Line]"')))
|
||||
def cmdwin(matcher_info):
|
||||
name = matcher_info['buffer'].name
|
||||
return name and os.path.basename(name) == '[Command Line]'
|
||||
|
|
|
@ -16,9 +16,9 @@ class Renderer(object):
|
|||
raise KeyError('There is already a local theme with given matcher')
|
||||
self.local_themes[matcher] = theme
|
||||
|
||||
def get_theme(self):
|
||||
def get_theme(self, matcher_info):
|
||||
for matcher in self.local_themes.keys():
|
||||
if matcher():
|
||||
if matcher(matcher_info):
|
||||
match = self.local_themes[matcher]
|
||||
if 'config' in match:
|
||||
match['theme'] = Theme(theme_config=match.pop('config'), **self.theme_kwargs)
|
||||
|
@ -26,7 +26,7 @@ class Renderer(object):
|
|||
else:
|
||||
return self.theme
|
||||
|
||||
def render(self, mode=None, width=None, theme=None, segments=None, side=None, output_raw=False):
|
||||
def render(self, mode=None, width=None, side=None, output_raw=False, segment_info=None, matcher_info=None):
|
||||
'''Render all segments.
|
||||
|
||||
When a width is provided, low-priority segments are dropped one at
|
||||
|
@ -35,8 +35,11 @@ class Renderer(object):
|
|||
provided they will fill the remaining space until the desired width is
|
||||
reached.
|
||||
'''
|
||||
theme = theme or self.get_theme()
|
||||
segments = segments or theme.get_segments(side)
|
||||
theme = self.get_theme(matcher_info)
|
||||
segments = theme.get_segments(side)
|
||||
|
||||
if segment_info:
|
||||
theme.segment_info.update(segment_info)
|
||||
|
||||
# Handle excluded/included segments for the current mode
|
||||
segments = [segment for segment in segments\
|
||||
|
|
|
@ -9,7 +9,6 @@ from powerline.colorscheme import ATTR_BOLD, ATTR_ITALIC, ATTR_UNDERLINE
|
|||
import vim
|
||||
|
||||
vim_mode = vim_get_func('mode')
|
||||
vim_winwidth = vim_get_func('winwidth', rettype=int)
|
||||
vim_getwinvar = vim_get_func('getwinvar')
|
||||
vim_setwinvar = vim_get_func('setwinvar')
|
||||
|
||||
|
@ -20,7 +19,6 @@ class VimRenderer(Renderer):
|
|||
def __init__(self, *args, **kwargs):
|
||||
super(VimRenderer, self).__init__(*args, **kwargs)
|
||||
self.hl_groups = {}
|
||||
self.window_cache = {}
|
||||
|
||||
def render(self, winnr, current):
|
||||
'''Render all segments.
|
||||
|
@ -30,19 +28,20 @@ class VimRenderer(Renderer):
|
|||
used in non-current windows.
|
||||
'''
|
||||
window_id = vim_getwinvar(winnr, 'window_id')
|
||||
winwidth = vim_winwidth(winnr)
|
||||
if current:
|
||||
mode = vim_mode()
|
||||
theme = self.get_theme()
|
||||
segments = [segment for segment in theme.get_segments()]
|
||||
self.window_cache[window_id] = (theme, segments)
|
||||
else:
|
||||
mode = 'nc'
|
||||
theme, segments = self.window_cache.get(window_id, (None, []))
|
||||
for segment in segments:
|
||||
segment['_space_left'] = 0
|
||||
segment['_space_right'] = 0
|
||||
statusline = super(VimRenderer, self).render(mode, winwidth, theme, segments)
|
||||
segment_info = {
|
||||
'window': vim.windows[winnr - 1],
|
||||
'winnr': winnr,
|
||||
'mode': mode,
|
||||
'window_id': window_id,
|
||||
}
|
||||
segment_info['buffer'] = segment_info['window'].buffer
|
||||
segment_info['bufnr'] = segment_info['buffer'].number
|
||||
winwidth = segment_info['window'].width
|
||||
statusline = super(VimRenderer, self).render(mode, winwidth, segment_info=segment_info, matcher_info=segment_info)
|
||||
return statusline
|
||||
|
||||
def reset_highlight(self):
|
||||
|
|
|
@ -8,17 +8,16 @@ try:
|
|||
except ImportError:
|
||||
vim = {}
|
||||
|
||||
from powerline.bindings.vim import vim_get_func
|
||||
from powerline.bindings.vim import vim_get_func, getbufvar
|
||||
from powerline.theme import requires_segment_info
|
||||
from powerline.lib import memoize, humanize_bytes
|
||||
from powerline.lib.vcs import guess
|
||||
|
||||
vim_funcs = {
|
||||
'col': vim_get_func('col', rettype=int),
|
||||
'virtcol': vim_get_func('virtcol', rettype=int),
|
||||
'expand': vim_get_func('expand'),
|
||||
'line': vim_get_func('line', rettype=int),
|
||||
'mode': vim_get_func('mode'),
|
||||
'fnamemodify': vim_get_func('fnamemodify'),
|
||||
'getfsize': vim_get_func('getfsize', rettype=int),
|
||||
'bufnr': vim_get_func('bufnr', rettype=int),
|
||||
}
|
||||
|
||||
vim_modes = {
|
||||
|
@ -48,13 +47,38 @@ mode_translations = {
|
|||
}
|
||||
|
||||
|
||||
def mode(override=None):
|
||||
def bufnr(segment_info, *args, **kwargs):
|
||||
'''Used for cache key, returns current buffer number'''
|
||||
return segment_info['bufnr']
|
||||
|
||||
|
||||
# TODO Remove cache when needed
|
||||
def window_cached(func):
|
||||
cache = {}
|
||||
|
||||
def ret(segment_info, *args, **kwargs):
|
||||
window_id = segment_info['window_id']
|
||||
if segment_info['mode'] == 'nc':
|
||||
return cache.get(window_id)
|
||||
else:
|
||||
r = func(*args, **kwargs)
|
||||
cache[window_id] = r
|
||||
return r
|
||||
ret = requires_segment_info(ret)
|
||||
ret.__name__ = func.__name__
|
||||
return ret
|
||||
|
||||
|
||||
@requires_segment_info
|
||||
def mode(segment_info, override=None):
|
||||
'''Return the current vim mode.
|
||||
|
||||
:param dict override:
|
||||
dict for overriding default mode strings, e.g. ``{ 'n': 'NORM' }``
|
||||
'''
|
||||
mode = vim_funcs['mode']().decode('utf-8')
|
||||
mode = segment_info['mode']
|
||||
if mode == 'nc':
|
||||
return None
|
||||
mode = mode_translations.get(mode, mode)
|
||||
if not override:
|
||||
return vim_modes[mode]
|
||||
|
@ -64,48 +88,54 @@ def mode(override=None):
|
|||
return vim_modes[mode]
|
||||
|
||||
|
||||
def modified_indicator(text=u'+'):
|
||||
@requires_segment_info
|
||||
def modified_indicator(segment_info, text=u'+'):
|
||||
'''Return a file modified indicator.
|
||||
|
||||
:param string text:
|
||||
text to display if the current buffer is modified
|
||||
'''
|
||||
return text if int(vim.eval('&modified')) else None
|
||||
return text if int(getbufvar(segment_info['bufnr'], '&modified')) else None
|
||||
|
||||
|
||||
def paste_indicator(text='PASTE'):
|
||||
@requires_segment_info
|
||||
def paste_indicator(segment_info, text='PASTE'):
|
||||
'''Return a paste mode indicator.
|
||||
|
||||
:param string text:
|
||||
text to display if paste mode is enabled
|
||||
'''
|
||||
return text if int(vim.eval('&paste')) else None
|
||||
return text if int(getbufvar(segment_info['bufnr'], '&paste')) else None
|
||||
|
||||
|
||||
def readonly_indicator(text=u''):
|
||||
@requires_segment_info
|
||||
def readonly_indicator(segment_info, text=u''):
|
||||
'''Return a read-only indicator.
|
||||
|
||||
:param string text:
|
||||
text to display if the current buffer is read-only
|
||||
'''
|
||||
return text if int(vim.eval('&readonly')) else None
|
||||
return text if int(getbufvar(segment_info['bufnr'], '&readonly')) else None
|
||||
|
||||
|
||||
def file_directory(shorten_home=False):
|
||||
@requires_segment_info
|
||||
def file_directory(segment_info, shorten_home=False):
|
||||
'''Return file directory (head component of the file path).
|
||||
|
||||
:param bool shorten_home:
|
||||
shorten all directories in :file:`/home/` to :file:`~user/` instead of :file:`/home/user/`.
|
||||
'''
|
||||
file_directory = vim_funcs['expand']('%:~:.:h')
|
||||
if file_directory is None:
|
||||
name = segment_info['buffer'].name
|
||||
if not name:
|
||||
return None
|
||||
file_directory = vim_funcs['fnamemodify'](name, ':~:.:h')
|
||||
if shorten_home and file_directory.startswith('/home/'):
|
||||
file_directory = '~' + file_directory[6:]
|
||||
return file_directory.decode('utf-8') + os.sep if file_directory else None
|
||||
|
||||
|
||||
def file_name(display_no_file=False, no_file_text='[No file]'):
|
||||
@requires_segment_info
|
||||
def file_name(segment_info, display_no_file=False, no_file_text='[No file]'):
|
||||
'''Return file name (tail component of the file path).
|
||||
|
||||
:param bool display_no_file:
|
||||
|
@ -113,19 +143,22 @@ def file_name(display_no_file=False, no_file_text='[No file]'):
|
|||
:param str no_file_text:
|
||||
the string to display if the buffer is missing a file name
|
||||
'''
|
||||
file_name = vim_funcs['expand']('%:~:.:t')
|
||||
if not file_name and not display_no_file:
|
||||
return None
|
||||
if not file_name:
|
||||
return [{
|
||||
'contents': no_file_text,
|
||||
'highlight_group': ['file_name_no_file', 'file_name'],
|
||||
}]
|
||||
name = segment_info['buffer'].name
|
||||
if not name:
|
||||
if display_no_file:
|
||||
return [{
|
||||
'contents': no_file_text,
|
||||
'highlight_group': ['file_name_no_file', 'file_name'],
|
||||
}]
|
||||
else:
|
||||
return None
|
||||
file_name = vim_funcs['fnamemodify'](name, ':~:.:t')
|
||||
return file_name.decode('utf-8')
|
||||
|
||||
|
||||
@memoize(2)
|
||||
def file_size(suffix='B', binary_prefix=False):
|
||||
@requires_segment_info
|
||||
@memoize(2, additional_key=bufnr)
|
||||
def file_size(segment_info, suffix='B', binary_prefix=False):
|
||||
'''Return file size.
|
||||
|
||||
:param str suffix:
|
||||
|
@ -134,45 +167,49 @@ def file_size(suffix='B', binary_prefix=False):
|
|||
use binary prefix, e.g. MiB instead of MB
|
||||
:return: file size or None if the file isn't saved or if the size is too big to fit in a number
|
||||
'''
|
||||
file_name = vim_funcs['expand']('%')
|
||||
file_name = segment_info['buffer'].name
|
||||
file_size = vim_funcs['getfsize'](file_name)
|
||||
if file_size < 0:
|
||||
return None
|
||||
return humanize_bytes(file_size, suffix, binary_prefix)
|
||||
|
||||
|
||||
def file_format():
|
||||
@requires_segment_info
|
||||
def file_format(segment_info):
|
||||
'''Return file format (i.e. line ending type).
|
||||
|
||||
:return: file format or None if unknown or missing file format
|
||||
'''
|
||||
return vim.eval('&fileformat') or None
|
||||
return getbufvar(segment_info['bufnr'], '&fileformat') or None
|
||||
|
||||
|
||||
def file_encoding():
|
||||
@requires_segment_info
|
||||
def file_encoding(segment_info):
|
||||
'''Return file encoding/character set.
|
||||
|
||||
:return: file encoding/character set or None if unknown or missing file encoding
|
||||
'''
|
||||
return vim.eval('&fileencoding') or None
|
||||
return getbufvar(segment_info['bufnr'], '&fileencoding') or None
|
||||
|
||||
|
||||
def file_type():
|
||||
@requires_segment_info
|
||||
def file_type(segment_info):
|
||||
'''Return file type.
|
||||
|
||||
:return: file type or None if unknown file type
|
||||
'''
|
||||
return vim.eval('&filetype') or None
|
||||
return getbufvar(segment_info['bufnr'], '&filetype') or None
|
||||
|
||||
|
||||
def line_percent(gradient=False):
|
||||
@requires_segment_info
|
||||
def line_percent(segment_info, gradient=False):
|
||||
'''Return the cursor position in the file as a percentage.
|
||||
|
||||
:param bool gradient:
|
||||
highlight the percentage with a color gradient (by default a green to red gradient)
|
||||
'''
|
||||
line_current = vim_funcs['line']('.')
|
||||
line_last = vim_funcs['line']('$')
|
||||
line_current = segment_info['window'].cursor[0]
|
||||
line_last = len(segment_info['buffer'])
|
||||
percentage = int(line_current * 100 // line_last)
|
||||
if not gradient:
|
||||
return percentage
|
||||
|
@ -182,18 +219,23 @@ def line_percent(gradient=False):
|
|||
}]
|
||||
|
||||
|
||||
def line_current():
|
||||
@requires_segment_info
|
||||
def line_current(segment_info):
|
||||
'''Return the current cursor line.'''
|
||||
return vim_funcs['line']('.')
|
||||
return segment_info['window'].cursor[0]
|
||||
|
||||
|
||||
def col_current(virtcol=True):
|
||||
@requires_segment_info
|
||||
def col_current(segment_info):
|
||||
'''Return the current cursor column.
|
||||
|
||||
:param bool virtcol:
|
||||
return visual column with concealed characters ingored
|
||||
'''
|
||||
return vim_funcs['virtcol' if virtcol else 'col']('.')
|
||||
return segment_info['window'].cursor[1] + 1
|
||||
|
||||
|
||||
@window_cached
|
||||
def virtcol_current():
|
||||
'''Return current visual column with concealed characters ingored'''
|
||||
return vim_funcs['virtcol']('.')
|
||||
|
||||
|
||||
def modified_buffers(text=u'+', join_str=','):
|
||||
|
@ -204,30 +246,33 @@ def modified_buffers(text=u'+', join_str=','):
|
|||
:param str join_str:
|
||||
string to use for joining the modified buffer list
|
||||
'''
|
||||
buffer_len = int(vim.eval('bufnr("$")'))
|
||||
buffer_mod = [str(bufnr) for bufnr in range(1, buffer_len + 1) if vim.eval('getbufvar({0}, "&mod")'.format(bufnr)) == '1']
|
||||
buffer_len = vim_funcs['bufnr']('$')
|
||||
buffer_mod = [str(bufnr) for bufnr in range(1, buffer_len + 1) if int(getbufvar(bufnr, '&modified'))]
|
||||
if buffer_mod:
|
||||
return u'{0} {1}'.format(text, join_str.join(buffer_mod))
|
||||
return None
|
||||
|
||||
|
||||
@requires_segment_info
|
||||
@memoize(2)
|
||||
def branch():
|
||||
def branch(segment_info):
|
||||
'''Return the current working branch.'''
|
||||
repo = guess(os.path.abspath(vim.current.buffer.name or os.getcwd()))
|
||||
repo = guess(os.path.abspath(segment_info['buffer'].name or os.getcwd()))
|
||||
if repo:
|
||||
return repo.branch()
|
||||
return None
|
||||
|
||||
|
||||
# TODO Drop cache on BufWrite event
|
||||
@memoize(2, additional_key=lambda: vim.current.buffer.number)
|
||||
def file_vcs_status():
|
||||
@requires_segment_info
|
||||
@memoize(2, additional_key=bufnr)
|
||||
def file_vcs_status(segment_info):
|
||||
'''Return the VCS status for this buffer.'''
|
||||
if vim.current.buffer.name and not vim.eval('&buftype'):
|
||||
repo = guess(os.path.abspath(vim.current.buffer.name))
|
||||
name = segment_info['buffer'].name
|
||||
if name and not getbufvar(segment_info['bufnr'], '&buftype'):
|
||||
repo = guess(os.path.abspath(name))
|
||||
if repo:
|
||||
status = repo.status(os.path.relpath(vim.current.buffer.name, repo.directory))
|
||||
status = repo.status(os.path.relpath(name, repo.directory))
|
||||
if not status:
|
||||
return None
|
||||
status = status.strip()
|
||||
|
@ -242,10 +287,11 @@ def file_vcs_status():
|
|||
return None
|
||||
|
||||
|
||||
@requires_segment_info
|
||||
@memoize(2)
|
||||
def repository_status():
|
||||
def repository_status(segment_info):
|
||||
'''Return the status for the current repo.'''
|
||||
repo = guess(os.path.abspath(vim.current.buffer.name or os.getcwd()))
|
||||
repo = guess(os.path.abspath(segment_info['buffer'].name or os.getcwd()))
|
||||
if repo:
|
||||
return repo.status()
|
||||
return None
|
||||
|
|
|
@ -11,6 +11,11 @@ except NameError:
|
|||
unicode = str
|
||||
|
||||
|
||||
def requires_segment_info(func):
|
||||
func.requires_powerline_segment_info = True
|
||||
return func
|
||||
|
||||
|
||||
class Theme(object):
|
||||
def __init__(self, ext, colorscheme, theme_config, common_config, segment_info=None):
|
||||
self.colorscheme = colorscheme
|
||||
|
|
Loading…
Reference in New Issue