mirror of
https://github.com/powerline/powerline.git
synced 2025-07-27 07:44:36 +02:00
Merge pull request #1007 from ZyX-I/tab-modified-indicator
Add tab_modified indicator
This commit is contained in:
commit
6e128c14ba
@ -136,6 +136,12 @@ else:
|
|||||||
if hasattr(vim, 'tabpages'):
|
if hasattr(vim, 'tabpages'):
|
||||||
current_tabpage = lambda: vim.current.tabpage
|
current_tabpage = lambda: vim.current.tabpage
|
||||||
list_tabpages = lambda: vim.tabpages
|
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:
|
else:
|
||||||
class FalseObject(object):
|
class FalseObject(object):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -205,6 +211,24 @@ else:
|
|||||||
def list_tabpages(): # NOQA
|
def list_tabpages(): # NOQA
|
||||||
return [Tabpage(nr) for nr in range(1, _last_tab_nr() + 1)]
|
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):
|
class VimEnviron(object):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -30,6 +30,11 @@
|
|||||||
},
|
},
|
||||||
"priority": 10
|
"priority": 10
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "tab_modified_indicator",
|
||||||
|
"exclude_modes": ["buf", "buf_nc"],
|
||||||
|
"priority": 5
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "modified_indicator",
|
"name": "modified_indicator",
|
||||||
"exclude_modes": ["tab", "tab_nc"],
|
"exclude_modes": ["tab", "tab_nc"],
|
||||||
|
@ -147,10 +147,17 @@ class Renderer(object):
|
|||||||
'''
|
'''
|
||||||
self.theme.shutdown()
|
self.theme.shutdown()
|
||||||
|
|
||||||
def _get_highlighting(self, segment, mode):
|
def _set_highlighting(self, segment):
|
||||||
segment['highlight'] = self.colorscheme.get_highlighting(segment['highlight_group'], mode, segment.get('gradient_level'))
|
segment['highlight'] = self.colorscheme.get_highlighting(
|
||||||
|
segment['highlight_group'],
|
||||||
|
segment['mode'],
|
||||||
|
segment.get('gradient_level')
|
||||||
|
)
|
||||||
if segment['divider_highlight_group']:
|
if segment['divider_highlight_group']:
|
||||||
segment['divider_highlight'] = self.colorscheme.get_highlighting(segment['divider_highlight_group'], mode)
|
segment['divider_highlight'] = self.colorscheme.get_highlighting(
|
||||||
|
segment['divider_highlight_group'],
|
||||||
|
segment['mode']
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
segment['divider_highlight'] = None
|
segment['divider_highlight'] = None
|
||||||
return segment
|
return segment
|
||||||
@ -254,19 +261,10 @@ class Renderer(object):
|
|||||||
def do_render(self, mode, width, side, line, output_raw, output_width, segment_info, theme):
|
def do_render(self, mode, width, side, line, output_raw, output_width, segment_info, theme):
|
||||||
'''Like Renderer.render(), but accept theme in place of matcher_info
|
'''Like Renderer.render(), but accept theme in place of matcher_info
|
||||||
'''
|
'''
|
||||||
segments = theme.get_segments(side, line, self.get_segment_info(segment_info, mode))
|
|
||||||
# Handle excluded/included segments for the current mode
|
|
||||||
segments = [
|
segments = [
|
||||||
self._get_highlighting(segment, segment_mode)
|
self._set_highlighting(segment)
|
||||||
for segment, segment_mode in (
|
for segment in (
|
||||||
(segment, segment['mode'] or mode)
|
theme.get_segments(side, line, self.get_segment_info(segment_info, mode), mode)
|
||||||
for segment in segments
|
|
||||||
) if (
|
|
||||||
segment_mode not in segment['exclude_modes']
|
|
||||||
and (
|
|
||||||
not segment['include_modes']
|
|
||||||
or segment_mode in segment['include_modes']
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -84,36 +84,33 @@ class VimRenderer(Renderer):
|
|||||||
def get_segment_info(self, segment_info, mode):
|
def get_segment_info(self, segment_info, mode):
|
||||||
return segment_info or self.segment_info
|
return segment_info or self.segment_info
|
||||||
|
|
||||||
def render(self, window=None, window_id=None, winnr=None):
|
def render(self, window=None, window_id=None, winnr=None, is_tabline=False):
|
||||||
'''Render all segments.'''
|
'''Render all segments.'''
|
||||||
segment_info = self.segment_info.copy()
|
segment_info = self.segment_info.copy()
|
||||||
if window is not None:
|
|
||||||
if window is vim.current.window:
|
if window is vim.current.window:
|
||||||
mode = vim_mode(1)
|
mode = vim_mode(1)
|
||||||
mode = mode_translations.get(mode, 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(),
|
|
||||||
)
|
|
||||||
segment_info['tabnr'] = segment_info['tabpage'].number
|
|
||||||
segment_info['bufnr'] = segment_info['buffer'].number
|
|
||||||
winwidth = segment_info['window'].width
|
|
||||||
matcher_info = segment_info
|
|
||||||
else:
|
else:
|
||||||
mode = None
|
mode = 'nc'
|
||||||
winwidth = int(vim.eval('&columns'))
|
|
||||||
matcher_info = None
|
segment_info.update(
|
||||||
|
window=window,
|
||||||
|
mode=mode,
|
||||||
|
window_id=window_id,
|
||||||
|
winnr=winnr,
|
||||||
|
buffer=window.buffer,
|
||||||
|
tabpage=current_tabpage(),
|
||||||
|
)
|
||||||
|
segment_info['tabnr'] = segment_info['tabpage'].number
|
||||||
|
segment_info['bufnr'] = segment_info['buffer'].number
|
||||||
|
winwidth = segment_info['window'].width
|
||||||
|
|
||||||
statusline = super(VimRenderer, self).render(
|
statusline = super(VimRenderer, self).render(
|
||||||
mode=mode,
|
mode=mode,
|
||||||
width=winwidth,
|
width=winwidth,
|
||||||
segment_info=segment_info,
|
segment_info=segment_info,
|
||||||
matcher_info=matcher_info,
|
matcher_info=(None if is_tabline else segment_info),
|
||||||
)
|
)
|
||||||
return statusline
|
return statusline
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
# vim:fileencoding=utf-8:noet
|
# vim:fileencoding=utf-8:noet
|
||||||
from __future__ import absolute_import, unicode_literals, division, print_function
|
from __future__ import absolute_import, unicode_literals, division, print_function
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from powerline.lib.watcher import create_file_watcher
|
from powerline.lib.watcher import create_file_watcher
|
||||||
|
|
||||||
|
|
||||||
@ -90,7 +88,7 @@ def get_attr_func(contents_func, key, args):
|
|||||||
return lambda pl, shutdown_event: func(pl=pl, shutdown_event=shutdown_event, **args)
|
return lambda pl, shutdown_event: func(pl=pl, shutdown_event=shutdown_event, **args)
|
||||||
|
|
||||||
|
|
||||||
def process_segment_lister(pl, segment_info, parsed_segments, side, lister, subsegments, patcher_args):
|
def process_segment_lister(pl, segment_info, parsed_segments, side, mode, lister, subsegments, patcher_args):
|
||||||
for subsegment_info, subsegment_update in lister(pl=pl, segment_info=segment_info, **patcher_args):
|
for subsegment_info, subsegment_update in lister(pl=pl, segment_info=segment_info, **patcher_args):
|
||||||
draw_inner_divider = subsegment_update.pop('draw_inner_divider', False)
|
draw_inner_divider = subsegment_update.pop('draw_inner_divider', False)
|
||||||
old_pslen = len(parsed_segments)
|
old_pslen = len(parsed_segments)
|
||||||
@ -100,7 +98,18 @@ def process_segment_lister(pl, segment_info, parsed_segments, side, lister, subs
|
|||||||
subsegment.update(subsegment_update)
|
subsegment.update(subsegment_update)
|
||||||
if subsegment_update['priority_multiplier'] and subsegment['priority']:
|
if subsegment_update['priority_multiplier'] and subsegment['priority']:
|
||||||
subsegment['priority'] *= subsegment_update['priority_multiplier']
|
subsegment['priority'] *= subsegment_update['priority_multiplier']
|
||||||
process_segment(pl, side, subsegment_info, parsed_segments, subsegment)
|
|
||||||
|
subsegment_mode = subsegment_update.get('mode')
|
||||||
|
if subsegment_mode and (
|
||||||
|
subsegment_mode in subsegment['exclude_modes']
|
||||||
|
or (
|
||||||
|
subsegment['include_modes']
|
||||||
|
and subsegment_mode not in subsegment['include_modes']
|
||||||
|
)
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
process_segment(pl, side, subsegment_info, parsed_segments, subsegment, subsegment_mode or mode)
|
||||||
new_pslen = len(parsed_segments)
|
new_pslen = len(parsed_segments)
|
||||||
if new_pslen > old_pslen + 1 and draw_inner_divider is not None:
|
if new_pslen > old_pslen + 1 and draw_inner_divider is not None:
|
||||||
for i in range(old_pslen, new_pslen - 1) if side == 'left' else range(old_pslen + 1, new_pslen):
|
for i in range(old_pslen, new_pslen - 1) if side == 'left' else range(old_pslen + 1, new_pslen):
|
||||||
@ -108,22 +117,27 @@ def process_segment_lister(pl, segment_info, parsed_segments, side, lister, subs
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def process_segment(pl, side, segment_info, parsed_segments, segment):
|
def process_segment(pl, side, segment_info, parsed_segments, segment, mode):
|
||||||
|
segment = segment.copy()
|
||||||
|
segment['mode'] = mode
|
||||||
if segment['type'] in ('function', 'segment_list'):
|
if segment['type'] in ('function', 'segment_list'):
|
||||||
pl.prefix = segment['name']
|
pl.prefix = segment['name']
|
||||||
try:
|
try:
|
||||||
if segment['type'] == 'function':
|
if segment['type'] == 'function':
|
||||||
contents = segment['contents_func'](pl, segment_info)
|
contents = segment['contents_func'](pl, segment_info)
|
||||||
else:
|
else:
|
||||||
contents = segment['contents_func'](pl, segment_info, parsed_segments, side)
|
contents = segment['contents_func'](pl, segment_info, parsed_segments, side, mode)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pl.exception('Exception while computing segment: {0}', str(e))
|
pl.exception('Exception while computing segment: {0}', str(e))
|
||||||
return
|
return
|
||||||
|
|
||||||
if contents is None:
|
if contents is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
if isinstance(contents, list):
|
if isinstance(contents, list):
|
||||||
segment_base = segment.copy()
|
# Needs copying here, but it was performed at the very start of the
|
||||||
|
# function
|
||||||
|
segment_base = segment
|
||||||
if contents:
|
if contents:
|
||||||
draw_divider_position = -1 if side == 'left' else 0
|
draw_divider_position = -1 if side == 'left' else 0
|
||||||
for key, i, newval in (
|
for key, i, newval in (
|
||||||
@ -206,8 +220,8 @@ def gen_segment_getter(pl, ext, common_config, theme_configs, default_module, ge
|
|||||||
'divider_highlight_group': None,
|
'divider_highlight_group': None,
|
||||||
'before': None,
|
'before': None,
|
||||||
'after': None,
|
'after': None,
|
||||||
'contents_func': lambda pl, segment_info, parsed_segments, side: process_segment_lister(
|
'contents_func': lambda pl, segment_info, parsed_segments, side, mode: process_segment_lister(
|
||||||
pl, segment_info, parsed_segments, side,
|
pl, segment_info, parsed_segments, side, mode,
|
||||||
patcher_args=args,
|
patcher_args=args,
|
||||||
subsegments=subsegments,
|
subsegments=subsegments,
|
||||||
lister=_contents_func,
|
lister=_contents_func,
|
||||||
|
@ -13,9 +13,10 @@ except ImportError:
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
from powerline.bindings.vim import (vim_get_func, getbufvar, vim_getbufoption,
|
from powerline.bindings.vim import (vim_get_func, getbufvar, vim_getbufoption,
|
||||||
buffer_name, vim_getwinvar,
|
buffer_name, vim_getwinvar,
|
||||||
register_buffer_cache, current_tabpage,
|
register_buffer_cache, current_tabpage,
|
||||||
list_tabpages)
|
list_tabpages,
|
||||||
|
list_tabpage_buffers_segment_info)
|
||||||
from powerline.theme import requires_segment_info, requires_filesystem_watcher
|
from powerline.theme import requires_segment_info, requires_filesystem_watcher
|
||||||
from powerline.lib import add_divider_highlight_group
|
from powerline.lib import add_divider_highlight_group
|
||||||
from powerline.lib.vcs import guess, tree_status
|
from powerline.lib.vcs import guess, tree_status
|
||||||
@ -167,6 +168,24 @@ def modified_indicator(pl, segment_info, text='+'):
|
|||||||
return text if int(vim_getbufoption(segment_info, 'modified')) else None
|
return text if int(vim_getbufoption(segment_info, 'modified')) else None
|
||||||
|
|
||||||
|
|
||||||
|
@requires_segment_info
|
||||||
|
def tab_modified_indicator(pl, segment_info, text='+'):
|
||||||
|
'''Return a file modified indicator for tabpages.
|
||||||
|
|
||||||
|
:param string text:
|
||||||
|
text to display if any buffer in the current tab is modified
|
||||||
|
|
||||||
|
Highlight groups used: ``tab_modified_indicator`` or ``modified_indicator``.
|
||||||
|
'''
|
||||||
|
for buf_segment_info in list_tabpage_buffers_segment_info(segment_info):
|
||||||
|
if int(vim_getbufoption(buf_segment_info, 'modified')):
|
||||||
|
return [{
|
||||||
|
'contents': text,
|
||||||
|
'highlight_group': ['tab_modified_indicator', 'modified_indicator'],
|
||||||
|
}]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
@requires_segment_info
|
@requires_segment_info
|
||||||
def paste_indicator(pl, segment_info, text='PASTE'):
|
def paste_indicator(pl, segment_info, text='PASTE'):
|
||||||
'''Return a paste mode indicator.
|
'''Return a paste mode indicator.
|
||||||
@ -427,7 +446,6 @@ def col_current(pl, segment_info):
|
|||||||
return str(segment_info['window'].cursor[1] + 1)
|
return str(segment_info['window'].cursor[1] + 1)
|
||||||
|
|
||||||
|
|
||||||
# TODO Add &textwidth-based gradient
|
|
||||||
@window_cached
|
@window_cached
|
||||||
def virtcol_current(pl, gradient=True):
|
def virtcol_current(pl, gradient=True):
|
||||||
'''Return current visual column with concealed characters ingored
|
'''Return current visual column with concealed characters ingored
|
||||||
|
@ -90,7 +90,7 @@ class Theme(object):
|
|||||||
def get_line_number(self):
|
def get_line_number(self):
|
||||||
return len(self.segments)
|
return len(self.segments)
|
||||||
|
|
||||||
def get_segments(self, side=None, line=0, segment_info=None):
|
def get_segments(self, side=None, line=0, segment_info=None, mode=None):
|
||||||
'''Return all segments.
|
'''Return all segments.
|
||||||
|
|
||||||
Function segments are called, and all segments get their before/after
|
Function segments are called, and all segments get their before/after
|
||||||
@ -103,7 +103,11 @@ class Theme(object):
|
|||||||
for side in [side] if side else ['left', 'right']:
|
for side in [side] if side else ['left', 'right']:
|
||||||
parsed_segments = []
|
parsed_segments = []
|
||||||
for segment in self.segments[line][side]:
|
for segment in self.segments[line][side]:
|
||||||
process_segment(self.pl, side, segment_info, parsed_segments, segment)
|
# No segment-local modes at this point
|
||||||
|
if mode not in segment['exclude_modes'] and (
|
||||||
|
not segment['include_modes'] or mode in segment['include_modes']
|
||||||
|
):
|
||||||
|
process_segment(self.pl, side, segment_info, parsed_segments, segment, mode)
|
||||||
for segment in parsed_segments:
|
for segment in parsed_segments:
|
||||||
segment['contents'] = segment['before'] + u(segment['contents'] if segment['contents'] is not None else '') + segment['after']
|
segment['contents'] = segment['before'] + u(segment['contents'] if segment['contents'] is not None else '') + segment['after']
|
||||||
# Align segment contents
|
# Align segment contents
|
||||||
|
@ -4,7 +4,7 @@ from __future__ import absolute_import
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
from powerline.bindings.vim import vim_get_func, vim_getvar
|
from powerline.bindings.vim import vim_get_func, vim_getvar
|
||||||
from powerline import Powerline
|
from powerline import Powerline, FailedUnicode
|
||||||
from powerline.lib import mergedicts
|
from powerline.lib import mergedicts
|
||||||
import vim
|
import vim
|
||||||
from itertools import count
|
from itertools import count
|
||||||
@ -228,15 +228,14 @@ class VimPowerline(Powerline):
|
|||||||
def statusline(self, window_id):
|
def statusline(self, window_id):
|
||||||
window, window_id, winnr = self.win_idx(window_id) or (None, None, None)
|
window, window_id, winnr = self.win_idx(window_id) or (None, None, None)
|
||||||
if not window:
|
if not window:
|
||||||
return 'No window {0}'.format(window_id)
|
return FailedUnicode('No window {0}'.format(window_id))
|
||||||
return self.render(window, window_id, winnr)
|
return self.render(window, window_id, winnr)
|
||||||
|
|
||||||
def tabline(self):
|
def tabline(self):
|
||||||
return self.render()
|
return self.render(*self.win_idx(None), is_tabline=True)
|
||||||
|
|
||||||
def new_window(self):
|
def new_window(self):
|
||||||
window, window_id, winnr = self.win_idx(None)
|
return self.render(*self.win_idx(None))
|
||||||
return self.render(window, window_id, winnr)
|
|
||||||
|
|
||||||
if not hasattr(vim, 'bindeval'):
|
if not hasattr(vim, 'bindeval'):
|
||||||
# Method for PowerlinePyeval function. Is here to reduce the number of
|
# Method for PowerlinePyeval function. Is here to reduce the number of
|
||||||
|
@ -53,7 +53,7 @@ class TestConfig(TestCase):
|
|||||||
outputs[out] = (i, (args, kwargs), mode)
|
outputs[out] = (i, (args, kwargs), mode)
|
||||||
|
|
||||||
with vim_module._with('bufname', '/tmp/foo.txt'):
|
with vim_module._with('bufname', '/tmp/foo.txt'):
|
||||||
out = powerline.render()
|
out = powerline.render(vim_module.current.window, 1, vim_module.current.window.number, is_tabline=True)
|
||||||
outputs[out] = (-1, (None, None), 'tab')
|
outputs[out] = (-1, (None, None), 'tab')
|
||||||
with vim_module._with('globals', powerline_config_path=cfg_path):
|
with vim_module._with('globals', powerline_config_path=cfg_path):
|
||||||
exclude = set(('no', 'v', 'V', VBLOCK, 's', 'S', SBLOCK, 'R', 'Rv', 'c', 'cv', 'ce', 'r', 'rm', 'r?', '!'))
|
exclude = set(('no', 'v', 'V', VBLOCK, 's', 'S', SBLOCK, 'R', 'Rv', 'c', 'cv', 'ce', 'r', 'rm', 'r?', '!'))
|
||||||
|
@ -903,6 +903,29 @@ class TestVim(TestCase):
|
|||||||
self.assertEqual(single_tab(multiple_text='m'), [{'highlight_group': ['single_tab'], 'contents': 'Bufs'}])
|
self.assertEqual(single_tab(multiple_text='m'), [{'highlight_group': ['single_tab'], 'contents': 'Bufs'}])
|
||||||
self.assertEqual(single_tab(single_text='s'), [{'highlight_group': ['single_tab'], 'contents': 's'}])
|
self.assertEqual(single_tab(single_text='s'), [{'highlight_group': ['single_tab'], 'contents': 's'}])
|
||||||
|
|
||||||
|
def test_segment_info(self):
|
||||||
|
pl = Pl()
|
||||||
|
with vim_module._with('tabpage'):
|
||||||
|
with vim_module._with('buffer', '1') as segment_info:
|
||||||
|
self.assertEqual(vim.tab_modified_indicator(pl=pl, segment_info=segment_info), None)
|
||||||
|
vim_module.current.buffer[0] = ' '
|
||||||
|
self.assertEqual(vim.tab_modified_indicator(pl=pl, segment_info=segment_info), [{
|
||||||
|
'contents': '+',
|
||||||
|
'highlight_group': ['tab_modified_indicator', 'modified_indicator'],
|
||||||
|
}])
|
||||||
|
vim_module._undo()
|
||||||
|
self.assertEqual(vim.tab_modified_indicator(pl=pl, segment_info=segment_info), None)
|
||||||
|
old_buffer = vim_module.current.buffer
|
||||||
|
vim_module._new('2')
|
||||||
|
segment_info = vim_module._get_segment_info()
|
||||||
|
self.assertEqual(vim.tab_modified_indicator(pl=pl, segment_info=segment_info), None)
|
||||||
|
old_buffer[0] = ' '
|
||||||
|
self.assertEqual(vim.modified_indicator(pl=pl, segment_info=segment_info), None)
|
||||||
|
self.assertEqual(vim.tab_modified_indicator(pl=pl, segment_info=segment_info), [{
|
||||||
|
'contents': '+',
|
||||||
|
'highlight_group': ['tab_modified_indicator', 'modified_indicator'],
|
||||||
|
}])
|
||||||
|
|
||||||
|
|
||||||
old_cwd = None
|
old_cwd = None
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user