From 1f5fa03015edb5ef418658bb784072536c8728ef Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 23 Jul 2021 10:19:42 +0530 Subject: [PATCH] Use a union for line attrs Allows faster construction of Line objects without needing to set individual booleans. And cleaner code. --- kitty/data-types.h | 23 +++++++++-------- kitty/history.c | 38 +++++++++++++--------------- kitty/line-buf.c | 63 +++++++++++++++++++++++----------------------- kitty/line.c | 4 +-- kitty/lineops.h | 15 ----------- kitty/rewrap.h | 8 +++--- kitty/screen.c | 40 ++++++++++++++--------------- 7 files changed, 89 insertions(+), 102 deletions(-) diff --git a/kitty/data-types.h b/kitty/data-types.h index 36908f6e3..75345b6a5 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -53,7 +53,6 @@ typedef uint32_t pixel; typedef unsigned int index_type; typedef uint16_t sprite_index; typedef uint16_t attrs_type; -typedef uint8_t line_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; @@ -83,12 +82,6 @@ typedef enum { TILING, SCALED, MIRRORED } BackgroundImageLayout; #define COL_MASK 0xFFFFFFFF #define DECORATION_FG_CODE 58 #define CHAR_IS_BLANK(ch) ((ch) == 32 || (ch) == 0) -enum { - CONTINUED_MASK=1, - TEXT_DIRTY_MASK=2, - PROMPT_START_MASK=4, - OUTPUT_START_MASK=8 -}; #define FG 1 #define BG 2 @@ -174,6 +167,15 @@ typedef struct { hyperlink_id_type hyperlink_id; } CPUCell; +typedef union LineAttrs { + struct { + uint8_t continued : 1; + uint8_t has_dirty_text : 1; + uint8_t is_prompt_start : 1; + uint8_t is_output_start : 1; + } bits; + uint8_t val; +} LineAttrs ; typedef struct { PyObject_HEAD @@ -181,7 +183,8 @@ typedef struct { GPUCell *gpu_cells; CPUCell *cpu_cells; index_type xnum, ynum; - bool continued, needs_free, has_dirty_text, is_prompt_start, is_output_start; + bool needs_free; + LineAttrs attrs; } Line; @@ -191,14 +194,14 @@ typedef struct { GPUCell *gpu_cell_buf; CPUCell *cpu_cell_buf; index_type xnum, ynum, *line_map, *scratch; - line_attrs_type *line_attrs; + LineAttrs *line_attrs; Line *line; } LineBuf; typedef struct { GPUCell *gpu_cells; CPUCell *cpu_cells; - line_attrs_type *line_attrs; + LineAttrs *line_attrs; } HistoryBufSegment; typedef struct { diff --git a/kitty/history.c b/kitty/history.c index 1fc161240..843877e91 100644 --- a/kitty/history.c +++ b/kitty/history.c @@ -22,10 +22,10 @@ add_segment(HistoryBuf *self) { HistoryBufSegment *s = self->segments + self->num_segments - 1; const size_t cpu_cells_size = self->xnum * SEGMENT_SIZE * sizeof(CPUCell); const size_t gpu_cells_size = self->xnum * SEGMENT_SIZE * sizeof(GPUCell); - s->cpu_cells = calloc(1, cpu_cells_size + gpu_cells_size + SEGMENT_SIZE * sizeof(line_attrs_type)); + s->cpu_cells = calloc(1, cpu_cells_size + gpu_cells_size + SEGMENT_SIZE * sizeof(LineAttrs)); if (!s->cpu_cells) fatal("Out of memory allocating new history buffer segment"); s->gpu_cells = (GPUCell*)(((uint8_t*)s->cpu_cells) + cpu_cells_size); - s->line_attrs = (line_attrs_type*)(((uint8_t*)s->gpu_cells) + gpu_cells_size); + s->line_attrs = (LineAttrs*)(((uint8_t*)s->gpu_cells) + gpu_cells_size); } static index_type @@ -53,7 +53,7 @@ gpu_lineptr(HistoryBuf *self, index_type y) { } -static line_attrs_type* +static LineAttrs* attrptr(HistoryBuf *self, index_type y) { seg_ptr(line_attrs, 1); } @@ -147,7 +147,7 @@ init_line(HistoryBuf *self, index_type num, Line *l) { // Initialize the line l, setting its pointer to the offsets for the line at index (buffer position) num l->cpu_cells = cpu_lineptr(self, num); l->gpu_cells = gpu_lineptr(self, num); - copy_line_attrs_to_line(*attrptr(self, num), l); + l->attrs = *attrptr(self, num); } void @@ -162,14 +162,12 @@ historybuf_cpu_cells(HistoryBuf *self, index_type lnum) { void historybuf_mark_line_clean(HistoryBuf *self, index_type y) { - line_attrs_type *p = attrptr(self, index_of(self, y)); - *p &= ~TEXT_DIRTY_MASK; + attrptr(self, index_of(self, y))->bits.has_dirty_text = false; } void historybuf_mark_line_dirty(HistoryBuf *self, index_type y) { - line_attrs_type *p = attrptr(self, index_of(self, y)); - *p |= TEXT_DIRTY_MASK; + attrptr(self, index_of(self, y))->bits.has_dirty_text = true; } void @@ -227,7 +225,7 @@ pagerhist_push(HistoryBuf *self, ANSIBuf *as_ansi_buf) { Line l = {.xnum=self->xnum}; init_line(self, self->start_of_data, &l); line_as_ansi(&l, as_ansi_buf, &prev_cell); - if (ringbuf_bytes_used(ph->ringbuf) && !l.continued) pagerhist_write_bytes(ph, (const uint8_t*)"\n", 1); + if (ringbuf_bytes_used(ph->ringbuf) && !l.attrs.bits.continued) pagerhist_write_bytes(ph, (const uint8_t*)"\n", 1); pagerhist_write_bytes(ph, (const uint8_t*)"\x1b[m", 3); if (pagerhist_write_ucs4(ph, as_ansi_buf->buf, as_ansi_buf->len)) pagerhist_write_bytes(ph, (const uint8_t*)"\r", 1); } @@ -247,7 +245,7 @@ void historybuf_add_line(HistoryBuf *self, const Line *line, ANSIBuf *as_ansi_buf) { index_type idx = historybuf_push(self, as_ansi_buf); copy_line(line, self->line); - *attrptr(self, idx) = line_attrs_from_line(line); + *attrptr(self, idx) = line->attrs; } bool @@ -306,10 +304,10 @@ as_ansi(HistoryBuf *self, PyObject *callback) { for(unsigned int i = 0; i < self->count; i++) { init_line(self, i, &l); if (i < self->count - 1) { - l.continued = *attrptr(self, index_of(self, i + 1)) & CONTINUED_MASK; - } else l.continued = false; + l.attrs.bits.continued = attrptr(self, index_of(self, i + 1))->bits.continued; + } else l.attrs.bits.continued = false; line_as_ansi(&l, &output, &prev_cell); - if (!l.continued) { + if (!l.attrs.bits.continued) { ensure_space_for(&output, buf, Py_UCS4, output.len + 1, capacity, 2048, false); output.buf[output.len++] = 10; // 10 = \n } @@ -411,12 +409,12 @@ pagerhist_as_bytes(HistoryBuf *self, PyObject *args UNUSED) { Line l = {.xnum=self->xnum}; get_line(self, 0, &l); size_t sz = ringbuf_bytes_used(ph->ringbuf); - if (!l.continued) sz += 1; + if (!l.attrs.bits.continued) sz += 1; PyObject *ans = PyBytes_FromStringAndSize(NULL, sz); if (!ans) return NULL; uint8_t *buf = (uint8_t*)PyBytes_AS_STRING(ans); ringbuf_memcpy_from(buf, ph->ringbuf, sz); - if (!l.continued) buf[sz-1] = '\n'; + if (!l.attrs.bits.continued) buf[sz-1] = '\n'; return ans; #undef ph } @@ -460,7 +458,7 @@ dirty_lines(HistoryBuf *self, PyObject *a UNUSED) { #define dirty_lines_doc "dirty_lines() -> Line numbers of all lines that have dirty text." PyObject *ans = PyList_New(0); for (index_type i = 0; i < self->count; i++) { - if (*attrptr(self, i) & TEXT_DIRTY_MASK) { + if (attrptr(self, i)->bits.has_dirty_text) { PyList_Append(ans, PyLong_FromUnsignedLong(i)); } } @@ -527,9 +525,9 @@ HistoryBuf *alloc_historybuf(unsigned int lines, unsigned int columns, unsigned #define init_src_line(src_y) init_line(src, map_src_index(src_y), src->line); -#define is_src_line_continued(src_y) (map_src_index(src_y) < src->ynum - 1 ? (*attrptr(src, map_src_index(src_y + 1)) & CONTINUED_MASK) : false) +#define is_src_line_continued(src_y) (map_src_index(src_y) < src->ynum - 1 ? (attrptr(src, map_src_index(src_y + 1))->bits.continued) : false) -#define next_dest_line(cont) *attrptr(dest, historybuf_push(dest, as_ansi_buf)) = (cont ? CONTINUED_MASK : 0) | line_attrs_from_line(src->line); dest->line->continued = cont; +#define next_dest_line(cont) { LineAttrs *lap = attrptr(dest, historybuf_push(dest, as_ansi_buf)); *lap = src->line->attrs; if (cont) lap->bits.continued = true; dest->line->attrs.bits.continued = cont; } #define first_dest_line next_dest_line(false); @@ -543,7 +541,7 @@ historybuf_rewrap(HistoryBuf *self, HistoryBuf *other, ANSIBuf *as_ansi_buf) { for (index_type i = 0; i < self->num_segments; i++) { memcpy(other->segments[i].cpu_cells, self->segments[i].cpu_cells, SEGMENT_SIZE * self->xnum * sizeof(CPUCell)); memcpy(other->segments[i].gpu_cells, self->segments[i].gpu_cells, SEGMENT_SIZE * self->xnum * sizeof(GPUCell)); - memcpy(other->segments[i].line_attrs, self->segments[i].line_attrs, SEGMENT_SIZE * sizeof(line_attrs_type)); + memcpy(other->segments[i].line_attrs, self->segments[i].line_attrs, SEGMENT_SIZE * sizeof(LineAttrs)); } other->count = self->count; other->start_of_data = self->start_of_data; return; @@ -553,7 +551,7 @@ historybuf_rewrap(HistoryBuf *self, HistoryBuf *other, ANSIBuf *as_ansi_buf) { other->count = 0; other->start_of_data = 0; if (self->count > 0) { rewrap_inner(self, other, self->count, NULL, NULL, as_ansi_buf); - for (index_type i = 0; i < other->count; i++) *attrptr(other, (other->start_of_data + i) % other->ynum) |= TEXT_DIRTY_MASK; + for (index_type i = 0; i < other->count; i++) attrptr(other, (other->start_of_data + i) % other->ynum)->bits.has_dirty_text = true; } } diff --git a/kitty/line-buf.c b/kitty/line-buf.c index 1b9c6d140..392e290a0 100644 --- a/kitty/line-buf.c +++ b/kitty/line-buf.c @@ -36,36 +36,37 @@ linebuf_clear(LineBuf *self, char_type ch) { if (ch != 0) { for (index_type i = 0; i < self->ynum; i++) { clear_chars_to(self, i, ch); - self->line_attrs[i] = TEXT_DIRTY_MASK; + self->line_attrs[i].val = 0; + self->line_attrs[i].bits.has_dirty_text = true; } } } void linebuf_mark_line_dirty(LineBuf *self, index_type y) { - self->line_attrs[y] |= TEXT_DIRTY_MASK; + self->line_attrs[y].bits.has_dirty_text = true; } void linebuf_mark_line_clean(LineBuf *self, index_type y) { - self->line_attrs[y] &= ~TEXT_DIRTY_MASK; + self->line_attrs[y].bits.has_dirty_text = false; } void linebuf_mark_line_as_not_continued(LineBuf *self, index_type y) { - self->line_attrs[y] &= ~CONTINUED_MASK; + self->line_attrs[y].bits.continued = false; } void linebuf_mark_line_as_prompt_start(LineBuf *self, index_type y) { - self->line_attrs[y] |= PROMPT_START_MASK; - self->line_attrs[y] &= ~OUTPUT_START_MASK; + self->line_attrs[y].bits.is_prompt_start = true; + self->line_attrs[y].bits.is_output_start = false; } void linebuf_mark_line_as_output_start(LineBuf *self, index_type y) { - self->line_attrs[y] &= ~PROMPT_START_MASK; - self->line_attrs[y] |= OUTPUT_START_MASK; + self->line_attrs[y].bits.is_prompt_start = false; + self->line_attrs[y].bits.is_output_start = true; } @@ -102,7 +103,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) { self->gpu_cell_buf = PyMem_Calloc(xnum * ynum, sizeof(GPUCell)); self->line_map = PyMem_Calloc(ynum, sizeof(index_type)); self->scratch = PyMem_Calloc(ynum, sizeof(index_type)); - self->line_attrs = PyMem_Calloc(ynum, sizeof(line_attrs_type)); + self->line_attrs = PyMem_Calloc(ynum, sizeof(LineAttrs)); self->line = alloc_line(); if (self->cpu_cell_buf == NULL || self->gpu_cell_buf == NULL || self->line_map == NULL || self->scratch == NULL || self->line_attrs == NULL || self->line == NULL) { PyErr_NoMemory(); @@ -141,7 +142,7 @@ void linebuf_init_line(LineBuf *self, index_type idx) { self->line->ynum = idx; self->line->xnum = self->xnum; - copy_line_attrs_to_line(self->line_attrs[idx], self->line); + self->line->attrs = self->line_attrs[idx]; init_line(self, self->line, self->line_map[idx]); } @@ -167,7 +168,7 @@ 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] |= TEXT_DIRTY_MASK; + self->line_attrs[y].bits.has_dirty_text = true; } } @@ -188,8 +189,7 @@ set_continued(LineBuf *self, PyObject *args) { int val; if (!PyArg_ParseTuple(args, "Ip", &y, &val)) return NULL; if (y >= self->ynum) { PyErr_SetString(PyExc_ValueError, "Out of bounds."); return NULL; } - if (val) self->line_attrs[y] |= CONTINUED_MASK; - else self->line_attrs[y] &= ~CONTINUED_MASK; + self->line_attrs[y].bits.continued = val; Py_RETURN_NONE; } @@ -198,7 +198,7 @@ dirty_lines(LineBuf *self, PyObject *a UNUSED) { #define dirty_lines_doc "dirty_lines() -> Line numbers of all lines that have dirty text." PyObject *ans = PyList_New(0); for (index_type i = 0; i < self->ynum; i++) { - if (self->line_attrs[i] & TEXT_DIRTY_MASK) { + if (self->line_attrs[i].bits.has_dirty_text) { PyList_Append(ans, PyLong_FromUnsignedLong(i)); } } @@ -229,7 +229,7 @@ create_line_copy_inner(LineBuf* self, index_type y) { src.xnum = self->xnum; line->xnum = self->xnum; if (!allocate_line_storage(line, 0)) { Py_CLEAR(line); return PyErr_NoMemory(); } line->ynum = y; - copy_line_attrs_to_line(self->line_attrs[y], line); + line->attrs = self->line_attrs[y]; init_line(self, &src, self->line_map[y]); copy_line(&src, line); return (PyObject*)line; @@ -251,7 +251,7 @@ copy_line_to(LineBuf *self, PyObject *args) { if (!PyArg_ParseTuple(args, "IO!", &y, &Line_Type, &dest)) return NULL; src.xnum = self->xnum; dest->xnum = self->xnum; dest->ynum = y; - copy_line_attrs_to_line(self->line_attrs[y], dest); + dest->attrs = self->line_attrs[y]; init_line(self, &src, self->line_map[y]); copy_line(&src, dest); Py_RETURN_NONE; @@ -262,7 +262,7 @@ clear_line_(Line *l, index_type xnum) { zero_at_ptr_count(l->cpu_cells, xnum); zero_at_ptr_count(l->gpu_cells, xnum); if (BLANK_CHAR != 0) clear_chars_in_line(l->cpu_cells, l->gpu_cells, xnum, BLANK_CHAR); - l->has_dirty_text = false; + l->attrs.bits.has_dirty_text = false; } void @@ -270,7 +270,7 @@ linebuf_clear_line(LineBuf *self, index_type y, bool clear_attrs) { Line l; init_line(self, &l, self->line_map[y]); clear_line_(&l, self->xnum); - if (clear_attrs) self->line_attrs[y] = 0; + if (clear_attrs) self->line_attrs[y].val = 0; } static PyObject* @@ -286,13 +286,13 @@ void linebuf_index(LineBuf* self, index_type top, index_type bottom) { if (top >= self->ynum - 1 || bottom >= self->ynum || bottom <= top) return; index_type old_top = self->line_map[top]; - line_attrs_type old_attrs = self->line_attrs[top]; + LineAttrs old_attrs = self->line_attrs[top]; for (index_type i = top; i < bottom; i++) { self->line_map[i] = self->line_map[i + 1]; self->line_attrs[i] = self->line_attrs[i + 1]; } self->line_map[bottom] = old_top; - self->line_attrs[bottom] = old_attrs; + self->line_attrs[bottom]= old_attrs; } static PyObject* @@ -308,7 +308,7 @@ void linebuf_reverse_index(LineBuf *self, index_type top, index_type bottom) { if (top >= self->ynum - 1 || bottom >= self->ynum || bottom <= top) return; index_type old_bottom = self->line_map[bottom]; - line_attrs_type old_attrs = self->line_attrs[bottom]; + LineAttrs old_attrs = self->line_attrs[bottom]; for (index_type i = bottom; i > top; i--) { self->line_map[i] = self->line_map[i - 1]; self->line_attrs[i] = self->line_attrs[i - 1]; @@ -332,7 +332,7 @@ is_continued(LineBuf *self, PyObject *val) { #define is_continued_doc "is_continued(y) -> Whether the line y is continued or not" unsigned long y = PyLong_AsUnsignedLong(val); if (y >= self->ynum) { PyErr_SetString(PyExc_ValueError, "Out of bounds."); return NULL; } - if (self->line_attrs[y] & CONTINUED_MASK) { Py_RETURN_TRUE; } + if (self->line_attrs[y].bits.continued) { Py_RETURN_TRUE; } Py_RETURN_FALSE; } @@ -350,7 +350,7 @@ linebuf_insert_lines(LineBuf *self, unsigned int num, unsigned int y, unsigned i self->line_map[i] = self->line_map[i - num]; self->line_attrs[i] = self->line_attrs[i - num]; } - if (y + num < self->ynum) self->line_attrs[y + num] &= ~CONTINUED_MASK; + if (y + num < self->ynum) self->line_attrs[y + num].bits.continued = false; for (i = 0; i < num; i++) { self->line_map[y + i] = self->scratch[ylimit - num + i]; } @@ -358,7 +358,7 @@ linebuf_insert_lines(LineBuf *self, unsigned int num, unsigned int y, unsigned i for (i = y; i < y + num; i++) { init_line(self, &l, self->line_map[i]); clear_line_(&l, self->xnum); - self->line_attrs[i] = 0; + self->line_attrs[i].val = 0; } } } @@ -385,7 +385,7 @@ linebuf_delete_lines(LineBuf *self, index_type num, index_type y, index_type bot self->line_map[i] = self->line_map[i + num]; self->line_attrs[i] = self->line_attrs[i + num]; } - self->line_attrs[y] &= ~CONTINUED_MASK; + self->line_attrs[y].bits.continued = false; for (i = 0; i < num; i++) { self->line_map[ylimit - num + i] = self->scratch[y + i]; } @@ -393,7 +393,7 @@ linebuf_delete_lines(LineBuf *self, index_type num, index_type y, index_type bot for (i = ylimit - num; i < ylimit; i++) { init_line(self, &l, self->line_map[i]); clear_line_(&l, self->xnum); - self->line_attrs[i] = 0; + self->line_attrs[i].val = 0; } } @@ -410,7 +410,8 @@ void linebuf_copy_line_to(LineBuf *self, Line *line, index_type where) { init_line(self, self->line, self->line_map[where]); copy_line(line, self->line); - self->line_attrs[where] = TEXT_DIRTY_MASK | line_attrs_from_line(line); + self->line_attrs[where] = line->attrs; + self->line_attrs[where].bits.has_dirty_text = true; } static PyObject* @@ -429,10 +430,10 @@ as_ansi(LineBuf *self, PyObject *callback) { } while(ylimit > 0); for(index_type i = 0; i <= ylimit; i++) { - l.continued = ((i < self->ynum - 1) ? self->line_attrs[i+1] : self->line_attrs[i]) & CONTINUED_MASK; + l.attrs.bits.continued = self->line_attrs[(i + 1 < self->ynum) ? i+1 : i].bits.continued; init_line(self, (&l), self->line_map[i]); line_as_ansi(&l, &output, &prev_cell); - if (!l.continued) { + if (!l.attrs.bits.continued) { ensure_space_for(&output, buf, Py_UCS4, output.len + 1, capacity, 2048, false); output.buf[output.len++] = 10; // 10 = \n } @@ -561,7 +562,7 @@ linebuf_rewrap(LineBuf *self, LineBuf *other, index_type *num_content_lines_befo // Fast path if (other->xnum == self->xnum && other->ynum == self->ynum) { memcpy(other->line_map, self->line_map, sizeof(index_type) * self->ynum); - memcpy(other->line_attrs, self->line_attrs, sizeof(bool) * self->ynum); + memcpy(other->line_attrs, self->line_attrs, sizeof(LineAttrs) * self->ynum); memcpy(other->cpu_cell_buf, self->cpu_cell_buf, (size_t)self->xnum * self->ynum * sizeof(CPUCell)); memcpy(other->gpu_cell_buf, self->gpu_cell_buf, (size_t)self->xnum * self->ynum * sizeof(GPUCell)); *num_content_lines_before = self->ynum; *num_content_lines_after = self->ynum; @@ -589,7 +590,7 @@ linebuf_rewrap(LineBuf *self, LineBuf *other, index_type *num_content_lines_befo *track_x = tcarr[0].x; *track_y = tcarr[0].y; *track_x2 = tcarr[1].x; *track_y2 = tcarr[1].y; *num_content_lines_after = other->line->ynum + 1; - for (i = 0; i < *num_content_lines_after; i++) other->line_attrs[i] |= TEXT_DIRTY_MASK; + for (i = 0; i < *num_content_lines_after; i++) other->line_attrs[i].bits.has_dirty_text = true; *num_content_lines_before = first + 1; } diff --git a/kitty/line.c b/kitty/line.c index 97fe76193..31eb9b378 100644 --- a/kitty/line.c +++ b/kitty/line.c @@ -373,7 +373,7 @@ as_ansi(Line* self, PyObject *a UNUSED) { static PyObject* is_continued(Line* self, PyObject *a UNUSED) { #define is_continued_doc "Return the line's continued flag" - PyObject *ans = self->continued ? Py_True : Py_False; + PyObject *ans = self->attrs.bits.continued ? Py_True : Py_False; Py_INCREF(ans); return ans; } @@ -813,7 +813,7 @@ as_text_generic(PyObject *args, void *container, get_line_func get_line, index_t ansibuf->active_hyperlink_id = 0; for (index_type y = 0; y < lines; y++) { Line *line = get_line(container, y); - if (!line->continued && y > 0) { + if (!line->attrs.bits.continued && y > 0) { ret = PyObject_CallFunctionObjArgs(callback, nl, NULL); if (ret == NULL) goto end; Py_CLEAR(ret); diff --git a/kitty/lineops.h b/kitty/lineops.h index c2932e247..e2f965949 100644 --- a/kitty/lineops.h +++ b/kitty/lineops.h @@ -67,21 +67,6 @@ left_shift_line(Line *line, index_type at, index_type num) { } } -static inline void -copy_line_attrs_to_line(const line_attrs_type attrs, Line *line) { -#define S(a, m) line->a = (attrs & m) ? true: false - S(continued, CONTINUED_MASK); S(has_dirty_text, TEXT_DIRTY_MASK); - S(is_prompt_start, PROMPT_START_MASK); S(is_output_start, OUTPUT_START_MASK); -#undef S -} - -static inline line_attrs_type -line_attrs_from_line(const Line *line) { -#define S(a, m) (line->a ? m : 0) - return S(continued, CONTINUED_MASK) | S(has_dirty_text, TEXT_DIRTY_MASK) | S(is_prompt_start, PROMPT_START_MASK) | S(is_output_start, OUTPUT_START_MASK); -#undef S -} - typedef Line*(get_line_func)(void *, int); void line_clear_text(Line *self, unsigned int at, unsigned int num, char_type ch); diff --git a/kitty/rewrap.h b/kitty/rewrap.h index 3f00b8ffa..7f151b402 100644 --- a/kitty/rewrap.h +++ b/kitty/rewrap.h @@ -16,10 +16,10 @@ #endif #ifndef init_dest_line -#define init_dest_line(dest_y) init_line(dest, dest->line, dest->line_map[dest_y]); copy_line_attrs_to_line(dest->line_attrs[dest_y], dest->line); +#define init_dest_line(dest_y) init_line(dest, dest->line, dest->line_map[dest_y]); dest->line->attrs = dest->line_attrs[dest_y]; #endif -#define set_dest_line_attrs(dest_y, continued) dest->line_attrs[dest_y] = (continued ? CONTINUED_MASK : 0) | line_attrs_from_line(src->line); +#define set_dest_line_attrs(dest_y, continued_) dest->line_attrs[dest_y] = src->line->attrs; if (continued_) dest->line_attrs[dest_y].bits.continued = true; #ifndef first_dest_line #define first_dest_line init_dest_line(0); set_dest_line_attrs(0, false) @@ -31,7 +31,7 @@ linebuf_index(dest, 0, dest->ynum - 1); \ if (historybuf != NULL) { \ init_dest_line(dest->ynum - 1); \ - dest->line->has_dirty_text = true; \ + dest->line->attrs.bits.has_dirty_text = true; \ historybuf_add_line(historybuf, dest->line, as_ansi_buf); \ }\ linebuf_clear_line(dest, dest->ynum - 1, true); \ @@ -41,7 +41,7 @@ #endif #ifndef is_src_line_continued -#define is_src_line_continued(src_y) (src_y < src->ynum - 1 ? (src->line_attrs[src_y + 1] & CONTINUED_MASK) : false) +#define is_src_line_continued(src_y) (src_y < src->ynum - 1 ? (src->line_attrs[src_y + 1].bits.continued) : false) #endif static inline void diff --git a/kitty/screen.c b/kitty/screen.c index 8b1520695..cabdda40c 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -284,8 +284,8 @@ prevent_current_prompt_from_rewrapping(Screen *self, index_type columns) { while (y >= 0) { linebuf_init_line(self->main_linebuf, y); Line *line = self->linebuf->line; - if (line->is_output_start) return; - if (line->is_prompt_start) break; + if (line->attrs.bits.is_output_start) return; + if (line->attrs.bits.is_prompt_start) break; y--; } if (y < 0) return; @@ -470,7 +470,7 @@ move_widened_char(Screen *self, CPUCell* cpu_cell, GPUCell *gpu_cell, index_type if (self->modes.mDECAWM) { // overflow goes onto next line screen_carriage_return(self); screen_linefeed(self); - self->linebuf->line_attrs[self->cursor->y] |= CONTINUED_MASK; + self->linebuf->line_attrs[self->cursor->y].bits.continued = true; linebuf_init_line(self->linebuf, self->cursor->y); dest_cpu = self->linebuf->line->cpu_cells; dest_gpu = self->linebuf->line->gpu_cells; @@ -644,7 +644,7 @@ screen_draw(Screen *self, uint32_t och, bool from_input_stream) { if (self->modes.mDECAWM) { screen_carriage_return(self); screen_linefeed(self); - self->linebuf->line_attrs[self->cursor->y] |= CONTINUED_MASK; + self->linebuf->line_attrs[self->cursor->y].bits.continued = true; } else { self->cursor->x = self->columns - char_width; } @@ -1352,8 +1352,8 @@ screen_cursor_at_a_shell_prompt(const Screen *self) { if (self->cursor->y >= self->lines || self->linebuf != self->main_linebuf) return false; for (index_type y=self->cursor->y + 1; y-- > 0; ) { linebuf_init_line(self->linebuf, y); - if (self->linebuf->line->is_output_start) return -1; - if (self->linebuf->line->is_prompt_start) return y; + if (self->linebuf->line->attrs.bits.is_output_start) return -1; + if (self->linebuf->line->attrs.bits.is_prompt_start) return y; } return -1; } @@ -1810,16 +1810,16 @@ screen_history_scroll_to_prompt(Screen *self, int num_of_prompts_to_jump) { num_of_prompts_to_jump = num_of_prompts_to_jump < 0 ? -num_of_prompts_to_jump : num_of_prompts_to_jump; int y = -self->scrolled_by; #define ensure_y_ok if (y >= (int)self->lines || -y > (int)self->historybuf->count) return false; -#define move_y_to_start_of_promt while (-y + 1 <= (int)self->historybuf->count && range_line_(self, y - 1)->is_prompt_start) y--; -#define move_y_to_end_of_promt while (y + 1 < (int)self->lines && range_line_(self, y + 1)->is_prompt_start) y++; +#define move_y_to_start_of_promt while (-y + 1 <= (int)self->historybuf->count && range_line_(self, y - 1)->attrs.bits.is_prompt_start) y--; +#define move_y_to_end_of_promt while (y + 1 < (int)self->lines && range_line_(self, y + 1)->attrs.bits.is_prompt_start) y++; ensure_y_ok; - if (range_line_(self, y)->is_prompt_start) { + if (range_line_(self, y)->attrs.bits.is_prompt_start) { if (delta < 0) { move_y_to_start_of_promt; } else { move_y_to_end_of_promt; } } while (num_of_prompts_to_jump) { y += delta; ensure_y_ok; - if (range_line_(self, y)->is_prompt_start) { + if (range_line_(self, y)->attrs.bits.is_prompt_start) { num_of_prompts_to_jump--; if (delta < 0) { move_y_to_start_of_promt; } else { move_y_to_end_of_promt; } } @@ -1948,7 +1948,7 @@ screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE fonts_dat for (index_type y = 0; y < MIN(self->lines, self->scrolled_by); y++) { lnum = self->scrolled_by - 1 - y; historybuf_init_line(self->historybuf, lnum, self->historybuf->line); - if (self->historybuf->line->has_dirty_text) { + if (self->historybuf->line->attrs.bits.has_dirty_text) { render_line(fonts_data, self->historybuf->line, lnum, self->cursor, self->disable_ligatures); if (screen_has_marker(self)) mark_text_in_line(self->marker, self->historybuf->line); historybuf_mark_line_clean(self->historybuf, lnum); @@ -1958,10 +1958,10 @@ screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE fonts_dat for (index_type y = self->scrolled_by; y < self->lines; y++) { lnum = y - self->scrolled_by; linebuf_init_line(self->linebuf, lnum); - if (self->linebuf->line->has_dirty_text || + if (self->linebuf->line->attrs.bits.has_dirty_text || (cursor_has_moved && (self->cursor->y == lnum || self->last_rendered.cursor_y == lnum))) { render_line(fonts_data, self->linebuf->line, lnum, self->cursor, self->disable_ligatures); - if (self->linebuf->line->has_dirty_text && screen_has_marker(self)) mark_text_in_line(self->marker, self->linebuf->line); + if (self->linebuf->line->attrs.bits.has_dirty_text && screen_has_marker(self)) mark_text_in_line(self->marker, self->linebuf->line); linebuf_mark_line_clean(self->linebuf, lnum); } @@ -2178,7 +2178,7 @@ text_for_range(Screen *self, const Selection *sel, bool insert_newlines) { for (int i = 0, y = idata.y; y < limit; y++, i++) { Line *line = range_line_(self, y); XRange xr = xrange_for_iteration(&idata, y, line); - char leading_char = (i > 0 && insert_newlines && !line->continued) ? '\n' : 0; + char leading_char = (i > 0 && insert_newlines && !line->attrs.bits.continued) ? '\n' : 0; PyObject *text = unicode_in_range(line, xr.x, xr.x_limit, true, leading_char, false); if (text == NULL) { Py_DECREF(ans); return PyErr_NoMemory(); } PyTuple_SET_ITEM(ans, i, text); @@ -2447,8 +2447,8 @@ last_cmd_output(Screen *self, PyObject *args) { const int limit = -self->historybuf->count; while (y >= limit) { Line *line = range_line_(self, y); - if (line->is_prompt_start) prompt_pos = y; - if (line->is_output_start) { + if (line->attrs.bits.is_prompt_start) prompt_pos = y; + if (line->attrs.bits.is_output_start) { oo.start = y; num_lines = prompt_pos - y; break; @@ -2790,7 +2790,7 @@ screen_selection_range_for_word(Screen *self, const index_type x, const index_ty start = x; end = x; while(true) { while(start > 0 && is_ok(start - 1)) start--; - if (start > 0 || !line->continued || *y1 == 0) break; + if (start > 0 || !line->attrs.bits.continued || *y1 == 0) break; line = visual_line_(self, *y1 - 1); if (!is_ok(self->columns - 1)) break; (*y1)--; start = self->columns - 1; @@ -2800,7 +2800,7 @@ screen_selection_range_for_word(Screen *self, const index_type x, const index_ty while(end < self->columns - 1 && is_ok(end + 1)) end++; if (end < self->columns - 1 || *y2 >= self->lines - 1) break; line = visual_line_(self, *y2 + 1); - if (!line->continued || !is_ok(0)) break; + if (!line->attrs.bits.continued || !is_ok(0)) break; (*y2)++; end = 0; } *s = start; *e = end; @@ -2968,7 +2968,7 @@ screen_mark_hyperlink(Screen *self, index_type x, index_type y) { static index_type continue_line_upwards(Screen *self, index_type top_line, SelectionBoundary *start, SelectionBoundary *end) { - while (top_line > 0 && visual_line_(self, top_line)->continued) { + while (top_line > 0 && visual_line_(self, top_line)->attrs.bits.continued) { if (!screen_selection_range_for_line(self, top_line - 1, &start->x, &end->x)) break; top_line--; } @@ -2977,7 +2977,7 @@ continue_line_upwards(Screen *self, index_type top_line, SelectionBoundary *star static index_type continue_line_downwards(Screen *self, index_type bottom_line, SelectionBoundary *start, SelectionBoundary *end) { - while (bottom_line < self->lines - 1 && visual_line_(self, bottom_line + 1)->continued) { + while (bottom_line < self->lines - 1 && visual_line_(self, bottom_line + 1)->attrs.bits.continued) { if (!screen_selection_range_for_line(self, bottom_line + 1, &start->x, &end->x)) break; bottom_line++; }