Merge pull request #1206 from ZyX-I/fbterm-support

Add support for fbterm
This commit is contained in:
Nikolai Aleksandrovich Pavlov 2014-12-06 17:08:41 +03:00
commit d2a1106c04
7 changed files with 164 additions and 5 deletions

View File

@ -26,6 +26,29 @@ Common configuration is a subdictionary that is a value of ``common`` key in
to the terminal emulator. See the :ref:`term-feature-support-matrix` for
information on whether your terminal emulator supports 24-bit colors.
This variable is forced to be ``false`` if :ref:`term_escape_style
<config-common-term_escape_style>` option is set to ``"fbterm"`` or if it is
set to ``"auto"`` and powerline detected fbterm.
.. _config-common-term_escape_style:
``term_escape_style``
Defines what escapes sequences should be used. Accepts three variants:
======= ===================================================================
Variant Description
======= ===================================================================
auto ``xterm`` or ``fbterm`` depending on ``$TERM`` variable value:
``TERM=fbterm`` implies ``fbterm`` escaping style, all other values
select ``xterm`` escaping.
xterm Uses ``\e[{fb};5;{color}m`` for colors (``{fb}`` is either ``38``
(foreground) or ``48`` (background)). Should be used for most
terminals.
fbterm Uses ``\e[{fb};{color}}`` for colors (``{fb}`` is either ``1``
(foreground) or ``2`` (background)). Should be used for fbterm:
framebuffer terminal.
======= ===================================================================
.. _config-common-ambiwidth:
``ambiwidth``

View File

@ -52,6 +52,7 @@ if your terminal emulator supports it.
Terminal.app OS X |i_yes| |i_no| |i_no|
libvte-based [#]_ Linux |i_yes| |i_yes| |i_yes| [#]_
xterm Linux |i_yes| |i_no| |i_partial| [#]_
fbterm Linux |i_yes| |i_yes| |i_no|
===================== ======= ===================== ===================== =====================
.. |i_yes| image:: _static/img/icons/tick.png

View File

@ -258,6 +258,7 @@ def finish_common_config(encoding, common_config):
common_config.setdefault('log_level', 'WARNING')
common_config.setdefault('log_format', '%(asctime)s:%(levelname)s:%(message)s')
common_config.setdefault('term_truecolor', False)
common_config.setdefault('term_escape_style', 'auto')
common_config.setdefault('ambiwidth', 1)
common_config.setdefault('additional_escapes', None)
common_config.setdefault('reload_config', True)
@ -474,6 +475,7 @@ class Powerline(object):
mergedicts(self.renderer_options, dict(
pl=self.pl,
term_truecolor=self.common_config['term_truecolor'],
term_escape_style=self.common_config['term_escape_style'],
ambiwidth=self.common_config['ambiwidth'],
tmux_escape=self.common_config['additional_escapes'] == 'tmux',
screen_escape=self.common_config['additional_escapes'] == 'screen',

View File

@ -57,6 +57,7 @@ main_spec = (Spec(
common=Spec(
default_top_theme=top_theme_spec().optional(),
term_truecolor=Spec().type(bool).optional(),
term_escape_style=Spec().type(unicode).oneof(set(('auto', 'xterm', 'fbterm'))).optional(),
# Python is capable of loading from zip archives. Thus checking path
# only for existence of the path, not for it being a directory
paths=Spec().list(

View File

@ -291,7 +291,7 @@ class Renderer(object):
line=line,
output_raw=output_raw,
output_width=output_width,
segment_info=segment_info,
segment_info=self.get_segment_info(segment_info, mode),
theme=theme,
)
@ -310,7 +310,7 @@ class Renderer(object):
def do_render(self, mode, width, side, line, output_raw, output_width, segment_info, theme):
'''Like Renderer.render(), but accept theme in place of matcher_info
'''
segments = list(theme.get_segments(side, line, self.get_segment_info(segment_info, mode), mode))
segments = list(theme.get_segments(side, line, segment_info, mode))
current_width = 0

View File

@ -18,6 +18,7 @@ class ShellRenderer(Renderer):
escape_hl_start = ''
escape_hl_end = ''
term_truecolor = False
term_escape_style = 'auto'
tmux_escape = False
screen_escape = False
@ -36,6 +37,13 @@ class ShellRenderer(Renderer):
)
def do_render(self, output_width, segment_info, side, theme, width=None, **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
if isinstance(segment_info, dict):
client_id = segment_info.get('client_id')
else:
@ -85,11 +93,13 @@ class ShellRenderer(Renderer):
is a valid color or attribute, its 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 self.term_truecolor:
if term_truecolor:
ansi += [38, 2] + list(int_to_rgb(fg[1]))
else:
ansi += [38, 5, fg[0]]
@ -97,7 +107,7 @@ class ShellRenderer(Renderer):
if bg is False or bg[0] is False:
ansi += [49]
else:
if self.term_truecolor:
if term_truecolor:
ansi += [48, 2] + list(int_to_rgb(bg[1]))
else:
ansi += [48, 5, bg[0]]
@ -113,7 +123,21 @@ class ShellRenderer(Renderer):
ansi += [3]
elif attr & ATTR_UNDERLINE:
ansi += [4]
r = '\033[{0}m'.format(';'.join(str(attr) for attr in ansi))
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:

View File

@ -39,6 +39,10 @@ config = {
'theme': 'default',
'colorscheme': 'default',
},
'shell': {
'theme': 'default',
'colorscheme': 'default',
},
},
},
'colors': {
@ -131,6 +135,14 @@ config = {
],
},
},
'themes/shell/default': {
'default_module': 'powerline.segments.common',
'segments': {
'left': [
highlighted_string('s', 'g1', width='auto'),
],
},
},
}
@ -639,6 +651,102 @@ class TestSegmentData(TestRender):
self.assertRenderEqual(p, '{56} 1S{56}>{56}3S{610}>>{910}3S{910}>{910}2S{10-}>>{--}')
class TestShellEscapes(TestCase):
@with_new_config
def test_escapes(self, config):
from powerline.shell import ShellPowerline
import powerline as powerline_module
with swap_attributes(config, powerline_module):
with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline:
self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1b[0;38;5;5;48;5;6m\xa0s\x1b[0;38;5;6;49;22m>>\x1b[0m')
@with_new_config
def test_tmux_escapes(self, config):
from powerline.shell import ShellPowerline
import powerline as powerline_module
config['config']['common']['additional_escapes'] = 'tmux'
with swap_attributes(config, powerline_module):
with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline:
self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1bPtmux;\x1b\x1b[0;38;5;5;48;5;6m\x1b\\\xa0s\x1bPtmux;\x1b\x1b[0;38;5;6;49;22m\x1b\\>>\x1bPtmux;\x1b\x1b[0m\x1b\\')
@with_new_config
def test_screen_escapes(self, config):
from powerline.shell import ShellPowerline
import powerline as powerline_module
config['config']['common']['additional_escapes'] = 'screen'
with swap_attributes(config, powerline_module):
with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline:
self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1bP\x1b\x1b[0;38;5;5;48;5;6m\x1b\\\xa0s\x1bP\x1b\x1b[0;38;5;6;49;22m\x1b\\>>\x1bP\x1b\x1b[0m\x1b\\')
@with_new_config
def test_fbterm_escapes(self, config):
from powerline.shell import ShellPowerline
import powerline as powerline_module
config['config']['common']['term_escape_style'] = 'fbterm'
with swap_attributes(config, powerline_module):
with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline:
self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1b[0m\x1b[1;5}\x1b[2;6}\xa0s\x1b[0m\x1b[1;6}\x1b[49m\x1b[22m>>\x1b[0m')
@with_new_config
def test_fbterm_tmux_escapes(self, config):
from powerline.shell import ShellPowerline
import powerline as powerline_module
config['config']['common']['term_escape_style'] = 'fbterm'
config['config']['common']['additional_escapes'] = 'tmux'
with swap_attributes(config, powerline_module):
with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline:
self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1bPtmux;\x1b\x1b[0m\x1b\x1b[1;5}\x1b\x1b[2;6}\x1b\\\xa0s\x1bPtmux;\x1b\x1b[0m\x1b\x1b[1;6}\x1b\x1b[49m\x1b\x1b[22m\x1b\\>>\x1bPtmux;\x1b\x1b[0m\x1b\\')
@with_new_config
def test_fbterm_screen_escapes(self, config):
from powerline.shell import ShellPowerline
import powerline as powerline_module
config['config']['common']['term_escape_style'] = 'fbterm'
config['config']['common']['additional_escapes'] = 'screen'
with swap_attributes(config, powerline_module):
with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline:
self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1bP\x1b\x1b[0m\x1b\x1b[1;5}\x1b\x1b[2;6}\x1b\\\xa0s\x1bP\x1b\x1b[0m\x1b\x1b[1;6}\x1b\x1b[49m\x1b\x1b[22m\x1b\\>>\x1bP\x1b\x1b[0m\x1b\\')
@with_new_config
def test_term_truecolor_escapes(self, config):
from powerline.shell import ShellPowerline
import powerline as powerline_module
config['config']['common']['term_truecolor'] = True
with swap_attributes(config, powerline_module):
with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline:
self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1b[0;38;2;192;0;192;48;2;0;128;128m\xa0s\x1b[0;38;2;0;128;128;49;22m>>\x1b[0m')
@with_new_config
def test_term_truecolor_fbterm_escapes(self, config):
from powerline.shell import ShellPowerline
import powerline as powerline_module
config['config']['common']['term_escape_style'] = 'fbterm'
config['config']['common']['term_truecolor'] = True
with swap_attributes(config, powerline_module):
with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline:
self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1b[0m\x1b[1;5}\x1b[2;6}\xa0s\x1b[0m\x1b[1;6}\x1b[49m\x1b[22m>>\x1b[0m')
@with_new_config
def test_term_truecolor_tmux_escapes(self, config):
from powerline.shell import ShellPowerline
import powerline as powerline_module
config['config']['common']['term_truecolor'] = True
config['config']['common']['additional_escapes'] = 'tmux'
with swap_attributes(config, powerline_module):
with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline:
self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1bPtmux;\x1b\x1b[0;38;2;192;0;192;48;2;0;128;128m\x1b\\\xa0s\x1bPtmux;\x1b\x1b[0;38;2;0;128;128;49;22m\x1b\\>>\x1bPtmux;\x1b\x1b[0m\x1b\\')
@with_new_config
def test_term_truecolor_screen_escapes(self, config):
from powerline.shell import ShellPowerline
import powerline as powerline_module
config['config']['common']['term_truecolor'] = True
config['config']['common']['additional_escapes'] = 'screen'
with swap_attributes(config, powerline_module):
with get_powerline_raw(config, ShellPowerline, args=Args(config_path=[''])) as powerline:
self.assertEqual(powerline.render(segment_info={}, side='left'), '\x1bP\x1b\x1b[0;38;2;192;0;192;48;2;0;128;128m\x1b\\\xa0s\x1bP\x1b\x1b[0;38;2;0;128;128;49;22m\x1b\\>>\x1bP\x1b\x1b[0m\x1b\\')
class TestVim(TestCase):
def test_environ_update(self):
# Regression test: test that segment obtains environment from vim, not