183 lines
5.1 KiB
Python
183 lines
5.1 KiB
Python
|
# 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):
|
|||
|
'''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
|
|||
|
|
|||
|
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
|