summaryrefslogtreecommitdiffstats
path: root/powerline/renderers
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:40:16 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:40:16 +0000
commit3f25952c13d5847d510c0cae22a8ba876638d570 (patch)
tree02f505f016ed5a1029277dcae520d5e2a75906fb /powerline/renderers
parentInitial commit. (diff)
downloadpowerline-upstream.tar.xz
powerline-upstream.zip
Adding upstream version 2.8.3.upstream/2.8.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'powerline/renderers')
-rw-r--r--powerline/renderers/__init__.py0
-rw-r--r--powerline/renderers/i3bar.py36
-rw-r--r--powerline/renderers/ipython/__init__.py34
-rw-r--r--powerline/renderers/ipython/pre_5.py56
-rw-r--r--powerline/renderers/ipython/since_5.py130
-rw-r--r--powerline/renderers/ipython/since_7.py91
-rw-r--r--powerline/renderers/lemonbar.py61
-rw-r--r--powerline/renderers/pango_markup.py39
-rw-r--r--powerline/renderers/pdb.py50
-rw-r--r--powerline/renderers/shell/__init__.py182
-rw-r--r--powerline/renderers/shell/bash.py96
-rw-r--r--powerline/renderers/shell/ksh.py19
-rw-r--r--powerline/renderers/shell/rcsh.py7
-rw-r--r--powerline/renderers/shell/readline.py14
-rw-r--r--powerline/renderers/shell/tcsh.py31
-rw-r--r--powerline/renderers/shell/zsh.py16
-rw-r--r--powerline/renderers/tmux.py81
-rw-r--r--powerline/renderers/vim.py188
18 files changed, 1131 insertions, 0 deletions
diff --git a/powerline/renderers/__init__.py b/powerline/renderers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/powerline/renderers/__init__.py
diff --git a/powerline/renderers/i3bar.py b/powerline/renderers/i3bar.py
new file mode 100644
index 0000000..3eab61f
--- /dev/null
+++ b/powerline/renderers/i3bar.py
@@ -0,0 +1,36 @@
+# vim:fileencoding=utf-8:noet
+from __future__ import (unicode_literals, division, absolute_import, print_function)
+
+import json
+
+from powerline.renderer import Renderer
+
+
+class I3barRenderer(Renderer):
+ '''I3bar Segment Renderer.
+
+ Currently works only for i3bgbar (i3 bar with custom patches).
+ '''
+
+ @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, **kwargs):
+ segment = {
+ 'full_text': contents,
+ 'separator': False,
+ 'separator_block_width': 0, # no separators
+ }
+
+ if fg is not None:
+ if fg is not False and fg[1] is not False:
+ segment['color'] = '#{0:06x}'.format(fg[1])
+ if bg is not None:
+ if bg is not False and bg[1] is not False:
+ segment['background'] = '#{0:06x}'.format(bg[1])
+ return json.dumps(segment) + ','
+
+
+renderer = I3barRenderer
diff --git a/powerline/renderers/ipython/__init__.py b/powerline/renderers/ipython/__init__.py
new file mode 100644
index 0000000..8f463b5
--- /dev/null
+++ b/powerline/renderers/ipython/__init__.py
@@ -0,0 +1,34 @@
+# vim:fileencoding=utf-8:noet
+from __future__ import (unicode_literals, division, absolute_import, print_function)
+
+from powerline.theme import Theme
+from powerline.renderers.shell import PromptRenderer
+
+
+class IPythonRenderer(PromptRenderer):
+ '''Powerline ipython segment renderer.'''
+ def get_segment_info(self, segment_info, mode):
+ r = self.segment_info.copy()
+ r['ipython'] = segment_info
+ return r
+
+ def get_theme(self, matcher_info):
+ if matcher_info == 'in':
+ return self.theme
+ else:
+ 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']
+
+ def shutdown(self):
+ self.theme.shutdown()
+ for match in self.local_themes.values():
+ if 'theme' in match:
+ match['theme'].shutdown()
diff --git a/powerline/renderers/ipython/pre_5.py b/powerline/renderers/ipython/pre_5.py
new file mode 100644
index 0000000..9fc8c21
--- /dev/null
+++ b/powerline/renderers/ipython/pre_5.py
@@ -0,0 +1,56 @@
+# vim:fileencoding=utf-8:noet
+from __future__ import (unicode_literals, division, absolute_import, print_function)
+
+from powerline.renderers.shell import ShellRenderer
+from powerline.renderers.shell.readline import ReadlineRenderer
+from powerline.renderers.ipython import IPythonRenderer
+
+
+class IPythonPre50Renderer(IPythonRenderer, ShellRenderer):
+ '''Powerline ipython segment renderer for pre-5.0 IPython versions.'''
+ def render(self, **kwargs):
+ # XXX super(ShellRenderer), *not* super(IPythonPre50Renderer)
+ return super(ShellRenderer, self).render(**kwargs)
+
+ def do_render(self, segment_info, **kwargs):
+ segment_info.update(client_id='ipython')
+ return super(IPythonPre50Renderer, self).do_render(
+ segment_info=segment_info,
+ **kwargs
+ )
+
+
+class IPythonPromptRenderer(IPythonPre50Renderer, ReadlineRenderer):
+ '''Powerline ipython prompt (in and in2) renderer'''
+ pass
+
+
+class IPythonNonPromptRenderer(IPythonPre50Renderer):
+ '''Powerline ipython non-prompt (out and rewrite) renderer'''
+ pass
+
+
+class RendererProxy(object):
+ '''Powerline IPython renderer proxy which chooses appropriate renderer
+
+ Instantiates two renderer objects: one will be used for prompts and the
+ other for non-prompts.
+ '''
+ def __init__(self, **kwargs):
+ old_widths = {}
+ self.non_prompt_renderer = IPythonNonPromptRenderer(old_widths=old_widths, **kwargs)
+ self.prompt_renderer = IPythonPromptRenderer(old_widths=old_widths, **kwargs)
+
+ def render_above_lines(self, *args, **kwargs):
+ return self.non_prompt_renderer.render_above_lines(*args, **kwargs)
+
+ def render(self, is_prompt, *args, **kwargs):
+ return (self.prompt_renderer if is_prompt else self.non_prompt_renderer).render(
+ *args, **kwargs)
+
+ def shutdown(self, *args, **kwargs):
+ self.prompt_renderer.shutdown(*args, **kwargs)
+ self.non_prompt_renderer.shutdown(*args, **kwargs)
+
+
+renderer = RendererProxy
diff --git a/powerline/renderers/ipython/since_5.py b/powerline/renderers/ipython/since_5.py
new file mode 100644
index 0000000..88c7625
--- /dev/null
+++ b/powerline/renderers/ipython/since_5.py
@@ -0,0 +1,130 @@
+# vim:fileencoding=utf-8:noet
+from __future__ import (unicode_literals, division, absolute_import, print_function)
+
+import operator
+
+from collections import defaultdict
+
+try:
+ from __builtin__ import reduce
+except ImportError:
+ from functools import reduce
+
+from pygments.token import Token
+from prompt_toolkit.styles import DynamicStyle, Attrs
+
+from powerline.renderers.ipython import IPythonRenderer
+from powerline.ipython import IPythonInfo
+from powerline.colorscheme import ATTR_BOLD, ATTR_ITALIC, ATTR_UNDERLINE
+
+
+PowerlinePromptToken = Token.Generic.Prompt.Powerline
+
+
+# Note: since 2.7 there is dict.__missing__ with same purpose. But in 2.6 one
+# must use defaultdict to get __missing__ working.
+class PowerlineStyleDict(defaultdict):
+ '''Dictionary used for getting pygments style for Powerline groups
+ '''
+ def __new__(cls, missing_func):
+ return defaultdict.__new__(cls)
+
+ def __init__(self, missing_func):
+ super(PowerlineStyleDict, self).__init__()
+ self.missing_func = missing_func
+
+ def __missing__(self, key):
+ return self.missing_func(key)
+
+
+class PowerlinePromptStyle(DynamicStyle):
+ def get_attrs_for_token(self, token):
+ if (
+ token not in PowerlinePromptToken
+ or len(token) != len(PowerlinePromptToken) + 1
+ or not token[-1].startswith('Pl')
+ or token[-1] == 'Pl'
+ ):
+ return super(PowerlinePromptStyle, self).get_attrs_for_token(token)
+ ret = {
+ 'color': None,
+ 'bgcolor': None,
+ 'bold': None,
+ 'underline': None,
+ 'italic': None,
+ 'reverse': False,
+ 'blink': False,
+ }
+ for prop in token[-1][3:].split('_'):
+ if prop[0] == 'a':
+ ret[prop[1:]] = True
+ elif prop[0] == 'f':
+ ret['color'] = prop[1:]
+ elif prop[0] == 'b':
+ ret['bgcolor'] = prop[1:]
+ return Attrs(**ret)
+
+ def get_token_to_attributes_dict(self):
+ dct = super(PowerlinePromptStyle, self).get_token_to_attributes_dict()
+
+ def fallback(key):
+ try:
+ return dct[key]
+ except KeyError:
+ return self.get_attrs_for_token(key)
+
+ return PowerlineStyleDict(fallback)
+
+ def invalidation_hash(self):
+ return super(PowerlinePromptStyle, self).invalidation_hash() + 1
+
+
+class IPythonPygmentsRenderer(IPythonRenderer):
+ reduce_initial = []
+
+ def get_segment_info(self, segment_info, mode):
+ return super(IPythonPygmentsRenderer, self).get_segment_info(
+ IPythonInfo(segment_info), mode)
+
+ @staticmethod
+ def hl_join(segments):
+ return reduce(operator.iadd, segments, [])
+
+ def hl(self, contents, fg=None, bg=None, attrs=None, **kwargs):
+ '''Output highlighted chunk.
+
+ This implementation outputs a list containing a single pair
+ (:py:class:`pygments.token.Token`,
+ :py:class:`powerline.lib.unicode.unicode`).
+ '''
+ guifg = None
+ guibg = None
+ attrs = []
+ if fg is not None and fg is not False:
+ guifg = fg[1]
+ if bg is not None and bg is not False:
+ guibg = bg[1]
+ if attrs:
+ attrs = []
+ if attrs & ATTR_BOLD:
+ attrs.append('bold')
+ if attrs & ATTR_ITALIC:
+ attrs.append('italic')
+ if attrs & ATTR_UNDERLINE:
+ attrs.append('underline')
+ name = (
+ 'Pl'
+ + ''.join(('_a' + attr for attr in attrs))
+ + (('_f%6x' % guifg) if guifg is not None else '')
+ + (('_b%6x' % guibg) if guibg is not None else '')
+ )
+ return [(getattr(Token.Generic.Prompt.Powerline, name), contents)]
+
+ def hlstyle(self, **kwargs):
+ return []
+
+ def get_client_id(self, segment_info):
+ return id(self)
+
+
+renderer = IPythonPygmentsRenderer
diff --git a/powerline/renderers/ipython/since_7.py b/powerline/renderers/ipython/since_7.py
new file mode 100644
index 0000000..ca2ea0e
--- /dev/null
+++ b/powerline/renderers/ipython/since_7.py
@@ -0,0 +1,91 @@
+# vim:fileencoding=utf-8:noet
+import operator
+
+try:
+ from __builtin__ import reduce
+except ImportError:
+ from functools import reduce
+
+from pygments.token import Token
+from prompt_toolkit.styles import DynamicStyle
+
+from powerline.renderers.ipython import IPythonRenderer
+from powerline.ipython import IPythonInfo
+from powerline.colorscheme import ATTR_BOLD, ATTR_ITALIC, ATTR_UNDERLINE
+
+used_styles = []
+seen = set()
+
+class PowerlinePromptStyle(DynamicStyle):
+ @property
+ def style_rules(self):
+ return (self.get_style() or self._dummy).style_rules + used_styles
+
+ def invalidation_hash(self):
+ return (h + 1 for h in tuple(super(PowerlinePromptStyle, self).invalidation_hash()))
+
+
+class IPythonPygmentsRenderer(IPythonRenderer):
+ reduce_initial = []
+
+ def __init__(self, **kwargs):
+ super(IPythonPygmentsRenderer, self).__init__(**kwargs)
+ self.character_translations[ord(' ')] = ' '
+
+ def get_segment_info(self, segment_info, mode):
+ return super(IPythonPygmentsRenderer, self).get_segment_info(
+ IPythonInfo(segment_info), mode)
+
+ @staticmethod
+ def hl_join(segments):
+ return reduce(operator.iadd, segments, [])
+
+ def hl(self, escaped_contents, fg=None, bg=None, attrs=None, *args, **kwargs):
+ '''Output highlighted chunk.
+
+ This implementation outputs a list containing a single pair
+ (:py:class:`string`,
+ :py:class:`powerline.lib.unicode.unicode`).
+ '''
+ guifg = None
+ guibg = None
+ att = []
+ if fg is not None and fg is not False:
+ guifg = fg[1]
+ if bg is not None and bg is not False:
+ guibg = bg[1]
+ if attrs:
+ att = []
+ if attrs & ATTR_BOLD:
+ att.append('bold')
+ if attrs & ATTR_ITALIC:
+ att.append('italic')
+ if attrs & ATTR_UNDERLINE:
+ att.append('underline')
+
+ fg = (('%06x' % guifg) if guifg is not None else '')
+ bg = (('%06x' % guibg) if guibg is not None else '')
+ name = (
+ 'pl'
+ + ''.join(('_a' + attr for attr in att))
+ + '_f' + fg + '_b' + bg
+ )
+
+ global seen
+ if not (name in seen):
+ global used_styles
+ used_styles += [('pygments.' + name,
+ ''.join((' ' + attr for attr in att))
+ + (' fg:#' + fg if fg != '' else ' fg:')
+ + (' bg:#' + bg if bg != '' else ' bg:'))]
+ seen.add(name)
+ return [((name,), escaped_contents)]
+
+ def hlstyle(self, *args, **kwargs):
+ return []
+
+ def get_client_id(self, segment_info):
+ return id(self)
+
+
+renderer = IPythonPygmentsRenderer
diff --git a/powerline/renderers/lemonbar.py b/powerline/renderers/lemonbar.py
new file mode 100644
index 0000000..8156807
--- /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 <https://github.com/LemonBoy/bar>`_ and :ref:`the usage instructions <lemonbar-usage>`
+ '''
+
+ 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, **kwargs):
+ 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/renderers/pango_markup.py b/powerline/renderers/pango_markup.py
new file mode 100644
index 0000000..3c1a675
--- /dev/null
+++ b/powerline/renderers/pango_markup.py
@@ -0,0 +1,39 @@
+# vim:fileencoding=utf-8:noet
+from __future__ import (unicode_literals, division, absolute_import, print_function)
+
+from xml.sax.saxutils import escape as _escape
+
+from powerline.renderer import Renderer
+from powerline.colorscheme import ATTR_BOLD, ATTR_ITALIC, ATTR_UNDERLINE
+
+
+class PangoMarkupRenderer(Renderer):
+ '''Powerline Pango markup segment renderer.'''
+
+ @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, **kwargs):
+ '''Highlight a segment.'''
+ awesome_attr = []
+ if fg is not None:
+ if fg is not False and fg[1] is not False:
+ awesome_attr += ['foreground="#{0:06x}"'.format(fg[1])]
+ if bg is not None:
+ if bg is not False and bg[1] is not False:
+ awesome_attr += ['background="#{0:06x}"'.format(bg[1])]
+ if attrs is not None and attrs is not False:
+ if attrs & ATTR_BOLD:
+ awesome_attr += ['font_weight="bold"']
+ if attrs & ATTR_ITALIC:
+ awesome_attr += ['font_style="italic"']
+ if attrs & ATTR_UNDERLINE:
+ awesome_attr += ['underline="single"']
+ return '<span ' + ' '.join(awesome_attr) + '>' + contents + '</span>'
+
+ escape = staticmethod(_escape)
+
+
+renderer = PangoMarkupRenderer
diff --git a/powerline/renderers/pdb.py b/powerline/renderers/pdb.py
new file mode 100644
index 0000000..040f0e1
--- /dev/null
+++ b/powerline/renderers/pdb.py
@@ -0,0 +1,50 @@
+# vim:fileencoding=utf-8:noet
+from __future__ import (unicode_literals, division, absolute_import, print_function)
+
+import sys
+import platform
+
+from powerline.renderers.shell.readline import ReadlineRenderer
+from powerline.renderer import Renderer
+
+
+class PDBRenderer(ReadlineRenderer):
+ '''PDB-specific powerline renderer
+ '''
+ pdb = None
+ initial_stack_length = None
+
+ def get_segment_info(self, segment_info, mode):
+ r = self.segment_info.copy()
+ r['pdb'] = self.pdb
+ r['initial_stack_length'] = self.initial_stack_length
+ r['curframe'] = self.pdb.curframe
+ return r
+
+ def set_pdb(self, pdb):
+ '''Record currently used :py:class:`pdb.Pdb` instance
+
+ Must be called before first calling :py:meth:`render` method.
+
+ :param pdb.Pdb pdb:
+ Used :py:class:`pdb.Pdb` instance. This instance will later be used
+ by :py:meth:`get_segment_info` for patching :ref:`segment_info
+ <dev-segments-info>` dictionary.
+ '''
+ self.pdb = pdb
+
+ def render(self, **kwargs):
+ if self.initial_stack_length is None:
+ self.initial_stack_length = len(self.pdb.stack) - 1
+ return Renderer.render(self, **kwargs)
+
+ if sys.version_info < (3,) and platform.python_implementation() == 'PyPy':
+ def do_render(self, **kwargs):
+ # Make sure that only ASCII characters survive
+ ret = super(PDBRenderer, self).do_render(**kwargs)
+ ret = ret.encode('ascii', 'replace')
+ ret = ret.decode('ascii')
+ return ret
+
+
+renderer = PDBRenderer
diff --git a/powerline/renderers/shell/__init__.py b/powerline/renderers/shell/__init__.py
new file mode 100644
index 0000000..d7dbf96
--- /dev/null
+++ b/powerline/renderers/shell/__init__.py
@@ -0,0 +1,182 @@
+# 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_BOLD, ATTR_ITALIC, ATTR_UNDERLINE
+
+
+def int_to_rgb(num):
+ r = (num >> 16) & 0xff
+ g = (num >> 8) & 0xff
+ b = num & 0xff
+ return r, g, b
+
+
+class PromptRenderer(Renderer):
+ '''Powerline generic prompt segment renderer'''
+
+ def __init__(self, old_widths=None, **kwargs):
+ super(PromptRenderer, self).__init__(**kwargs)
+ self.old_widths = old_widths if old_widths is not None else {}
+
+ def get_client_id(self, segment_info):
+ '''Get client ID given segment info
+
+ This is used by daemon to correctly cache widths for different clients
+ using a single renderer instance.
+
+ :param dict segment_info:
+ :ref:`Segment info dictionary <dev-segments-info>`. Out of it only
+ ``client_id`` key is used. It is OK for this dictionary to not
+ contain this key.
+
+ :return: Any hashable value or ``None``.
+ '''
+ return segment_info.get('client_id') if isinstance(segment_info, dict) else None
+
+ def do_render(self, output_width, segment_info, side, theme, width=None, **kwargs):
+ client_id = self.get_client_id(segment_info)
+ if client_id is not None:
+ local_key = (client_id, side, None if theme is self.theme else id(theme))
+ key = (client_id, side, None)
+ did_width = False
+ if local_key[-1] != key[-1] and side == 'left':
+ try:
+ width = self.old_widths[key]
+ except KeyError:
+ pass
+ else:
+ did_width = True
+ if not did_width and width is not None:
+ if theme.cursor_space_multiplier is not None:
+ width = int(width * theme.cursor_space_multiplier)
+ elif theme.cursor_columns:
+ width -= theme.cursor_columns
+
+ if side == 'right':
+ try:
+ width -= self.old_widths[(client_id, 'left', local_key[-1])]
+ except KeyError:
+ pass
+ res = super(PromptRenderer, self).do_render(
+ output_width=True,
+ width=width,
+ theme=theme,
+ segment_info=segment_info,
+ side=side,
+ **kwargs
+ )
+ if client_id is not None:
+ self.old_widths[local_key] = res[-1]
+ ret = res if output_width else res[:-1]
+ if len(ret) == 1:
+ return ret[0]
+ else:
+ return ret
+
+
+class ShellRenderer(PromptRenderer):
+ '''Powerline shell segment renderer.'''
+ escape_hl_start = ''
+ escape_hl_end = ''
+ term_truecolor = False
+ term_escape_style = 'auto'
+ tmux_escape = False
+ screen_escape = False
+
+ character_translations = Renderer.character_translations.copy()
+
+ def render(self, segment_info, **kwargs):
+ local_theme = segment_info.get('local_theme')
+ return super(ShellRenderer, self).render(
+ matcher_info=local_theme,
+ segment_info=segment_info,
+ **kwargs
+ )
+
+ def do_render(self, segment_info, **kwargs):
+ if self.term_escape_style == 'auto':
+ if segment_info['environ'].get('TERM') == 'fbterm':
+ self.used_term_escape_style = 'fbterm'
+ else:
+ self.used_term_escape_style = 'xterm'
+ else:
+ self.used_term_escape_style = self.term_escape_style
+ return super(ShellRenderer, self).do_render(segment_info=segment_info, **kwargs)
+
+ def hlstyle(self, fg=None, bg=None, attrs=None, escape=True, **kwargs):
+ '''Highlight a segment.
+
+ If an argument is None, the argument is ignored. If an argument is
+ False, the argument is reset to the terminal defaults. If an argument
+ is a valid color or attribute, it’s added to the ANSI escape code.
+ '''
+ ansi = [0]
+ is_fbterm = self.used_term_escape_style == 'fbterm'
+ term_truecolor = not is_fbterm and self.term_truecolor
+ if fg is not None:
+ if fg is False or fg[0] is False:
+ ansi += [39]
+ else:
+ if term_truecolor:
+ ansi += [38, 2] + list(int_to_rgb(fg[1]))
+ else:
+ ansi += [38, 5, fg[0]]
+ if bg is not None:
+ if bg is False or bg[0] is False:
+ ansi += [49]
+ else:
+ if term_truecolor:
+ ansi += [48, 2] + list(int_to_rgb(bg[1]))
+ else:
+ ansi += [48, 5, bg[0]]
+ if attrs is not None:
+ if attrs is False:
+ ansi += [22]
+ else:
+ if attrs & ATTR_BOLD:
+ ansi += [1]
+ elif attrs & ATTR_ITALIC:
+ # Note: is likely not to work or even be inverse in place of
+ # italic. Omit using this in colorschemes.
+ ansi += [3]
+ elif attrs & ATTR_UNDERLINE:
+ ansi += [4]
+ if is_fbterm:
+ r = []
+ while ansi:
+ cur_ansi = ansi.pop(0)
+ if cur_ansi == 38:
+ ansi.pop(0)
+ r.append('\033[1;{0}}}'.format(ansi.pop(0)))
+ elif cur_ansi == 48:
+ ansi.pop(0)
+ r.append('\033[2;{0}}}'.format(ansi.pop(0)))
+ else:
+ r.append('\033[{0}m'.format(cur_ansi))
+ r = ''.join(r)
+ else:
+ r = '\033[{0}m'.format(';'.join(str(attr) for attr in ansi))
+ if self.tmux_escape:
+ r = '\033Ptmux;' + r.replace('\033', '\033\033') + '\033\\'
+ elif self.screen_escape:
+ r = '\033P' + r.replace('\033', '\033\033') + '\033\\'
+ return self.escape_hl_start + r + self.escape_hl_end if escape else r
+
+ def get_theme(self, matcher_info):
+ if not matcher_info:
+ 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 = ShellRenderer
diff --git a/powerline/renderers/shell/bash.py b/powerline/renderers/shell/bash.py
new file mode 100644
index 0000000..5ccf206
--- /dev/null
+++ b/powerline/renderers/shell/bash.py
@@ -0,0 +1,96 @@
+# vim:fileencoding=utf-8:noet
+from __future__ import (unicode_literals, division, absolute_import, print_function)
+
+from powerline.renderers.shell import ShellRenderer
+
+
+class BashPromptRenderer(ShellRenderer):
+ '''Powerline bash prompt segment renderer.'''
+ escape_hl_start = '\\['
+ escape_hl_end = '\\]'
+
+ character_translations = ShellRenderer.character_translations.copy()
+ character_translations[ord('$')] = '\\$'
+ character_translations[ord('`')] = '\\`'
+ character_translations[ord('\\')] = '\\\\'
+
+ def do_render(self, side, line, width, output_width, output_raw, hl_args, **kwargs):
+
+ # we are rendering the normal left prompt
+ if side == 'left' and line == 0 and width is not None:
+
+ # we need left prompt's width to render the raw spacer
+ output_width = output_width or output_raw
+
+ left = super(BashPromptRenderer, self).do_render(
+ side=side,
+ line=line,
+ output_width=output_width,
+ width=width,
+ output_raw=output_raw,
+ hl_args=hl_args,
+ **kwargs
+ )
+ left_rendered = left[0] if output_width else left
+
+ # we don't escape color sequences in the right prompt so we can do escaping as a whole
+ if hl_args:
+ hl_args = hl_args.copy()
+ hl_args.update({'escape': False})
+ else:
+ hl_args = {'escape': False}
+
+ right = super(BashPromptRenderer, self).do_render(
+ side='right',
+ line=line,
+ output_width=True,
+ width=width,
+ output_raw=output_raw,
+ hl_args=hl_args,
+ **kwargs
+ )
+
+ ret = []
+ if right[-1] > 0:
+ # if the right prompt is not empty we embed it in the left prompt
+ # it must be escaped as a whole so readline doesn't see it
+ ret.append(''.join((
+ left_rendered,
+ self.escape_hl_start,
+ '\033[s', # save the cursor position
+ '\033[{0}C'.format(width), # move to the right edge of the terminal
+ '\033[{0}D'.format(right[-1] - 1), # move back to the right prompt position
+ right[0],
+ '\033[u', # restore the cursor position
+ self.escape_hl_end
+ )))
+ if output_raw:
+ ret.append(''.join((
+ left[1],
+ ' ' * (width - left[-1] - right[-1]),
+ right[1]
+ )))
+ else:
+ ret.append(left_rendered)
+ if output_raw:
+ ret.append(left[1])
+ if output_width:
+ ret.append(left[-1])
+ if len(ret) == 1:
+ return ret[0]
+ else:
+ return ret
+
+ else:
+ return super(BashPromptRenderer, self).do_render(
+ side=side,
+ line=line,
+ width=width,
+ output_width=output_width,
+ output_raw=output_raw,
+ hl_args=hl_args,
+ **kwargs
+ )
+
+
+renderer = BashPromptRenderer
diff --git a/powerline/renderers/shell/ksh.py b/powerline/renderers/shell/ksh.py
new file mode 100644
index 0000000..0828e57
--- /dev/null
+++ b/powerline/renderers/shell/ksh.py
@@ -0,0 +1,19 @@
+# vim:fileencoding=utf-8:noet
+from __future__ import (unicode_literals, division, absolute_import, print_function)
+
+from powerline.renderers.shell import ShellRenderer
+
+
+ESCAPE_CHAR = '\001'
+
+
+class KshPromptRenderer(ShellRenderer):
+ '''Powerline bash prompt segment renderer.'''
+ escape_hl_start = '\001'
+ escape_hl_end = '\001'
+
+ def render(self, *args, **kwargs):
+ return '\001\r' + super(KshPromptRenderer, self).render(*args, **kwargs)
+
+
+renderer = KshPromptRenderer
diff --git a/powerline/renderers/shell/rcsh.py b/powerline/renderers/shell/rcsh.py
new file mode 100644
index 0000000..75ccb22
--- /dev/null
+++ b/powerline/renderers/shell/rcsh.py
@@ -0,0 +1,7 @@
+# vim:fileencoding=utf-8:noet
+from __future__ import (unicode_literals, division, absolute_import, print_function)
+
+from powerline.renderers.shell.readline import ReadlineRenderer
+
+
+renderer = ReadlineRenderer
diff --git a/powerline/renderers/shell/readline.py b/powerline/renderers/shell/readline.py
new file mode 100644
index 0000000..a72dff0
--- /dev/null
+++ b/powerline/renderers/shell/readline.py
@@ -0,0 +1,14 @@
+# vim:fileencoding=utf-8:noet
+from __future__ import (unicode_literals, division, absolute_import, print_function)
+
+from powerline.renderers.shell import ShellRenderer
+
+
+class ReadlineRenderer(ShellRenderer):
+ '''Renderer useful for some applications that use readline
+ '''
+ escape_hl_start = '\x01'
+ escape_hl_end = '\x02'
+
+
+renderer = ReadlineRenderer
diff --git a/powerline/renderers/shell/tcsh.py b/powerline/renderers/shell/tcsh.py
new file mode 100644
index 0000000..bf0697d
--- /dev/null
+++ b/powerline/renderers/shell/tcsh.py
@@ -0,0 +1,31 @@
+# vim:fileencoding=utf-8:noet
+from __future__ import (unicode_literals, division, absolute_import, print_function)
+
+from powerline.renderers.shell.zsh import ZshPromptRenderer
+
+
+class TcshPromptRenderer(ZshPromptRenderer):
+ '''Powerline tcsh prompt segment renderer.'''
+ character_translations = ZshPromptRenderer.character_translations.copy()
+ character_translations[ord('%')] = '%%'
+ character_translations[ord('\\')] = '\\\\'
+ character_translations[ord('^')] = '\\^'
+ character_translations[ord('!')] = '\\!'
+
+ def do_render(self, **kwargs):
+ ret = super(TcshPromptRenderer, self).do_render(**kwargs)
+ nbsp = self.character_translations.get(ord(' '), ' ')
+ end = self.hlstyle()
+ assert not ret or ret.endswith(end)
+ if ret.endswith(nbsp + end):
+ # Exchange nbsp and highlight end because tcsh removes trailing
+ # %{%} part of the prompt for whatever reason
+ ret = ret[:-(len(nbsp) + len(end))] + end + nbsp
+ else:
+ # We *must* end prompt with non-%{%} sequence for the reasons
+ # explained above. So add nbsp if it is not already there.
+ ret += nbsp
+ return ret
+
+
+renderer = TcshPromptRenderer
diff --git a/powerline/renderers/shell/zsh.py b/powerline/renderers/shell/zsh.py
new file mode 100644
index 0000000..a231512
--- /dev/null
+++ b/powerline/renderers/shell/zsh.py
@@ -0,0 +1,16 @@
+# vim:fileencoding=utf-8:noet
+from __future__ import (unicode_literals, division, absolute_import, print_function)
+
+from powerline.renderers.shell import ShellRenderer
+
+
+class ZshPromptRenderer(ShellRenderer):
+ '''Powerline zsh prompt segment renderer.'''
+ escape_hl_start = '%{'
+ escape_hl_end = '%}'
+
+ character_translations = ShellRenderer.character_translations.copy()
+ character_translations[ord('%')] = '%%'
+
+
+renderer = ZshPromptRenderer
diff --git a/powerline/renderers/tmux.py b/powerline/renderers/tmux.py
new file mode 100644
index 0000000..fc3282a
--- /dev/null
+++ b/powerline/renderers/tmux.py
@@ -0,0 +1,81 @@
+# 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_BOLD, ATTR_ITALIC, ATTR_UNDERLINE
+
+
+def attrs_to_tmux_attrs(attrs):
+ if attrs is False:
+ return ['nobold', 'noitalics', 'nounderscore']
+ else:
+ ret = []
+ if attrs & ATTR_BOLD:
+ ret += ['bold']
+ else:
+ ret += ['nobold']
+ if attrs & ATTR_ITALIC:
+ ret += ['italics']
+ else:
+ ret += ['noitalics']
+ if attrs & ATTR_UNDERLINE:
+ ret += ['underscore']
+ else:
+ ret += ['nounderscore']
+ return ret
+
+
+class TmuxRenderer(Renderer):
+ '''Powerline tmux segment renderer.'''
+
+ character_translations = Renderer.character_translations.copy()
+ character_translations[ord('#')] = '##[]'
+
+ def render(self, width=None, segment_info={}, **kwargs):
+ if width and segment_info:
+ width -= segment_info.get('width_adjust', 0)
+ if width < 10:
+ width = 10
+ return super(TmuxRenderer, self).render(width=width, segment_info=segment_info, **kwargs)
+
+ def hlstyle(self, fg=None, bg=None, attrs=None, **kwargs):
+ '''Highlight a segment.'''
+ # We don’t need to explicitly reset attributes, so skip those calls
+ if not attrs and not bg and not fg:
+ return ''
+ tmux_attrs = []
+ if fg is not None:
+ if fg is False or fg[0] is False:
+ tmux_attrs += ['fg=default']
+ else:
+ if self.term_truecolor and fg[1]:
+ tmux_attrs += ['fg=#{0:06x}'.format(int(fg[1]))]
+ else:
+ tmux_attrs += ['fg=colour' + str(fg[0])]
+ if bg is not None:
+ if bg is False or bg[0] is False:
+ tmux_attrs += ['bg=default']
+ else:
+ if self.term_truecolor and bg[1]:
+ tmux_attrs += ['bg=#{0:06x}'.format(int(bg[1]))]
+ else:
+ tmux_attrs += ['bg=colour' + str(bg[0])]
+ if attrs is not None:
+ tmux_attrs += attrs_to_tmux_attrs(attrs)
+ return '#[' + ','.join(tmux_attrs) + ']'
+
+ def get_segment_info(self, segment_info, mode):
+ r = self.segment_info.copy()
+ if segment_info:
+ r.update(segment_info)
+ if 'pane_current_path' in r:
+ r['getcwd'] = lambda: r['pane_current_path']
+ elif 'pane_id' in r:
+ varname = 'TMUX_PWD_' + str(r['pane_id'])
+ if varname in r['environ']:
+ r['getcwd'] = lambda: r['environ'][varname]
+ r['mode'] = mode
+ return r
+
+
+renderer = TmuxRenderer
diff --git a/powerline/renderers/vim.py b/powerline/renderers/vim.py
new file mode 100644
index 0000000..a92d51c
--- /dev/null
+++ b/powerline/renderers/vim.py
@@ -0,0 +1,188 @@
+# vim:fileencoding=utf-8:noet
+from __future__ import (unicode_literals, division, absolute_import, print_function)
+
+import sys
+
+import vim
+
+from powerline.bindings.vim import vim_get_func, vim_getoption, environ, current_tabpage, get_vim_encoding
+from powerline.renderer import Renderer
+from powerline.colorscheme import ATTR_BOLD, ATTR_ITALIC, ATTR_UNDERLINE
+from powerline.theme import Theme
+from powerline.lib.unicode import unichr, register_strwidth_error
+
+
+vim_mode = vim_get_func('mode', rettype='unicode')
+if int(vim.eval('v:version')) >= 702:
+ _vim_mode = vim_mode
+ vim_mode = lambda: _vim_mode(1)
+
+mode_translations = {
+ unichr(ord('V') - 0x40): '^V',
+ unichr(ord('S') - 0x40): '^S',
+}
+
+
+class VimRenderer(Renderer):
+ '''Powerline vim segment renderer.'''
+
+ character_translations = Renderer.character_translations.copy()
+ character_translations[ord('%')] = '%%'
+
+ segment_info = Renderer.segment_info.copy()
+ segment_info.update(environ=environ)
+
+ def __init__(self, *args, **kwargs):
+ if not hasattr(vim, 'strwidth'):
+ # Hope nobody want to change this at runtime
+ if vim.eval('&ambiwidth') == 'double':
+ kwargs = dict(**kwargs)
+ kwargs['ambigious'] = 2
+ super(VimRenderer, self).__init__(*args, **kwargs)
+ self.hl_groups = {}
+ self.prev_highlight = None
+ self.strwidth_error_name = register_strwidth_error(self.strwidth)
+ self.encoding = get_vim_encoding()
+
+ def shutdown(self):
+ self.theme.shutdown()
+ for match in self.local_themes.values():
+ if 'theme' in match:
+ match['theme'].shutdown()
+
+ def add_local_theme(self, matcher, theme):
+ if matcher in self.local_themes:
+ raise KeyError('There is already a local theme with given matcher')
+ self.local_themes[matcher] = theme
+
+ def get_matched_theme(self, match):
+ 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']
+
+ def get_theme(self, matcher_info):
+ if matcher_info is None:
+ return self.get_matched_theme(self.local_themes[None])
+ for matcher in self.local_themes.keys():
+ if matcher and matcher(matcher_info):
+ return self.get_matched_theme(self.local_themes[matcher])
+ else:
+ return self.theme
+
+ if hasattr(vim, 'strwidth'):
+ if sys.version_info < (3,):
+ def strwidth(self, string):
+ # Does not work with tabs, but neither is strwidth from default
+ # renderer
+ return vim.strwidth(string.encode(self.encoding, 'replace'))
+ else:
+ @staticmethod
+ def strwidth(string):
+ return vim.strwidth(string)
+
+ def get_segment_info(self, segment_info, mode):
+ return segment_info or self.segment_info
+
+ def render(self, window=None, window_id=None, winnr=None, is_tabline=False):
+ '''Render all segments.'''
+ segment_info = self.segment_info.copy()
+
+ if window is vim.current.window:
+ mode = vim_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(),
+ encoding=self.encoding,
+ )
+ segment_info['tabnr'] = segment_info['tabpage'].number
+ segment_info['bufnr'] = segment_info['buffer'].number
+ if is_tabline:
+ winwidth = int(vim_getoption('columns'))
+ else:
+ winwidth = segment_info['window'].width
+
+ statusline = super(VimRenderer, self).render(
+ mode=mode,
+ width=winwidth,
+ segment_info=segment_info,
+ matcher_info=(None if is_tabline else segment_info),
+ )
+ statusline = statusline.encode(self.encoding, self.strwidth_error_name)
+ return statusline
+
+ def reset_highlight(self):
+ self.hl_groups.clear()
+
+ def hlstyle(self, fg=None, bg=None, attrs=None, **kwargs):
+ '''Highlight a segment.
+
+ If an argument is None, the argument is ignored. If an argument is
+ False, the argument is reset to the terminal defaults. If an argument
+ is a valid color or attribute, it’s added to the vim highlight group.
+ '''
+ # In order not to hit E541 two consequent identical highlighting
+ # specifiers may be squashed into one.
+ attrs = attrs or 0 # Normalize `attrs`
+ if (fg, bg, attrs) == self.prev_highlight:
+ return ''
+ self.prev_highlight = (fg, bg, attrs)
+
+ # We don’t need to explicitly reset attributes in vim, so skip those
+ # calls
+ if not attrs and not bg and not fg:
+ return ''
+
+ if not (fg, bg, attrs) in self.hl_groups:
+ hl_group = {
+ 'ctermfg': 'NONE',
+ 'guifg': None,
+ 'ctermbg': 'NONE',
+ 'guibg': None,
+ 'attrs': ['NONE'],
+ 'name': '',
+ }
+ if fg is not None and fg is not False:
+ hl_group['ctermfg'] = fg[0]
+ hl_group['guifg'] = fg[1]
+ if bg is not None and bg is not False:
+ hl_group['ctermbg'] = bg[0]
+ hl_group['guibg'] = bg[1]
+ if attrs:
+ hl_group['attrs'] = []
+ if attrs & ATTR_BOLD:
+ hl_group['attrs'].append('bold')
+ if attrs & ATTR_ITALIC:
+ hl_group['attrs'].append('italic')
+ if attrs & ATTR_UNDERLINE:
+ hl_group['attrs'].append('underline')
+ hl_group['name'] = (
+ 'Pl_'
+ + str(hl_group['ctermfg']) + '_'
+ + str(hl_group['guifg']) + '_'
+ + str(hl_group['ctermbg']) + '_'
+ + str(hl_group['guibg']) + '_'
+ + ''.join(hl_group['attrs'])
+ )
+ self.hl_groups[(fg, bg, attrs)] = hl_group
+ vim.command('hi {group} ctermfg={ctermfg} guifg={guifg} guibg={guibg} ctermbg={ctermbg} cterm={attrs} gui={attrs}'.format(
+ group=hl_group['name'],
+ ctermfg=hl_group['ctermfg'],
+ guifg='#{0:06x}'.format(hl_group['guifg']) if hl_group['guifg'] is not None else 'NONE',
+ ctermbg=hl_group['ctermbg'],
+ guibg='#{0:06x}'.format(hl_group['guibg']) if hl_group['guibg'] is not None else 'NONE',
+ attrs=','.join(hl_group['attrs']),
+ ))
+ return '%#' + self.hl_groups[(fg, bg, attrs)]['name'] + '#'
+
+
+renderer = VimRenderer