powerline/tests/modules/lib/vterm.py

192 lines
4.6 KiB
Python

# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
import ctypes
from collections import namedtuple
from powerline.lib.unicode import unicode, unichr, tointiter
Dimensions = namedtuple('Dimensions', ('rows', 'cols'))
class CTypesFunction(object):
def __init__(self, library, name, rettype, args):
self.name = name
self.prototype = ctypes.CFUNCTYPE(rettype, *[
arg[1] for arg in args
])
self.args = args
self.func = self.prototype((name, library), tuple((
(1, arg[0]) for arg in args
)))
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)
def __repr__(self):
return '{cls}(<library>, {name!r}, {rettype!r}, {args!r})'.format(
cls=self.__class__.__name__,
**self.__dict__
)
class CTypesLibraryFuncsCollection(object):
def __init__(self, lib, **kwargs):
self.lib = lib
library_loader = ctypes.LibraryLoader(ctypes.CDLL)
library = library_loader.LoadLibrary(lib)
self.library = library
for name, args in kwargs.items():
self.__dict__[name] = CTypesFunction(library, name, *args)
class VTermPos_s(ctypes.Structure):
_fields_ = (
('row', ctypes.c_int),
('col', ctypes.c_int),
)
class VTermColor_s(ctypes.Structure):
_fields_ = (
('red', ctypes.c_uint8),
('green', ctypes.c_uint8),
('blue', ctypes.c_uint8),
)
class VTermScreenCellAttrs_s(ctypes.Structure):
_fields_ = (
('bold', ctypes.c_uint, 1),
('underline', ctypes.c_uint, 2),
('italic', ctypes.c_uint, 1),
('blink', ctypes.c_uint, 1),
('reverse', ctypes.c_uint, 1),
('strike', ctypes.c_uint, 1),
('font', ctypes.c_uint, 4),
('dwl', ctypes.c_uint, 1),
('dhl', ctypes.c_uint, 2),
)
VTERM_MAX_CHARS_PER_CELL = 6
class VTermScreenCell_s(ctypes.Structure):
_fields_ = (
('chars', ctypes.ARRAY(ctypes.c_uint32, VTERM_MAX_CHARS_PER_CELL)),
('width', ctypes.c_char),
('attrs', VTermScreenCellAttrs_s),
('fg', VTermColor_s),
('bg', VTermColor_s),
)
VTerm_p = ctypes.c_void_p
VTermScreen_p = ctypes.c_void_p
def get_functions(lib):
return CTypesLibraryFuncsCollection(
lib,
vterm_new=(VTerm_p, (
('rows', ctypes.c_int),
('cols', ctypes.c_int)
)),
vterm_obtain_screen=(VTermScreen_p, (('vt', VTerm_p),)),
vterm_set_size=(None, (
('vt', VTerm_p),
('rows', ctypes.c_int),
('cols', ctypes.c_int)
)),
vterm_screen_reset=(None, (
('screen', VTermScreen_p),
('hard', ctypes.c_int)
)),
vterm_input_write=(ctypes.c_size_t, (
('vt', VTerm_p),
('bytes', ctypes.POINTER(ctypes.c_char)),
('size', ctypes.c_size_t),
)),
vterm_screen_get_cell=(ctypes.c_int, (
('screen', VTermScreen_p),
('pos', VTermPos_s),
('cell', ctypes.POINTER(VTermScreenCell_s))
)),
vterm_free=(None, (('vt', VTerm_p),)),
)
class VTermColor(object):
__slots__ = ('red', 'green', 'blue')
def __init__(self, color):
self.red = color.red
self.green = color.green
self.blue = color.blue
@property
def color_key(self):
return (self.red, self.green, self.blue)
class VTermScreenCell(object):
def __init__(self, vtsc):
for field in VTermScreenCellAttrs_s._fields_:
field_name = field[0]
setattr(self, field_name, getattr(vtsc.attrs, field_name))
self.text = ''.join((
unichr(vtsc.chars[i]) for i in range(VTERM_MAX_CHARS_PER_CELL)
)).rstrip('\x00')
self.width = next(tointiter(vtsc.width))
self.fg = VTermColor(vtsc.fg)
self.bg = VTermColor(vtsc.bg)
self.cell_properties_key = (
self.fg.color_key,
self.bg.color_key,
self.bold,
self.underline,
self.italic,
)
class VTermScreen(object):
def __init__(self, functions, screen):
self.functions = functions
self.screen = screen
def __getitem__(self, position):
pos = VTermPos_s(*position)
cell = VTermScreenCell_s()
ret = self.functions.vterm_screen_get_cell(self.screen, pos, cell)
if ret != 1:
raise ValueError('vterm_screen_get_cell returned {0}'.format(ret))
return VTermScreenCell(cell)
def reset(self, hard):
self.functions.vterm_screen_reset(self.screen, int(bool(hard)))
class VTerm(object):
def __init__(self, lib, dim):
self.functions = get_functions(lib)
self.vt = self.functions.vterm_new(dim.rows, dim.cols)
self.vtscreen = VTermScreen(self.functions, self.functions.vterm_obtain_screen(self.vt))
self.vtscreen.reset(True)
def push(self, data):
if isinstance(data, unicode):
data = data.encode('utf-8')
return self.functions.vterm_input_write(self.vt, data, len(data))
def resize(self, dim):
self.functions.vterm_set_size(self.vt, dim.rows, dim.cols)
def __del__(self):
try:
self.functions.vterm_free(self.vt)
except AttributeError:
pass