Implement restitch during rewrap

Faster, less code and gets us multicell handling during restitching for
free.
This commit is contained in:
Kovid Goyal
2024-12-30 08:00:01 +05:30
parent b3c39f4921
commit c4a32862d1
4 changed files with 37 additions and 102 deletions

View File

@@ -596,81 +596,6 @@ copy_old(LineBuf *self, PyObject *y) {
Py_RETURN_NONE;
}
static index_type
restitch(Line *dest, index_type at, LineBuf *src, const index_type src_y, TrackCursor *cursors) {
index_type y = src_y, num_of_lines_removed = 0, num_cells_removed_on_last_line = 0;
bool last_char_has_wrapped_flag = true;
CPUCell *cp; GPUCell *gp;
// copy the cells into dest
while (at < dest->xnum && y < src->ynum) {
linebuf_init_cells(src, y, &cp, &gp);
index_type x = 0;
bool found_text = false;
while (at < dest->xnum && x < src->xnum) {
if (!found_text && cell_has_text(&cp[x])) found_text = true;
if (cp[x].is_multicell) {
// TODO: handle multiline chars
if (dest->xnum - at > cp[x].width) {
for (index_type i = 0; i < cp[x].width; i++) {
dest->cpu_cells[at] = cp[x];
dest->gpu_cells[at++] = gp[x++];
}
} else {
dest->cpu_cells[at] = (CPUCell){0};
dest->gpu_cells[at] = (GPUCell){0};
at = dest->xnum;
}
} else {
dest->cpu_cells[at] = cp[x];
dest->gpu_cells[at] = gp[x];
at++; x++;
}
}
if (!found_text) {
last_char_has_wrapped_flag = false;
break;
}
if (x >= src->xnum) { // Entire line was copied
num_of_lines_removed++;
bool line_ends_with_newline = !linebuf_line_ends_with_continuation(src, y);
if (line_ends_with_newline) {
last_char_has_wrapped_flag = false;
break;
}
} else {
num_cells_removed_on_last_line = x;
break;
}
y++;
}
dest->cpu_cells[dest->xnum - 1].next_char_was_wrapped = last_char_has_wrapped_flag;
// remove the copied lines and cells from src
if (num_of_lines_removed) {
for (index_type i = 0; i < num_of_lines_removed; i++) {
linebuf_clear_line(src, src_y, true);
linebuf_index(src, src_y, src->ynum - 1);
}
for (TrackCursor *tc = cursors; !tc->is_sentinel; tc++) if (tc->dest_y >= src_y) tc->dest_y -= num_of_lines_removed;
}
if (num_cells_removed_on_last_line) {
bool line_is_continued_to_next = linebuf_line_ends_with_continuation(src, src_y);
linebuf_init_cells(src, src_y, &cp, &gp);
for (TrackCursor *tc = cursors; !tc->is_sentinel; tc++) if (tc->dest_y == src_y && tc->dest_x >= num_cells_removed_on_last_line) tc->dest_x -= num_cells_removed_on_last_line;
index_type remaining_cells = src->xnum - num_cells_removed_on_last_line;
memmove(cp, cp + num_cells_removed_on_last_line, remaining_cells * sizeof(cp[0]));
memset(cp + remaining_cells, 0, num_cells_removed_on_last_line * sizeof(cp[0]));
memmove(gp, gp + num_cells_removed_on_last_line, remaining_cells * sizeof(gp[0]));
memset(gp + remaining_cells, 0, num_cells_removed_on_last_line * sizeof(gp[0]));
if (line_is_continued_to_next && remaining_cells < src->xnum && src->ynum > src_y + 1) {
Line next_dest = {.xnum=src->xnum};
init_line(src, &next_dest, src_y);
num_of_lines_removed += restitch(&next_dest, remaining_cells, src, src_y + 1, cursors);
}
}
return num_of_lines_removed;
}
void
linebuf_rewrap(
LineBuf *self, LineBuf *other, index_type *num_content_lines_before, index_type *num_content_lines_after,
@@ -711,24 +636,9 @@ linebuf_rewrap(
{.x = *track_x2, .y = *track_y2, .dest_x=*track_x2, .dest_y = *track_y2 },
{.is_sentinel = true}
};
*num_content_lines_after = 1 + linebuf_rewrap_inner(self, other, *num_content_lines_before, historybuf, (TrackCursor*)tcarr, as_ansi_buf);
*num_content_lines_after = 1 + linebuf_rewrap_inner(self, other, *num_content_lines_before, historybuf, (TrackCursor*)tcarr, as_ansi_buf, history_buf_last_line_is_split && historybuf != NULL);
*track_x = tcarr[0].dest_x; *track_y = tcarr[0].dest_y;
*track_x2 = tcarr[1].dest_x; *track_y2 = tcarr[1].dest_y;
if (history_buf_last_line_is_split && historybuf) {
historybuf_init_line(historybuf, 0, historybuf->line);
index_type xlimit = xlimit_for_line(historybuf->line);
if (xlimit < historybuf->line->xnum) {
TrackCursor tcarr[3] = {
{.x = *track_x, .y = *track_y, .dest_x=*track_x, .dest_y = *track_y },
{.x = *track_x2, .y = *track_y2, .dest_x=*track_x2, .dest_y = *track_y2 },
{.is_sentinel = true}
};
index_type num_of_lines_removed = restitch(historybuf->line, xlimit, other, 0, tcarr);
*track_x = tcarr[0].dest_x; *track_y = tcarr[0].dest_y;
*track_x2 = tcarr[1].dest_x; *track_y2 = tcarr[1].dest_y;
*num_content_lines_after -= num_of_lines_removed;
}
}
for (i = 0; i < *num_content_lines_after; i++) other->line_attrs[i].has_dirty_text = true;
}

View File

@@ -80,12 +80,13 @@ typedef struct Rewrap {
index_type src_limit;
Line src, dest, src_scratch, dest_scratch;
index_type src_y, src_x, dest_x, dest_y, num, src_x_limit;
index_type src_y, src_x, dest_x, dest_y, num, src_x_limit, history_buf_last_line_xlimit;
init_line_func_t init_line;
first_dest_line_func_t first_dest_line;
next_dest_line_func_t next_dest_line;
LineBuf *scratch;
bool current_dest_line_has_multiline_cells, current_src_line_has_multline_cells, prev_src_line_ended_with_wrap;
bool current_dest_line_is_last_history_line;
} Rewrap;
static void
@@ -102,9 +103,13 @@ setup_line(TextCache *tc, index_type xnum, Line *l) {
static void
next_dest_line(Rewrap *r, bool continued) {
r->dest_y = r->next_dest_line(r->dest_buf, r->historybuf, r->as_ansi_buf, &r->src, r->dest_y, &r->dest, continued);
r->dest_x = 0;
r->current_dest_line_has_multiline_cells = false;
if (r->current_dest_line_is_last_history_line) {
r->dest.cpu_cells[r->dest_xnum-1].next_char_was_wrapped = continued;
r->current_dest_line_is_last_history_line = false;
r->dest_y = r->first_dest_line(r->dest_buf, r->as_ansi_buf, &r->src, &r->dest);
} else r->dest_y = r->next_dest_line(r->dest_buf, r->historybuf, r->as_ansi_buf, &r->src, r->dest_y, &r->dest, continued);
if (r->scratch->line_attrs[0].has_dirty_text) {
CPUCell *cpu_cells; GPUCell *gpu_cells;
linebuf_init_cells(r->scratch, 0, &cpu_cells, &gpu_cells);
@@ -120,7 +125,15 @@ next_dest_line(Rewrap *r, bool continued) {
static void
first_dest_line(Rewrap *r) {
r->dest_y = r->first_dest_line(r->dest_buf, r->as_ansi_buf, &r->src, &r->dest);
if (r->history_buf_last_line_xlimit < r->dest_xnum && r->historybuf) {
r->dest_y = 0;
r->dest_x = r->history_buf_last_line_xlimit;
r->current_dest_line_has_multiline_cells = true;
r->current_dest_line_is_last_history_line = true;
historybuf_init_line(r->historybuf, 0, &r->dest);
} else {
r->dest_y = r->first_dest_line(r->dest_buf, r->as_ansi_buf, &r->src, &r->dest);
}
}
static bool
@@ -145,10 +158,14 @@ static void
update_tracked_cursors(Rewrap *r, index_type num_cells, index_type y, index_type x_limit) {
for (TrackCursor *t = r->cursors; !t->is_sentinel; t++) {
if (t->y == y && r->src_x <= t->x && (t->x < r->src_x + num_cells || t->x >= x_limit)) {
index_type x = t->x;
if (x >= x_limit) x = MAX(1u, x_limit) - 1;
t->dest_y = r->dest_y;
t->dest_x = r->dest_x + (x - r->src_x + (x > 0));
if (r->current_dest_line_is_last_history_line) {
t->dest_x = 0; t->dest_y = 0;
} else {
index_type x = t->x;
if (x >= x_limit) x = MAX(1u, x_limit) - 1;
t->dest_y = r->dest_y;
t->dest_x = r->dest_x + (x - r->src_x + (x > 0));
}
}
}
}
@@ -257,10 +274,16 @@ rewrap_inner(Rewrap *r) {
}
index_type
linebuf_rewrap_inner(LineBuf *src, LineBuf *dest, const index_type src_limit, HistoryBuf *historybuf, TrackCursor *track, ANSIBuf *as_ansi_buf) {
linebuf_rewrap_inner(LineBuf *src, LineBuf *dest, const index_type src_limit, HistoryBuf *historybuf, TrackCursor *track, ANSIBuf *as_ansi_buf, bool history_buf_last_line_is_split) {
index_type xlimit = dest->xnum;
if (history_buf_last_line_is_split && historybuf) {
historybuf_init_line(historybuf, 0, historybuf->line);
xlimit = xlimit_for_line(historybuf->line);
}
Rewrap r = {
.src_buf = src, .dest_buf = dest, .as_ansi_buf = as_ansi_buf, .text_cache = src->text_cache, .cursors = track,
.src_limit = src_limit, .historybuf=historybuf, .src_xnum = src->xnum, .dest_xnum = dest->xnum,
.history_buf_last_line_xlimit = xlimit,
.init_line = LineBuf_init_line, .next_dest_line = LineBuf_next_dest_line, .first_dest_line = LineBuf_first_dest_line,
};
@@ -272,7 +295,7 @@ historybuf_rewrap_inner(HistoryBuf *src, HistoryBuf *dest, const index_type src_
static TrackCursor t = {.is_sentinel = true };
Rewrap r = {
.src_buf = src, .dest_buf = dest, .as_ansi_buf = as_ansi_buf, .text_cache = src->text_cache,
.src_limit = src_limit, .src_xnum = src->xnum, .dest_xnum = dest->xnum, .cursors=&t,
.src_limit = src_limit, .src_xnum = src->xnum, .dest_xnum = dest->xnum, .cursors=&t, .history_buf_last_line_xlimit = dest->xnum,
.init_line = HistoryBuf_init_line, .next_dest_line = HistoryBuf_next_dest_line, .first_dest_line = HistoryBuf_first_dest_line,
};

View File

@@ -16,7 +16,7 @@ typedef struct TrackCursor {
} TrackCursor;
index_type linebuf_rewrap_inner(LineBuf *src, LineBuf *dest, const index_type src_limit, HistoryBuf *historybuf, TrackCursor *track, ANSIBuf *as_ansi_buf);
index_type linebuf_rewrap_inner(LineBuf *src, LineBuf *dest, const index_type src_limit, HistoryBuf *historybuf, TrackCursor *track, ANSIBuf *as_ansi_buf, bool history_buf_last_line_is_split);
index_type historybuf_rewrap_inner(HistoryBuf *src, HistoryBuf *dest, const index_type src_limit, ANSIBuf *as_ansi_buf);