Merge pull request #957 from ZyX-I/better-visual-range

Improve visual_range segment
This commit is contained in:
Nikolai Aleksandrovich Pavlov 2014-08-05 23:16:05 +04:00
commit b1a2b44db1
4 changed files with 124 additions and 25 deletions

View File

@ -22,7 +22,7 @@
},
{
"name": "visual_range",
"exclude_modes": ["nc"],
"include_modes": ["v", "V", "^V", "s", "S", "^S"],
"priority": 10
},
{

View File

@ -74,7 +74,10 @@ def window_cached(func):
if segment_info['mode'] == 'nc':
return cache.get(window_id)
else:
r = func(**kwargs)
if getattr(func, 'powerline_requires_segment_info', False):
r = func(segment_info=segment_info, **kwargs)
else:
r = func(**kwargs)
cache[window_id] = r
return r
@ -99,29 +102,57 @@ def mode(pl, segment_info, override=None):
return vim_modes[mode]
@window_cached
@requires_segment_info
def visual_range(pl, segment_info):
def visual_range(pl, segment_info, CTRL_V_text='{rows} × {vcols}', v_text_oneline='C:{vcols}', v_text_multiline='L:{rows}', V_text='L:{rows}'):
'''Return the current visual selection range.
Returns a value similar to `showcmd`.
:param str CTRL_V_text:
Text to display when in block visual or select mode.
:param str v_text_oneline:
Text to display when in charaterwise visual or select mode, assuming
selection occupies only one line.
:param str v_text_multiline:
Text to display when in charaterwise visual or select mode, assuming
selection occupies more then one line.
:param str V_text:
Text to display when in linewise visual or select mode.
All texts are format strings which are passed the following parameters:
========= =============================================================
Parameter Description
========= =============================================================
sline Line number of the first line of the selection
eline Line number of the last line of the selection
scol Column number of the first character of the selection
ecol Column number of the last character of the selection
svcol Virtual column number of the first character of the selection
secol Virtual column number of the last character of the selection
rows Number of lines in the selection
cols Number of columns in the selection
vcols Number of virtual columns in the selection
========= =============================================================
'''
if segment_info['mode'] not in ('v', 'V', '^V'):
return None
pos_start = vim_funcs['getpos']('v')
pos_end = vim_funcs['getpos']('.')
# Workaround for vim's "excellent" handling of multibyte characters and display widths
pos_start[2] = vim_funcs['virtcol']([pos_start[1], pos_start[2], pos_start[3]])
pos_end[2] = vim_funcs['virtcol']([pos_end[1], pos_end[2], pos_end[3]])
visual_start = (int(pos_start[1]), int(pos_start[2]))
visual_end = (int(pos_end[1]), int(pos_end[2]))
diff_rows = abs(visual_end[0] - visual_start[0]) + 1
diff_cols = abs(visual_end[1] - visual_start[1]) + 1
if segment_info['mode'] == '^V':
return '{0} × {1}'.format(diff_rows, diff_cols)
elif segment_info['mode'] == 'V' or diff_rows > 1:
return '{0} rows'.format(diff_rows)
else:
return '{0} cols'.format(diff_cols)
sline, scol, soff = [int(v) for v in vim_funcs['getpos']("v")[1:]]
eline, ecol, eoff = [int(v) for v in vim_funcs['getpos'](".")[1:]]
svcol = vim_funcs['virtcol']([sline, scol, soff])
evcol = vim_funcs['virtcol']([eline, ecol, eoff])
rows = abs(eline - sline) + 1
cols = abs(ecol - scol) + 1
vcols = abs(evcol - svcol) + 1
return {
'^': CTRL_V_text,
's': v_text_oneline if rows == 1 else v_text_multiline,
'S': V_text,
'v': v_text_oneline if rows == 1 else v_text_multiline,
'V': V_text,
}.get(segment_info['mode'][0], '').format(
sline=sline, eline=eline,
scol=scol, ecol=ecol,
svcol=svcol, evcol=evcol,
rows=rows, cols=cols, vcols=vcols,
)
@requires_segment_info

View File

@ -589,8 +589,50 @@ class TestVim(TestCase):
self.assertEqual(vim.mode(pl=pl, segment_info=segment_info, override={'^V': 'VBLK'}), 'VBLK')
def test_visual_range(self):
# TODO
pass
pl = Pl()
vr = partial(vim.visual_range, pl=pl)
vim_module.current.window.cursor = [0, 0]
try:
with vim_module._with('mode', 'i') as segment_info:
self.assertEqual(vr(segment_info=segment_info), '')
with vim_module._with('mode', '^V') as segment_info:
self.assertEqual(vr(segment_info=segment_info), '1 × 1')
with vim_module._with('vpos', line=5, col=5, off=0):
self.assertEqual(vr(segment_info=segment_info), '5 × 5')
with vim_module._with('vpos', line=5, col=4, off=0):
self.assertEqual(vr(segment_info=segment_info), '5 × 4')
with vim_module._with('mode', '^S') as segment_info:
self.assertEqual(vr(segment_info=segment_info), '1 × 1')
with vim_module._with('vpos', line=5, col=5, off=0):
self.assertEqual(vr(segment_info=segment_info), '5 × 5')
with vim_module._with('vpos', line=5, col=4, off=0):
self.assertEqual(vr(segment_info=segment_info), '5 × 4')
with vim_module._with('mode', 'V') as segment_info:
self.assertEqual(vr(segment_info=segment_info), 'L:1')
with vim_module._with('vpos', line=5, col=5, off=0):
self.assertEqual(vr(segment_info=segment_info), 'L:5')
with vim_module._with('vpos', line=5, col=4, off=0):
self.assertEqual(vr(segment_info=segment_info), 'L:5')
with vim_module._with('mode', 'S') as segment_info:
self.assertEqual(vr(segment_info=segment_info), 'L:1')
with vim_module._with('vpos', line=5, col=5, off=0):
self.assertEqual(vr(segment_info=segment_info), 'L:5')
with vim_module._with('vpos', line=5, col=4, off=0):
self.assertEqual(vr(segment_info=segment_info), 'L:5')
with vim_module._with('mode', 'v') as segment_info:
self.assertEqual(vr(segment_info=segment_info), 'C:1')
with vim_module._with('vpos', line=5, col=5, off=0):
self.assertEqual(vr(segment_info=segment_info), 'L:5')
with vim_module._with('vpos', line=5, col=4, off=0):
self.assertEqual(vr(segment_info=segment_info), 'L:5')
with vim_module._with('mode', 's') as segment_info:
self.assertEqual(vr(segment_info=segment_info), 'C:1')
with vim_module._with('vpos', line=5, col=5, off=0):
self.assertEqual(vr(segment_info=segment_info), 'L:5')
with vim_module._with('vpos', line=5, col=4, off=0):
self.assertEqual(vr(segment_info=segment_info), 'L:5')
finally:
vim_module._close(1)
def test_modified_indicator(self):
pl = Pl()

View File

@ -342,15 +342,22 @@ def _emul_setwinvar(winnr, varname, value):
@_vim
def _emul_virtcol(expr):
if expr == '.' or isinstance(expr, list):
if expr == '.':
return current.window.cursor[1] + 1
if isinstance(expr, list) and len(expr) == 3:
return expr[-2] + expr[-1]
raise NotImplementedError
_v_pos = None
@_vim
def _emul_getpos(expr):
if expr == '.' or expr == 'v':
if expr == '.':
return [0, current.window.cursor[0] + 1, current.window.cursor[1] + 1, 0]
if expr == 'v':
return _v_pos or [0, current.window.cursor[0] + 1, current.window.cursor[1] + 1, 0]
raise NotImplementedError
@ -848,6 +855,23 @@ class _WithNewTabPage(object):
self.tab._close()
class _WithGlobal(object):
def __init__(self, **kwargs):
self.kwargs = kwargs
def __enter__(self):
self.empty = object()
self.old = dict(((key, globals().get(key, self.empty)) for key in self.kwargs))
globals().update(self.kwargs)
def __exit__(self, *args):
for k, v in self.old.items():
if v is self.empty:
globals().pop(k, None)
else:
globals()[k] = v
@_vim
def _with(key, *args, **kwargs):
if key == 'buffer':
@ -870,6 +894,8 @@ def _with(key, *args, **kwargs):
return _WithSplit()
elif key == 'tabpage':
return _WithNewTabPage(*args, **kwargs)
elif key == 'vpos':
return _WithGlobal(_v_pos=[0, kwargs['line'], kwargs['col'], kwargs['off']])
class error(Exception):