Use a union for line attrs
Allows faster construction of Line objects without needing to set individual booleans. And cleaner code.
This commit is contained in:
parent
000e1012c6
commit
1f5fa03015
7 changed files with 89 additions and 102 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue