# 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}(, {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),)), vterm_set_utf8=(None, (('vt', VTerm_p), ('is_utf8', ctypes.c_int))), ) 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.functions.vterm_set_utf8(self.vt, 1) 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