From ee5f471b491cec3f0b6f08095f4aa91d5320435a Mon Sep 17 00:00:00 2001 From: S0lll0s Date: Tue, 5 Jan 2016 01:15:09 +0100 Subject: [PATCH] Deprecate "bar" bindings in favor of lemonbar --- docs/source/configuration/reference.rst | 4 + docs/source/usage/wm-widgets.rst | 21 +++-- powerline/bindings/bar/powerline-bar.py | 18 ++-- .../bindings/lemonbar/powerline-lemonbar.py | 91 +++++++++++++++++++ powerline/lemonbar.py | 21 +++++ powerline/lint/__init__.py | 6 ++ powerline/renderers/bar.py | 45 --------- powerline/renderers/lemonbar.py | 61 +++++++++++++ powerline/segments/i3wm.py | 7 +- tests/test_configuration.py | 12 +-- 10 files changed, 212 insertions(+), 74 deletions(-) create mode 100755 powerline/bindings/lemonbar/powerline-lemonbar.py create mode 100644 powerline/lemonbar.py delete mode 100644 powerline/renderers/bar.py create mode 100644 powerline/renderers/lemonbar.py diff --git a/docs/source/configuration/reference.rst b/docs/source/configuration/reference.rst index e32ee06b..99b32be1 100644 --- a/docs/source/configuration/reference.rst +++ b/docs/source/configuration/reference.rst @@ -187,6 +187,10 @@ Common configuration is a subdictionary that is a value of ``ext`` key in ``out`` and ``rewrite`` prompts (refer to IPython documentation for more details) while ``in`` prompt is the default. + For wm (:ref:`lemonbar ` only) it is a dictionary + ``{output : theme_name}`` that maps the ``xrandr`` output names to the + local themes to use on that output. + ``components`` Determines which extension components should be enabled. This key is highly extension-specific, here is the table of extensions and corresponding diff --git a/docs/source/usage/wm-widgets.rst b/docs/source/usage/wm-widgets.rst index 6c0806e2..cd32c763 100644 --- a/docs/source/usage/wm-widgets.rst +++ b/docs/source/usage/wm-widgets.rst @@ -50,24 +50,27 @@ Add the following to :file:`~/.config/qtile/config.py`: ), ] -.. _bar-usage: +.. _lemonbar-usage: -bar-aint-recursive -================== +lemonbar (formerly bar-aint-recursive) +====================================== -To run the bar simply pipe the output of the binding script into ``bar`` and -specify appropriate options, for example like this:: +To run the bar simply start the binding script: - python /path/to/powerline/bindings/bar/powerline-bar.py | bar + python /path/to/powerline/bindings/lemonbar/powerline-lemonbar.py -to run with i3, simply ``exec`` this in i3 config file:: +You can specify options to be passed to ``lemonbar`` after ``--``, like so: - exec python /path/to/powerline/bindings/bar/powerline-bar.py --i3 | bar + python /path/to/powerline/bindings/lemonbar/powerline-lemonbar.py --height 16 -- -f "Source Code Pro for Powerline-9" + +to run with i3, simply ``exec`` this in the i3 config file and set the ``--i3`` switch: + + exec python /path/to/powerline/bindings/lemonbar/powerline-lemonbar.py --i3 Running the binding in i3-mode will require `i3ipc `_ (or the outdated `i3-py `_). -See the `bar documentation `_ for more +See the `lemonbar documentation `_ for more information and options. I3 bar diff --git a/powerline/bindings/bar/powerline-bar.py b/powerline/bindings/bar/powerline-bar.py index 35496f6f..05ef7685 100755 --- a/powerline/bindings/bar/powerline-bar.py +++ b/powerline/bindings/bar/powerline-bar.py @@ -2,31 +2,27 @@ # vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) +import os import sys import time from threading import Lock, Timer from argparse import ArgumentParser -from powerline import Powerline +from powerline.lemonbar import LemonbarPowerline from powerline.lib.encoding import get_unicode_writer -class BarPowerline(Powerline): - get_encoding = staticmethod(lambda: 'utf-8') - - def init(self): - super(BarPowerline, self).init(ext='wm', renderer_module='bar') - - if __name__ == '__main__': - parser = ArgumentParser(description='Powerline BAR bindings.') + parser = ArgumentParser(description='Powerline lemonbar bindings.') parser.add_argument( '--i3', action='store_true', help='Subscribe for i3 events.' ) args = parser.parse_args() - powerline = BarPowerline() + powerline = LemonbarPowerline() + powerline.update_renderer() + powerline.pl.warn("The 'bar' bindings are deprecated, please switch to 'lemonbar'") lock = Lock() modes = ['default'] write = get_unicode_writer(encoding='utf-8') @@ -60,4 +56,4 @@ if __name__ == '__main__': conn.main() while True: - time.sleep(1e10) + time.sleep(1e8) diff --git a/powerline/bindings/lemonbar/powerline-lemonbar.py b/powerline/bindings/lemonbar/powerline-lemonbar.py new file mode 100755 index 00000000..ca658813 --- /dev/null +++ b/powerline/bindings/lemonbar/powerline-lemonbar.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import time +import re +import subprocess + +from threading import Lock, Timer +from argparse import ArgumentParser, REMAINDER + +from powerline.lemonbar import LemonbarPowerline +from powerline.lib.shell import run_cmd + + +if __name__ == '__main__': + parser = ArgumentParser( + description='Powerline BAR bindings.', + usage='%(prog)s [-h] [--i3] [--height HEIGHT] [--interval INTERVAL] [--bar-command CMD] -- args' + ) + parser.add_argument( + '--i3', action='store_true', + help='Subscribe for i3 events.' + ) + parser.add_argument( + '--height', default='', + help='Bar height.' + ) + parser.add_argument( + '--interval', '-i', + type=float, default=0.5, + help='Refresh interval.' + ) + parser.add_argument( + '--bar-command', '-c', + default='lemonbar', + help='Name of the lemonbar executable to use.' + ) + parser.add_argument( + 'args', nargs=REMAINDER, + help='Extra arguments for lemonbar.' + ) + args = parser.parse_args() + + powerline = LemonbarPowerline() + powerline.update_renderer() + bars = [] + active_screens = [match.groupdict() for match in re.finditer( + '^(?P[0-9A-Za-z-]+) connected (?P\d+)x(?P\d+)\+(?P\d+)\+(?P\d+)', + run_cmd(powerline.pl, ['xrandr', '-q']), + re.MULTILINE + )] + + for screen in active_screens: + command = [args.bar_command, '-g', '{0}x{1}+{2}'.format(screen['width'], args.height, screen['x'])] + args.args[1:] + process = subprocess.Popen(command, stdin=subprocess.PIPE) + bars.append((screen['name'], process, int(screen['width']) / 5)) + + lock = Lock() + modes = ['default'] + + def render(reschedule=False): + if reschedule: + Timer(args.interval, render, kwargs={'reschedule': True}).start() + + global lock + with lock: + for output, process, width in bars: + process.stdin.write(powerline.render(mode=modes[0], width=width, matcher_info=output).encode('utf-8') + b'\n') + process.stdin.flush() + + def update(evt): + modes[0] = evt.change + render() + + render(reschedule=True) + + if args.i3: + try: + import i3ipc + except ImportError: + import i3 + i3.Subscription(lambda evt, data, sub: render(), 'workspace') + else: + conn = i3ipc.Connection() + conn.on('workspace::focus', lambda conn, evt: render()) + conn.on('mode', lambda conn, evt: update(evt)) + conn.main() + + while True: + time.sleep(1e8) diff --git a/powerline/lemonbar.py b/powerline/lemonbar.py new file mode 100644 index 00000000..b49f86b5 --- /dev/null +++ b/powerline/lemonbar.py @@ -0,0 +1,21 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +from powerline import Powerline +from powerline.lib.dict import mergedicts + + +class LemonbarPowerline(Powerline): + def init(self): + super(LemonbarPowerline, self).init(ext='wm', renderer_module='lemonbar') + + get_encoding = staticmethod(lambda: 'utf-8') + + def get_local_themes(self, local_themes): + if not local_themes: + return {} + + return dict(( + (key, {'config': self.load_theme_config(val)}) + for key, val in local_themes.items() + )) diff --git a/powerline/lint/__init__.py b/powerline/lint/__init__.py index c464a52a..6f7fa4b2 100644 --- a/powerline/lint/__init__.py +++ b/powerline/lint/__init__.py @@ -126,6 +126,12 @@ main_spec = (Spec( select=ext_theme_spec(), ), ).optional(), + wm=ext_spec().update( + local_themes=Spec().unknown_spec( + Spec().re('^[0-9A-Za-z-]+$'), + ext_theme_spec() + ).optional() + ).optional(), ).unknown_spec( check_ext, ext_spec(), diff --git a/powerline/renderers/bar.py b/powerline/renderers/bar.py deleted file mode 100644 index 1a0684aa..00000000 --- a/powerline/renderers/bar.py +++ /dev/null @@ -1,45 +0,0 @@ -# vim:fileencoding=utf-8:noet -from __future__ import (unicode_literals, division, absolute_import, print_function) - -from powerline.renderer import Renderer -from powerline.colorscheme import ATTR_UNDERLINE - - -class BarRenderer(Renderer): - '''bar (bar ain't recursive) renderer - - - See documentation of `bar `_ and :ref:`the usage instructions ` - ''' - - character_translations = Renderer.character_translations.copy() - character_translations[ord('%')] = '%%' - - @staticmethod - def hlstyle(*args, **kwargs): - # We don’t need to explicitly reset attributes, so skip those calls - return '' - - def hl(self, contents, fg=None, bg=None, attrs=None): - text = '' - - if fg is not None: - if fg is not False and fg[1] is not False: - text += '%{{F#ff{0:06x}}}'.format(fg[1]) - if bg is not None: - if bg is not False and bg[1] is not False: - text += '%{{B#ff{0:06x}}}'.format(bg[1]) - - if attrs & ATTR_UNDERLINE: - text += '%{+u}' - - return text + contents + '%{F-B--u}' - - def render(self, *args, **kwargs): - return '%{{l}}{0}%{{r}}{1}'.format( - super(BarRenderer, self).render(side='left', *args, **kwargs), - super(BarRenderer, self).render(side='right', *args, **kwargs), - ) - - -renderer = BarRenderer diff --git a/powerline/renderers/lemonbar.py b/powerline/renderers/lemonbar.py new file mode 100644 index 00000000..f378f235 --- /dev/null +++ b/powerline/renderers/lemonbar.py @@ -0,0 +1,61 @@ +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +from powerline.renderer import Renderer +from powerline.theme import Theme +from powerline.colorscheme import ATTR_UNDERLINE + + +class LemonbarRenderer(Renderer): + '''lemonbar (formerly bar/bar ain't recursive) renderer + + + See documentation of `lemonbar `_ and :ref:`the usage instructions ` + ''' + + character_translations = Renderer.character_translations.copy() + character_translations[ord('%')] = '%%{}' + + @staticmethod + def hlstyle(*args, **kwargs): + # We don’t need to explicitly reset attributes, so skip those calls + return '' + + def hl(self, contents, fg=None, bg=None, attrs=None): + text = '' + + if fg is not None: + if fg is not False and fg[1] is not False: + text += '%{{F#ff{0:06x}}}'.format(fg[1]) + if bg is not None: + if bg is not False and bg[1] is not False: + text += '%{{B#ff{0:06x}}}'.format(bg[1]) + + if attrs & ATTR_UNDERLINE: + text += '%{+u}' + + return text + contents + '%{F-B--u}' + + def render(self, *args, **kwargs): + return '%{{l}}{0}%{{r}}{1}'.format( + super(LemonbarRenderer, self).render(side='left', segment_info={'output': kwargs.get('matcher_info')}, *args, **kwargs), + super(LemonbarRenderer, self).render(side='right', segment_info={'output': kwargs.get('matcher_info')}, *args, **kwargs), + ) + + def get_theme(self, matcher_info): + if not matcher_info or matcher_info not in self.local_themes: + return self.theme + match = self.local_themes[matcher_info] + + 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'] + + +renderer = LemonbarRenderer diff --git a/powerline/segments/i3wm.py b/powerline/segments/i3wm.py index ea0217d6..9d214cfe 100644 --- a/powerline/segments/i3wm.py +++ b/powerline/segments/i3wm.py @@ -29,8 +29,9 @@ def workspaces(pl, segment_info, only_show=None, output=None, strip=0): are shown. :param str output: - If specified, only workspaces on this output are shown. If unspecified, - may be set by the lemonbar renderer and bindings. + May be set to the name of an X output. If specified, only workspaces + on that output are shown. Overrides automatic output detection by + the lemonbar renderer and bindings. :param int strip: Specifies how many characters from the front of each workspace name @@ -47,7 +48,7 @@ def workspaces(pl, segment_info, only_show=None, output=None, strip=0): else: conn = i3ipc.Connection() - output = output or ('output' in segment_info and segment_info['output']) + output = output or segment_info.get('output') return [{ 'contents': w['name'][min(len(w['name']), strip):], diff --git a/tests/test_configuration.py b/tests/test_configuration.py index c0708c3d..3cd7d387 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -825,28 +825,28 @@ class TestVim(TestCase): sys.path.pop(0) -class TestBar(TestRender): - def test_bar(self): +class TestLemonbar(TestRender): + def test_lemonbar(self): import powerline as powerline_module with swap_attributes(config, powerline_module): - with get_powerline_raw(config, powerline_module.Powerline, replace_gcp=True, ext='wm', renderer_module='bar') as powerline: + with get_powerline_raw(config, powerline_module.Powerline, replace_gcp=True, ext='wm', renderer_module='lemonbar') as powerline: self.assertRenderEqual( powerline, '%{l}%{F#ffc00000}%{B#ff008000}%{+u} A%{F-B--u}%{F#ff008000}%{B#ffc00000}>>%{F-B--u}%{F#ff008000}%{B#ffc00000}B%{F-B--u}%{F#ffc00000}>>%{F-B--u}%{r}%{F#ffc00000}<<%{F-B--u}%{F#ff804000}%{B#ffc00000}%{+u}C%{F-B--u}%{F#ff0000c0}%{B#ffc00000}<<%{F-B--u}%{F#ff008000}%{B#ff0000c0}D %{F-B--u}' ) @with_new_config - def test_bar_escape(self, config): + def test_lemonbar_escape(self, config): import powerline as powerline_module config['themes/wm/default']['segments']['left'] = ( highlighted_string('%{asd}', 'hl1'), highlighted_string('10% %', 'hl2'), ) with swap_attributes(config, powerline_module): - with get_powerline_raw(config, powerline_module.Powerline, replace_gcp=True, ext='wm', renderer_module='bar') as powerline: + with get_powerline_raw(config, powerline_module.Powerline, replace_gcp=True, ext='wm', renderer_module='lemonbar') as powerline: self.assertRenderEqual( powerline, - '%{l}%{F#ffc00000}%{B#ff008000}%{+u} %%{asd}%{F-B--u}%{F#ff008000}%{B#ffc00000}>>%{F-B--u}%{F#ff008000}%{B#ffc00000}10%% %%%{F-B--u}%{F#ffc00000}>>%{F-B--u}%{r}%{F#ffc00000}<<%{F-B--u}%{F#ff804000}%{B#ffc00000}%{+u}C%{F-B--u}%{F#ff0000c0}%{B#ffc00000}<<%{F-B--u}%{F#ff008000}%{B#ff0000c0}D %{F-B--u}' + '%{l}%{F#ffc00000}%{B#ff008000}%{+u} %%{}{asd}%{F-B--u}%{F#ff008000}%{B#ffc00000}>>%{F-B--u}%{F#ff008000}%{B#ffc00000}10%%{} %%{}%{F-B--u}%{F#ffc00000}>>%{F-B--u}%{r}%{F#ffc00000}<<%{F-B--u}%{F#ff804000}%{B#ffc00000}%{+u}C%{F-B--u}%{F#ff0000c0}%{B#ffc00000}<<%{F-B--u}%{F#ff008000}%{B#ff0000c0}D %{F-B--u}' )