mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-16 13:34:48 +02:00
More work on rewrapping multicells
This commit is contained in:
@@ -650,12 +650,12 @@ restitch(Line *dest, index_type at, LineBuf *src, const index_type src_y, TrackC
|
||||
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->y >= src_y) tc->y -= num_of_lines_removed;
|
||||
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->y == src_y && tc->x >= num_cells_removed_on_last_line) tc->x -= num_cells_removed_on_last_line;
|
||||
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]));
|
||||
@@ -706,18 +706,26 @@ linebuf_rewrap(
|
||||
return;
|
||||
}
|
||||
*num_content_lines_before = first + 1;
|
||||
TrackCursor tcarr[3] = {{.x = *track_x, .y = *track_y }, {.x = *track_x2, .y = *track_y2}, {.is_sentinel = true}};
|
||||
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}
|
||||
};
|
||||
*num_content_lines_after = 1 + linebuf_rewrap_inner(self, other, *num_content_lines_before, historybuf, (TrackCursor*)tcarr, as_ansi_buf);
|
||||
*track_x = tcarr[0].x; *track_y = tcarr[0].y;
|
||||
*track_x2 = tcarr[1].x; *track_y2 = tcarr[1].y;
|
||||
*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 }, {.x = *track_x2, .y = *track_y2}, {.is_sentinel = true}};
|
||||
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].x; *track_y = tcarr[0].y;
|
||||
*track_x2 = tcarr[1].x; *track_y2 = tcarr[1].y;
|
||||
*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;
|
||||
}
|
||||
}
|
||||
|
||||
146
kitty/rewrap.c
146
kitty/rewrap.c
@@ -79,7 +79,7 @@ typedef struct Rewrap {
|
||||
TrackCursor *cursors;
|
||||
index_type src_limit;
|
||||
|
||||
Line src, dest;
|
||||
Line src, dest, src_scratch, dest_scratch;
|
||||
index_type src_y, src_x, dest_x, dest_y, num, src_x_limit;
|
||||
init_line_func_t init_line;
|
||||
first_dest_line_func_t first_dest_line;
|
||||
@@ -135,42 +135,119 @@ init_src_line(Rewrap *r) {
|
||||
r->prev_src_line_ended_with_wrap = r->src.cpu_cells[r->src_xnum - 1].next_char_was_wrapped;
|
||||
r->src.cpu_cells[r->src_xnum - 1].next_char_was_wrapped = false;
|
||||
r->src_x = 0;
|
||||
for (TrackCursor *t = r->cursors; !t->is_sentinel; t++) {
|
||||
if (r->src_y == t->y) {
|
||||
t->is_tracked_line = true;
|
||||
if (t->x >= r->src_x_limit) t->x = MAX(1u, r->src_x_limit) - 1;
|
||||
} else t->is_tracked_line = false;
|
||||
r->current_src_line_has_multline_cells = false;
|
||||
for (index_type i = 0; i < r->src_x_limit; i++) if (r->src.cpu_cells[i].is_multicell && r->src.cpu_cells[i].scale > 1) {
|
||||
r->current_src_line_has_multline_cells = true;
|
||||
break;
|
||||
}
|
||||
return newline_needed;
|
||||
}
|
||||
|
||||
static index_type
|
||||
rewrap_inner(Rewrap r) {
|
||||
setup_line(r.text_cache, r.src_xnum, &r.src); setup_line(r.text_cache, r.dest_xnum, &r.dest);
|
||||
static TrackCursor tc_end = {.is_sentinel = true };
|
||||
if (!r.cursors) r.cursors = &tc_end;
|
||||
r.scratch = alloc_linebuf(SCALE_BITS << 1, r.dest_xnum, r.text_cache);
|
||||
if (!r.scratch) fatal("Out of memory");
|
||||
RAII_PyObject(scratch, (PyObject*)r.scratch);
|
||||
for (; r.src_y < r.src_limit; r.src_y++) {
|
||||
if (init_src_line(&r)) {
|
||||
if (r.src_y) next_dest_line(&r, false);
|
||||
else first_dest_line(&r);
|
||||
}
|
||||
while (r.src_x < r.src_x_limit) {
|
||||
if (r.dest_x >= r.dest_xnum) next_dest_line(&r, true);
|
||||
index_type num = MIN(r.src.xnum - r.src_x, r.dest_xnum - r.dest_x);
|
||||
copy_range(&r.src, r.src_x, &r.dest, r.dest_x, num);
|
||||
for (TrackCursor *t = r.cursors; !t->is_sentinel; t++) {
|
||||
if (t->is_tracked_line && r.src_x <= t->x && t->x < r.src_x + num) {
|
||||
t->y = r.dest_y;
|
||||
t->x = r.dest_x + (t->x - r.src_x + (t->x > 0));
|
||||
}
|
||||
}
|
||||
r.src_x += num; r.dest_x += num;
|
||||
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));
|
||||
}
|
||||
}
|
||||
return r.dest_y;
|
||||
}
|
||||
|
||||
static void
|
||||
fast_copy_src_to_dest(Rewrap *r) {
|
||||
CPUCell *c; index_type mc_width;
|
||||
while (r->src_x < r->src_x_limit) {
|
||||
if (r->dest_x >= r->dest_xnum) next_dest_line(r, true);
|
||||
index_type num = MIN(r->src_x_limit - r->src_x, r->dest_xnum - r->dest_x);
|
||||
bool do_copy = true;
|
||||
if (num && (c = &r->src.cpu_cells[r->src_x + num - 1])->is_multicell && c->x != (mc_width = mcd_x_limit(c)) - 1) {
|
||||
// we have a split multicell at the right edge of the copy region
|
||||
if (num > mc_width) num -= mc_width;
|
||||
else {
|
||||
if (mc_width > r->dest_xnum) do_copy = false;
|
||||
else {
|
||||
r->dest_x = r->dest_xnum;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (do_copy) copy_range(&r->src, r->src_x, &r->dest, r->dest_x, num);
|
||||
update_tracked_cursors(r, num, r->src_y, r->src_x_limit);
|
||||
r->src_x += num; r->dest_x += num;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
find_space_in_dest_line(Rewrap *r, index_type num_cells) {
|
||||
while (r->dest_x + num_cells <= r->dest_xnum) {
|
||||
index_type before = r->dest_x;
|
||||
for (index_type x = r->dest_x; x < r->dest_x + num_cells; x++) {
|
||||
if (r->dest.cpu_cells[x].is_multicell) {
|
||||
r->dest_x = x + mcd_x_limit(r->dest.cpu_cells + x);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (before == r->dest_x) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
find_space_in_dest(Rewrap *r, index_type num_cells) {
|
||||
while (!find_space_in_dest_line(r, num_cells)) next_dest_line(r, true);
|
||||
}
|
||||
|
||||
static void
|
||||
copy_multiline_extra_lines(Rewrap *r, CPUCell *src_cell, index_type mc_width) {
|
||||
for (index_type i = 1; i < src_cell->scale; i++) {
|
||||
r->init_line(r->src_buf, r->src_y + i, &r->src_scratch);
|
||||
linebuf_init_line_at(r->scratch, i - 1, &r->dest_scratch);
|
||||
linebuf_mark_line_dirty(r->scratch, i - 1);
|
||||
copy_range(&r->src_scratch, r->src_x, &r->dest_scratch, r->dest_x, mc_width);
|
||||
update_tracked_cursors(r, mc_width, r->src_y + i, r->src_xnum + 10000 /* ensure cursor is moved only if in region being copied */);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
multiline_copy_src_to_dest(Rewrap *r) {
|
||||
CPUCell *c; index_type mc_width;
|
||||
while (r->src_x < r->src_x_limit) {
|
||||
c = &r->src.cpu_cells[r->src_x];
|
||||
if (c->is_multicell) {
|
||||
mc_width = mcd_x_limit(c);
|
||||
if (c->y || mc_width > r->dest_xnum) {
|
||||
update_tracked_cursors(r, mc_width, r->src_y, r->src_x_limit);
|
||||
r->src_x += mc_width;
|
||||
continue;
|
||||
}
|
||||
} else mc_width = 1;
|
||||
find_space_in_dest(r, mc_width);
|
||||
copy_range(&r->src, r->src_x, &r->dest, r->dest_x, mc_width);
|
||||
update_tracked_cursors(r, mc_width, r->src_y, r->src_x_limit);
|
||||
if (c->scale > 1) copy_multiline_extra_lines(r, c, mc_width);
|
||||
r->src_x += mc_width; r->dest_x += mc_width;
|
||||
}
|
||||
}
|
||||
|
||||
static index_type
|
||||
rewrap_inner(Rewrap *r) {
|
||||
setup_line(r->text_cache, r->src_xnum, &r->src); setup_line(r->text_cache, r->dest_xnum, &r->dest);
|
||||
setup_line(r->text_cache, r->src_xnum, &r->src_scratch); setup_line(r->text_cache, r->dest_xnum, &r->dest_scratch);
|
||||
|
||||
r->scratch = alloc_linebuf(SCALE_BITS << 1, r->dest_xnum, r->text_cache);
|
||||
if (!r->scratch) fatal("Out of memory");
|
||||
RAII_PyObject(scratch, (PyObject*)r->scratch); (void)scratch;
|
||||
for (; r->src_y < r->src_limit; r->src_y++) {
|
||||
if (init_src_line(r)) {
|
||||
if (r->src_y) next_dest_line(r, false);
|
||||
else first_dest_line(r);
|
||||
}
|
||||
if (r->current_src_line_has_multline_cells || r->current_dest_line_has_multiline_cells) multiline_copy_src_to_dest(r);
|
||||
else fast_copy_src_to_dest(r);
|
||||
}
|
||||
return r->dest_y;
|
||||
}
|
||||
|
||||
index_type
|
||||
@@ -181,16 +258,17 @@ linebuf_rewrap_inner(LineBuf *src, LineBuf *dest, const index_type src_limit, Hi
|
||||
|
||||
.init_line = LineBuf_init_line, .next_dest_line = LineBuf_next_dest_line, .first_dest_line = LineBuf_first_dest_line,
|
||||
};
|
||||
return rewrap_inner(r);
|
||||
return rewrap_inner(&r);
|
||||
}
|
||||
|
||||
index_type
|
||||
historybuf_rewrap_inner(HistoryBuf *src, HistoryBuf *dest, const index_type src_limit, ANSIBuf *as_ansi_buf) {
|
||||
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,
|
||||
.src_limit = src_limit, .src_xnum = src->xnum, .dest_xnum = dest->xnum, .cursors=&t,
|
||||
|
||||
.init_line = HistoryBuf_init_line, .next_dest_line = HistoryBuf_next_dest_line, .first_dest_line = HistoryBuf_first_dest_line,
|
||||
};
|
||||
return rewrap_inner(r);
|
||||
return rewrap_inner(&r);
|
||||
}
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
#include "history.h"
|
||||
|
||||
typedef struct TrackCursor {
|
||||
index_type x, y;
|
||||
bool is_tracked_line, is_sentinel;
|
||||
const index_type x, y;
|
||||
index_type dest_x, dest_y;
|
||||
bool is_sentinel;
|
||||
} TrackCursor;
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user