More work on native streams
This commit is contained in:
parent
62fc6cc4a0
commit
fab2213c25
57
generate-unicode-data.py
Normal file
57
generate-unicode-data.py
Normal 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
|
||||||
@ -97,10 +97,10 @@ class Boss(Thread):
|
|||||||
|
|
||||||
def on_focus(self, window, focused):
|
def on_focus(self, window, focused):
|
||||||
if focused:
|
if focused:
|
||||||
if self.screen.enable_focus_tracking:
|
if self.screen.enable_focus_tracking():
|
||||||
self.write_to_child(b'\x1b[I')
|
self.write_to_child(b'\x1b[I')
|
||||||
else:
|
else:
|
||||||
if self.screen.enable_focus_tracking:
|
if self.screen.enable_focus_tracking():
|
||||||
self.write_to_child(b'\x1b[O')
|
self.write_to_child(b'\x1b[O')
|
||||||
|
|
||||||
def on_mouse_button(self, window, button, action, mods):
|
def on_mouse_button(self, window, button, action, mods):
|
||||||
@ -110,7 +110,7 @@ class Boss(Thread):
|
|||||||
# text = glfw.glfwGetClipboardString(window)
|
# text = glfw.glfwGetClipboardString(window)
|
||||||
text = subprocess.check_output(['xsel'])
|
text = subprocess.check_output(['xsel'])
|
||||||
if text:
|
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')
|
text = BRACKETED_PASTE_START.encode('ascii') + text + BRACKETED_PASTE_END.encode('ascii')
|
||||||
self.write_to_child(text)
|
self.write_to_child(text)
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,8 @@ from .fast_data_types import (
|
|||||||
glBlendFunc, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, glClear,
|
glBlendFunc, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, glClear,
|
||||||
GL_COLOR_BUFFER_BIT, glClearColor, glViewport, glUniform2ui, glUniform4f,
|
GL_COLOR_BUFFER_BIT, glClearColor, glViewport, glUniform2ui, glUniform4f,
|
||||||
glUniform1i, glUniform2f, glDrawArraysInstanced, GL_TRIANGLE_FAN,
|
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')
|
Size = namedtuple('Size', 'width height')
|
||||||
@ -303,11 +304,11 @@ class CharGrid:
|
|||||||
col = cursor.color or self.default_cursor.color
|
col = cursor.color or self.default_cursor.color
|
||||||
shape = cursor.shape or self.default_cursor.shape
|
shape = cursor.shape or self.default_cursor.shape
|
||||||
alpha = self.opts.cursor_opacity
|
alpha = self.opts.cursor_opacity
|
||||||
if alpha < 1.0 and shape == 'block':
|
if alpha < 1.0 and shape == CURSOR_BLOCK:
|
||||||
glEnable(GL_BLEND)
|
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
|
bottom = top - sg.dy
|
||||||
if shape == 'underline':
|
if shape == CURSOR_UNDERLINE:
|
||||||
top = bottom + width(vert=False)
|
top = bottom + width(vert=False)
|
||||||
glUniform4f(ul('color'), col[0], col[1], col[2], alpha)
|
glUniform4f(ul('color'), col[0], col[1], col[2], alpha)
|
||||||
glUniform2f(ul('xpos'), left, right)
|
glUniform2f(ul('xpos'), left, right)
|
||||||
|
|||||||
@ -166,3 +166,33 @@ uint16_t* translation_table(char which) {
|
|||||||
}
|
}
|
||||||
return charset_translations[0];
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@ -63,7 +63,7 @@ new(PyTypeObject *type, PyObject UNUSED *args, PyObject UNUSED *kwds) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dealloc(Cursor* self) {
|
dealloc(ColorProfile* self) {
|
||||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import re
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from itertools import repeat
|
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+(.+)$')
|
key_pat = re.compile(r'([a-zA-Z][a-zA-Z0-9_-]*)\s+(.+)$')
|
||||||
# Color definitions {{{
|
# Color definitions {{{
|
||||||
@ -186,12 +187,14 @@ def to_font_size(x):
|
|||||||
return max(6, float(x))
|
return max(6, float(x))
|
||||||
|
|
||||||
|
|
||||||
|
cshapes = {'block': CURSOR_BLOCK, 'beam': CURSOR_BEAM, 'underline': CURSOR_UNDERLINE}
|
||||||
|
|
||||||
|
|
||||||
def to_cursor_shape(x):
|
def to_cursor_shape(x):
|
||||||
shapes = 'block underline beam'
|
try:
|
||||||
x = x.lower()
|
return cshapes[x.lower()]
|
||||||
if x not in shapes.split():
|
except KeyError:
|
||||||
raise ValueError('Invalid cursor shape: {} allowed values are {}'.format(x, shapes))
|
raise ValueError('Invalid cursor shape: {} allowed values are {}'.format(x, ', '.join(cshapes)))
|
||||||
return x
|
|
||||||
|
|
||||||
|
|
||||||
def to_bool(x):
|
def to_bool(x):
|
||||||
|
|||||||
@ -9,50 +9,30 @@
|
|||||||
|
|
||||||
#include <structmember.h>
|
#include <structmember.h>
|
||||||
|
|
||||||
#define INIT_NONE(x) Py_INCREF(Py_None); x = Py_None;
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
new(PyTypeObject *type, PyObject UNUSED *args, PyObject UNUSED *kwds) {
|
new(PyTypeObject *type, PyObject UNUSED *args, PyObject UNUSED *kwds) {
|
||||||
Cursor *self;
|
Cursor *self;
|
||||||
|
|
||||||
self = (Cursor *)type->tp_alloc(type, 0);
|
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;
|
return (PyObject*) self;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dealloc(Cursor* self) {
|
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);
|
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define EQ(x) (a->x == b->x)
|
#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) {
|
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)
|
#define BOOL(x) ((x) ? Py_True : Py_False)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
repr(Cursor *self) {
|
repr(Cursor *self) {
|
||||||
return PyUnicode_FromFormat(
|
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)",
|
"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, 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
|
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;
|
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*
|
static PyObject*
|
||||||
copy(Cursor *self, PyObject *args);
|
copy(Cursor *self);
|
||||||
#define copy_doc "Create a clone of this cursor"
|
#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 {{{
|
// Boilerplate {{{
|
||||||
|
|
||||||
BOOL_GETSET(Cursor, bold)
|
BOOL_GETSET(Cursor, bold)
|
||||||
BOOL_GETSET(Cursor, italic)
|
BOOL_GETSET(Cursor, italic)
|
||||||
BOOL_GETSET(Cursor, reverse)
|
BOOL_GETSET(Cursor, reverse)
|
||||||
BOOL_GETSET(Cursor, strikethrough)
|
BOOL_GETSET(Cursor, strikethrough)
|
||||||
|
BOOL_GETSET(Cursor, hidden)
|
||||||
|
BOOL_GETSET(Cursor, blink)
|
||||||
|
|
||||||
static PyMemberDef members[] = {
|
static PyMemberDef members[] = {
|
||||||
{"x", T_OBJECT_EX, offsetof(Cursor, x), 0, "x"},
|
{"x", T_INT, offsetof(Cursor, x), 0, "x"},
|
||||||
{"y", T_OBJECT_EX, offsetof(Cursor, y), 0, "y"},
|
{"y", T_INT, offsetof(Cursor, y), 0, "y"},
|
||||||
{"shape", T_OBJECT_EX, offsetof(Cursor, shape), 0, "shape"},
|
{"shape", T_UBYTE, offsetof(Cursor, shape), 0, "shape"},
|
||||||
{"blink", T_OBJECT_EX, offsetof(Cursor, blink), 0, "blink"},
|
{"color", T_ULONG, offsetof(Cursor, color), 0, "color"},
|
||||||
{"color", T_OBJECT_EX, offsetof(Cursor, color), 0, "color"},
|
|
||||||
{"hidden", T_OBJECT_EX, offsetof(Cursor, hidden), 0, "hidden"},
|
|
||||||
|
|
||||||
{"decoration", T_UBYTE, offsetof(Cursor, decoration), 0, "decoration"},
|
{"decoration", T_UBYTE, offsetof(Cursor, decoration), 0, "decoration"},
|
||||||
{"fg", T_UINT, offsetof(Cursor, fg), 0, "fg"},
|
{"fg", T_ULONG, offsetof(Cursor, fg), 0, "fg"},
|
||||||
{"bg", T_UINT, offsetof(Cursor, bg), 0, "bg"},
|
{"bg", T_ULONG, offsetof(Cursor, bg), 0, "bg"},
|
||||||
{"decoration_fg", T_UINT, offsetof(Cursor, decoration_fg), 0, "decoration_fg"},
|
{"decoration_fg", T_ULONG, offsetof(Cursor, decoration_fg), 0, "decoration_fg"},
|
||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -95,6 +85,9 @@ static PyGetSetDef getseters[] = {
|
|||||||
GETSET(italic)
|
GETSET(italic)
|
||||||
GETSET(reverse)
|
GETSET(reverse)
|
||||||
GETSET(strikethrough)
|
GETSET(strikethrough)
|
||||||
|
GETSET(hidden)
|
||||||
|
GETSET(blink)
|
||||||
|
{"color", (getter) color_get, NULL, "color", NULL},
|
||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -127,16 +120,20 @@ RICHCMP(Cursor)
|
|||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
static PyObject*
|
Cursor*
|
||||||
copy(Cursor *self, PyObject UNUSED *args) {
|
cursor_copy(Cursor *self) {
|
||||||
#define CPY(x) ans->x = self->x; Py_XINCREF(self->x);
|
|
||||||
#define CCY(x) ans->x = self->x;
|
#define CCY(x) ans->x = self->x;
|
||||||
Cursor* ans;
|
Cursor* ans;
|
||||||
ans = alloc_cursor();
|
ans = alloc_cursor();
|
||||||
if (ans == NULL) { PyErr_NoMemory(); return NULL; }
|
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);
|
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() {
|
Cursor *alloc_cursor() {
|
||||||
|
|||||||
@ -6,16 +6,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "data-types.h"
|
#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 "gl.h"
|
||||||
#include "modes.h"
|
#include "modes.h"
|
||||||
|
|
||||||
@ -58,6 +48,9 @@ PyInit_fast_data_types(void) {
|
|||||||
PyModule_AddIntConstant(m, "DECORATION", DECORATION_SHIFT);
|
PyModule_AddIntConstant(m, "DECORATION", DECORATION_SHIFT);
|
||||||
PyModule_AddStringMacro(m, BRACKETED_PASTE_START);
|
PyModule_AddStringMacro(m, BRACKETED_PASTE_START);
|
||||||
PyModule_AddStringMacro(m, BRACKETED_PASTE_END);
|
PyModule_AddStringMacro(m, BRACKETED_PASTE_END);
|
||||||
|
PyModule_AddIntMacro(m, CURSOR_BLOCK);
|
||||||
|
PyModule_AddIntMacro(m, CURSOR_BEAM);
|
||||||
|
PyModule_AddIntMacro(m, CURSOR_UNDERLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
|
|||||||
@ -37,6 +37,12 @@ typedef unsigned int index_type;
|
|||||||
#define HAS_BG_MASK (0xFF << COL_SHIFT)
|
#define HAS_BG_MASK (0xFF << COL_SHIFT)
|
||||||
#define CC_MASK 0xFFFF
|
#define CC_MASK 0xFFFF
|
||||||
#define CC_SHIFT 16
|
#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) \
|
#define CURSOR_TO_ATTRS(c, w) \
|
||||||
((w) | (((c->decoration & 3) << DECORATION_SHIFT) | ((c->bold & 1) << BOLD_SHIFT) | \
|
((w) | (((c->decoration & 3) << DECORATION_SHIFT) | ((c->bold & 1) << BOLD_SHIFT) | \
|
||||||
@ -119,6 +125,7 @@ typedef struct {
|
|||||||
bool continued;
|
bool continued;
|
||||||
bool needs_free;
|
bool needs_free;
|
||||||
} Line;
|
} Line;
|
||||||
|
PyTypeObject Line_Type;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -136,17 +143,19 @@ typedef struct {
|
|||||||
decoration_type *decoration_fg;
|
decoration_type *decoration_fg;
|
||||||
combining_type *combining_chars;
|
combining_type *combining_chars;
|
||||||
} LineBuf;
|
} LineBuf;
|
||||||
|
PyTypeObject LineBuf_Type;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
|
|
||||||
PyObject *x, *y, *shape, *blink, *hidden, *color;
|
bool bold, italic, reverse, strikethrough, blink, hidden;
|
||||||
bool bold, italic, reverse, strikethrough;
|
int x, y;
|
||||||
uint8_t decoration;
|
uint8_t decoration, shape;
|
||||||
uint32_t fg, bg, decoration_fg;
|
unsigned long fg, bg, decoration_fg, color;
|
||||||
|
|
||||||
} Cursor;
|
} Cursor;
|
||||||
|
PyTypeObject Cursor_Type;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -156,6 +165,7 @@ typedef struct {
|
|||||||
uint32_t ansi_color_table[120];
|
uint32_t ansi_color_table[120];
|
||||||
|
|
||||||
} ColorProfile;
|
} ColorProfile;
|
||||||
|
PyTypeObject ColorProfile_Type;
|
||||||
|
|
||||||
typedef struct SpritePosition SpritePosition;
|
typedef struct SpritePosition SpritePosition;
|
||||||
struct SpritePosition {
|
struct SpritePosition {
|
||||||
@ -167,6 +177,7 @@ struct SpritePosition {
|
|||||||
bool filled;
|
bool filled;
|
||||||
bool rendered;
|
bool rendered;
|
||||||
};
|
};
|
||||||
|
PyTypeObject SpritePosition_Type;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
@ -177,6 +188,7 @@ typedef struct {
|
|||||||
bool dirty;
|
bool dirty;
|
||||||
|
|
||||||
} SpriteMap;
|
} SpriteMap;
|
||||||
|
PyTypeObject SpriteMap_Type;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
@ -190,12 +202,26 @@ typedef struct {
|
|||||||
bool *changed_cells;
|
bool *changed_cells;
|
||||||
unsigned int history_line_added_count;
|
unsigned int history_line_added_count;
|
||||||
} ChangeTracker;
|
} ChangeTracker;
|
||||||
|
PyTypeObject ChangeTracker_Type;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool LNM, IRM, DECTEM, DECSCNM, DECOM, DECAWM, DECCOLM;
|
bool mLNM, mIRM, mDECTCEM, mDECSCNM, mDECOM, mDECAWM, mDECCOLM, mBRACKETED_PASTE, mFOCUS_TRACKING;
|
||||||
} ScreenModes;
|
} 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 {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
@ -215,14 +241,56 @@ typedef struct {
|
|||||||
bool parser_has_pending_text;
|
bool parser_has_pending_text;
|
||||||
|
|
||||||
} Screen;
|
} Screen;
|
||||||
|
PyTypeObject Screen_Type;
|
||||||
|
|
||||||
Line* alloc_line();
|
Line* alloc_line();
|
||||||
Cursor* alloc_cursor();
|
Cursor* alloc_cursor();
|
||||||
LineBuf* alloc_linebuf();
|
LineBuf* alloc_linebuf();
|
||||||
ChangeTracker* alloc_change_tracker();
|
ChangeTracker* alloc_change_tracker();
|
||||||
|
Savepoint* alloc_savepoint();
|
||||||
|
|
||||||
#define left_shift_line(line, at, num) \
|
#define left_shift_line(line, at, num) \
|
||||||
for(index_type __i__ = (at); __i__ < (line)->xnum - (num); __i__++) { \
|
for(index_type __i__ = (at); __i__ < (line)->xnum - (num); __i__++) { \
|
||||||
COPY_CELL(line, __i__ + (num), line, __i__) \
|
COPY_CELL(line, __i__ + (num), line, __i__) \
|
||||||
} \
|
} \
|
||||||
if ((((line)->chars[(at)] >> ATTRS_SHIFT) & WIDTH_MASK) != 1) (line)->chars[(at)] = (1 << ATTRS_SHIFT) | 32;
|
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)
|
||||||
|
|||||||
@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
#include "data-types.h"
|
#include "data-types.h"
|
||||||
#include <structmember.h>
|
#include <structmember.h>
|
||||||
extern PyTypeObject Line_Type;
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
clear_chars_to_space(LineBuf* linebuf, index_type y) {
|
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;
|
for (index_type i = 0; i < linebuf->xnum; i++) chars[i] = (1 << ATTRS_SHIFT) | 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
void linebuf_clear(LineBuf *self) {
|
||||||
clear(LineBuf *self) {
|
|
||||||
#define clear_doc "Clear all lines in this LineBuf"
|
|
||||||
memset(self->buf, 0, self->block_size * CELL_SIZE);
|
memset(self->buf, 0, self->block_size * CELL_SIZE);
|
||||||
memset(self->continued_map, 0, self->ynum * sizeof(bool));
|
memset(self->continued_map, 0, self->ynum * sizeof(bool));
|
||||||
for (index_type i = 0; i < self->ynum; i++) {
|
for (index_type i = 0; i < self->ynum; i++) {
|
||||||
clear_chars_to_space(self, i);
|
clear_chars_to_space(self, i);
|
||||||
self->line_map[i] = 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;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,16 +113,20 @@ line(LineBuf *self, PyObject *y) {
|
|||||||
return (PyObject*)self->line;
|
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*
|
static PyObject*
|
||||||
set_attribute(LineBuf *self, PyObject *args) {
|
set_attribute(LineBuf *self, PyObject *args) {
|
||||||
#define set_attribute_doc "set_attribute(which, val) -> Set the attribute on all cells in the line."
|
#define set_attribute_doc "set_attribute(which, val) -> Set the attribute on all cells in the line."
|
||||||
unsigned int shift, val;
|
unsigned int shift, val;
|
||||||
char_type mask;
|
|
||||||
if (!PyArg_ParseTuple(args, "II", &shift, &val)) return NULL;
|
if (!PyArg_ParseTuple(args, "II", &shift, &val)) return NULL;
|
||||||
if (shift < DECORATION_SHIFT || shift > STRIKE_SHIFT) { PyErr_SetString(PyExc_ValueError, "Unknown attribute"); 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++) {
|
linebuf_set_attribute(self, shift, val);
|
||||||
SET_ATTRIBUTE(self->chars + y * self->xnum, shift, val);
|
|
||||||
}
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
73
kitty/line.c
73
kitty/line.c
@ -6,7 +6,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "data-types.h"
|
#include "data-types.h"
|
||||||
extern PyTypeObject Cursor_Type;
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
new(PyTypeObject UNUSED *type, PyObject UNUSED *args, PyObject UNUSED *kwds) {
|
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]);
|
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*
|
static PyObject*
|
||||||
add_combining_char(Line* self, PyObject *args) {
|
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."
|
#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");
|
PyErr_SetString(PyExc_ValueError, "Column index out of bounds");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
combining_type c = self->combining_chars[x];
|
line_add_combining_char(self, new_char, 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;
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +137,6 @@ set_text(Line* self, PyObject *args) {
|
|||||||
Cursor *cursor;
|
Cursor *cursor;
|
||||||
int kind;
|
int kind;
|
||||||
void *buf;
|
void *buf;
|
||||||
unsigned long x;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "UnnO!", &src, &offset, &sz, &Cursor_Type, &cursor)) return NULL;
|
if (!PyArg_ParseTuple(args, "UnnO!", &src, &offset, &sz, &Cursor_Type, &cursor)) return NULL;
|
||||||
if (PyUnicode_READY(src) != 0) {
|
if (PyUnicode_READY(src) != 0) {
|
||||||
@ -148,12 +150,11 @@ set_text(Line* self, PyObject *args) {
|
|||||||
PyErr_SetString(PyExc_ValueError, "Out of bounds offset/sz");
|
PyErr_SetString(PyExc_ValueError, "Out of bounds offset/sz");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
x = PyLong_AsUnsignedLong(cursor->x);
|
|
||||||
attrs = CURSOR_TO_ATTRS(cursor, 1);
|
attrs = CURSOR_TO_ATTRS(cursor, 1);
|
||||||
color_type col = (cursor->fg & COL_MASK) | ((color_type)(cursor->bg & COL_MASK) << COL_SHIFT);
|
color_type col = (cursor->fg & COL_MASK) | ((color_type)(cursor->bg & COL_MASK) << COL_SHIFT);
|
||||||
decoration_type dfg = cursor->decoration_fg & COL_MASK;
|
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->chars[i] = (PyUnicode_READ(kind, buf, offset) & CHAR_MASK) | attrs;
|
||||||
self->colors[i] = col;
|
self->colors[i] = col;
|
||||||
self->decoration_fg[i] = dfg;
|
self->decoration_fg[i] = dfg;
|
||||||
@ -166,23 +167,16 @@ set_text(Line* self, PyObject *args) {
|
|||||||
static PyObject*
|
static PyObject*
|
||||||
cursor_from(Line* self, PyObject *args) {
|
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."
|
#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;
|
unsigned int x, y = 0;
|
||||||
PyObject *xo, *yo;
|
|
||||||
Cursor* ans;
|
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) {
|
if (x >= self->xnum) {
|
||||||
PyErr_SetString(PyExc_ValueError, "Out of bounds x");
|
PyErr_SetString(PyExc_ValueError, "Out of bounds x");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ans = alloc_cursor();
|
ans = alloc_cursor();
|
||||||
if (ans == NULL) { PyErr_NoMemory(); return NULL; }
|
if (ans == NULL) { PyErr_NoMemory(); return NULL; }
|
||||||
xo = PyLong_FromUnsignedLong(x); yo = PyLong_FromUnsignedLong(y);
|
ans->x = x; ans->y = 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;
|
|
||||||
char_type attrs = self->chars[x] >> ATTRS_SHIFT;
|
char_type attrs = self->chars[x] >> ATTRS_SHIFT;
|
||||||
ATTRS_TO_CURSOR(attrs, ans);
|
ATTRS_TO_CURSOR(attrs, ans);
|
||||||
COLORS_TO_CURSOR(self->colors[x], ans);
|
COLORS_TO_CURSOR(self->colors[x], ans);
|
||||||
@ -228,6 +222,15 @@ apply_cursor(Line* self, PyObject *args) {
|
|||||||
Py_RETURN_NONE;
|
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*
|
static PyObject*
|
||||||
right_shift(Line *self, PyObject *args) {
|
right_shift(Line *self, PyObject *args) {
|
||||||
#define right_shift_doc "right_shift(at, num) -> ..."
|
#define right_shift_doc "right_shift(at, num) -> ..."
|
||||||
@ -238,12 +241,7 @@ right_shift(Line *self, PyObject *args) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (num > 0) {
|
if (num > 0) {
|
||||||
for(index_type i = self->xnum - 1; i >= at + num; i--) {
|
line_right_shift(self, at, num);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
@ -261,20 +259,8 @@ left_shift(Line *self, PyObject *args) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
void line_set_char(Line *self, unsigned int at, uint32_t ch, unsigned int width, Cursor *cursor) {
|
||||||
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;
|
|
||||||
char_type attrs;
|
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) {
|
if (cursor == NULL) {
|
||||||
attrs = (((self->chars[at] >> ATTRS_SHIFT) & ~3) | (width & 3)) << ATTRS_SHIFT;
|
attrs = (((self->chars[at] >> ATTRS_SHIFT) & ~3) | (width & 3)) << ATTRS_SHIFT;
|
||||||
} else {
|
} else {
|
||||||
@ -284,6 +270,21 @@ set_char(Line *self, PyObject *args) {
|
|||||||
}
|
}
|
||||||
self->chars[at] = (ch & CHAR_MASK) | attrs;
|
self->chars[at] = (ch & CHAR_MASK) | attrs;
|
||||||
self->combining_chars[at] = 0;
|
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;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
right margin are lost. Otherwise, new display characters replace
|
right margin are lost. Otherwise, new display characters replace
|
||||||
old display characters at the cursor position.
|
old display characters at the cursor position.
|
||||||
*/
|
*/
|
||||||
#define IRM
|
#define IRM 4
|
||||||
|
|
||||||
|
|
||||||
// Private modes.
|
// Private modes.
|
||||||
|
|||||||
@ -8,24 +8,12 @@
|
|||||||
#include "data-types.h"
|
#include "data-types.h"
|
||||||
#include "control-codes.h"
|
#include "control-codes.h"
|
||||||
|
|
||||||
extern PyTypeObject Screen_Type;
|
|
||||||
|
|
||||||
#define NORMAL_STATE 0
|
#define NORMAL_STATE 0
|
||||||
#define ESC_STATE 1
|
#define ESC_STATE 1
|
||||||
#define CSI_STATE 2
|
#define CSI_STATE 2
|
||||||
#define OSC_STATE 3
|
#define OSC_STATE 3
|
||||||
#define DCS_STATE 4
|
#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 {{{
|
// Parse text {{{
|
||||||
static inline bool
|
static inline bool
|
||||||
read_text(Screen *screen, uint8_t *buf, unsigned int buflen, unsigned int *pos) {
|
read_text(Screen *screen, uint8_t *buf, unsigned int buflen, unsigned int *pos) {
|
||||||
|
|||||||
47
kitty/savepoints.c
Normal file
47
kitty/savepoints.c
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
332
kitty/screen.c
332
kitty/screen.c
@ -6,19 +6,27 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "data-types.h"
|
#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*
|
static PyObject*
|
||||||
new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||||
Screen *self;
|
Screen *self;
|
||||||
PyObject *callbacks = Py_None;
|
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);
|
self = (Screen *)type->tp_alloc(type, 0);
|
||||||
if (self != NULL) {
|
if (self != NULL) {
|
||||||
self->current_charset = 2;
|
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->modes = empty_modes;
|
||||||
self->utf8_state = 0;
|
self->utf8_state = 0;
|
||||||
self->margin_top = 0; self->margin_bottom = self->lines - 1;
|
self->margin_top = 0; self->margin_bottom = self->lines - 1;
|
||||||
@ -42,59 +50,348 @@ dealloc(Screen* self) {
|
|||||||
Py_CLEAR(self->cursor); Py_CLEAR(self->main_linebuf); Py_CLEAR(self->alt_linebuf);
|
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_CLEAR(self->main_savepoints); Py_CLEAR(self->alt_savepoints); Py_CLEAR(self->change_tracker);
|
||||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
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");
|
FILE *f = fopen("/dev/tty", "w");
|
||||||
if (f != NULL) {
|
if (f != NULL) {
|
||||||
fwrite(&ch, 1, 1, f);
|
fwrite(&ch, 1, 1, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
return true;
|
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
|
// TODO: Implement this
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool screen_backspace(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_tab(Screen UNUSED *scr, uint8_t UNUSED ch) {
|
|
||||||
// TODO: Implement this
|
// TODO: Implement this
|
||||||
return true;
|
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
|
// TODO: Implement this
|
||||||
return true;
|
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
|
// TODO: Implement this
|
||||||
return true;
|
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
|
// TODO: Implement this
|
||||||
return true;
|
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
|
// TODO: Implement this
|
||||||
return true;
|
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 {{{
|
// Boilerplate {{{
|
||||||
|
|
||||||
static PyMethodDef methods[] = {
|
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 */
|
{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 = {
|
PyTypeObject Screen_Type = {
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
PyVarObject_HEAD_INIT(NULL, 0)
|
||||||
@ -104,6 +401,7 @@ PyTypeObject Screen_Type = {
|
|||||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||||
.tp_doc = "Screen",
|
.tp_doc = "Screen",
|
||||||
.tp_methods = methods,
|
.tp_methods = methods,
|
||||||
|
.tp_members = members,
|
||||||
.tp_new = new,
|
.tp_new = new,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,7 @@ from typing import Sequence
|
|||||||
from pyte import charsets as cs, graphics as g, modes as mo
|
from pyte import charsets as cs, graphics as g, modes as mo
|
||||||
from .utils import wcwidth, is_simple_string, sanitize_title
|
from .utils import wcwidth, is_simple_string, sanitize_title
|
||||||
from .unicode import ignore_pat
|
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.
|
#: 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:
|
if mo.ALTERNATE_SCREEN in self.mode and self.linebuf is self.main_linebuf:
|
||||||
self.toggle_screen_buffer()
|
self.toggle_screen_buffer()
|
||||||
|
|
||||||
@property
|
|
||||||
def in_bracketed_paste_mode(self):
|
def in_bracketed_paste_mode(self):
|
||||||
return mo.BRACKETED_PASTE in self.mode
|
return mo.BRACKETED_PASTE in self.mode
|
||||||
|
|
||||||
@property
|
|
||||||
def enable_focus_tracking(self):
|
def enable_focus_tracking(self):
|
||||||
return mo.FOCUS_TRACKING in self.mode
|
return mo.FOCUS_TRACKING in self.mode
|
||||||
|
|
||||||
@ -302,7 +300,6 @@ class Screen:
|
|||||||
from ``b"B0UK"``, otherwise ignored.
|
from ``b"B0UK"``, otherwise ignored.
|
||||||
:param str mode: if ``"("`` ``G0`` charset is defined, if
|
:param str mode: if ``"("`` ``G0`` charset is defined, if
|
||||||
``")"`` -- we operate on ``G1``.
|
``")"`` -- we operate on ``G1``.
|
||||||
|
|
||||||
.. warning:: User-defined charsets are currently not supported.
|
.. warning:: User-defined charsets are currently not supported.
|
||||||
"""
|
"""
|
||||||
if code in cs.MAPS:
|
if code in cs.MAPS:
|
||||||
@ -984,7 +981,7 @@ class Screen:
|
|||||||
shape = blink = None
|
shape = blink = None
|
||||||
if mode > 0:
|
if mode > 0:
|
||||||
blink = bool(mode % 2)
|
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:
|
if shape != self.cursor.shape or blink != self.cursor.blink:
|
||||||
self.cursor.shape, self.cursor.blink = shape, blink
|
self.cursor.shape, self.cursor.blink = shape, blink
|
||||||
self.cursor_changed()
|
self.cursor_changed()
|
||||||
|
|||||||
@ -7,10 +7,6 @@
|
|||||||
|
|
||||||
#include "data-types.h"
|
#include "data-types.h"
|
||||||
#include <structmember.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*
|
static PyObject*
|
||||||
new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||||
|
|||||||
@ -7,11 +7,6 @@
|
|||||||
|
|
||||||
#include "data-types.h"
|
#include "data-types.h"
|
||||||
#include "tracker.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) \
|
#define RESET_STATE_VARS(self) \
|
||||||
self->screen_changed = false; self->cursor_changed = false; self->dirty = false; self->history_line_added_count = 0;
|
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)
|
PyVarObject_HEAD_INIT(NULL, 0)
|
||||||
.tp_name = "fast_data_types.ChangeTracker",
|
.tp_name = "fast_data_types.ChangeTracker",
|
||||||
.tp_basicsize = sizeof(ChangeTracker),
|
.tp_basicsize = sizeof(ChangeTracker),
|
||||||
|
|||||||
11
kitty/unicode-data.h
Normal file
11
kitty/unicode-data.h
Normal file
File diff suppressed because one or more lines are too long
@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
from kitty.screen import Screen
|
from kitty.screen import Screen as S
|
||||||
from kitty.fast_data_types import LineBuf, Cursor
|
from kitty.fast_data_types import LineBuf, Cursor, Screen
|
||||||
|
|
||||||
|
|
||||||
def filled_line_buf(ynum=5, xnum=5, cursor=Cursor()):
|
def filled_line_buf(ynum=5, xnum=5, cursor=Cursor()):
|
||||||
@ -31,8 +31,10 @@ class BaseTest(TestCase):
|
|||||||
ae = TestCase.assertEqual
|
ae = TestCase.assertEqual
|
||||||
|
|
||||||
def create_screen(self, cols=5, lines=5, history_size=5):
|
def create_screen(self, cols=5, lines=5, history_size=5):
|
||||||
s = Screen(history_size, columns=cols, lines=lines)
|
return S(history_size, columns=cols, lines=lines)
|
||||||
return s
|
|
||||||
|
def create_screen2(self, cols=5, lines=5, history_size=5):
|
||||||
|
return Screen(history_size, None, lines, cols)
|
||||||
|
|
||||||
def assertEqualAttributes(self, c1, c2):
|
def assertEqualAttributes(self, c1, c2):
|
||||||
x1, y1, c1.x, c1.y = c1.x, c1.y, 0, 0
|
x1, y1, c1.x, c1.y = c1.x, c1.y, 0, 0
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user