Move the text attributes out of the char type
This means that more text attributes can be added in the future (there are 8 bits available) and there is no need to keep bit twiddling when accessing the chars themselves. Also means less data needs to be sent to the GPU. Cell size does not change since there were currently 2 unused bytes because of alignment.
This commit is contained in:
parent
85ed5c1515
commit
a92b3c605f
@ -9,8 +9,7 @@ uniform uvec4 url_range; // The range for the currently highlighted URL (start_x
|
|||||||
uniform ColorTable {
|
uniform ColorTable {
|
||||||
uint color_table[256]; // The color table
|
uint color_table[256]; // The color table
|
||||||
};
|
};
|
||||||
in uint text_attrs;
|
in uvec4 sprite_coords;
|
||||||
in uvec3 sprite_coords;
|
|
||||||
in uvec3 colors;
|
in uvec3 colors;
|
||||||
in float is_selected;
|
in float is_selected;
|
||||||
out vec3 sprite_pos;
|
out vec3 sprite_pos;
|
||||||
@ -95,7 +94,8 @@ void main() {
|
|||||||
gl_Position = vec4(xpos[pos.x], ypos[pos.y], 0, 1);
|
gl_Position = vec4(xpos[pos.x], ypos[pos.y], 0, 1);
|
||||||
|
|
||||||
sprite_pos = to_sprite_pos(pos, sprite_coords.x, sprite_coords.y, sprite_coords.z & SHORT_MASK);
|
sprite_pos = to_sprite_pos(pos, sprite_coords.x, sprite_coords.y, sprite_coords.z & SHORT_MASK);
|
||||||
uint reverse = (text_attrs >> 30) & STRIKE_MASK;
|
uint text_attrs = sprite_coords[3];
|
||||||
|
uint reverse = (text_attrs >> 6) & STRIKE_MASK;
|
||||||
uint fg = colors[color_indices[reverse]];
|
uint fg = colors[color_indices[reverse]];
|
||||||
uint bg = colors[color_indices[ONE - reverse]];
|
uint bg = colors[color_indices[ONE - reverse]];
|
||||||
uint resolved_fg = as_color(fg, default_colors[color_indices[0]]);
|
uint resolved_fg = as_color(fg, default_colors[color_indices[0]]);
|
||||||
@ -103,6 +103,6 @@ void main() {
|
|||||||
background = apply_selection(to_color(bg, default_colors[color_indices[1]]), default_colors[3]);
|
background = apply_selection(to_color(bg, default_colors[color_indices[1]]), default_colors[3]);
|
||||||
float in_url = in_range(url_range, c, r);
|
float in_url = in_range(url_range, c, r);
|
||||||
decoration_fg = mix_vecs(in_url, color_to_vec(url_color), to_color(colors[2], resolved_fg));
|
decoration_fg = mix_vecs(in_url, color_to_vec(url_color), to_color(colors[2], resolved_fg));
|
||||||
underline_pos = mix_vecs(in_url, to_sprite_pos(pos, TWO, ZERO, ZERO), to_sprite_pos(pos, (text_attrs >> 26) & DECORATION_MASK, ZERO, ZERO));
|
underline_pos = mix_vecs(in_url, to_sprite_pos(pos, TWO, ZERO, ZERO), to_sprite_pos(pos, (text_attrs >> 2) & DECORATION_MASK, ZERO, ZERO));
|
||||||
strike_pos = to_sprite_pos(pos, ((text_attrs >> 31) & STRIKE_MASK) * THREE, ZERO, ZERO);
|
strike_pos = to_sprite_pos(pos, ((text_attrs >> 7) & STRIKE_MASK) * THREE, ZERO, ZERO);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,6 +29,7 @@ typedef uint32_t color_type;
|
|||||||
typedef uint32_t combining_type;
|
typedef uint32_t combining_type;
|
||||||
typedef unsigned int index_type;
|
typedef unsigned int index_type;
|
||||||
typedef uint16_t sprite_index;
|
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 CursorShapes { NO_CURSOR_SHAPE, CURSOR_BLOCK, CURSOR_BEAM, CURSOR_UNDERLINE, NUM_OF_CURSOR_SHAPES } CursorShape;
|
||||||
|
|
||||||
#define ERROR_PREFIX "[PARSE ERROR]"
|
#define ERROR_PREFIX "[PARSE ERROR]"
|
||||||
@ -38,15 +39,12 @@ typedef enum MouseShapes { BEAM, HAND, ARROW } MouseShape;
|
|||||||
|
|
||||||
#define MAX_CHILDREN 256
|
#define MAX_CHILDREN 256
|
||||||
#define BLANK_CHAR 0
|
#define BLANK_CHAR 0
|
||||||
#define CHAR_MASK 0xFFFFFF
|
#define ATTRS_MASK_WITHOUT_WIDTH 0xFFC
|
||||||
#define ATTRS_SHIFT 24
|
|
||||||
#define ATTRS_MASK_WITHOUT_WIDTH 0xFC000000
|
|
||||||
#define WIDTH_MASK 3
|
#define WIDTH_MASK 3
|
||||||
#define DECORATION_SHIFT 2
|
#define DECORATION_SHIFT 2
|
||||||
#define DECORATION_MASK 3
|
#define DECORATION_MASK 3
|
||||||
#define BOLD_SHIFT 4
|
#define BOLD_SHIFT 4
|
||||||
#define ITALIC_SHIFT 5
|
#define ITALIC_SHIFT 5
|
||||||
#define POSCHAR_MASK 0x30FFFFFF
|
|
||||||
#define REVERSE_SHIFT 6
|
#define REVERSE_SHIFT 6
|
||||||
#define STRIKE_SHIFT 7
|
#define STRIKE_SHIFT 7
|
||||||
#define COL_MASK 0xFFFFFFFF
|
#define COL_MASK 0xFFFFFFFF
|
||||||
@ -56,14 +54,14 @@ typedef enum MouseShapes { BEAM, HAND, ARROW } MouseShape;
|
|||||||
#define UTF8_REJECT 1
|
#define UTF8_REJECT 1
|
||||||
#define UNDERCURL_CODE 6
|
#define UNDERCURL_CODE 6
|
||||||
#define DECORATION_FG_CODE 58
|
#define DECORATION_FG_CODE 58
|
||||||
#define CHAR_IS_BLANK(ch) ((ch & CHAR_MASK) == 32 || (ch & CHAR_MASK) == 0)
|
#define CHAR_IS_BLANK(ch) ((ch) == 32 || (ch) == 0)
|
||||||
|
|
||||||
#define FG 1
|
#define FG 1
|
||||||
#define BG 2
|
#define BG 2
|
||||||
|
|
||||||
#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) | \
|
||||||
((c->italic & 1) << ITALIC_SHIFT) | ((c->reverse & 1) << REVERSE_SHIFT) | ((c->strikethrough & 1) << STRIKE_SHIFT))) << ATTRS_SHIFT
|
((c->italic & 1) << ITALIC_SHIFT) | ((c->reverse & 1) << REVERSE_SHIFT) | ((c->strikethrough & 1) << STRIKE_SHIFT)))
|
||||||
|
|
||||||
#define ATTRS_TO_CURSOR(a, c) \
|
#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->decoration = (a >> DECORATION_SHIFT) & 3; c->bold = (a >> BOLD_SHIFT) & 1; c->italic = (a >> ITALIC_SHIFT) & 1; \
|
||||||
@ -126,6 +124,7 @@ typedef struct {
|
|||||||
color_type fg, bg, decoration_fg;
|
color_type fg, bg, decoration_fg;
|
||||||
combining_type cc;
|
combining_type cc;
|
||||||
sprite_index sprite_x, sprite_y, sprite_z;
|
sprite_index sprite_x, sprite_y, sprite_z;
|
||||||
|
attrs_type attrs;
|
||||||
} Cell;
|
} Cell;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -280,8 +279,9 @@ PyTypeObject ChildMonitor_Type;
|
|||||||
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)->cells[(at)].ch >> ATTRS_SHIFT) & WIDTH_MASK) != 1) { \
|
if ((((line)->cells[(at)].attrs) & WIDTH_MASK) != 1) { \
|
||||||
(line)->cells[(at)].ch = (1 << ATTRS_SHIFT) | BLANK_CHAR; \
|
(line)->cells[(at)].ch = BLANK_CHAR; \
|
||||||
|
(line)->cells[(at)].attrs = BLANK_CHAR ? 1 : 0; \
|
||||||
clear_sprite_position((line)->cells[(at)]); \
|
clear_sprite_position((line)->cells[(at)]); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -116,7 +116,7 @@ line(LineBuf *self, PyObject *y) {
|
|||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
linebuf_char_width_at(LineBuf *self, index_type x, index_type y) {
|
linebuf_char_width_at(LineBuf *self, index_type x, index_type y) {
|
||||||
return (lineptr(self, self->line_map[y])[x].ch >> ATTRS_SHIFT) & WIDTH_MASK;
|
return (lineptr(self, self->line_map[y])[x].attrs) & WIDTH_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -453,7 +453,7 @@ linebuf_rewrap(LineBuf *self, LineBuf *other, int *cursor_y_out, HistoryBuf *his
|
|||||||
for (first = self->ynum - 1; true; first--) {
|
for (first = self->ynum - 1; true; first--) {
|
||||||
Cell *cells = lineptr(self, first);
|
Cell *cells = lineptr(self, first);
|
||||||
for(i = 0; i < self->xnum; i++) {
|
for(i = 0; i < self->xnum; i++) {
|
||||||
if ((cells[i].ch & CHAR_MASK) != BLANK_CHAR) { is_empty = false; break; }
|
if ((cells[i].ch) != BLANK_CHAR) { is_empty = false; break; }
|
||||||
}
|
}
|
||||||
if (!is_empty || !first) break;
|
if (!is_empty || !first) break;
|
||||||
}
|
}
|
||||||
|
|||||||
56
kitty/line.c
56
kitty/line.c
@ -27,7 +27,7 @@ unsigned int
|
|||||||
line_length(Line *self) {
|
line_length(Line *self) {
|
||||||
index_type last = self->xnum - 1;
|
index_type last = self->xnum - 1;
|
||||||
for (index_type i = 0; i < self->xnum; i++) {
|
for (index_type i = 0; i < self->xnum; i++) {
|
||||||
if ((self->cells[last - i].ch & CHAR_MASK) != BLANK_CHAR) return self->xnum - i;
|
if ((self->cells[last - i].ch) != BLANK_CHAR) return self->xnum - i;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -68,7 +68,7 @@ find_colon_slash(Line *self, index_type x, index_type limit) {
|
|||||||
limit = MAX(2, limit);
|
limit = MAX(2, limit);
|
||||||
if (pos < limit) return 0;
|
if (pos < limit) return 0;
|
||||||
do {
|
do {
|
||||||
char_type ch = self->cells[pos].ch & CHAR_MASK;
|
char_type ch = self->cells[pos].ch;
|
||||||
if (!is_url_char(ch)) return false;
|
if (!is_url_char(ch)) return false;
|
||||||
switch(state) {
|
switch(state) {
|
||||||
case ANY:
|
case ANY:
|
||||||
@ -92,7 +92,7 @@ prefix_matches(Line *self, index_type at, const char* prefix, index_type prefix_
|
|||||||
if (prefix_len > at) return false;
|
if (prefix_len > at) return false;
|
||||||
index_type p, i;
|
index_type p, i;
|
||||||
for (p = at - prefix_len, i = 0; i < prefix_len && p < self->xnum; i++, p++) {
|
for (p = at - prefix_len, i = 0; i < prefix_len && p < self->xnum; i++, p++) {
|
||||||
if ((self->cells[p].ch & CHAR_MASK) != (unsigned char)prefix[i]) return false;
|
if ((self->cells[p].ch) != (unsigned char)prefix[i]) return false;
|
||||||
}
|
}
|
||||||
return i == prefix_len;
|
return i == prefix_len;
|
||||||
}
|
}
|
||||||
@ -117,7 +117,7 @@ static inline bool
|
|||||||
has_url_beyond(Line *self, index_type x) {
|
has_url_beyond(Line *self, index_type x) {
|
||||||
if (self->xnum <= x + MIN_URL_LEN + 3) return false;
|
if (self->xnum <= x + MIN_URL_LEN + 3) return false;
|
||||||
for (index_type i = x; i < MIN(x + MIN_URL_LEN + 3, self->xnum); i++) {
|
for (index_type i = x; i < MIN(x + MIN_URL_LEN + 3, self->xnum); i++) {
|
||||||
if (!is_url_char(self->cells[i].ch & CHAR_MASK)) return false;
|
if (!is_url_char(self->cells[i].ch)) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -143,9 +143,9 @@ index_type
|
|||||||
line_url_end_at(Line *self, index_type x) {
|
line_url_end_at(Line *self, index_type x) {
|
||||||
index_type ans = x;
|
index_type ans = x;
|
||||||
if (x >= self->xnum || self->xnum <= MIN_URL_LEN + 3) return 0;
|
if (x >= self->xnum || self->xnum <= MIN_URL_LEN + 3) return 0;
|
||||||
while (ans < self->xnum && is_url_char(self->cells[ans].ch & CHAR_MASK)) ans++;
|
while (ans < self->xnum && is_url_char(self->cells[ans].ch)) ans++;
|
||||||
ans--;
|
ans--;
|
||||||
while (ans > x && can_strip_from_end_of_url(self->cells[ans].ch & CHAR_MASK)) ans--;
|
while (ans > x && can_strip_from_end_of_url(self->cells[ans].ch)) ans--;
|
||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ static PyObject*
|
|||||||
text_at(Line* self, Py_ssize_t xval) {
|
text_at(Line* self, Py_ssize_t xval) {
|
||||||
#define text_at_doc "[x] -> Return the text in the specified cell"
|
#define text_at_doc "[x] -> Return the text in the specified cell"
|
||||||
if (xval >= self->xnum) { PyErr_SetString(PyExc_IndexError, "Column number out of bounds"); return NULL; }
|
if (xval >= self->xnum) { PyErr_SetString(PyExc_IndexError, "Column number out of bounds"); return NULL; }
|
||||||
return line_text_at(self->cells[xval].ch & CHAR_MASK, self->cells[xval].cc);
|
return line_text_at(self->cells[xval].ch, self->cells[xval].cc);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject*
|
PyObject*
|
||||||
@ -177,7 +177,7 @@ unicode_in_range(Line *self, index_type start, index_type limit, bool include_cc
|
|||||||
if (leading_char) buf[n++] = leading_char;
|
if (leading_char) buf[n++] = leading_char;
|
||||||
char_type previous_width = 0;
|
char_type previous_width = 0;
|
||||||
for(index_type i = start; i < limit && n < sizeof(buf)/sizeof(buf[0]) - 4; i++) {
|
for(index_type i = start; i < limit && n < sizeof(buf)/sizeof(buf[0]) - 4; i++) {
|
||||||
char_type ch = self->cells[i].ch & CHAR_MASK;
|
char_type ch = self->cells[i].ch;
|
||||||
if (ch == 0) {
|
if (ch == 0) {
|
||||||
if (previous_width == 2) { previous_width = 0; continue; };
|
if (previous_width == 2) { previous_width = 0; continue; };
|
||||||
ch = ' ';
|
ch = ' ';
|
||||||
@ -192,7 +192,7 @@ unicode_in_range(Line *self, index_type start, index_type limit, bool include_cc
|
|||||||
if (cc2) buf[n++] = cc2;
|
if (cc2) buf[n++] = cc2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
previous_width = (self->cells[i].ch >> ATTRS_SHIFT) & WIDTH_MASK;
|
previous_width = self->cells[i].attrs & WIDTH_MASK;
|
||||||
}
|
}
|
||||||
return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buf, n);
|
return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buf, n);
|
||||||
}
|
}
|
||||||
@ -247,7 +247,7 @@ line_as_ansi(Line *self, Py_UCS4 *buf, index_type buflen) {
|
|||||||
|
|
||||||
WRITE_SGR(0);
|
WRITE_SGR(0);
|
||||||
for (index_type pos=0; pos < limit; pos++) {
|
for (index_type pos=0; pos < limit; pos++) {
|
||||||
char_type attrs = self->cells[pos].ch >> ATTRS_SHIFT, ch = self->cells[pos].ch & CHAR_MASK;
|
char_type attrs = self->cells[pos].attrs, ch = self->cells[pos].ch;
|
||||||
if (ch == 0) {
|
if (ch == 0) {
|
||||||
if (previous_width == 2) { previous_width = 0; continue; }
|
if (previous_width == 2) { previous_width = 0; continue; }
|
||||||
ch = ' ';
|
ch = ' ';
|
||||||
@ -319,7 +319,7 @@ width(Line *self, PyObject *val) {
|
|||||||
#define width_doc "width(x) -> the width of the character at x"
|
#define width_doc "width(x) -> the width of the character at x"
|
||||||
unsigned long x = PyLong_AsUnsignedLong(val);
|
unsigned long x = PyLong_AsUnsignedLong(val);
|
||||||
if (x >= self->xnum) { PyErr_SetString(PyExc_ValueError, "Out of bounds"); return NULL; }
|
if (x >= self->xnum) { PyErr_SetString(PyExc_ValueError, "Out of bounds"); return NULL; }
|
||||||
char_type attrs = self->cells[x].ch >> ATTRS_SHIFT;
|
char_type attrs = self->cells[x].attrs;
|
||||||
return PyLong_FromUnsignedLong((unsigned long) (attrs & WIDTH_MASK));
|
return PyLong_FromUnsignedLong((unsigned long) (attrs & WIDTH_MASK));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,7 +375,8 @@ set_text(Line* self, PyObject *args) {
|
|||||||
color_type dfg = cursor->decoration_fg & COL_MASK;
|
color_type dfg = cursor->decoration_fg & COL_MASK;
|
||||||
|
|
||||||
for (index_type i = cursor->x; offset < limit && i < self->xnum; i++, offset++) {
|
for (index_type i = cursor->x; offset < limit && i < self->xnum; i++, offset++) {
|
||||||
self->cells[i].ch = (PyUnicode_READ(kind, buf, offset) & CHAR_MASK) | attrs;
|
self->cells[i].ch = (PyUnicode_READ(kind, buf, offset));
|
||||||
|
self->cells[i].attrs = attrs;
|
||||||
self->cells[i].fg = fg;
|
self->cells[i].fg = fg;
|
||||||
self->cells[i].bg = bg;
|
self->cells[i].bg = bg;
|
||||||
self->cells[i].decoration_fg = dfg;
|
self->cells[i].decoration_fg = dfg;
|
||||||
@ -399,7 +400,7 @@ cursor_from(Line* self, PyObject *args) {
|
|||||||
ans = alloc_cursor();
|
ans = alloc_cursor();
|
||||||
if (ans == NULL) { PyErr_NoMemory(); return NULL; }
|
if (ans == NULL) { PyErr_NoMemory(); return NULL; }
|
||||||
ans->x = x; ans->y = y;
|
ans->x = x; ans->y = y;
|
||||||
char_type attrs = self->cells[x].ch >> ATTRS_SHIFT;
|
char_type attrs = self->cells[x].attrs;
|
||||||
ATTRS_TO_CURSOR(attrs, ans);
|
ATTRS_TO_CURSOR(attrs, ans);
|
||||||
ans->fg = self->cells[x].fg; ans->bg = self->cells[x].bg;
|
ans->fg = self->cells[x].fg; ans->bg = self->cells[x].bg;
|
||||||
ans->decoration_fg = self->cells[x].decoration_fg & COL_MASK;
|
ans->decoration_fg = self->cells[x].decoration_fg & COL_MASK;
|
||||||
@ -408,12 +409,12 @@ cursor_from(Line* self, PyObject *args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
line_clear_text(Line *self, unsigned int at, unsigned int num, int ch) {
|
line_clear_text(Line *self, unsigned int at, unsigned int num, char_type ch) {
|
||||||
const char_type repl = ((char_type)ch & CHAR_MASK) | ( (ch ? 1 : 0) << ATTRS_SHIFT);
|
attrs_type width = ch ? 1 : 0;
|
||||||
#define PREFIX \
|
#define PREFIX \
|
||||||
for (index_type i = at; i < MIN(self->xnum, at + num); i++) { \
|
for (index_type i = at; i < MIN(self->xnum, at + num); i++) { \
|
||||||
self->cells[i].ch = (self->cells[i].ch & ATTRS_MASK_WITHOUT_WIDTH) | repl; \
|
self->cells[i].ch = ch; self->cells[i].cc = 0; \
|
||||||
self->cells[i].cc = 0;
|
self->cells[i].attrs = (self->cells[i].attrs & ATTRS_MASK_WITHOUT_WIDTH) | width;
|
||||||
if (CHAR_IS_BLANK(ch)) {
|
if (CHAR_IS_BLANK(ch)) {
|
||||||
PREFIX
|
PREFIX
|
||||||
clear_sprite_position(self->cells[i]); }
|
clear_sprite_position(self->cells[i]); }
|
||||||
@ -438,16 +439,17 @@ line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int num,
|
|||||||
char_type attrs = CURSOR_TO_ATTRS(cursor, 1);
|
char_type attrs = CURSOR_TO_ATTRS(cursor, 1);
|
||||||
color_type fg = (cursor->fg & COL_MASK), bg = (cursor->bg & COL_MASK);
|
color_type fg = (cursor->fg & COL_MASK), bg = (cursor->bg & COL_MASK);
|
||||||
color_type dfg = cursor->decoration_fg & COL_MASK;
|
color_type dfg = cursor->decoration_fg & COL_MASK;
|
||||||
if (!clear_char) attrs = ((attrs >> ATTRS_SHIFT) & ~WIDTH_MASK) << ATTRS_SHIFT;
|
if (!clear_char) attrs = attrs & ATTRS_MASK_WITHOUT_WIDTH;
|
||||||
|
|
||||||
for (index_type i = at; i < self->xnum && i < at + num; i++) {
|
for (index_type i = at; i < self->xnum && i < at + num; i++) {
|
||||||
if (clear_char) {
|
if (clear_char) {
|
||||||
self->cells[i].ch = BLANK_CHAR | attrs;
|
self->cells[i].ch = BLANK_CHAR;
|
||||||
self->cells[i].cc = 0;
|
self->cells[i].cc = 0;
|
||||||
|
self->cells[i].attrs = attrs;
|
||||||
clear_sprite_position(self->cells[i]);
|
clear_sprite_position(self->cells[i]);
|
||||||
} else {
|
} else {
|
||||||
char_type w = ((self->cells[i].ch >> ATTRS_SHIFT) & WIDTH_MASK) << ATTRS_SHIFT;
|
attrs_type w = self->cells[i].attrs & WIDTH_MASK;
|
||||||
self->cells[i].ch = (self->cells[i].ch & CHAR_MASK) | attrs | w;
|
self->cells[i].attrs = attrs | w;
|
||||||
set_sprite_position_at(i);
|
set_sprite_position_at(i);
|
||||||
}
|
}
|
||||||
self->cells[i].fg = fg; self->cells[i].bg = bg;
|
self->cells[i].fg = fg; self->cells[i].bg = bg;
|
||||||
@ -471,9 +473,10 @@ void line_right_shift(Line *self, unsigned int at, unsigned int num) {
|
|||||||
COPY_SELF_CELL(i - num, i)
|
COPY_SELF_CELL(i - num, i)
|
||||||
}
|
}
|
||||||
// Check if a wide character was split at the right edge
|
// Check if a wide character was split at the right edge
|
||||||
char_type w = (self->cells[self->xnum - 1].ch >> ATTRS_SHIFT) & WIDTH_MASK;
|
char_type w = (self->cells[self->xnum - 1].attrs) & WIDTH_MASK;
|
||||||
if (w != 1) {
|
if (w != 1) {
|
||||||
self->cells[self->xnum - 1].ch = ((BLANK_CHAR ? 1 : 0) << ATTRS_SHIFT) | BLANK_CHAR;
|
self->cells[self->xnum - 1].ch = BLANK_CHAR;
|
||||||
|
self->cells[self->xnum - 1].attrs = BLANK_CHAR ? 1 : 0;
|
||||||
clear_sprite_position(self->cells[self->xnum - 1]);
|
clear_sprite_position(self->cells[self->xnum - 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -508,16 +511,15 @@ left_shift(Line *self, PyObject *args) {
|
|||||||
|
|
||||||
void
|
void
|
||||||
line_set_char(Line *self, unsigned int at, uint32_t ch, unsigned int width, Cursor *cursor, bool is_second) {
|
line_set_char(Line *self, unsigned int at, uint32_t ch, unsigned int width, Cursor *cursor, bool is_second) {
|
||||||
char_type attrs;
|
|
||||||
if (cursor == NULL) {
|
if (cursor == NULL) {
|
||||||
attrs = (((self->cells[at].ch >> ATTRS_SHIFT) & ~WIDTH_MASK) | (width & WIDTH_MASK)) << ATTRS_SHIFT;
|
self->cells[at].attrs = (self->cells[at].attrs & ATTRS_MASK_WITHOUT_WIDTH) | width;
|
||||||
} else {
|
} else {
|
||||||
attrs = CURSOR_TO_ATTRS(cursor, width & WIDTH_MASK);
|
self->cells[at].attrs = CURSOR_TO_ATTRS(cursor, width & WIDTH_MASK);
|
||||||
self->cells[at].fg = (cursor->fg & COL_MASK);
|
self->cells[at].fg = (cursor->fg & COL_MASK);
|
||||||
self->cells[at].bg = (cursor->bg & COL_MASK);
|
self->cells[at].bg = (cursor->bg & COL_MASK);
|
||||||
self->cells[at].decoration_fg = cursor->decoration_fg & COL_MASK;
|
self->cells[at].decoration_fg = cursor->decoration_fg & COL_MASK;
|
||||||
}
|
}
|
||||||
self->cells[at].ch = (ch & CHAR_MASK) | attrs;
|
self->cells[at].ch = ch;
|
||||||
self->cells[at].cc = 0;
|
self->cells[at].cc = 0;
|
||||||
if (!is_second && CHAR_IS_BLANK(ch)) { clear_sprite_position(self->cells[at]); }
|
if (!is_second && CHAR_IS_BLANK(ch)) { clear_sprite_position(self->cells[at]); }
|
||||||
else set_sprite_position_at(at);
|
else set_sprite_position_at(at);
|
||||||
|
|||||||
@ -22,10 +22,11 @@ update_sprites_in_line(Cell *cells, index_type xnum) {
|
|||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
set_attribute_on_line(Cell *cells, uint32_t shift, uint32_t val, index_type xnum) {
|
set_attribute_on_line(Cell *cells, uint32_t shift, uint32_t val, index_type xnum) {
|
||||||
uint32_t mask = shift == DECORATION_SHIFT ? 3 : 1;
|
// Set a single attribute on all cells in the line
|
||||||
uint32_t aval = (val & mask) << (ATTRS_SHIFT + shift);
|
attrs_type mask = shift == DECORATION_SHIFT ? 3 : 1;
|
||||||
mask = ~(mask << (ATTRS_SHIFT + shift));
|
attrs_type aval = (val & mask) << shift;
|
||||||
for (index_type i = 0; i < xnum; i++) cells[i].ch = (cells[i].ch & mask) | aval;
|
mask = ~(mask << shift);
|
||||||
|
for (index_type i = 0; i < xnum; i++) cells[i].attrs = (cells[i].attrs & mask) | aval;
|
||||||
if (shift == BOLD_SHIFT || shift == ITALIC_SHIFT) update_sprites_in_line(cells, xnum);
|
if (shift == BOLD_SHIFT || shift == ITALIC_SHIFT) update_sprites_in_line(cells, xnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,21 +43,22 @@ copy_line(const Line *src, Line *dest) {
|
|||||||
static inline void
|
static inline void
|
||||||
clear_chars_in_line(Cell *cells, index_type xnum, char_type ch) {
|
clear_chars_in_line(Cell *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
|
// Clear only the char part of each cell, the rest must have been cleared by a memset or similar
|
||||||
char_type c = (1 << ATTRS_SHIFT) | ch;
|
if (ch) {
|
||||||
for (index_type i = 0; i < xnum; i++) cells[i].ch = c;
|
for (index_type i = 0; i < xnum; i++) { cells[i].ch = ch; cells[i].attrs = 1; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline index_type
|
static inline index_type
|
||||||
xlimit_for_line(Line *line) {
|
xlimit_for_line(Line *line) {
|
||||||
index_type xlimit = line->xnum;
|
index_type xlimit = line->xnum;
|
||||||
if (BLANK_CHAR == 0) {
|
if (BLANK_CHAR == 0) {
|
||||||
while (xlimit > 0 && (line->cells[xlimit - 1].ch & CHAR_MASK) == BLANK_CHAR) xlimit--;
|
while (xlimit > 0 && (line->cells[xlimit - 1].ch) == BLANK_CHAR) xlimit--;
|
||||||
}
|
}
|
||||||
return xlimit;
|
return xlimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* line_text_at(char_type, combining_type);
|
PyObject* line_text_at(char_type, combining_type);
|
||||||
void line_clear_text(Line *self, unsigned int at, unsigned int num, int ch);
|
void line_clear_text(Line *self, unsigned int at, unsigned int num, char_type ch);
|
||||||
void line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int num, bool clear_char);
|
void line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int num, bool clear_char);
|
||||||
void line_set_char(Line *, unsigned int , uint32_t , unsigned int , Cursor *, bool);
|
void line_set_char(Line *, unsigned int , uint32_t , unsigned int , Cursor *, bool);
|
||||||
void line_right_shift(Line *, unsigned int , unsigned int );
|
void line_right_shift(Line *, unsigned int , unsigned int );
|
||||||
|
|||||||
@ -59,7 +59,7 @@ rewrap_inner(BufType *src, BufType *dest, const index_type src_limit, HistoryBuf
|
|||||||
src_x_limit = src->xnum;
|
src_x_limit = src->xnum;
|
||||||
if (!src_line_is_continued) {
|
if (!src_line_is_continued) {
|
||||||
// Trim trailing blanks since there is a hard line break at the end of this line
|
// Trim trailing blanks since there is a hard line break at the end of this line
|
||||||
while(src_x_limit && (src->line->cells[src_x_limit - 1].ch & CHAR_MASK) == BLANK_CHAR) src_x_limit--;
|
while(src_x_limit && (src->line->cells[src_x_limit - 1].ch) == BLANK_CHAR) src_x_limit--;
|
||||||
|
|
||||||
}
|
}
|
||||||
while (src_x < src_x_limit) {
|
while (src_x < src_x_limit) {
|
||||||
|
|||||||
@ -1366,7 +1366,7 @@ screen_selection_range_for_word(Screen *self, index_type x, index_type y, index_
|
|||||||
if (y >= self->lines || x >= self->columns) return false;
|
if (y >= self->lines || x >= self->columns) return false;
|
||||||
index_type start, end;
|
index_type start, end;
|
||||||
Line *line = visual_line_(self, y);
|
Line *line = visual_line_(self, y);
|
||||||
#define is_ok(x) (is_word_char((line->cells[x].ch) & CHAR_MASK) || is_opt_word_char(line->cells[x].ch & CHAR_MASK))
|
#define is_ok(x) (is_word_char((line->cells[x].ch)) || is_opt_word_char(line->cells[x].ch))
|
||||||
if (!is_ok(x)) {
|
if (!is_ok(x)) {
|
||||||
start = x; end = x + 1;
|
start = x; end = x + 1;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -591,8 +591,7 @@ create_cell_vao() {
|
|||||||
#define A1(name, size, dtype, offset) A(name, size, dtype, (void*)(offsetof(Cell, offset)), sizeof(Cell))
|
#define A1(name, size, dtype, offset) A(name, size, dtype, (void*)(offsetof(Cell, offset)), sizeof(Cell))
|
||||||
|
|
||||||
add_buffer_to_vao(vao_idx, GL_ARRAY_BUFFER);
|
add_buffer_to_vao(vao_idx, GL_ARRAY_BUFFER);
|
||||||
A1(text_attrs, 1, GL_UNSIGNED_INT, ch);
|
A1(sprite_coords, 4, GL_UNSIGNED_SHORT, sprite_x);
|
||||||
A1(sprite_coords, 3, GL_UNSIGNED_SHORT, sprite_x);
|
|
||||||
A1(colors, 3, GL_UNSIGNED_INT, fg);
|
A1(colors, 3, GL_UNSIGNED_INT, fg);
|
||||||
add_buffer_to_vao(vao_idx, GL_ARRAY_BUFFER);
|
add_buffer_to_vao(vao_idx, GL_ARRAY_BUFFER);
|
||||||
A(is_selected, 1, GL_FLOAT, NULL, 0);
|
A(is_selected, 1, GL_FLOAT, NULL, 0);
|
||||||
|
|||||||
@ -15,6 +15,7 @@ struct SpritePosition {
|
|||||||
sprite_index x, y, z;
|
sprite_index x, y, z;
|
||||||
char_type ch;
|
char_type ch;
|
||||||
combining_type cc;
|
combining_type cc;
|
||||||
|
bool bold, italic;
|
||||||
bool is_second;
|
bool is_second;
|
||||||
bool filled;
|
bool filled;
|
||||||
bool rendered;
|
bool rendered;
|
||||||
@ -88,15 +89,15 @@ do_increment(int *error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SpritePosition*
|
SpritePosition*
|
||||||
sprite_map_position_for(char_type ch, combining_type cc, bool is_second, int *error) {
|
sprite_map_position_for(char_type ch, attrs_type attrs, combining_type cc, bool is_second, int *error) {
|
||||||
char_type pos_char = ch & POSCHAR_MASK; // Includes only the char and bold and italic bits
|
uint8_t bold_italic = (attrs >> BOLD_SHIFT) & 3;
|
||||||
unsigned int idx = ((ch >> (ATTRS_SHIFT - 4)) & 0x300) | (ch & 0xFF); // Includes only italic, bold and lowest byte of ch
|
unsigned int idx = (ch & 0xFF) | (bold_italic << 8); // Only bold italic bits and lowest byte of char
|
||||||
SpritePosition *s = &(sprite_map.cache[idx]);
|
SpritePosition *s = &(sprite_map.cache[idx]);
|
||||||
// Optimize for the common case of an ASCII char already in the cache
|
// Optimize for the common case of an ASCII char already in the cache
|
||||||
if (LIKELY(s->ch == pos_char && s->filled && s->cc == cc && s->is_second == is_second)) return s; // Cache hit
|
if (LIKELY(s->ch == ch && s->filled && s->cc == cc && s->is_second == is_second)) return s; // Cache hit
|
||||||
while(true) {
|
while(true) {
|
||||||
if (s->filled) {
|
if (s->filled) {
|
||||||
if (s->ch == pos_char && s->cc == cc && s->is_second == is_second) return s; // Cache hit
|
if (s->ch == ch && s->cc == cc && s->is_second == is_second) return s; // Cache hit
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -106,11 +107,13 @@ sprite_map_position_for(char_type ch, combining_type cc, bool is_second, int *er
|
|||||||
}
|
}
|
||||||
s = s->next;
|
s = s->next;
|
||||||
}
|
}
|
||||||
s->ch = pos_char;
|
s->ch = ch;
|
||||||
s->cc = cc;
|
s->cc = cc;
|
||||||
s->is_second = is_second;
|
s->is_second = is_second;
|
||||||
s->filled = true;
|
s->filled = true;
|
||||||
s->rendered = false;
|
s->rendered = false;
|
||||||
|
s->bold = bold_italic & 1;
|
||||||
|
s->italic = bold_italic >> 1;
|
||||||
s->x = sprite_map.x; s->y = sprite_map.y; s->z = sprite_map.z;
|
s->x = sprite_map.x; s->y = sprite_map.y; s->z = sprite_map.z;
|
||||||
do_increment(error);
|
do_increment(error);
|
||||||
sprite_map.dirty = true;
|
sprite_map.dirty = true;
|
||||||
@ -122,10 +125,10 @@ void
|
|||||||
set_sprite_position(Cell *cell, Cell *previous_cell) {
|
set_sprite_position(Cell *cell, Cell *previous_cell) {
|
||||||
SpritePosition *sp;
|
SpritePosition *sp;
|
||||||
static int error;
|
static int error;
|
||||||
if (UNLIKELY(previous_cell != NULL && ((previous_cell->ch >> ATTRS_SHIFT) & WIDTH_MASK) == 2)) {
|
if (UNLIKELY(previous_cell != NULL && ((previous_cell->attrs) & WIDTH_MASK) == 2)) {
|
||||||
sp = sprite_map_position_for(previous_cell->ch, 0, true, &error);
|
sp = sprite_map_position_for(previous_cell->ch, previous_cell->attrs, 0, true, &error);
|
||||||
} else {
|
} else {
|
||||||
sp = sprite_map_position_for(cell->ch, cell->cc, false, &error);
|
sp = sprite_map_position_for(cell->ch, cell->attrs, cell->cc, false, &error);
|
||||||
}
|
}
|
||||||
cell->sprite_x = sp->x;
|
cell->sprite_x = sp->x;
|
||||||
cell->sprite_y = sp->y;
|
cell->sprite_y = sp->y;
|
||||||
@ -178,12 +181,13 @@ sprite_map_current_layout(unsigned int *x, unsigned int *y, unsigned int *z) {
|
|||||||
|
|
||||||
PyObject*
|
PyObject*
|
||||||
sprite_position_for(PyObject UNUSED *self, PyObject *args) {
|
sprite_position_for(PyObject UNUSED *self, PyObject *args) {
|
||||||
#define position_for_doc "position_for(ch, cc, is_second) -> x, y, z the sprite position for the specified text"
|
#define sprite_position_for_doc "sprite_position_for(ch, cc, is_second, attrs) -> x, y, z the sprite position for the specified text"
|
||||||
unsigned long ch = 0;
|
unsigned long ch = 0;
|
||||||
unsigned long long cc = 0;
|
unsigned long long cc = 0;
|
||||||
|
unsigned int attrs = 1;
|
||||||
int is_second = 0, error = 0;
|
int is_second = 0, error = 0;
|
||||||
if (!PyArg_ParseTuple(args, "|kKp", &ch, &cc, &is_second)) return NULL;
|
if (!PyArg_ParseTuple(args, "|kKpI", &ch, &cc, &is_second, &attrs)) return NULL;
|
||||||
SpritePosition *pos = sprite_map_position_for(ch, cc, is_second, &error);
|
SpritePosition *pos = sprite_map_position_for(ch, attrs, cc, is_second, &error);
|
||||||
if (pos == NULL) { sprite_map_set_error(error); return NULL; }
|
if (pos == NULL) { sprite_map_set_error(error); return NULL; }
|
||||||
return Py_BuildValue("III", pos->x, pos->y, pos->z);
|
return Py_BuildValue("III", pos->x, pos->y, pos->z);
|
||||||
}
|
}
|
||||||
@ -197,10 +201,8 @@ render_dirty_sprites(void (*render)(PyObject*, bool, bool, bool, sprite_index, s
|
|||||||
SpritePosition *sp = &(sprite_map.cache[i]);
|
SpritePosition *sp = &(sprite_map.cache[i]);
|
||||||
do {
|
do {
|
||||||
if (sp->filled && !sp->rendered) {
|
if (sp->filled && !sp->rendered) {
|
||||||
PyObject *text = line_text_at(sp->ch & CHAR_MASK, sp->cc);
|
PyObject *text = line_text_at(sp->ch, sp->cc);
|
||||||
char_type attrs = sp->ch >> ATTRS_SHIFT;
|
render(text, sp->bold, sp->italic, sp->is_second, sp->x, sp->y, sp->z);
|
||||||
bool bold = (attrs >> BOLD_SHIFT) & 1, italic = (attrs >> ITALIC_SHIFT) & 1;
|
|
||||||
render(text, bold, italic, sp->is_second, sp->x, sp->y, sp->z);
|
|
||||||
Py_CLEAR(text);
|
Py_CLEAR(text);
|
||||||
sp->rendered = true;
|
sp->rendered = true;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user