Use a union for cell attributes
Cleaner code, no performance impact
This commit is contained in:
@@ -138,12 +138,9 @@ END_ALLOW_CASE_RANGE
|
||||
void
|
||||
apply_sgr_to_cells(GPUCell *first_cell, unsigned int cell_count, int *params, unsigned int count) {
|
||||
#define RANGE for(unsigned c = 0; c < cell_count; c++, cell++)
|
||||
#define SET(shift) RANGE { cell->attrs |= (1 << shift); } break;
|
||||
#define RESET(shift) RANGE { cell->attrs &= ~(1 << shift); } break;
|
||||
#define RESET2(shift1, shift2) RANGE { cell->attrs &= ~((1 << shift1) | (1 << shift2)); } break;
|
||||
#define SETM(val, mask, shift) { RANGE { cell->attrs &= ~(mask << shift); cell->attrs |= ((val) << shift); } break; }
|
||||
#define SET_COLOR(which) { color_type color = 0; parse_color(params, &i, count, &color); if (color) { RANGE { cell->which = color; }} } break;
|
||||
#define SIMPLE(which, val) RANGE { cell->which = (val); } break;
|
||||
#define S(which, val) RANGE { cell->attrs.bits.which = (val); } break;
|
||||
|
||||
unsigned int i = 0, attr;
|
||||
if (!count) { params[0] = 0; count = 1; }
|
||||
@@ -151,34 +148,38 @@ apply_sgr_to_cells(GPUCell *first_cell, unsigned int cell_count, int *params, un
|
||||
GPUCell *cell = first_cell;
|
||||
attr = params[i++];
|
||||
switch(attr) {
|
||||
case 0:
|
||||
RANGE { cell->attrs &= WIDTH_MASK; cell->fg = 0; cell->bg = 0; cell->decoration_fg = 0; }
|
||||
case 0: {
|
||||
const CellAttrs remove_sgr_mask = {.val=~SGR_MASK};
|
||||
RANGE { cell->attrs.val &= remove_sgr_mask.val; cell->fg = 0; cell->bg = 0; cell->decoration_fg = 0; }
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
SET(BOLD_SHIFT);
|
||||
S(bold, true);
|
||||
case 2:
|
||||
SET(DIM_SHIFT);
|
||||
S(dim, true);
|
||||
case 3:
|
||||
SET(ITALIC_SHIFT);
|
||||
case 4:
|
||||
if (i < count) { uint8_t val = MIN(3, params[i]); i++; SETM(val, DECORATION_MASK, DECORATION_SHIFT); }
|
||||
else { SETM(1, DECORATION_MASK, DECORATION_SHIFT); }
|
||||
S(italic, true);
|
||||
case 4: {
|
||||
uint8_t val = 1;
|
||||
if (i < count) { val = MIN(3, params[i]); i++; }
|
||||
S(decoration, val);
|
||||
}
|
||||
case 7:
|
||||
SET(REVERSE_SHIFT);
|
||||
S(reverse, true);
|
||||
case 9:
|
||||
SET(STRIKE_SHIFT);
|
||||
S(strike, true);
|
||||
case 21:
|
||||
SETM(2, DECORATION_MASK, DECORATION_SHIFT);
|
||||
S(decoration, 2);
|
||||
case 22:
|
||||
RESET2(DIM_SHIFT, BOLD_SHIFT);
|
||||
RANGE { cell->attrs.bits.bold = false; cell->attrs.bits.dim = false; } break;
|
||||
case 23:
|
||||
RESET(ITALIC_SHIFT);
|
||||
S(italic, false);
|
||||
case 24:
|
||||
SETM(0, DECORATION_MASK, DECORATION_SHIFT);
|
||||
S(decoration, 0);
|
||||
case 27:
|
||||
RESET(REVERSE_SHIFT);
|
||||
S(reverse, false);
|
||||
case 29:
|
||||
RESET(STRIKE_SHIFT);
|
||||
S(strike, false);
|
||||
START_ALLOW_CASE_RANGE
|
||||
case 30 ... 37:
|
||||
SIMPLE(fg, ((attr - 30) << 8) | 1);
|
||||
@@ -203,18 +204,16 @@ END_ALLOW_CASE_RANGE
|
||||
SIMPLE(decoration_fg, 0);
|
||||
}
|
||||
}
|
||||
#undef RESET
|
||||
#undef RESET2
|
||||
#undef SET_COLOR
|
||||
#undef SET
|
||||
#undef SETM
|
||||
#undef RANGE
|
||||
#undef SIMPLE
|
||||
#undef S
|
||||
}
|
||||
|
||||
const char*
|
||||
cursor_as_sgr(const Cursor *self) {
|
||||
GPUCell blank_cell = { 0 }, cursor_cell = {
|
||||
.attrs = CURSOR_TO_ATTRS(self, 1),
|
||||
.attrs = cursor_to_attrs(self, 1),
|
||||
.fg = self->fg & COL_MASK,
|
||||
.bg = self->bg & COL_MASK,
|
||||
.decoration_fg = self->decoration_fg & COL_MASK,
|
||||
|
||||
@@ -235,10 +235,26 @@ extern bool init_freetype_library(PyObject*);
|
||||
extern bool init_freetype_render_ui_text(PyObject*);
|
||||
#endif
|
||||
|
||||
static unsigned
|
||||
shift_to_first_set_bit(CellAttrs x) {
|
||||
unsigned num_of_bits = 8 * sizeof(x.val);
|
||||
unsigned ans = 0;
|
||||
while (num_of_bits--) {
|
||||
if (x.val & 1) return ans;
|
||||
x.val >>= 1;
|
||||
ans++;
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
|
||||
EXPORTED PyMODINIT_FUNC
|
||||
PyInit_fast_data_types(void) {
|
||||
PyObject *m;
|
||||
if (sizeof(CellAttrs) != 2u) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Size of CellAttrs is not 2 on this platform");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m = PyModule_Create(&module);
|
||||
if (m == NULL) return NULL;
|
||||
@@ -278,13 +294,11 @@ PyInit_fast_data_types(void) {
|
||||
#endif
|
||||
if (!init_fonts(m)) return NULL;
|
||||
|
||||
PyModule_AddIntConstant(m, "BOLD", BOLD_SHIFT);
|
||||
PyModule_AddIntConstant(m, "ITALIC", ITALIC_SHIFT);
|
||||
PyModule_AddIntConstant(m, "REVERSE", REVERSE_SHIFT);
|
||||
PyModule_AddIntConstant(m, "STRIKETHROUGH", STRIKE_SHIFT);
|
||||
PyModule_AddIntConstant(m, "DIM", DIM_SHIFT);
|
||||
PyModule_AddIntConstant(m, "DECORATION", DECORATION_SHIFT);
|
||||
PyModule_AddIntConstant(m, "MARK", MARK_SHIFT);
|
||||
CellAttrs a;
|
||||
#define s(name, attr) { a.val = 0; a.bits.attr = 1; PyModule_AddIntConstant(m, #name, shift_to_first_set_bit(a)); }
|
||||
s(BOLD, bold); s(ITALIC, italic); s(REVERSE, reverse); s(MARK, mark);
|
||||
s(STRIKETHROUGH, strike); s(DIM, dim); s(DECORATION, decoration);
|
||||
#undef s
|
||||
PyModule_AddIntConstant(m, "MARK_MASK", MARK_MASK);
|
||||
PyModule_AddStringMacro(m, ERROR_PREFIX);
|
||||
#ifdef KITTY_VCS_REV
|
||||
|
||||
@@ -52,7 +52,6 @@ typedef uint16_t glyph_index;
|
||||
typedef uint32_t pixel;
|
||||
typedef unsigned int index_type;
|
||||
typedef uint16_t sprite_index;
|
||||
typedef uint16_t attrs_type;
|
||||
typedef enum CursorShapes { NO_CURSOR_SHAPE, CURSOR_BLOCK, CURSOR_BEAM, CURSOR_UNDERLINE, NUM_OF_CURSOR_SHAPES } CursorShape;
|
||||
typedef enum { DISABLE_LIGATURES_NEVER, DISABLE_LIGATURES_CURSOR, DISABLE_LIGATURES_ALWAYS } DisableLigature;
|
||||
|
||||
@@ -65,20 +64,6 @@ typedef enum { TILING, SCALED, MIRRORED } BackgroundImageLayout;
|
||||
|
||||
#define MAX_CHILDREN 512
|
||||
#define BLANK_CHAR 0
|
||||
#define ATTRS_MASK_WITHOUT_WIDTH 0xFFFC
|
||||
#define WIDTH_MASK 3
|
||||
#define DECORATION_SHIFT 2
|
||||
#define DECORATION_MASK 3
|
||||
#define BOLD_SHIFT 4
|
||||
#define ITALIC_SHIFT 5
|
||||
#define BI_VAL(attrs) ((attrs >> 4) & 3)
|
||||
#define REVERSE_SHIFT 6
|
||||
#define STRIKE_SHIFT 7
|
||||
#define DIM_SHIFT 8
|
||||
#define MARK_SHIFT 9
|
||||
#define ATTRS_MASK_WITHOUT_MARK 0xf9ff
|
||||
#define ATTRS_MASK_FOR_SGR (ATTRS_MASK_WITHOUT_MARK | ATTRS_MASK_WITHOUT_WIDTH)
|
||||
#define MARK_MASK 3
|
||||
#define COL_MASK 0xFFFFFFFF
|
||||
#define DECORATION_FG_CODE 58
|
||||
#define CHAR_IS_BLANK(ch) ((ch) == 32 || (ch) == 0)
|
||||
@@ -86,15 +71,6 @@ typedef enum { TILING, SCALED, MIRRORED } BackgroundImageLayout;
|
||||
#define FG 1
|
||||
#define BG 2
|
||||
|
||||
#define CURSOR_TO_ATTRS(c, w) \
|
||||
((w) | (((c->decoration & 3) << DECORATION_SHIFT) | ((c->bold & 1) << BOLD_SHIFT) | \
|
||||
((c->italic & 1) << ITALIC_SHIFT) | ((c->reverse & 1) << REVERSE_SHIFT) | \
|
||||
((c->strikethrough & 1) << STRIKE_SHIFT) | ((c->dim & 1) << DIM_SHIFT)))
|
||||
|
||||
#define ATTRS_TO_CURSOR(a, c) \
|
||||
(c)->decoration = (a >> DECORATION_SHIFT) & 3; (c)->bold = (a >> BOLD_SHIFT) & 1; (c)->italic = (a >> ITALIC_SHIFT) & 1; \
|
||||
(c)->reverse = (a >> REVERSE_SHIFT) & 1; (c)->strikethrough = (a >> STRIKE_SHIFT) & 1; (c)->dim = (a >> DIM_SHIFT) & 1;
|
||||
|
||||
#define COPY_CELL(src, s, dest, d) \
|
||||
(dest)->cpu_cells[d] = (src)->cpu_cells[s]; (dest)->gpu_cells[d] = (src)->gpu_cells[s];
|
||||
|
||||
@@ -155,10 +131,27 @@ typedef struct {
|
||||
uint32_t left, top, right, bottom;
|
||||
} Region;
|
||||
|
||||
typedef union CellAttrs {
|
||||
struct {
|
||||
uint16_t width : 2;
|
||||
uint16_t decoration : 2;
|
||||
uint16_t bold : 1;
|
||||
uint16_t italic : 1;
|
||||
uint16_t reverse : 1;
|
||||
uint16_t strike : 1;
|
||||
uint16_t dim : 1;
|
||||
uint16_t mark : 2;
|
||||
} bits;
|
||||
uint16_t val;
|
||||
} CellAttrs;
|
||||
#define MARK_MASK (3u)
|
||||
#define WIDTH_MASK (3u)
|
||||
#define SGR_MASK (~(((CellAttrs){.bits={.width=WIDTH_MASK, .mark=MARK_MASK}}).val))
|
||||
|
||||
typedef struct {
|
||||
color_type fg, bg, decoration_fg;
|
||||
sprite_index sprite_x, sprite_y, sprite_z;
|
||||
attrs_type attrs;
|
||||
CellAttrs attrs;
|
||||
} GPUCell;
|
||||
|
||||
typedef struct {
|
||||
@@ -295,6 +288,21 @@ typedef struct {FONTS_DATA_HEAD} *FONTS_DATA_HANDLE;
|
||||
memmove((array) + (i), (array) + (i) + 1, sizeof((array)[0]) * ((count) - (i))); \
|
||||
}}
|
||||
|
||||
static inline CellAttrs
|
||||
cursor_to_attrs(const Cursor *c, const uint16_t width) {
|
||||
CellAttrs ans = {.bits={
|
||||
.width=width, .decoration=c->decoration, .bold=c->bold, .italic=c->italic, .reverse=c->reverse,
|
||||
.strike=c->strikethrough, .dim=c->dim}};
|
||||
return ans;
|
||||
}
|
||||
|
||||
static inline void
|
||||
attrs_to_cursor(const CellAttrs attrs, Cursor *c) {
|
||||
c->decoration = attrs.bits.decoration; c->bold = attrs.bits.bold; c->italic = attrs.bits.italic;
|
||||
c->reverse = attrs.bits.reverse; c->strikethrough = attrs.bits.strike; c->dim = attrs.bits.dim;
|
||||
}
|
||||
|
||||
|
||||
// Global functions
|
||||
const char* base64_decode(const uint32_t *src, size_t src_sz, uint8_t *dest, size_t dest_capacity, size_t *dest_sz);
|
||||
Line* alloc_line(void);
|
||||
|
||||
@@ -378,7 +378,7 @@ face_has_codepoint(PyObject* face, char_type cp) {
|
||||
|
||||
static bool
|
||||
has_emoji_presentation(CPUCell *cpu_cell, GPUCell *gpu_cell) {
|
||||
return (gpu_cell->attrs & WIDTH_MASK) == 2 && is_emoji(cpu_cell->ch) && cpu_cell->cc_idx[0] != VS15;
|
||||
return gpu_cell->attrs.bits.width == 2 && is_emoji(cpu_cell->ch) && cpu_cell->cc_idx[0] != VS15;
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -458,8 +458,8 @@ load_fallback_font(FontGroup *fg, CPUCell *cell, bool bold, bool italic, bool em
|
||||
|
||||
static ssize_t
|
||||
fallback_font(FontGroup *fg, CPUCell *cpu_cell, GPUCell *gpu_cell) {
|
||||
bool bold = (gpu_cell->attrs >> BOLD_SHIFT) & 1;
|
||||
bool italic = (gpu_cell->attrs >> ITALIC_SHIFT) & 1;
|
||||
bool bold = gpu_cell->attrs.bits.bold;
|
||||
bool italic = gpu_cell->attrs.bits.italic;
|
||||
bool emoji_presentation = has_emoji_presentation(cpu_cell, gpu_cell);
|
||||
|
||||
// Check if one of the existing fallback fonts has this text
|
||||
@@ -512,7 +512,7 @@ START_ALLOW_CASE_RANGE
|
||||
default:
|
||||
ans = in_symbol_maps(fg, cpu_cell->ch);
|
||||
if (ans > -1) return ans;
|
||||
switch(BI_VAL(gpu_cell->attrs)) {
|
||||
switch(gpu_cell->attrs.bits.bold | (gpu_cell->attrs.bits.italic << 1)) {
|
||||
case 0:
|
||||
ans = fg->medium_font_idx; break;
|
||||
case 1:
|
||||
@@ -601,11 +601,11 @@ load_hb_buffer(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_
|
||||
index_type num;
|
||||
hb_buffer_clear_contents(harfbuzz_buffer);
|
||||
while (num_cells) {
|
||||
attrs_type prev_width = 0;
|
||||
uint16_t prev_width = 0;
|
||||
for (num = 0; num_cells && num < arraysz(shape_buffer) - 20 - arraysz(first_cpu_cell->cc_idx); first_cpu_cell++, first_gpu_cell++, num_cells--) {
|
||||
if (prev_width == 2) { prev_width = 0; continue; }
|
||||
shape_buffer[num++] = first_cpu_cell->ch;
|
||||
prev_width = first_gpu_cell->attrs & WIDTH_MASK;
|
||||
prev_width = first_gpu_cell->attrs.bits.width;
|
||||
for (unsigned i = 0; i < arraysz(first_cpu_cell->cc_idx) && first_cpu_cell->cc_idx[i]; i++) {
|
||||
shape_buffer[num++] = codepoint_for_mark(first_cpu_cell->cc_idx[i]);
|
||||
}
|
||||
@@ -660,7 +660,7 @@ render_group(FontGroup *fg, unsigned int num_cells, unsigned int num_glyphs, CPU
|
||||
}
|
||||
|
||||
ensure_canvas_can_fit(fg, num_cells + 1);
|
||||
bool was_colored = (gpu_cells->attrs & WIDTH_MASK) == 2 && is_emoji(cpu_cells->ch);
|
||||
bool was_colored = gpu_cells->attrs.bits.width == 2 && is_emoji(cpu_cells->ch);
|
||||
render_glyphs_in_cells(font->face, font->bold, font->italic, info, positions, num_glyphs, fg->canvas.buf, fg->cell_width, fg->cell_height, num_cells, fg->baseline, &was_colored, (FONTS_DATA_HANDLE)fg, center_glyph);
|
||||
if (PyErr_Occurred()) PyErr_Print();
|
||||
|
||||
@@ -780,7 +780,7 @@ static unsigned int
|
||||
check_cell_consumed(CellData *cell_data, CPUCell *last_cpu_cell) {
|
||||
cell_data->codepoints_consumed++;
|
||||
if (cell_data->codepoints_consumed >= cell_data->num_codepoints) {
|
||||
attrs_type width = cell_data->gpu_cell->attrs & WIDTH_MASK;
|
||||
uint16_t width = cell_data->gpu_cell->attrs.bits.width;
|
||||
cell_data->cpu_cell += MAX(1, width);
|
||||
cell_data->gpu_cell += MAX(1, width);
|
||||
cell_data->codepoints_consumed = 0;
|
||||
@@ -829,7 +829,8 @@ ligature_type_from_glyph_name(const char *glyph_name, SpacerStrategy strategy) {
|
||||
static void
|
||||
detect_spacer_strategy(hb_font_t *hbf, Font *font) {
|
||||
CPUCell cpu_cells[3] = {{.ch = '='}, {.ch = '='}, {.ch = '='}};
|
||||
GPUCell gpu_cells[3] = {{.attrs = 1}, {.attrs = 1}, {.attrs = 1}};
|
||||
const CellAttrs w1 = {.bits={.width=1}};
|
||||
GPUCell gpu_cells[3] = {{.attrs = w1}, {.attrs = w1}, {.attrs = w1}};
|
||||
shape(cpu_cells, gpu_cells, arraysz(cpu_cells), hbf, font, false);
|
||||
font->spacer_strategy = SPACERS_BEFORE;
|
||||
if (G(num_glyphs) > 1) {
|
||||
@@ -1087,7 +1088,7 @@ merge_groups_for_pua_space_ligature(void) {
|
||||
static bool
|
||||
is_group_calt_ligature(const Group *group) {
|
||||
GPUCell *first_cell = G(first_gpu_cell) + group->first_cell_idx;
|
||||
return group->num_cells > 1 && group->has_special_glyph && (first_cell->attrs & WIDTH_MASK) == 1;
|
||||
return group->num_cells > 1 && group->has_special_glyph && first_cell->attrs.bits.width == 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1141,7 +1142,7 @@ test_shape(PyObject UNUSED *self, PyObject *args) {
|
||||
int index = 0;
|
||||
if(!PyArg_ParseTuple(args, "O!|zi", &Line_Type, &line, &path, &index)) return NULL;
|
||||
index_type num = 0;
|
||||
while(num < line->xnum && line->cpu_cells[num].ch) num += line->gpu_cells[num].attrs & WIDTH_MASK;
|
||||
while(num < line->xnum && line->cpu_cells[num].ch) num += line->gpu_cells[num].attrs.bits.width;
|
||||
PyObject *face = NULL;
|
||||
Font *font;
|
||||
if (!num_font_groups) { PyErr_SetString(PyExc_RuntimeError, "must create at least one font group first"); return NULL; }
|
||||
@@ -1228,7 +1229,7 @@ render_line(FONTS_DATA_HANDLE fg_, Line *line, index_type lnum, Cursor *cursor,
|
||||
bool center_glyph = false;
|
||||
bool disable_ligature_at_cursor = cursor != NULL && disable_ligature_strategy == DISABLE_LIGATURES_CURSOR && lnum == cursor->y;
|
||||
index_type first_cell_in_run, i;
|
||||
attrs_type prev_width = 0;
|
||||
uint16_t prev_width = 0;
|
||||
for (i=0, first_cell_in_run=0; i < line->xnum; i++) {
|
||||
if (prev_width == 2) { prev_width = 0; continue; }
|
||||
CPUCell *cpu_cell = line->cpu_cells + i;
|
||||
@@ -1271,12 +1272,12 @@ render_line(FONTS_DATA_HANDLE fg_, Line *line, index_type lnum, Cursor *cursor,
|
||||
render_run(fg, line->cpu_cells + i, line->gpu_cells + i, num_spaces + 1, cell_font_idx, true, center_glyph, -1, disable_ligature_strategy);
|
||||
run_font_idx = NO_FONT;
|
||||
first_cell_in_run = i + num_spaces + 1;
|
||||
prev_width = line->gpu_cells[i+num_spaces].attrs & WIDTH_MASK;
|
||||
prev_width = line->gpu_cells[i+num_spaces].attrs.bits.width;
|
||||
i += num_spaces;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
prev_width = gpu_cell->attrs & WIDTH_MASK;
|
||||
prev_width = gpu_cell->attrs.bits.width;
|
||||
if (run_font_idx == NO_FONT) run_font_idx = cell_font_idx;
|
||||
if (run_font_idx == cell_font_idx) continue;
|
||||
RENDER
|
||||
@@ -1548,8 +1549,8 @@ get_fallback_font(PyObject UNUSED *self, PyObject *args) {
|
||||
if (!PyUnicode_AsUCS4(text, char_buf, arraysz(char_buf), 1)) return NULL;
|
||||
cpu_cell.ch = char_buf[0];
|
||||
for (unsigned i = 0; i + 1 < (unsigned) PyUnicode_GetLength(text) && i < arraysz(cpu_cell.cc_idx); i++) cpu_cell.cc_idx[i] = mark_for_codepoint(char_buf[i + 1]);
|
||||
if (bold) gpu_cell.attrs |= 1 << BOLD_SHIFT;
|
||||
if (italic) gpu_cell.attrs |= 1 << ITALIC_SHIFT;
|
||||
if (bold) gpu_cell.attrs.bits.bold = true;
|
||||
if (italic) gpu_cell.attrs.bits.italic = true;
|
||||
FontGroup *fg = font_groups;
|
||||
ssize_t ans = fallback_font(fg, &cpu_cell, &gpu_cell);
|
||||
if (ans == MISSING_FONT) { PyErr_SetString(PyExc_ValueError, "No fallback font found"); return NULL; }
|
||||
|
||||
@@ -161,24 +161,21 @@ line(LineBuf *self, PyObject *y) {
|
||||
|
||||
unsigned int
|
||||
linebuf_char_width_at(LineBuf *self, index_type x, index_type y) {
|
||||
return (gpu_lineptr(self, self->line_map[y])[x].attrs) & WIDTH_MASK;
|
||||
}
|
||||
|
||||
void
|
||||
linebuf_set_attribute(LineBuf *self, unsigned int shift, unsigned int val) {
|
||||
for (index_type y = 0; y < self->ynum; y++) {
|
||||
set_attribute_on_line(gpu_lineptr(self, y), shift, val, self->xnum);
|
||||
self->line_attrs[y].bits.has_dirty_text = true;
|
||||
}
|
||||
return gpu_lineptr(self, self->line_map[y])[x].attrs.bits.width;
|
||||
}
|
||||
|
||||
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;
|
||||
if (!PyArg_ParseTuple(args, "II", &shift, &val)) return NULL;
|
||||
if (shift < DECORATION_SHIFT || shift > DIM_SHIFT) { PyErr_SetString(PyExc_ValueError, "Unknown attribute"); return NULL; }
|
||||
linebuf_set_attribute(self, shift, val);
|
||||
unsigned int val;
|
||||
char *which;
|
||||
if (!PyArg_ParseTuple(args, "sI", &which, &val)) return NULL;
|
||||
for (index_type y = 0; y < self->ynum; y++) {
|
||||
if (!set_named_attribute_on_line(gpu_lineptr(self, y), which, val, self->xnum)) {
|
||||
PyErr_SetString(PyExc_KeyError, "Unknown cell attribute"); return NULL;
|
||||
}
|
||||
self->line_attrs[y].bits.has_dirty_text = true;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
101
kitty/line.c
101
kitty/line.c
@@ -249,7 +249,7 @@ unicode_in_range(const Line *self, const index_type start, const index_type limi
|
||||
} else {
|
||||
n += cell_as_unicode(self->cpu_cells + i, include_cc, buf + n, ' ');
|
||||
}
|
||||
previous_width = self->gpu_cells[i].attrs & WIDTH_MASK;
|
||||
previous_width = self->gpu_cells[i].attrs.bits.width;
|
||||
}
|
||||
return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buf, n);
|
||||
}
|
||||
@@ -315,6 +315,7 @@ line_as_ansi(Line *self, ANSIBuf *output, const GPUCell** prev_cell) {
|
||||
static const GPUCell blank_cell = { 0 };
|
||||
GPUCell *cell;
|
||||
if (*prev_cell == NULL) *prev_cell = &blank_cell;
|
||||
const CellAttrs mask_for_sgr = {.val=SGR_MASK};
|
||||
|
||||
for (index_type pos=0; pos < limit; pos++) {
|
||||
char_type ch = self->cpu_cells[pos].ch;
|
||||
@@ -331,7 +332,7 @@ line_as_ansi(Line *self, ANSIBuf *output, const GPUCell** prev_cell) {
|
||||
|
||||
cell = &self->gpu_cells[pos];
|
||||
|
||||
#define CMP_ATTRS (cell->attrs & ATTRS_MASK_FOR_SGR) != ((*prev_cell)->attrs & ATTRS_MASK_FOR_SGR)
|
||||
#define CMP_ATTRS (cell->attrs.val & mask_for_sgr.val) != ((*prev_cell)->attrs.val & mask_for_sgr.val)
|
||||
#define CMP(x) cell->x != (*prev_cell)->x
|
||||
if (CMP_ATTRS || CMP(fg) || CMP(bg) || CMP(decoration_fg)) {
|
||||
const char *sgr = cell_as_sgr(cell, *prev_cell);
|
||||
@@ -349,7 +350,7 @@ line_as_ansi(Line *self, ANSIBuf *output, const GPUCell** prev_cell) {
|
||||
WRITE_CH(codepoint_for_mark(self->cpu_cells[pos].cc_idx[c]));
|
||||
}
|
||||
}
|
||||
previous_width = cell->attrs & WIDTH_MASK;
|
||||
previous_width = cell->attrs.bits.width;
|
||||
}
|
||||
#undef CMP_ATTRS
|
||||
#undef CMP
|
||||
@@ -398,15 +399,14 @@ width(Line *self, PyObject *val) {
|
||||
#define width_doc "width(x) -> the width of the character at x"
|
||||
unsigned long x = PyLong_AsUnsignedLong(val);
|
||||
if (x >= self->xnum) { PyErr_SetString(PyExc_ValueError, "Out of bounds"); return NULL; }
|
||||
char_type attrs = self->gpu_cells[x].attrs;
|
||||
return PyLong_FromUnsignedLong((unsigned long) (attrs & WIDTH_MASK));
|
||||
return PyLong_FromUnsignedLong((unsigned long) (self->gpu_cells[x].attrs.bits.width));
|
||||
}
|
||||
|
||||
void
|
||||
line_add_combining_char(Line *self, uint32_t ch, unsigned int x) {
|
||||
CPUCell *cell = self->cpu_cells + x;
|
||||
if (!cell->ch) {
|
||||
if (x > 0 && (self->gpu_cells[x-1].attrs & WIDTH_MASK) == 2 && self->cpu_cells[x-1].ch) cell = self->cpu_cells + x - 1;
|
||||
if (x > 0 && (self->gpu_cells[x-1].attrs.bits.width) == 2 && self->cpu_cells[x-1].ch) cell = self->cpu_cells + x - 1;
|
||||
else return; // don't allow adding combining chars to a null cell
|
||||
}
|
||||
for (unsigned i = 0; i < arraysz(cell->cc_idx); i++) {
|
||||
@@ -435,7 +435,6 @@ set_text(Line* self, PyObject *args) {
|
||||
#define set_text_doc "set_text(src, offset, sz, cursor) -> Set the characters and attributes from the specified text and cursor"
|
||||
PyObject *src;
|
||||
Py_ssize_t offset, sz, limit;
|
||||
char_type attrs;
|
||||
Cursor *cursor;
|
||||
int kind;
|
||||
void *buf;
|
||||
@@ -452,7 +451,7 @@ set_text(Line* self, PyObject *args) {
|
||||
PyErr_SetString(PyExc_ValueError, "Out of bounds offset/sz");
|
||||
return NULL;
|
||||
}
|
||||
attrs = CURSOR_TO_ATTRS(cursor, 1);
|
||||
CellAttrs attrs = cursor_to_attrs(cursor, 1);
|
||||
color_type fg = (cursor->fg & COL_MASK), bg = cursor->bg & COL_MASK;
|
||||
color_type dfg = cursor->decoration_fg & COL_MASK;
|
||||
|
||||
@@ -482,8 +481,7 @@ cursor_from(Line* self, PyObject *args) {
|
||||
ans = alloc_cursor();
|
||||
if (ans == NULL) { PyErr_NoMemory(); return NULL; }
|
||||
ans->x = x; ans->y = y;
|
||||
char_type attrs = self->gpu_cells[x].attrs;
|
||||
ATTRS_TO_CURSOR(attrs, ans);
|
||||
attrs_to_cursor(self->gpu_cells[x].attrs, ans);
|
||||
ans->fg = self->gpu_cells[x].fg; ans->bg = self->gpu_cells[x].bg;
|
||||
ans->decoration_fg = self->gpu_cells[x].decoration_fg & COL_MASK;
|
||||
|
||||
@@ -492,11 +490,11 @@ cursor_from(Line* self, PyObject *args) {
|
||||
|
||||
void
|
||||
line_clear_text(Line *self, unsigned int at, unsigned int num, char_type ch) {
|
||||
attrs_type width = ch ? 1 : 0;
|
||||
const uint16_t width = ch ? 1 : 0;
|
||||
for (index_type i = at; i < MIN(self->xnum, at + num); i++) {
|
||||
self->cpu_cells[i].ch = ch; memset(self->cpu_cells[i].cc_idx, 0, sizeof(self->cpu_cells[i].cc_idx));
|
||||
self->cpu_cells[i].hyperlink_id = 0;
|
||||
self->gpu_cells[i].attrs = (self->gpu_cells[i].attrs & ATTRS_MASK_WITHOUT_WIDTH) | width;
|
||||
self->gpu_cells[i].attrs.bits.width = width;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -512,10 +510,9 @@ clear_text(Line* self, PyObject *args) {
|
||||
|
||||
void
|
||||
line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int num, bool clear_char) {
|
||||
char_type attrs = CURSOR_TO_ATTRS(cursor, 1);
|
||||
CellAttrs attrs = cursor_to_attrs(cursor, 0);
|
||||
color_type fg = (cursor->fg & COL_MASK), bg = (cursor->bg & COL_MASK);
|
||||
color_type dfg = cursor->decoration_fg & COL_MASK;
|
||||
if (!clear_char) attrs = attrs & ATTRS_MASK_WITHOUT_WIDTH;
|
||||
|
||||
for (index_type i = at; i < self->xnum && i < at + num; i++) {
|
||||
if (clear_char) {
|
||||
@@ -525,8 +522,9 @@ line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int num,
|
||||
self->gpu_cells[i].attrs = attrs;
|
||||
clear_sprite_position(self->gpu_cells[i]);
|
||||
} else {
|
||||
attrs_type w = self->gpu_cells[i].attrs & WIDTH_MASK;
|
||||
self->gpu_cells[i].attrs = attrs | w;
|
||||
attrs.bits.width = self->gpu_cells[i].attrs.bits.width;
|
||||
attrs.bits.mark = self->gpu_cells[i].attrs.bits.mark;
|
||||
self->gpu_cells[i].attrs = attrs;
|
||||
}
|
||||
self->gpu_cells[i].fg = fg; self->gpu_cells[i].bg = bg;
|
||||
self->gpu_cells[i].decoration_fg = dfg;
|
||||
@@ -549,11 +547,10 @@ void line_right_shift(Line *self, unsigned int at, unsigned int num) {
|
||||
COPY_SELF_CELL(i - num, i)
|
||||
}
|
||||
// Check if a wide character was split at the right edge
|
||||
char_type w = (self->gpu_cells[self->xnum - 1].attrs) & WIDTH_MASK;
|
||||
if (w != 1) {
|
||||
if (self->gpu_cells[self->xnum - 1].attrs.bits.width != 1) {
|
||||
self->cpu_cells[self->xnum - 1].ch = BLANK_CHAR;
|
||||
self->cpu_cells[self->xnum - 1].hyperlink_id = 0;
|
||||
self->gpu_cells[self->xnum - 1].attrs = BLANK_CHAR ? 1 : 0;
|
||||
self->gpu_cells[self->xnum - 1].attrs = (CellAttrs){.bits={.width=BLANK_CHAR ? 1 : 0}};
|
||||
clear_sprite_position(self->gpu_cells[self->xnum - 1]);
|
||||
}
|
||||
}
|
||||
@@ -589,7 +586,7 @@ left_shift(Line *self, PyObject *args) {
|
||||
char_type
|
||||
line_get_char(Line *self, index_type at) {
|
||||
char_type ch = self->cpu_cells[at].ch;
|
||||
if (!ch && at > 0 && (self->gpu_cells[at-1].attrs & WIDTH_MASK) > 1) ch = self->cpu_cells[at-1].ch;
|
||||
if (!ch && at > 0 && (self->gpu_cells[at-1].attrs.bits.width) > 1) ch = self->cpu_cells[at-1].ch;
|
||||
return ch;
|
||||
}
|
||||
|
||||
@@ -597,9 +594,9 @@ void
|
||||
line_set_char(Line *self, unsigned int at, uint32_t ch, unsigned int width, Cursor *cursor, hyperlink_id_type hyperlink_id) {
|
||||
GPUCell *g = self->gpu_cells + at;
|
||||
if (cursor == NULL) {
|
||||
g->attrs = (self->gpu_cells[at].attrs & ATTRS_MASK_WITHOUT_WIDTH) | width;
|
||||
g->attrs.bits.width = width;
|
||||
} else {
|
||||
g->attrs = CURSOR_TO_ATTRS(cursor, width & WIDTH_MASK);
|
||||
g->attrs = cursor_to_attrs(cursor, width);
|
||||
g->fg = cursor->fg & COL_MASK;
|
||||
g->bg = cursor->bg & COL_MASK;
|
||||
g->decoration_fg = cursor->decoration_fg & COL_MASK;
|
||||
@@ -629,10 +626,12 @@ set_char(Line *self, PyObject *args) {
|
||||
static PyObject*
|
||||
set_attribute(Line *self, PyObject *args) {
|
||||
#define set_attribute_doc "set_attribute(which, val) -> Set the attribute on all cells in the line."
|
||||
unsigned int shift, val;
|
||||
if (!PyArg_ParseTuple(args, "II", &shift, &val)) return NULL;
|
||||
if (shift < DECORATION_SHIFT || shift > DIM_SHIFT) { PyErr_SetString(PyExc_ValueError, "Unknown attribute"); return NULL; }
|
||||
set_attribute_on_line(self->gpu_cells, shift, val, self->xnum);
|
||||
unsigned int val;
|
||||
char *which;
|
||||
if (!PyArg_ParseTuple(args, "sI", &which, &val)) return NULL;
|
||||
if (!set_named_attribute_on_line(self->gpu_cells, which, val, self->xnum)) {
|
||||
PyErr_SetString(PyExc_KeyError, "Unknown cell attribute"); return NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
@@ -669,32 +668,22 @@ cell_as_sgr(const GPUCell *cell, const GPUCell *prev) {
|
||||
#define SZ sizeof(buf) - (p - buf) - 2
|
||||
#define P(s) { size_t len = strlen(s); if (SZ > len) { memcpy(p, s, len); p += len; } }
|
||||
char *p = buf;
|
||||
#define CMP(attr) (attr(cell) != attr(prev))
|
||||
#define BOLD(cell) (cell->attrs & (1 << BOLD_SHIFT))
|
||||
#define DIM(cell) (cell->attrs & (1 << DIM_SHIFT))
|
||||
#define ITALIC(cell) (cell->attrs & (1 << ITALIC_SHIFT))
|
||||
#define REVERSE(cell) (cell->attrs & (1 << REVERSE_SHIFT))
|
||||
#define STRIKETHROUGH(cell) (cell->attrs & (1 << STRIKE_SHIFT))
|
||||
#define DECORATION(cell) (cell->attrs & (DECORATION_MASK << DECORATION_SHIFT))
|
||||
bool intensity_differs = CMP(BOLD) || CMP(DIM);
|
||||
#define CA cell->attrs.bits
|
||||
#define PA prev->attrs.bits
|
||||
bool intensity_differs = CA.bold != PA.bold || CA.dim != PA.dim;
|
||||
if (intensity_differs) {
|
||||
if (!BOLD(cell) && !DIM(cell)) { P("22;"); }
|
||||
else { if (BOLD(cell)) P("1;"); if (DIM(cell)) P("2;"); }
|
||||
if (!CA.bold && !CA.dim) { P("22;"); }
|
||||
else { if (CA.bold) P("1;"); if (CA.dim) P("2;"); }
|
||||
}
|
||||
if (CMP(ITALIC)) P(ITALIC(cell) ? "3;" : "23;");
|
||||
if (CMP(REVERSE)) P(REVERSE(cell) ? "7;" : "27;");
|
||||
if (CMP(STRIKETHROUGH)) P(STRIKETHROUGH(cell) ? "9;" : "29;");
|
||||
if (CA.italic != PA.italic) P(CA.italic ? "3;" : "23;");
|
||||
if (CA.reverse != PA.reverse) P(CA.reverse ? "7;" : "27;");
|
||||
if (CA.strike != PA.strike) P(CA.strike ? "9;" : "29;");
|
||||
if (cell->fg != prev->fg) p += color_as_sgr(p, SZ, cell->fg, 30, 90, 38);
|
||||
if (cell->bg != prev->bg) p += color_as_sgr(p, SZ, cell->bg, 40, 100, 48);
|
||||
if (cell->decoration_fg != prev->decoration_fg) p += color_as_sgr(p, SZ, cell->decoration_fg, 0, 0, DECORATION_FG_CODE);
|
||||
if (CMP(DECORATION)) P(decoration_as_sgr((cell->attrs >> DECORATION_SHIFT) & DECORATION_MASK));
|
||||
#undef CMP
|
||||
#undef BOLD
|
||||
#undef DIM
|
||||
#undef ITALIC
|
||||
#undef REVERSE
|
||||
#undef STRIKETHROUGH
|
||||
#undef DECORATION
|
||||
if (CA.decoration != PA.decoration) P(decoration_as_sgr(CA.decoration));
|
||||
#undef PA
|
||||
#undef CA
|
||||
#undef P
|
||||
#undef SZ
|
||||
if (p > buf) *(p - 1) = 0; // remove trailing semi-colon
|
||||
@@ -714,9 +703,9 @@ __eq__(Line *a, Line *b) {
|
||||
}
|
||||
|
||||
bool
|
||||
line_has_mark(Line *line, attrs_type mark) {
|
||||
line_has_mark(Line *line, uint16_t mark) {
|
||||
for (index_type x = 0; x < line->xnum; x++) {
|
||||
attrs_type m = (line->gpu_cells[x].attrs >> MARK_SHIFT) & MARK_MASK;
|
||||
const uint16_t m = line->gpu_cells[x].attrs.bits.mark;
|
||||
if (m && (!mark || mark == m)) return true;
|
||||
}
|
||||
return false;
|
||||
@@ -731,8 +720,8 @@ report_marker_error(PyObject *marker) {
|
||||
}
|
||||
|
||||
static void
|
||||
apply_mark(Line *line, const attrs_type mark, index_type *cell_pos, unsigned int *match_pos) {
|
||||
#define MARK { line->gpu_cells[x].attrs &= ATTRS_MASK_WITHOUT_MARK; line->gpu_cells[x].attrs |= mark; }
|
||||
apply_mark(Line *line, const uint16_t mark, index_type *cell_pos, unsigned int *match_pos) {
|
||||
#define MARK { line->gpu_cells[x].attrs.bits.mark = mark; }
|
||||
index_type x = *cell_pos;
|
||||
MARK;
|
||||
(*match_pos)++;
|
||||
@@ -744,7 +733,7 @@ apply_mark(Line *line, const attrs_type mark, index_type *cell_pos, unsigned int
|
||||
num_cells_to_skip_for_tab--;
|
||||
MARK;
|
||||
}
|
||||
} else if ((line->gpu_cells[x].attrs & WIDTH_MASK) > 1 && x + 1 < line->xnum && !line->cpu_cells[x+1].ch) {
|
||||
} else if ((line->gpu_cells[x].attrs.bits.width) > 1 && x + 1 < line->xnum && !line->cpu_cells[x+1].ch) {
|
||||
x++;
|
||||
MARK;
|
||||
} else {
|
||||
@@ -773,28 +762,28 @@ apply_marker(PyObject *marker, Line *line, const PyObject *text) {
|
||||
while (match_pos < l && x < line->xnum) {
|
||||
apply_mark(line, 0, &x, &match_pos);
|
||||
}
|
||||
attrs_type am = (col & MARK_MASK) << MARK_SHIFT;
|
||||
uint16_t am = (col & MARK_MASK);
|
||||
while(x < line->xnum && match_pos <= r) {
|
||||
apply_mark(line, am, &x, &match_pos);
|
||||
}
|
||||
|
||||
}
|
||||
Py_DECREF(iter);
|
||||
while(x < line->xnum) line->gpu_cells[x++].attrs &= ATTRS_MASK_WITHOUT_MARK;
|
||||
while(x < line->xnum) line->gpu_cells[x++].attrs.bits.mark = 0;
|
||||
if (PyErr_Occurred()) report_marker_error(marker);
|
||||
}
|
||||
|
||||
void
|
||||
mark_text_in_line(PyObject *marker, Line *line) {
|
||||
if (!marker) {
|
||||
for (index_type i = 0; i < line->xnum; i++) line->gpu_cells[i].attrs &= ATTRS_MASK_WITHOUT_MARK;
|
||||
for (index_type i = 0; i < line->xnum; i++) line->gpu_cells[i].attrs.bits.mark = 0;
|
||||
return;
|
||||
}
|
||||
PyObject *text = line_as_unicode(line, false);
|
||||
if (PyUnicode_GET_LENGTH(text) > 0) {
|
||||
apply_marker(marker, line, text);
|
||||
} else {
|
||||
for (index_type i = 0; i < line->xnum; i++) line->gpu_cells[i].attrs &= ATTRS_MASK_WITHOUT_MARK;
|
||||
for (index_type i = 0; i < line->xnum; i++) line->gpu_cells[i].attrs.bits.mark = 0;
|
||||
}
|
||||
Py_DECREF(text);
|
||||
}
|
||||
|
||||
@@ -8,13 +8,16 @@
|
||||
|
||||
#include "data-types.h"
|
||||
|
||||
static inline void
|
||||
set_attribute_on_line(GPUCell *cells, uint32_t shift, uint32_t val, index_type xnum) {
|
||||
#define set_attribute_on_line(cells, which, val, xnum) { \
|
||||
for (index_type i__ = 0; i__ < xnum; i__++) cells[i__].attrs.bits.which = val; }
|
||||
|
||||
static inline bool
|
||||
set_named_attribute_on_line(GPUCell *cells, const char* which, uint16_t val, index_type xnum) {
|
||||
// Set a single attribute on all cells in the line
|
||||
attrs_type mask = shift == DECORATION_SHIFT ? 3 : 1;
|
||||
attrs_type aval = (val & mask) << shift;
|
||||
mask = ~(mask << shift);
|
||||
for (index_type i = 0; i < xnum; i++) cells[i].attrs = (cells[i].attrs & mask) | aval;
|
||||
#define s(q) if (strcmp(#q, which) == 0) { set_attribute_on_line(cells, q, val, xnum); return true; }
|
||||
s(reverse); s(width); s(strike); s(dim); s(mark); s(bold); s(italic); s(decoration);
|
||||
return false;
|
||||
#undef s
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +31,8 @@ static inline void
|
||||
clear_chars_in_line(CPUCell *cpu_cells, GPUCell *gpu_cells, index_type xnum, char_type ch) {
|
||||
// Clear only the char part of each cell, the rest must have been cleared by a memset or similar
|
||||
if (ch) {
|
||||
for (index_type i = 0; i < xnum; i++) { cpu_cells[i].ch = ch; cpu_cells[i].hyperlink_id = 0; gpu_cells[i].attrs = 1; }
|
||||
const CellAttrs empty = {.bits={.width=1}};
|
||||
for (index_type i = 0; i < xnum; i++) { cpu_cells[i].ch = ch; cpu_cells[i].hyperlink_id = 0; gpu_cells[i].attrs = empty; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +41,7 @@ xlimit_for_line(const Line *line) {
|
||||
index_type xlimit = line->xnum;
|
||||
if (BLANK_CHAR == 0) {
|
||||
while (xlimit > 0 && (line->cpu_cells[xlimit - 1].ch) == BLANK_CHAR) xlimit--;
|
||||
if (xlimit < line->xnum && (line->gpu_cells[xlimit > 0 ? xlimit - 1 : xlimit].attrs & WIDTH_MASK) == 2) xlimit++;
|
||||
if (xlimit < line->xnum && line->gpu_cells[xlimit > 0 ? xlimit - 1 : xlimit].attrs.bits.width == 2) xlimit++;
|
||||
}
|
||||
return xlimit;
|
||||
}
|
||||
@@ -59,10 +63,12 @@ left_shift_line(Line *line, index_type at, index_type num) {
|
||||
for (index_type i = at; i < line->xnum - num; i++) {
|
||||
COPY_CELL(line, i + num, line, i);
|
||||
}
|
||||
if (at < line->xnum && ((line->gpu_cells[at].attrs) & WIDTH_MASK) != 1) {
|
||||
const CellAttrs empty = {.bits={.width=1}};
|
||||
const CellAttrs zero = {0};
|
||||
if (at < line->xnum && line->gpu_cells[at].attrs.bits.width != 1) {
|
||||
line->cpu_cells[at].ch = BLANK_CHAR;
|
||||
line->cpu_cells[at].hyperlink_id = 0;
|
||||
line->gpu_cells[at].attrs = BLANK_CHAR ? 1 : 0;
|
||||
line->gpu_cells[at].attrs = BLANK_CHAR ? empty : zero;
|
||||
clear_sprite_position(line->gpu_cells[at]);
|
||||
}
|
||||
}
|
||||
@@ -95,7 +101,6 @@ void linebuf_clear_line(LineBuf *self, index_type y, bool clear_attrs);
|
||||
void linebuf_insert_lines(LineBuf *self, unsigned int num, unsigned int y, unsigned int bottom);
|
||||
void linebuf_delete_lines(LineBuf *self, index_type num, index_type y, index_type bottom);
|
||||
void linebuf_copy_line_to(LineBuf *, Line *, index_type);
|
||||
void linebuf_set_attribute(LineBuf *, unsigned int , unsigned int );
|
||||
void linebuf_rewrap(LineBuf *self, LineBuf *other, index_type *, index_type *, HistoryBuf *, index_type *, index_type *, index_type *, index_type *, ANSIBuf*);
|
||||
void linebuf_mark_line_dirty(LineBuf *self, index_type y);
|
||||
void linebuf_mark_line_clean(LineBuf *self, index_type y);
|
||||
@@ -114,5 +119,5 @@ void historybuf_mark_line_dirty(HistoryBuf *self, index_type y);
|
||||
void historybuf_refresh_sprite_positions(HistoryBuf *self);
|
||||
void historybuf_clear(HistoryBuf *self);
|
||||
void mark_text_in_line(PyObject *marker, Line *line);
|
||||
bool line_has_mark(Line *, attrs_type mark);
|
||||
bool line_has_mark(Line *, uint16_t mark);
|
||||
PyObject* as_text_generic(PyObject *args, void *container, get_line_func get_line, index_type lines, ANSIBuf *ansibuf);
|
||||
|
||||
@@ -594,24 +594,24 @@ draw_combining_char(Screen *self, char_type ch) {
|
||||
if (ch == 0xfe0f) { // emoji presentation variation marker makes default text presentation emoji (narrow emoji) into wide emoji
|
||||
CPUCell *cpu_cell = self->linebuf->line->cpu_cells + xpos;
|
||||
GPUCell *gpu_cell = self->linebuf->line->gpu_cells + xpos;
|
||||
if ((gpu_cell->attrs & WIDTH_MASK) != 2 && cpu_cell->cc_idx[0] == VS16 && is_emoji_presentation_base(cpu_cell->ch)) {
|
||||
if (gpu_cell->attrs.bits.width != 2 && cpu_cell->cc_idx[0] == VS16 && is_emoji_presentation_base(cpu_cell->ch)) {
|
||||
if (self->cursor->x <= self->columns - 1) line_set_char(self->linebuf->line, self->cursor->x, 0, 0, self->cursor, self->active_hyperlink_id);
|
||||
gpu_cell->attrs = (gpu_cell->attrs & !WIDTH_MASK) | 2;
|
||||
gpu_cell->attrs.bits.width = 2;
|
||||
if (xpos == self->columns - 1) move_widened_char(self, cpu_cell, gpu_cell, xpos, ypos);
|
||||
else self->cursor->x++;
|
||||
}
|
||||
} else if (ch == 0xfe0e) {
|
||||
CPUCell *cpu_cell = self->linebuf->line->cpu_cells + xpos;
|
||||
GPUCell *gpu_cell = self->linebuf->line->gpu_cells + xpos;
|
||||
if ((gpu_cell->attrs & WIDTH_MASK) == 0 && cpu_cell->ch == 0 && xpos > 0) {
|
||||
if (gpu_cell->attrs.bits.width == 0 && cpu_cell->ch == 0 && xpos > 0) {
|
||||
xpos--;
|
||||
if (self->cursor->x > 0) self->cursor->x--;
|
||||
cpu_cell = self->linebuf->line->cpu_cells + xpos;
|
||||
gpu_cell = self->linebuf->line->gpu_cells + xpos;
|
||||
}
|
||||
|
||||
if ((gpu_cell->attrs & WIDTH_MASK) == 2 && cpu_cell->cc_idx[0] == VS15 && is_emoji_presentation_base(cpu_cell->ch)) {
|
||||
gpu_cell->attrs = (gpu_cell->attrs & !WIDTH_MASK) | 1;
|
||||
if (gpu_cell->attrs.bits.width == 2 && cpu_cell->cc_idx[0] == VS15 && is_emoji_presentation_base(cpu_cell->ch)) {
|
||||
gpu_cell->attrs.bits.width = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3230,7 +3230,7 @@ marked_cells(Screen *self, PyObject *o UNUSED) {
|
||||
linebuf_init_line(self->linebuf, y);
|
||||
for (index_type x = 0; x < self->columns; x++) {
|
||||
GPUCell *gpu_cell = self->linebuf->line->gpu_cells + x;
|
||||
unsigned int mark = (gpu_cell->attrs >> MARK_SHIFT) & MARK_MASK;
|
||||
const unsigned int mark = gpu_cell->attrs.bits.mark;
|
||||
if (mark) {
|
||||
PyObject *t = Py_BuildValue("III", x, y, mark);
|
||||
if (!t) { Py_DECREF(ans); return NULL; }
|
||||
|
||||
@@ -7,7 +7,7 @@ import tempfile
|
||||
|
||||
from kitty.config import build_ansi_color_table, defaults
|
||||
from kitty.fast_data_types import (
|
||||
REVERSE, ColorProfile, Cursor as C, HistoryBuf, LineBuf,
|
||||
ColorProfile, Cursor as C, HistoryBuf, LineBuf,
|
||||
parse_input_from_terminal, truncate_point_for_length, wcswidth, wcwidth
|
||||
)
|
||||
from kitty.rgb import to_color
|
||||
@@ -51,7 +51,7 @@ class TestDataTypes(BaseTest):
|
||||
self.ae(new.line(0), old.line(1))
|
||||
new.clear()
|
||||
self.ae(str(new.line(0)), '')
|
||||
old.set_attribute(REVERSE, False)
|
||||
old.set_attribute('reverse', False)
|
||||
for y in range(old.ynum):
|
||||
for x in range(old.xnum):
|
||||
l0 = old.line(y)
|
||||
|
||||
Reference in New Issue
Block a user