diff --git a/kitty/line-buf.c b/kitty/line-buf.c index 05736041a..01ebead61 100644 --- a/kitty/line-buf.c +++ b/kitty/line-buf.c @@ -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; } diff --git a/kitty/rewrap.c b/kitty/rewrap.c index bc8177493..4311467f5 100644 --- a/kitty/rewrap.c +++ b/kitty/rewrap.c @@ -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, }; diff --git a/kitty/rewrap.h b/kitty/rewrap.h index fb9bb9559..b008ec35a 100644 --- a/kitty/rewrap.h +++ b/kitty/rewrap.h @@ -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); diff --git a/kitty_tests/screen.py b/kitty_tests/screen.py index 55e598e4c..31357b117 100644 --- a/kitty_tests/screen.py +++ b/kitty_tests/screen.py @@ -357,8 +357,10 @@ class TestScreen(BaseTest): s = self.create_screen(scrollback=20) s.draw(''.join(str(i) * s.columns for i in range(s.lines*2))) self.ae(str(s.linebuf), '55555\n66666\n77777\n88888\n99999') + before = at() s.resize(5, 2) - self.ae(str(s.linebuf), '88\n88\n99\n99\n9') + self.ae(before, at()) + self.ae(str(s.linebuf), '88\n88\n89\n99\n99') s = self.create_screen() s.draw('a' * s.columns) s.linefeed(), s.carriage_return()