More work on native streams

This commit is contained in:
Kovid Goyal 2016-11-13 10:21:54 +05:30
parent 62fc6cc4a0
commit fab2213c25
20 changed files with 652 additions and 161 deletions

57
generate-unicode-data.py Normal file
View File

@ -0,0 +1,57 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
import unicodedata
import itertools
import sys
IGNORED_CATEGORIES = ('Cc', 'Cf', 'Cn', 'Cs')
def ranges(i):
for a, b in itertools.groupby(enumerate(i), lambda r: r[1] - r[0]):
b = list(b)
yield b[0][1], b[-1][1]
def generate_data(chars):
points, cranges = [], []
for l, r in ranges(chars):
if l == r:
points.append(l)
else:
cranges.append((l, r))
return points, cranges
def generate_predicate(name, chars):
points, ranges = generate_data(chars)
ranges = ['(0x%s %s ch && ch <= 0x%s)' % (l, '<' if l == 0 else '<=', r) for l, r in ranges]
points = ['(ch == 0x%x)' % p for p in points]
return '''
static inline bool %s(uint32_t ch) {
return %s || %s;
}
''' % (name, '||'.join(ranges), '||'.join(points))
def main():
combining_chars = []
igchars = []
for c in map(chr, range(sys.maxunicode + 1)):
if unicodedata.category(c) in IGNORED_CATEGORIES:
igchars.append(ord(c))
if unicodedata.combining(c):
combining_chars.append(ord(c))
cc = generate_predicate('is_combining_char', combining_chars)
ig = generate_predicate('is_ignored_char', igchars)
with open('kitty/unicode-data.h', 'w') as f:
print('#pragma once', file=f)
print(cc, file=f)
print(ig, file=f)
if __name__ == '__main__':
main()
# TODO: delete kitty/unicode.py alongwith kitty/screen.py

View File

@ -97,10 +97,10 @@ class Boss(Thread):
def on_focus(self, window, focused):
if focused:
if self.screen.enable_focus_tracking:
if self.screen.enable_focus_tracking():
self.write_to_child(b'\x1b[I')
else:
if self.screen.enable_focus_tracking:
if self.screen.enable_focus_tracking():
self.write_to_child(b'\x1b[O')
def on_mouse_button(self, window, button, action, mods):
@ -110,7 +110,7 @@ class Boss(Thread):
# text = glfw.glfwGetClipboardString(window)
text = subprocess.check_output(['xsel'])
if text:
if self.screen.in_bracketed_paste_mode:
if self.screen.in_bracketed_paste_mode():
text = BRACKETED_PASTE_START.encode('ascii') + text + BRACKETED_PASTE_END.encode('ascii')
self.write_to_child(text)

View File

@ -16,7 +16,8 @@ from .fast_data_types import (
glBlendFunc, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, glClear,
GL_COLOR_BUFFER_BIT, glClearColor, glViewport, glUniform2ui, glUniform4f,
glUniform1i, glUniform2f, glDrawArraysInstanced, GL_TRIANGLE_FAN,
glEnable, glDisable, GL_BLEND, glDrawArrays, ColorProfile, REVERSE
glEnable, glDisable, GL_BLEND, glDrawArrays, ColorProfile, REVERSE,
CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE
)
Size = namedtuple('Size', 'width height')
@ -303,11 +304,11 @@ class CharGrid:
col = cursor.color or self.default_cursor.color
shape = cursor.shape or self.default_cursor.shape
alpha = self.opts.cursor_opacity
if alpha < 1.0 and shape == 'block':
if alpha < 1.0 and shape == CURSOR_BLOCK:
glEnable(GL_BLEND)
right = left + (width(1.5) if shape == 'beam' else sg.dx)
right = left + (width(1.5) if shape == CURSOR_BEAM else sg.dx)
bottom = top - sg.dy
if shape == 'underline':
if shape == CURSOR_UNDERLINE:
top = bottom + width(vert=False)
glUniform4f(ul('color'), col[0], col[1], col[2], alpha)
glUniform2f(ul('xpos'), left, right)

View File

@ -166,3 +166,33 @@ uint16_t* translation_table(char which) {
}
return charset_translations[0];
}
// UTF-8 decode taken from: http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
static const uint8_t utf8_data[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
};
uint32_t decode_utf8(uint32_t* state, uint32_t* codep, uint8_t byte) {
uint32_t type = utf8_data[byte];
*codep = (*state != UTF8_ACCEPT) ?
(byte & 0x3fu) | (*codep << 6) :
(0xff >> type) & (byte);
*state = utf8_data[256 + *state*16 + type];
return *state;
}

View File

@ -63,7 +63,7 @@ new(PyTypeObject *type, PyObject UNUSED *args, PyObject UNUSED *kwds) {
}
static void
dealloc(Cursor* self) {
dealloc(ColorProfile* self) {
Py_TYPE(self)->tp_free((PyObject*)self);
}

View File

@ -6,6 +6,7 @@ import re
from collections import namedtuple
from itertools import repeat
from .fast_data_types import CURSOR_BLOCK, CURSOR_BEAM, CURSOR_UNDERLINE
key_pat = re.compile(r'([a-zA-Z][a-zA-Z0-9_-]*)\s+(.+)$')
# Color definitions {{{
@ -186,12 +187,14 @@ def to_font_size(x):
return max(6, float(x))
cshapes = {'block': CURSOR_BLOCK, 'beam': CURSOR_BEAM, 'underline': CURSOR_UNDERLINE}
def to_cursor_shape(x):
shapes = 'block underline beam'
x = x.lower()
if x not in shapes.split():
raise ValueError('Invalid cursor shape: {} allowed values are {}'.format(x, shapes))
return x
try:
return cshapes[x.lower()]
except KeyError:
raise ValueError('Invalid cursor shape: {} allowed values are {}'.format(x, ', '.join(cshapes)))
def to_bool(x):

View File

@ -9,50 +9,30 @@
#include <structmember.h>
#define INIT_NONE(x) Py_INCREF(Py_None); x = Py_None;
static PyObject *
new(PyTypeObject *type, PyObject UNUSED *args, PyObject UNUSED *kwds) {
Cursor *self;
self = (Cursor *)type->tp_alloc(type, 0);
if (self != NULL) {
self->x = PyLong_FromLong(0);
if (self->x == NULL) { Py_CLEAR(self); return NULL; }
self->y = self->x; Py_INCREF(self->y);
INIT_NONE(self->shape);
INIT_NONE(self->blink);
INIT_NONE(self->color);
self->hidden = Py_False; Py_INCREF(Py_False);
self->bold = 0; self->italic = 0; self->reverse = 0; self->strikethrough = 0; self->decoration = 0;
self->fg = 0; self->bg = 0; self->decoration_fg = 0;
}
return (PyObject*) self;
}
static void
dealloc(Cursor* self) {
Py_CLEAR(self->shape);
Py_CLEAR(self->blink);
Py_CLEAR(self->color);
Py_CLEAR(self->hidden);
Py_CLEAR(self->x);
Py_CLEAR(self->y);
Py_TYPE(self)->tp_free((PyObject*)self);
}
#define EQ(x) (a->x == b->x)
#define PEQ(x) (PyObject_RichCompareBool(a->x, b->x, Py_EQ) == 1)
static int __eq__(Cursor *a, Cursor *b) {
return EQ(bold) && EQ(italic) && EQ(strikethrough) && EQ(reverse) && EQ(decoration) && EQ(fg) && EQ(bg) && EQ(decoration_fg) && PEQ(x) && PEQ(y) && PEQ(shape) && PEQ(blink) && PEQ(color) && PEQ(hidden);
return EQ(bold) && EQ(italic) && EQ(strikethrough) && EQ(reverse) && EQ(decoration) && EQ(fg) && EQ(bg) && EQ(decoration_fg) && EQ(x) && EQ(y) && EQ(shape) && EQ(blink) && EQ(color) && EQ(hidden);
}
#define BOOL(x) ((x) ? Py_True : Py_False)
static PyObject *
repr(Cursor *self) {
return PyUnicode_FromFormat(
"Cursor(x=%R, y=%R, shape=%R, blink=%R, hidden=%R, color=%R, fg=#%08x, bg=#%08x, bold=%R, italic=%R, reverse=%R, strikethrough=%R, decoration=%d, decoration_fg=#%08x)",
self->x, self->y, self->shape, self->blink, self->hidden, self->color, self->fg, self->bg, BOOL(self->bold), BOOL(self->italic), BOOL(self->reverse), BOOL(self->strikethrough), self->decoration, self->decoration_fg
"Cursor(x=%u, y=%u, shape=%d, blink=%R, hidden=%R, color=#%08x, fg=#%08x, bg=#%08x, bold=%R, italic=%R, reverse=%R, strikethrough=%R, decoration=%d, decoration_fg=#%08x)",
self->x, self->y, self->shape, BOOL(self->blink), BOOL(self->hidden), self->color, self->fg, self->bg, BOOL(self->bold), BOOL(self->italic), BOOL(self->reverse), BOOL(self->strikethrough), self->decoration, self->decoration_fg
);
}
@ -64,29 +44,39 @@ reset_display_attrs(Cursor *self) {
Py_RETURN_NONE;
}
void cursor_reset(Cursor *self) {
self->x = 0; self->y = 0;
self->shape = 0; self->blink = false;
self->color = 0; self->hidden = false;
}
static PyObject*
copy(Cursor *self, PyObject *args);
copy(Cursor *self);
#define copy_doc "Create a clone of this cursor"
static PyObject* color_get(Cursor *self, void UNUSED *closure) {
if (!(self->color & 0xFF)) { Py_RETURN_NONE; }
return Py_BuildValue("BBB", (self->color >> 24) & 0xFF, (self->color >> 16) & 0xFF, (self->color >> 8) & 0xFF);
}
// Boilerplate {{{
BOOL_GETSET(Cursor, bold)
BOOL_GETSET(Cursor, italic)
BOOL_GETSET(Cursor, reverse)
BOOL_GETSET(Cursor, strikethrough)
BOOL_GETSET(Cursor, hidden)
BOOL_GETSET(Cursor, blink)
static PyMemberDef members[] = {
{"x", T_OBJECT_EX, offsetof(Cursor, x), 0, "x"},
{"y", T_OBJECT_EX, offsetof(Cursor, y), 0, "y"},
{"shape", T_OBJECT_EX, offsetof(Cursor, shape), 0, "shape"},
{"blink", T_OBJECT_EX, offsetof(Cursor, blink), 0, "blink"},
{"color", T_OBJECT_EX, offsetof(Cursor, color), 0, "color"},
{"hidden", T_OBJECT_EX, offsetof(Cursor, hidden), 0, "hidden"},
{"x", T_INT, offsetof(Cursor, x), 0, "x"},
{"y", T_INT, offsetof(Cursor, y), 0, "y"},
{"shape", T_UBYTE, offsetof(Cursor, shape), 0, "shape"},
{"color", T_ULONG, offsetof(Cursor, color), 0, "color"},
{"decoration", T_UBYTE, offsetof(Cursor, decoration), 0, "decoration"},
{"fg", T_UINT, offsetof(Cursor, fg), 0, "fg"},
{"bg", T_UINT, offsetof(Cursor, bg), 0, "bg"},
{"decoration_fg", T_UINT, offsetof(Cursor, decoration_fg), 0, "decoration_fg"},
{"fg", T_ULONG, offsetof(Cursor, fg), 0, "fg"},
{"bg", T_ULONG, offsetof(Cursor, bg), 0, "bg"},
{"decoration_fg", T_ULONG, offsetof(Cursor, decoration_fg), 0, "decoration_fg"},
{NULL} /* Sentinel */
};
@ -95,6 +85,9 @@ static PyGetSetDef getseters[] = {
GETSET(italic)
GETSET(reverse)
GETSET(strikethrough)
GETSET(hidden)
GETSET(blink)
{"color", (getter) color_get, NULL, "color", NULL},
{NULL} /* Sentinel */
};
@ -127,16 +120,20 @@ RICHCMP(Cursor)
// }}}
static PyObject*
copy(Cursor *self, PyObject UNUSED *args) {
#define CPY(x) ans->x = self->x; Py_XINCREF(self->x);
Cursor*
cursor_copy(Cursor *self) {
#define CCY(x) ans->x = self->x;
Cursor* ans;
ans = alloc_cursor();
if (ans == NULL) { PyErr_NoMemory(); return NULL; }
CPY(x); CPY(y); CPY(shape); CPY(blink); CPY(color); CPY(hidden);
CCY(x); CCY(y); CCY(shape); CCY(blink); CCY(color); CCY(hidden);
CCY(bold); CCY(italic); CCY(strikethrough); CCY(reverse); CCY(decoration); CCY(fg); CCY(bg); CCY(decoration_fg);
return (PyObject*)ans;
return ans;
}
static PyObject*
copy(Cursor *self) {
return (PyObject*)cursor_copy(self);
}
Cursor *alloc_cursor() {

View File

@ -6,16 +6,6 @@
*/
#include "data-types.h"
extern int init_LineBuf(PyObject *);
extern int init_Cursor(PyObject *);
extern int init_Line(PyObject *);
extern int init_ColorProfile(PyObject *);
extern int init_SpriteMap(PyObject *);
extern int init_ChangeTracker(PyObject *);
extern int init_Screen(PyObject *);
extern PyObject* create_256_color_table();
extern PyObject* parse_bytes_dump(PyObject UNUSED *self, PyObject *val);
extern PyObject* parse_bytes(PyObject UNUSED *self, PyObject *val);
#include "gl.h"
#include "modes.h"
@ -58,6 +48,9 @@ PyInit_fast_data_types(void) {
PyModule_AddIntConstant(m, "DECORATION", DECORATION_SHIFT);
PyModule_AddStringMacro(m, BRACKETED_PASTE_START);
PyModule_AddStringMacro(m, BRACKETED_PASTE_END);
PyModule_AddIntMacro(m, CURSOR_BLOCK);
PyModule_AddIntMacro(m, CURSOR_BEAM);
PyModule_AddIntMacro(m, CURSOR_UNDERLINE);
}
return m;

View File

@ -37,6 +37,12 @@ typedef unsigned int index_type;
#define HAS_BG_MASK (0xFF << COL_SHIFT)
#define CC_MASK 0xFFFF
#define CC_SHIFT 16
#define UTF8_ACCEPT 0
#define UTF8_REJECT 1
#define CURSOR_BLOCK 1
#define CURSOR_BEAM 2
#define CURSOR_UNDERLINE 3
#define CURSOR_TO_ATTRS(c, w) \
((w) | (((c->decoration & 3) << DECORATION_SHIFT) | ((c->bold & 1) << BOLD_SHIFT) | \
@ -119,6 +125,7 @@ typedef struct {
bool continued;
bool needs_free;
} Line;
PyTypeObject Line_Type;
typedef struct {
@ -136,17 +143,19 @@ typedef struct {
decoration_type *decoration_fg;
combining_type *combining_chars;
} LineBuf;
PyTypeObject LineBuf_Type;
typedef struct {
PyObject_HEAD
PyObject *x, *y, *shape, *blink, *hidden, *color;
bool bold, italic, reverse, strikethrough;
uint8_t decoration;
uint32_t fg, bg, decoration_fg;
bool bold, italic, reverse, strikethrough, blink, hidden;
int x, y;
uint8_t decoration, shape;
unsigned long fg, bg, decoration_fg, color;
} Cursor;
PyTypeObject Cursor_Type;
typedef struct {
@ -156,6 +165,7 @@ typedef struct {
uint32_t ansi_color_table[120];
} ColorProfile;
PyTypeObject ColorProfile_Type;
typedef struct SpritePosition SpritePosition;
struct SpritePosition {
@ -167,6 +177,7 @@ struct SpritePosition {
bool filled;
bool rendered;
};
PyTypeObject SpritePosition_Type;
typedef struct {
PyObject_HEAD
@ -177,6 +188,7 @@ typedef struct {
bool dirty;
} SpriteMap;
PyTypeObject SpriteMap_Type;
typedef struct {
PyObject_HEAD
@ -190,12 +202,26 @@ typedef struct {
bool *changed_cells;
unsigned int history_line_added_count;
} ChangeTracker;
PyTypeObject ChangeTracker_Type;
typedef struct {
bool LNM, IRM, DECTEM, DECSCNM, DECOM, DECAWM, DECCOLM;
bool mLNM, mIRM, mDECTCEM, mDECSCNM, mDECOM, mDECAWM, mDECCOLM, mBRACKETED_PASTE, mFOCUS_TRACKING;
} ScreenModes;
PyTypeObject ScreenModes_Type;
typedef struct {
PyObject_HEAD
unsigned int current_charset;
uint16_t *g0_charset, *g1_charset;
uint32_t utf8_state;
Cursor *cursor;
bool mDECOM;
bool mDECAWM;
} Savepoint;
PyTypeObject Savepoint_Type;
typedef struct {
PyObject_HEAD
@ -215,14 +241,56 @@ typedef struct {
bool parser_has_pending_text;
} Screen;
PyTypeObject Screen_Type;
Line* alloc_line();
Cursor* alloc_cursor();
LineBuf* alloc_linebuf();
ChangeTracker* alloc_change_tracker();
Savepoint* alloc_savepoint();
#define left_shift_line(line, at, num) \
for(index_type __i__ = (at); __i__ < (line)->xnum - (num); __i__++) { \
COPY_CELL(line, __i__ + (num), line, __i__) \
} \
if ((((line)->chars[(at)] >> ATTRS_SHIFT) & WIDTH_MASK) != 1) (line)->chars[(at)] = (1 << ATTRS_SHIFT) | 32;
// Global functions
int init_LineBuf(PyObject *);
int init_Cursor(PyObject *);
int init_Line(PyObject *);
int init_ColorProfile(PyObject *);
int init_SpriteMap(PyObject *);
int init_ChangeTracker(PyObject *);
int init_Screen(PyObject *);
PyObject* create_256_color_table();
PyObject* parse_bytes_dump(PyObject UNUSED *, PyObject *);
PyObject* parse_bytes(PyObject UNUSED *, PyObject *);
uint16_t* translation_table(char);
uint32_t decode_utf8(uint32_t*, uint32_t*, uint8_t byte);
void linebuf_init_line(LineBuf *, index_type);
void line_set_char(Line *, unsigned int , uint32_t , unsigned int , Cursor *);
void line_right_shift(Line *, unsigned int , unsigned int );
void line_add_combining_char(Line *, uint32_t , unsigned int );
void cursor_reset(Cursor*);
void linebuf_set_attribute(LineBuf *, unsigned int , unsigned int );
Cursor* cursor_copy(Cursor*);
void linebuf_clear(LineBuf *);
bool screen_restore_cursor(Screen *);
bool screen_save_cursor(Screen *);
bool screen_cursor_position(Screen*, unsigned int, unsigned int);
bool screen_erase_in_display(Screen *, unsigned int, bool);
bool screen_draw(Screen *screen, uint8_t *buf, unsigned int buflen);
bool update_cell_range_data(SpriteMap *, Line *, unsigned int, unsigned int, ColorProfile *, const uint32_t, const uint32_t, unsigned int *);
uint32_t to_color(ColorProfile *, uint32_t, uint32_t);
PyObject* line_text_at(char_type, combining_type);
void linebuf_init_line(LineBuf *, index_type);
#define DECLARE_CH_SCREEN_HANDLER(name) bool screen_##name(Screen *screen, uint8_t ch);
DECLARE_CH_SCREEN_HANDLER(bell)
DECLARE_CH_SCREEN_HANDLER(backspace)
DECLARE_CH_SCREEN_HANDLER(tab)
DECLARE_CH_SCREEN_HANDLER(linefeed)
DECLARE_CH_SCREEN_HANDLER(carriage_return)
DECLARE_CH_SCREEN_HANDLER(shift_out)
DECLARE_CH_SCREEN_HANDLER(shift_in)

View File

@ -7,7 +7,6 @@
#include "data-types.h"
#include <structmember.h>
extern PyTypeObject Line_Type;
static inline void
clear_chars_to_space(LineBuf* linebuf, index_type y) {
@ -15,15 +14,19 @@ clear_chars_to_space(LineBuf* linebuf, index_type y) {
for (index_type i = 0; i < linebuf->xnum; i++) chars[i] = (1 << ATTRS_SHIFT) | 32;
}
static PyObject*
clear(LineBuf *self) {
#define clear_doc "Clear all lines in this LineBuf"
void linebuf_clear(LineBuf *self) {
memset(self->buf, 0, self->block_size * CELL_SIZE);
memset(self->continued_map, 0, self->ynum * sizeof(bool));
for (index_type i = 0; i < self->ynum; i++) {
clear_chars_to_space(self, i);
self->line_map[i] = i;
}
}
static PyObject*
clear(LineBuf *self) {
#define clear_doc "Clear all lines in this LineBuf"
linebuf_clear(self);
Py_RETURN_NONE;
}
@ -110,16 +113,20 @@ line(LineBuf *self, PyObject *y) {
return (PyObject*)self->line;
}
void linebuf_set_attribute(LineBuf *self, unsigned int shift, unsigned int val) {
char_type mask;
for (index_type y = 0; y < self->ynum; y++) {
SET_ATTRIBUTE(self->chars + y * self->xnum, shift, val);
}
}
static PyObject*
set_attribute(LineBuf *self, PyObject *args) {
#define set_attribute_doc "set_attribute(which, val) -> Set the attribute on all cells in the line."
unsigned int shift, val;
char_type mask;
if (!PyArg_ParseTuple(args, "II", &shift, &val)) return NULL;
if (shift < DECORATION_SHIFT || shift > STRIKE_SHIFT) { PyErr_SetString(PyExc_ValueError, "Unknown attribute"); return NULL; }
for (index_type y = 0; y < self->ynum; y++) {
SET_ATTRIBUTE(self->chars + y * self->xnum, shift, val);
}
linebuf_set_attribute(self, shift, val);
Py_RETURN_NONE;
}

View File

@ -6,7 +6,6 @@
*/
#include "data-types.h"
extern PyTypeObject Cursor_Type;
static PyObject *
new(PyTypeObject UNUSED *type, PyObject UNUSED *args, PyObject UNUSED *kwds) {
@ -108,6 +107,12 @@ basic_cell_data(Line *self, PyObject *val) {
return Py_BuildValue("IBK", (unsigned int)(ch & CHAR_MASK), (unsigned char)(ch >> ATTRS_SHIFT), (unsigned long long)self->colors[x]);
}
void line_add_combining_char(Line *self, uint32_t ch, unsigned int x) {
combining_type c = self->combining_chars[x];
if (c & CC_MASK) self->combining_chars[x] = (c & CC_MASK) | ( (ch & CC_MASK) << CC_SHIFT );
else self->combining_chars[x] = ch & CC_MASK;
}
static PyObject*
add_combining_char(Line* self, PyObject *args) {
#define add_combining_char_doc "add_combining_char(x, ch) -> Add the specified character as a combining char to the specified cell."
@ -118,9 +123,7 @@ add_combining_char(Line* self, PyObject *args) {
PyErr_SetString(PyExc_ValueError, "Column index out of bounds");
return NULL;
}
combining_type c = self->combining_chars[x];
if (c & CC_MASK) self->combining_chars[x] = (c & CC_MASK) | ( (new_char & CC_MASK) << CC_SHIFT );
else self->combining_chars[x] = new_char & CC_MASK;
line_add_combining_char(self, new_char, x);
Py_RETURN_NONE;
}
@ -134,7 +137,6 @@ set_text(Line* self, PyObject *args) {
Cursor *cursor;
int kind;
void *buf;
unsigned long x;
if (!PyArg_ParseTuple(args, "UnnO!", &src, &offset, &sz, &Cursor_Type, &cursor)) return NULL;
if (PyUnicode_READY(src) != 0) {
@ -148,12 +150,11 @@ set_text(Line* self, PyObject *args) {
PyErr_SetString(PyExc_ValueError, "Out of bounds offset/sz");
return NULL;
}
x = PyLong_AsUnsignedLong(cursor->x);
attrs = CURSOR_TO_ATTRS(cursor, 1);
color_type col = (cursor->fg & COL_MASK) | ((color_type)(cursor->bg & COL_MASK) << COL_SHIFT);
decoration_type dfg = cursor->decoration_fg & COL_MASK;
for (index_type i = x; offset < limit && i < self->xnum; i++, offset++) {
for (index_type i = cursor->x; offset < limit && i < self->xnum; i++, offset++) {
self->chars[i] = (PyUnicode_READ(kind, buf, offset) & CHAR_MASK) | attrs;
self->colors[i] = col;
self->decoration_fg[i] = dfg;
@ -166,23 +167,16 @@ set_text(Line* self, PyObject *args) {
static PyObject*
cursor_from(Line* self, PyObject *args) {
#define cursor_from_doc "cursor_from(x, y=0) -> Create a cursor object based on the formatting attributes at the specified x position. The y value of the cursor is set as specified."
unsigned long x, y = 0;
PyObject *xo, *yo;
unsigned int x, y = 0;
Cursor* ans;
if (!PyArg_ParseTuple(args, "k|k", &x, &y)) return NULL;
if (!PyArg_ParseTuple(args, "I|I", &x, &y)) return NULL;
if (x >= self->xnum) {
PyErr_SetString(PyExc_ValueError, "Out of bounds x");
return NULL;
}
ans = alloc_cursor();
if (ans == NULL) { PyErr_NoMemory(); return NULL; }
xo = PyLong_FromUnsignedLong(x); yo = PyLong_FromUnsignedLong(y);
if (xo == NULL || yo == NULL) {
Py_CLEAR(ans); Py_CLEAR(xo); Py_CLEAR(yo);
PyErr_NoMemory(); return NULL;
}
Py_CLEAR(ans->x); Py_CLEAR(ans->y);
ans->x = xo; ans->y = yo;
ans->x = x; ans->y = y;
char_type attrs = self->chars[x] >> ATTRS_SHIFT;
ATTRS_TO_CURSOR(attrs, ans);
COLORS_TO_CURSOR(self->colors[x], ans);
@ -228,6 +222,15 @@ apply_cursor(Line* self, PyObject *args) {
Py_RETURN_NONE;
}
void line_right_shift(Line *self, unsigned int at, unsigned int num) {
for(index_type i = self->xnum - 1; i >= at + num; i--) {
COPY_SELF_CELL(i - num, i)
}
// Check if a wide character was split at the right edge
char_type w = (self->chars[self->xnum - 1] >> ATTRS_SHIFT) & 3;
if (w != 1) self->chars[self->xnum - 1] = (1 << ATTRS_SHIFT) | 32;
}
static PyObject*
right_shift(Line *self, PyObject *args) {
#define right_shift_doc "right_shift(at, num) -> ..."
@ -238,12 +241,7 @@ right_shift(Line *self, PyObject *args) {
return NULL;
}
if (num > 0) {
for(index_type i = self->xnum - 1; i >= at + num; i--) {
COPY_SELF_CELL(i - num, i)
}
// Check if a wide character was split at the right edge
char_type w = (self->chars[self->xnum - 1] >> ATTRS_SHIFT) & 3;
if (w != 1) self->chars[self->xnum - 1] = (1 << ATTRS_SHIFT) | 32;
line_right_shift(self, at, num);
}
Py_RETURN_NONE;
}
@ -261,20 +259,8 @@ left_shift(Line *self, PyObject *args) {
Py_RETURN_NONE;
}
static PyObject*
set_char(Line *self, PyObject *args) {
#define set_char_doc "set_char(at, ch, width=1, cursor=None) -> Set the character at the specified cell. If cursor is not None, also set attributes from that cursor."
unsigned int at, width=1;
int ch;
Cursor *cursor = NULL;
void line_set_char(Line *self, unsigned int at, uint32_t ch, unsigned int width, Cursor *cursor) {
char_type attrs;
if (!PyArg_ParseTuple(args, "IC|IO!", &at, &ch, &width, &Cursor_Type, &cursor)) return NULL;
if (at >= self->xnum) {
PyErr_SetString(PyExc_ValueError, "Out of bounds");
return NULL;
}
if (cursor == NULL) {
attrs = (((self->chars[at] >> ATTRS_SHIFT) & ~3) | (width & 3)) << ATTRS_SHIFT;
} else {
@ -284,6 +270,21 @@ set_char(Line *self, PyObject *args) {
}
self->chars[at] = (ch & CHAR_MASK) | attrs;
self->combining_chars[at] = 0;
}
static PyObject*
set_char(Line *self, PyObject *args) {
#define set_char_doc "set_char(at, ch, width=1, cursor=None) -> Set the character at the specified cell. If cursor is not None, also set attributes from that cursor."
unsigned int at, width=1;
int ch;
Cursor *cursor = NULL;
if (!PyArg_ParseTuple(args, "IC|IO!", &at, &ch, &width, &Cursor_Type, &cursor)) return NULL;
if (at >= self->xnum) {
PyErr_SetString(PyExc_ValueError, "Out of bounds");
return NULL;
}
line_set_char(self, at, ch, width, cursor);
Py_RETURN_NONE;
}

View File

@ -18,7 +18,7 @@
right margin are lost. Otherwise, new display characters replace
old display characters at the cursor position.
*/
#define IRM
#define IRM 4
// Private modes.

View File

@ -8,24 +8,12 @@
#include "data-types.h"
#include "control-codes.h"
extern PyTypeObject Screen_Type;
#define NORMAL_STATE 0
#define ESC_STATE 1
#define CSI_STATE 2
#define OSC_STATE 3
#define DCS_STATE 4
#define DECLARE_CH_SCREEN_HANDLER(name) extern bool screen_##name(Screen *screen, uint8_t ch);
DECLARE_CH_SCREEN_HANDLER(bell)
DECLARE_CH_SCREEN_HANDLER(backspace)
DECLARE_CH_SCREEN_HANDLER(tab)
DECLARE_CH_SCREEN_HANDLER(linefeed)
DECLARE_CH_SCREEN_HANDLER(carriage_return)
DECLARE_CH_SCREEN_HANDLER(shift_out)
DECLARE_CH_SCREEN_HANDLER(shift_in)
extern bool screen_draw(Screen *screen, uint8_t *buf, unsigned int buflen);
// Parse text {{{
static inline bool
read_text(Screen *screen, uint8_t *buf, unsigned int buflen, unsigned int *pos) {

47
kitty/savepoints.c Normal file
View File

@ -0,0 +1,47 @@
/*
* savepoints.c
* Copyright (C) 2016 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#include "data-types.h"
static PyObject *
new(PyTypeObject *type, PyObject UNUSED *args, PyObject UNUSED *kwds) {
Savepoint *self;
self = (Savepoint *)type->tp_alloc(type, 0);
return (PyObject*) self;
}
static void
dealloc(Savepoint* self) {
Py_TYPE(self)->tp_free((PyObject*)self);
}
// Boilerplate {{{
static PyMethodDef methods[] = {
{NULL} /* Sentinel */
};
PyTypeObject Savepoint_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "fast_data_types.Savepoint",
.tp_basicsize = sizeof(Savepoint),
.tp_dealloc = (destructor)dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_doc = "Savepoint",
.tp_methods = methods,
.tp_new = new,
};
INIT_TYPE(Savepoint)
Savepoint *alloc_savepoint() {
return (Savepoint*)new(&Savepoint_Type, NULL, NULL);
}
// }}}

View File

@ -6,19 +6,27 @@
*/
#include "data-types.h"
#include <structmember.h>
#include "unicode-data.h"
#include "tracker.h"
#include "modes.h"
static const ScreenModes empty_modes = {0};
static const ScreenModes empty_modes = {0, .mDECAWM=true, .mDECTCEM=true};
// Constructor/destructor {{{
static PyObject*
new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
Screen *self;
PyObject *callbacks = Py_None;
if (!PyArg_ParseTuple(args, "|O", &callbacks)) return NULL;
unsigned int columns, lines;
if (!PyArg_ParseTuple(args, "|OII", &callbacks, &lines, &columns)) return NULL;
self = (Screen *)type->tp_alloc(type, 0);
if (self != NULL) {
self->current_charset = 2;
self->columns = 80; self->lines=24;
self->g0_charset = translation_table('B');
self->g1_charset = translation_table('0');
self->columns = columns; self->lines = lines;
self->modes = empty_modes;
self->utf8_state = 0;
self->margin_top = 0; self->margin_bottom = self->lines - 1;
@ -42,60 +50,349 @@ dealloc(Screen* self) {
Py_CLEAR(self->cursor); Py_CLEAR(self->main_linebuf); Py_CLEAR(self->alt_linebuf);
Py_CLEAR(self->main_savepoints); Py_CLEAR(self->alt_savepoints); Py_CLEAR(self->change_tracker);
Py_TYPE(self)->tp_free((PyObject*)self);
}
} // }}}
bool screen_bell(Screen UNUSED *scr, uint8_t ch) {
bool screen_bell(Screen UNUSED *self, uint8_t ch) { // {{{
FILE *f = fopen("/dev/tty", "w");
if (f != NULL) {
fwrite(&ch, 1, 1, f);
fclose(f);
}
return true;
}
} // }}}
bool screen_draw(Screen UNUSED *scr, uint8_t UNUSED ch) {
bool screen_linefeed(Screen UNUSED *self, uint8_t UNUSED ch) {
// TODO: Implement this
return true;
}
bool screen_backspace(Screen UNUSED *scr, uint8_t UNUSED ch) {
// TODO: Implement this
return true;
}
bool screen_tab(Screen UNUSED *scr, uint8_t UNUSED ch) {
bool screen_carriage_return(Screen UNUSED *self, uint8_t UNUSED ch) {
// TODO: Implement this
return true;
}
bool screen_linefeed(Screen UNUSED *scr, uint8_t UNUSED ch) {
// Draw text {{{
static inline int safe_wcwidth(uint32_t ch) {
int ans = wcwidth(ch);
if (ans < 0) ans = 1;
return MIN(2, ans);
}
static inline bool
draw_codepoint(Screen UNUSED *self, uint32_t ch) {
if (is_ignored_char(ch)) return true;
int char_width = safe_wcwidth(ch);
int space_left_in_line = self->columns - self->cursor->x;
if (space_left_in_line < char_width) {
if (self->modes.mDECAWM) {
if (!screen_carriage_return(self, 13)) return false;
if (!screen_linefeed(self, 10)) return false;
self->linebuf->continued_map[self->cursor->y] = true;
} else {
self->cursor->x = self->columns - char_width;
}
}
if (char_width > 0) {
unsigned int cx = self->cursor->x;
linebuf_init_line(self->linebuf, self->cursor->y);
if (self->modes.mIRM) {
line_right_shift(self->linebuf->line, self->cursor->x, char_width);
}
line_set_char(self->linebuf->line, self->cursor->x, ch, char_width, self->cursor);
self->cursor->x++;
if (char_width == 2) {
line_set_char(self->linebuf->line, self->cursor->x, 0, 0, self->cursor);
self->cursor->x++;
}
unsigned int right = self->modes.mIRM ? self->columns - 1 : MIN((unsigned int)(MAX(self->cursor->x, 1) - 1), self->columns - 1);
tracker_update_cell_range(self->change_tracker, self->cursor->y, cx, right);
} else if (is_combining_char(ch)) {
if (self->cursor->x > 0) {
linebuf_init_line(self->linebuf, self->cursor->y);
line_add_combining_char(self->linebuf->line, ch, self->cursor->x - 1);
tracker_update_cell_range(self->change_tracker, self->cursor->y, self->cursor->x - 1, self->cursor->x - 1);
} else if (self->cursor->y > 0) {
linebuf_init_line(self->linebuf, self->cursor->y - 1);
line_add_combining_char(self->linebuf->line, ch, self->columns - 1);
tracker_update_cell_range(self->change_tracker, self->cursor->y - 1, self->columns - 1, self->columns - 1);
}
}
return true;
}
static inline bool
screen_draw_utf8(Screen *self, uint8_t *buf, unsigned int buflen) {
uint32_t prev = UTF8_ACCEPT, codepoint = 0;
for (unsigned int i = 0; i < buflen; i++, prev = self->utf8_state) {
switch (decode_utf8(&self->utf8_state, &codepoint, buf[i])) {
case UTF8_ACCEPT:
if (!draw_codepoint(self, codepoint)) return false;
break;
case UTF8_REJECT:
self->utf8_state = UTF8_ACCEPT;
if (prev != UTF8_ACCEPT) i--;
break;
}
}
return true;
}
static inline bool
screen_draw_charset(Screen *self, unsigned short *table, uint8_t *buf, unsigned int buflen) {
for (unsigned int i = 0; i < buflen; i++) {
if (!draw_codepoint(self, table[buf[i]])) return false;
}
return true;
}
bool screen_draw(Screen *self, uint8_t *buf, unsigned int buflen) {
switch(self->current_charset) {
case 0:
return screen_draw_charset(self, self->g0_charset, buf, buflen);
break;
case 1:
return screen_draw_charset(self, self->g1_charset, buf, buflen);
break;
default:
return screen_draw_utf8(self, buf, buflen); break;
}
}
// }}}
bool screen_backspace(Screen UNUSED *self, uint8_t UNUSED ch) {
// TODO: Implement this
return true;
}
bool screen_carriage_return(Screen UNUSED *scr, uint8_t UNUSED ch) {
bool screen_tab(Screen UNUSED *self, uint8_t UNUSED ch) {
// TODO: Implement this
return true;
}
bool screen_shift_out(Screen UNUSED *scr, uint8_t UNUSED ch) {
bool screen_shift_out(Screen UNUSED *self, uint8_t UNUSED ch) {
// TODO: Implement this
return true;
}
bool screen_shift_in(Screen UNUSED *scr, uint8_t UNUSED ch) {
bool screen_shift_in(Screen UNUSED *self, uint8_t UNUSED ch) {
// TODO: Implement this
return true;
}
bool screen_toggle_screen_buffer(Screen *self) {
if (!screen_save_cursor(self)) return false;
if (self->linebuf == self->main_linebuf) {
self->linebuf = self->alt_linebuf;
self->savepoints = self->alt_savepoints;
} else {
self->linebuf = self->main_linebuf;
self->savepoints = self->main_savepoints;
}
screen_restore_cursor(self);
tracker_update_screen(self->change_tracker);
return true;
}
// Modes {{{
static inline void set_mode_from_const(Screen *self, int mode, bool val) {
switch(mode) {
case LNM:
self->modes.mLNM = val; break;
case IRM:
self->modes.mIRM = val; break;
case DECTCEM:
self->modes.mDECTCEM = val; break;
case DECSCNM:
self->modes.mDECSCNM = val; break;
case DECOM:
self->modes.mDECOM = val; break;
case DECAWM:
self->modes.mDECAWM = val; break;
case DECCOLM:
self->modes.mDECCOLM = val; break;
case BRACKETED_PASTE:
self->modes.mBRACKETED_PASTE = val; break;
case FOCUS_TRACKING:
self->modes.mFOCUS_TRACKING = val; break;
}
}
bool screen_set_mode(Screen *self, int mode) {
if (mode == DECCOLM) {
// When DECCOLM mode is set, the screen is erased and the cursor
// moves to the home position.
if (!screen_erase_in_display(self, 2, false)) return false;
if (!screen_cursor_position(self, 1, 1)) return false;
}
// According to `vttest`, DECOM should also home the cursor, see
// vttest/main.c:303.
if (mode == DECOM) { if (!screen_cursor_position(self, 1, 1)) return false; }
if (mode == DECSCNM) {
// Mark all displayed characters as reverse.
linebuf_set_attribute(self->linebuf, REVERSE_SHIFT, 1);
tracker_update_screen(self->change_tracker);
self->cursor->reverse = true;
tracker_cursor_changed(self->change_tracker);
}
if (mode == DECTCEM && self->cursor->hidden) {
self->cursor->hidden = false;
tracker_cursor_changed(self->change_tracker);
}
if (mode == ALTERNATE_SCREEN && self->linebuf == self->main_linebuf) {
if (!screen_toggle_screen_buffer(self)) return false;
}
set_mode_from_const(self, mode, true);
return true;
}
static PyObject*
in_bracketed_paste_mode(Screen *self) {
#define in_bracketed_paste_mode_doc ""
PyObject *ans = self->modes.mBRACKETED_PASTE ? Py_True : Py_False;
Py_INCREF(ans);
return ans;
}
static PyObject*
enable_focus_tracking(Screen *self) {
#define enable_focus_tracking_doc ""
PyObject *ans = self->modes.mFOCUS_TRACKING ? Py_True : Py_False;
Py_INCREF(ans);
return ans;
}
bool screen_reset_mode(Screen *self, int mode) {
if (mode == DECCOLM) {
// When DECCOLM mode is set, the screen is erased and the cursor
// moves to the home position.
if (!screen_erase_in_display(self, 2, false)) return false;
if (!screen_cursor_position(self, 1, 1)) return false;
}
// According to `vttest`, DECOM should also home the cursor, see
// vttest/main.c:303.
if (mode == DECOM) { if (!screen_cursor_position(self, 1, 1)) return false; }
if (mode == DECSCNM) {
// Mark all displayed characters as reverse.
linebuf_set_attribute(self->linebuf, REVERSE_SHIFT, 0);
tracker_update_screen(self->change_tracker);
self->cursor->reverse = false;
tracker_cursor_changed(self->change_tracker);
}
if (mode == DECTCEM && !self->cursor->hidden) {
self->cursor->hidden = true;
tracker_cursor_changed(self->change_tracker);
}
if (mode == ALTERNATE_SCREEN && self->linebuf != self->main_linebuf) {
if (!screen_toggle_screen_buffer(self)) return false;
}
set_mode_from_const(self, mode, false);
return true;
}
// }}}
// Cursor {{{
bool screen_save_cursor(Screen *self) {
Savepoint *sp = alloc_savepoint();
if (sp == NULL) return false;
sp->cursor = cursor_copy(self->cursor);
if (sp->cursor == NULL) { Py_CLEAR(sp); return NULL; }
sp->g0_charset = self->g0_charset;
sp->g1_charset = self->g1_charset;
sp->current_charset = self->current_charset;
sp->mDECOM = self->modes.mDECOM;
sp->mDECAWM = self->modes.mDECAWM;
sp->utf8_state = self->utf8_state;
bool ret = PyList_Append(self->savepoints, (PyObject*)sp) == 0;
Py_CLEAR(sp);
return ret;
}
bool screen_restore_cursor(Screen *self) {
Py_ssize_t sz = PyList_GET_SIZE(self->savepoints);
if (sz > 0) {
Savepoint *sp = (Savepoint*)PyList_GET_ITEM(self->savepoints, sz - 1);
self->g0_charset = sp->g0_charset;
self->g1_charset = sp->g1_charset;
self->current_charset = sp->current_charset;
self->utf8_state = sp->utf8_state;
if (sp->mDECOM) screen_set_mode(self, DECOM);
if (sp->mDECAWM) screen_set_mode(self, DECAWM);
PyList_SetSlice(self->savepoints, sz-1, sz, NULL);
} else {
screen_cursor_position(self, 1, 1);
tracker_cursor_changed(self->change_tracker);
screen_reset_mode(self, DECOM);
}
return true;
}
bool screen_cursor_position(Screen UNUSED *self, unsigned int UNUSED line, unsigned int UNUSED column) {
return true; // TODO: Implement this
}
// }}}
// Editing {{{
bool screen_erase_in_display(Screen UNUSED *self, unsigned int UNUSED how, bool UNUSED private) {
return true; // TODO: Implement this
}
// }}}
bool screen_reset(Screen *self) {
if (self->linebuf == self->alt_linebuf) {if (!screen_toggle_screen_buffer(self)) return false; }
linebuf_clear(self->linebuf);
// TODO: Implement this
return true;
}
static PyObject*
line(Screen *self, PyObject *val) {
#define line_doc ""
unsigned long y = PyLong_AsUnsignedLong(val);
if (y >= self->lines) { PyErr_SetString(PyExc_IndexError, "Out of bounds"); return NULL; }
linebuf_init_line(self->linebuf, y);
Py_INCREF(self->linebuf->line);
return (PyObject*) self->linebuf->line;
}
static PyObject*
draw(Screen *self, PyObject *args) {
#define draw_doc ""
Py_buffer pybuf;
if(!PyArg_ParseTuple(args, "y*", &pybuf)) return NULL;
if (!screen_draw(self, pybuf.buf, pybuf.len)) return NULL;
Py_RETURN_NONE;
}
// Boilerplate {{{
static PyMethodDef methods[] = {
METHOD(line, METH_O)
METHOD(draw, METH_VARARGS)
METHOD(enable_focus_tracking, METH_NOARGS)
METHOD(in_bracketed_paste_mode, METH_NOARGS)
{NULL} /* Sentinel */
};
static PyMemberDef members[] = {
{"cursor", T_OBJECT_EX, offsetof(Screen, cursor), 0, "cursor"},
{"linebuf", T_OBJECT_EX, offsetof(Screen, linebuf), 0, "linebuf"},
{NULL}
};
PyTypeObject Screen_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "fast_data_types.Screen",
@ -104,6 +401,7 @@ PyTypeObject Screen_Type = {
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_doc = "Screen",
.tp_methods = methods,
.tp_members = members,
.tp_new = new,
};

View File

@ -11,7 +11,7 @@ from typing import Sequence
from pyte import charsets as cs, graphics as g, modes as mo
from .utils import wcwidth, is_simple_string, sanitize_title
from .unicode import ignore_pat
from .fast_data_types import LineBuf, REVERSE, Cursor, ChangeTracker
from .fast_data_types import LineBuf, REVERSE, Cursor, ChangeTracker, CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE
#: A container for screen's scroll margins.
@ -251,11 +251,9 @@ class Screen:
if mo.ALTERNATE_SCREEN in self.mode and self.linebuf is self.main_linebuf:
self.toggle_screen_buffer()
@property
def in_bracketed_paste_mode(self):
return mo.BRACKETED_PASTE in self.mode
@property
def enable_focus_tracking(self):
return mo.FOCUS_TRACKING in self.mode
@ -302,7 +300,6 @@ class Screen:
from ``b"B0UK"``, otherwise ignored.
:param str mode: if ``"("`` ``G0`` charset is defined, if
``")"`` -- we operate on ``G1``.
.. warning:: User-defined charsets are currently not supported.
"""
if code in cs.MAPS:
@ -984,7 +981,7 @@ class Screen:
shape = blink = None
if mode > 0:
blink = bool(mode % 2)
shape = 'block' if mode < 3 else 'underline' if mode < 5 else 'beam' if mode < 7 else None
shape = CURSOR_BLOCK if mode < 3 else CURSOR_UNDERLINE if mode < 5 else CURSOR_BEAM if mode < 7 else None
if shape != self.cursor.shape or blink != self.cursor.blink:
self.cursor.shape, self.cursor.blink = shape, blink
self.cursor_changed()

View File

@ -7,10 +7,6 @@
#include "data-types.h"
#include <structmember.h>
extern PyTypeObject Line_Type;
extern PyTypeObject ColorProfile_Type;
extern uint32_t to_color(ColorProfile *, uint32_t, uint32_t);
extern PyObject* line_text_at(char_type, combining_type);
static PyObject*
new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {

View File

@ -7,11 +7,6 @@
#include "data-types.h"
#include "tracker.h"
extern PyTypeObject SpriteMap_Type;
extern PyTypeObject ColorProfile_Type;
extern PyTypeObject LineBuf_Type;
extern bool update_cell_range_data(SpriteMap *, Line *, unsigned int, unsigned int, ColorProfile *, const uint32_t, const uint32_t, unsigned int *);
extern void linebuf_init_line(LineBuf *, index_type);
#define RESET_STATE_VARS(self) \
self->screen_changed = false; self->cursor_changed = false; self->dirty = false; self->history_line_added_count = 0;
@ -273,7 +268,7 @@ static PyMethodDef methods[] = {
};
static PyTypeObject ChangeTracker_Type = {
PyTypeObject ChangeTracker_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "fast_data_types.ChangeTracker",
.tp_basicsize = sizeof(ChangeTracker),

11
kitty/unicode-data.h Normal file

File diff suppressed because one or more lines are too long

View File

@ -4,8 +4,8 @@
from unittest import TestCase
from kitty.screen import Screen
from kitty.fast_data_types import LineBuf, Cursor
from kitty.screen import Screen as S
from kitty.fast_data_types import LineBuf, Cursor, Screen
def filled_line_buf(ynum=5, xnum=5, cursor=Cursor()):
@ -31,8 +31,10 @@ class BaseTest(TestCase):
ae = TestCase.assertEqual
def create_screen(self, cols=5, lines=5, history_size=5):
s = Screen(history_size, columns=cols, lines=lines)
return s
return S(history_size, columns=cols, lines=lines)
def create_screen2(self, cols=5, lines=5, history_size=5):
return Screen(history_size, None, lines, cols)
def assertEqualAttributes(self, c1, c2):
x1, y1, c1.x, c1.y = c1.x, c1.y, 0, 0