Implement segment truncation

Closes #161 (requires implementation for specific segments though)
This commit is contained in:
ZyX 2014-08-30 18:19:56 +04:00
parent d6c603daf0
commit 2505d0b827
4 changed files with 55 additions and 12 deletions

View File

@ -102,6 +102,16 @@ powerline:
It must return new value of :ref:`contents <dev-segments-seg-contents>` key. It must return new value of :ref:`contents <dev-segments-seg-contents>` key.
.. _dev-segments-truncate:
``truncate``
Like :ref:`expand function <dev-segments-expand>`, but for truncating
segments. Here ``amount`` means the number of display cells which must be
freed.
This function is called for all segments before powerline starts purging
them to free space.
This callable object should may return either a string (``unicode`` in Python2 This callable object should may return either a string (``unicode`` in Python2
or ``str`` in Python3, *not* ``str`` in Python2 or ``bytes`` in Python3) object or ``str`` in Python3, *not* ``str`` in Python2 or ``bytes`` in Python3) object
or a list of dictionaries. String object is a short form of the following return or a list of dictionaries. String object is a short form of the following return
@ -251,10 +261,11 @@ Segment dictionary contains the following keys:
``width``, ``align`` ``width``, ``align``
:ref:`Width and align options <config-themes-seg-align>`. May be ``None``. :ref:`Width and align options <config-themes-seg-align>`. May be ``None``.
``expand`` ``expand``, ``truncate``
Partially applied :ref:`expand function <dev-segments-expand>`. Accepts Partially applied :ref:`expand <dev-segments-expand>` or :ref:`truncate
``pl``, ``amount`` and ``segment`` positional parameters, keyword parameters <dev-segments-truncate>` function. Accepts ``pl``, ``amount`` and
from :ref:`args <config-themes-seg-args>` key were applied. ``segment`` positional parameters, keyword parameters from :ref:`args
<config-themes-seg-args>` key were applied.
``startup`` ``startup``
Partially applied :ref:`startup function <dev-segments-startup>`. Accepts Partially applied :ref:`startup function <dev-segments-startup>`. Accepts

View File

@ -1,9 +1,12 @@
# vim:fileencoding=utf-8:noet # vim:fileencoding=utf-8:noet
from powerline.theme import Theme
from unicodedata import east_asian_width, combining
import os import os
from unicodedata import east_asian_width, combining
from itertools import chain
from powerline.theme import Theme
try: try:
NBSP = unicode(' ', 'utf-8') NBSP = unicode(' ', 'utf-8')
except NameError: except NameError:
@ -262,11 +265,17 @@ class Renderer(object):
# Create an ordered list of segments that can be dropped # Create an ordered list of segments that can be dropped
segments_priority = sorted((segment for segment in segments if segment['priority'] is not None), key=lambda segment: segment['priority'], reverse=True) segments_priority = sorted((segment for segment in segments if segment['priority'] is not None), key=lambda segment: segment['priority'], reverse=True)
for segment in segments_priority: no_priority_segments = filter(lambda segment: segment['priority'] is None, segments)
current_width = self._render_length(theme, segments, divider_widths) current_width = self._render_length(theme, segments, divider_widths)
if current_width <= width: if current_width > width:
break for segment in chain(segments_priority, no_priority_segments):
segments.remove(segment) if segment['truncate'] is not None:
segment['contents'] = segment['truncate'](self.pl, current_width - width, segment)
for segment in segments_priority:
if current_width <= width:
break
segments.remove(segment)
current_width = self._render_length(theme, segments, divider_widths)
# Distribute the remaining space on spacer segments # Distribute the remaining space on spacer segments
segments_spacers = [segment for segment in segments if segment['expand'] is not None] segments_spacers = [segment for segment in segments if segment['expand'] is not None]

View File

@ -93,7 +93,7 @@ def get_attr_func(contents_func, key, args, is_space_func=False):
try: try:
return func(pl=pl, amount=amount, segment=segment, **args) return func(pl=pl, amount=amount, segment=segment, **args)
except Exception as e: except Exception as e:
pl.exception('Exception while computing segment expansion: {0}', str(e)) pl.exception('Exception while computing {0} function: {1}', key, str(e))
return segment['contents'] + (' ' * amount) return segment['contents'] + (' ' * amount)
return expand_func return expand_func
else: else:
@ -292,6 +292,7 @@ def gen_segment_getter(pl, ext, common_config, theme_configs, default_module, ge
'width': None, 'width': None,
'align': None, 'align': None,
'expand': None, 'expand': None,
'truncate': None,
'startup': None, 'startup': None,
'shutdown': None, 'shutdown': None,
'mode': None, 'mode': None,
@ -305,6 +306,7 @@ def gen_segment_getter(pl, ext, common_config, theme_configs, default_module, ge
startup_func = get_attr_func(_contents_func, 'startup', args) startup_func = get_attr_func(_contents_func, 'startup', args)
shutdown_func = getattr(_contents_func, 'shutdown', None) shutdown_func = getattr(_contents_func, 'shutdown', None)
expand_func = get_attr_func(_contents_func, 'expand', args, True) expand_func = get_attr_func(_contents_func, 'expand', args, True)
truncate_func = get_attr_func(_contents_func, 'truncate', args, True)
if hasattr(_contents_func, 'powerline_requires_filesystem_watcher'): if hasattr(_contents_func, 'powerline_requires_filesystem_watcher'):
create_watcher = lambda: create_file_watcher(pl, common_config['watcher']) create_watcher = lambda: create_file_watcher(pl, common_config['watcher'])
@ -319,6 +321,7 @@ def gen_segment_getter(pl, ext, common_config, theme_configs, default_module, ge
shutdown_func = None shutdown_func = None
contents_func = None contents_func = None
expand_func = None expand_func = None
truncate_func = None
return { return {
'name': name or function_name, 'name': name or function_name,
@ -339,6 +342,7 @@ def gen_segment_getter(pl, ext, common_config, theme_configs, default_module, ge
'width': segment.get('width'), 'width': segment.get('width'),
'align': segment.get('align', 'l'), 'align': segment.get('align', 'l'),
'expand': expand_func, 'expand': expand_func,
'truncate': truncate_func,
'startup': startup_func, 'startup': startup_func,
'shutdown': shutdown_func, 'shutdown': shutdown_func,
'mode': None, 'mode': None,

View File

@ -494,6 +494,25 @@ class TestSegmentAttributes(TestRender):
} }
self.assertRenderEqual(p, '{56} ----pl,{6-}>>{--}', width=10) self.assertRenderEqual(p, '{56} ----pl,{6-}>>{--}', width=10)
@add_args
def test_truncate(self, p, config):
def m1(divider=',', **kwargs):
return divider.join(kwargs.keys()) + divider
def truncate(pl, amount, segment, **kwargs):
return segment['contents'][:-amount]
m1.truncate = truncate
sys.modules['bar'] = Args(m1=m1)
config['themes/test/default']['segments'] = {
'left': [
{
'function': 'bar.m1'
}
]
}
self.assertRenderEqual(p, '{56} p{6-}>>{--}', width=4)
class TestSegmentData(TestRender): class TestSegmentData(TestRender):
@add_args @add_args