Track cursor position explicitly during rewrap
Instead of using heuristics to position the cursor after a resize, track the position during re-wrapping and place the cursor at the re-wrapped position. Fixes #242 (I hope)
This commit is contained in:
parent
4c53a74fa9
commit
2ee9844c2b
@ -279,8 +279,9 @@ void historybuf_rewrap(HistoryBuf *self, HistoryBuf *other) {
|
||||
return;
|
||||
}
|
||||
other->count = 0; other->start_of_data = 0;
|
||||
index_type x = 0, y = 0;
|
||||
if (self->count > 0) {
|
||||
rewrap_inner(self, other, self->count, NULL);
|
||||
rewrap_inner(self, other, self->count, NULL, &x, &y);
|
||||
for (index_type i = 0; i < other->count; i++) other->line_attrs[(other->start_of_data + i) % other->ynum] |= TEXT_DIRTY_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
@ -494,7 +494,7 @@ copy_old(LineBuf *self, PyObject *y) {
|
||||
#include "rewrap.h"
|
||||
|
||||
void
|
||||
linebuf_rewrap(LineBuf *self, LineBuf *other, index_type *num_content_lines_before, index_type *num_content_lines_after, HistoryBuf *historybuf) {
|
||||
linebuf_rewrap(LineBuf *self, LineBuf *other, index_type *num_content_lines_before, index_type *num_content_lines_after, HistoryBuf *historybuf, index_type *track_x, index_type *track_y) {
|
||||
index_type first, i;
|
||||
bool is_empty = true;
|
||||
|
||||
@ -523,7 +523,7 @@ linebuf_rewrap(LineBuf *self, LineBuf *other, index_type *num_content_lines_befo
|
||||
return;
|
||||
}
|
||||
|
||||
rewrap_inner(self, other, first + 1, historybuf);
|
||||
rewrap_inner(self, other, first + 1, historybuf, track_x, track_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;
|
||||
*num_content_lines_before = first + 1;
|
||||
@ -536,7 +536,8 @@ rewrap(LineBuf *self, PyObject *args) {
|
||||
unsigned int nclb, ncla;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O!O!", &LineBuf_Type, &other, &HistoryBuf_Type, &historybuf)) return NULL;
|
||||
linebuf_rewrap(self, other, &nclb, &ncla, historybuf);
|
||||
index_type x = 0, y = 0;
|
||||
linebuf_rewrap(self, other, &nclb, &ncla, historybuf, &x, &y);
|
||||
|
||||
return Py_BuildValue("II", nclb, ncla);
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ void linebuf_clear_line(LineBuf *self, index_type y);
|
||||
void linebuf_insert_lines(LineBuf *self, unsigned int num, unsigned int y, unsigned int bottom);
|
||||
void linebuf_delete_lines(LineBuf *self, index_type num, index_type y, index_type bottom);
|
||||
void linebuf_set_attribute(LineBuf *, unsigned int , unsigned int );
|
||||
void linebuf_rewrap(LineBuf *self, LineBuf *other, index_type *, index_type *, HistoryBuf *);
|
||||
void linebuf_rewrap(LineBuf *self, LineBuf *other, index_type *, index_type *, HistoryBuf *, index_type *, index_type *);
|
||||
void linebuf_mark_line_dirty(LineBuf *self, index_type y);
|
||||
void linebuf_mark_line_clean(LineBuf *self, index_type y);
|
||||
unsigned int linebuf_char_width_at(LineBuf *self, index_type x, index_type y);
|
||||
|
||||
@ -48,12 +48,13 @@ copy_range(Line *src, index_type src_at, Line* dest, index_type dest_at, index_t
|
||||
|
||||
|
||||
static void
|
||||
rewrap_inner(BufType *src, BufType *dest, const index_type src_limit, HistoryBuf UNUSED *historybuf) {
|
||||
rewrap_inner(BufType *src, BufType *dest, const index_type src_limit, HistoryBuf UNUSED *historybuf, index_type *track_x, index_type *track_y) {
|
||||
bool src_line_is_continued = false;
|
||||
index_type src_y = 0, src_x = 0, dest_x = 0, dest_y = 0, num = 0, src_x_limit = 0;
|
||||
|
||||
first_dest_line;
|
||||
do {
|
||||
bool is_tracked_line = src_y == *track_y;
|
||||
init_src_line(src_y);
|
||||
src_line_is_continued = is_src_line_continued(src_y);
|
||||
src_x_limit = src->xnum;
|
||||
@ -62,10 +63,15 @@ rewrap_inner(BufType *src, BufType *dest, const index_type src_limit, HistoryBuf
|
||||
while(src_x_limit && (src->line->cells[src_x_limit - 1].ch) == BLANK_CHAR) src_x_limit--;
|
||||
|
||||
}
|
||||
if (is_tracked_line && *track_x >= src_x_limit) *track_x = MAX(1, src_x_limit) - 1;
|
||||
while (src_x < src_x_limit) {
|
||||
if (dest_x >= dest->xnum) { next_dest_line(true); dest_x = 0; }
|
||||
num = MIN(src->line->xnum - src_x, dest->xnum - dest_x);
|
||||
copy_range(src->line, src_x, dest->line, dest_x, num);
|
||||
if (is_tracked_line && src_x <= *track_x && *track_x < src_x + num) {
|
||||
*track_y = dest_y;
|
||||
*track_x = dest_x + (*track_x - src_x);
|
||||
}
|
||||
src_x += num; dest_x += num;
|
||||
}
|
||||
src_y++; src_x = 0;
|
||||
|
||||
@ -135,10 +135,10 @@ realloc_hb(HistoryBuf *old, unsigned int lines, unsigned int columns) {
|
||||
}
|
||||
|
||||
static inline LineBuf*
|
||||
realloc_lb(LineBuf *old, unsigned int lines, unsigned int columns, index_type *nclb, index_type *ncla, HistoryBuf *hb) {
|
||||
realloc_lb(LineBuf *old, unsigned int lines, unsigned int columns, index_type *nclb, index_type *ncla, HistoryBuf *hb, index_type *x, index_type *y) {
|
||||
LineBuf *ans = alloc_linebuf(lines, columns);
|
||||
if (ans == NULL) { PyErr_NoMemory(); return NULL; }
|
||||
linebuf_rewrap(old, ans, nclb, ncla, hb);
|
||||
linebuf_rewrap(old, ans, nclb, ncla, hb, x, y);
|
||||
return ans;
|
||||
}
|
||||
|
||||
@ -147,31 +147,37 @@ screen_resize(Screen *self, unsigned int lines, unsigned int columns) {
|
||||
lines = MAX(1, lines); columns = MAX(1, columns);
|
||||
|
||||
bool is_main = self->linebuf == self->main_linebuf;
|
||||
index_type num_content_lines_before, num_content_lines_after;
|
||||
index_type num_content_lines = 0, old_columns = self->columns;
|
||||
bool cursor_on_last_content_line = false;
|
||||
index_type num_content_lines_before, num_content_lines_after, num_content_lines;
|
||||
unsigned int cursor_x = 0, cursor_y = 0;
|
||||
bool cursor_is_beyond_content = false;
|
||||
#define setup_cursor() { \
|
||||
cursor_x = x; cursor_y = y; \
|
||||
cursor_is_beyond_content = num_content_lines_before > 0 && self->cursor->y >= num_content_lines_before; \
|
||||
num_content_lines = num_content_lines_after; \
|
||||
}
|
||||
|
||||
// Resize main linebuf
|
||||
HistoryBuf *nh = realloc_hb(self->historybuf, self->historybuf->ynum, columns);
|
||||
if (nh == NULL) return false;
|
||||
Py_CLEAR(self->historybuf); self->historybuf = nh;
|
||||
LineBuf *n = realloc_lb(self->main_linebuf, lines, columns, &num_content_lines_before, &num_content_lines_after, self->historybuf);
|
||||
index_type x = self->cursor->x, y = self->cursor->y;
|
||||
LineBuf *n = realloc_lb(self->main_linebuf, lines, columns, &num_content_lines_before, &num_content_lines_after, self->historybuf, &x, &y);
|
||||
if (n == NULL) return false;
|
||||
Py_CLEAR(self->main_linebuf); self->main_linebuf = n;
|
||||
if (is_main) {
|
||||
num_content_lines = num_content_lines_after;
|
||||
cursor_on_last_content_line = num_content_lines_before == self->cursor->y + 1 || !num_content_lines_before;
|
||||
}
|
||||
if (is_main) setup_cursor();
|
||||
grman_resize(self->main_grman, self->lines, lines, self->columns, columns);
|
||||
|
||||
// Resize alt linebuf
|
||||
n = realloc_lb(self->alt_linebuf, lines, columns, &num_content_lines_before, &num_content_lines_after, NULL);
|
||||
x = self->cursor->x, y = self->cursor->y;
|
||||
n = realloc_lb(self->alt_linebuf, lines, columns, &num_content_lines_before, &num_content_lines_after, NULL, &x, &y);
|
||||
if (n == NULL) return false;
|
||||
Py_CLEAR(self->alt_linebuf); self->alt_linebuf = n;
|
||||
if (!is_main) num_content_lines = num_content_lines_after;
|
||||
if (!is_main) setup_cursor();
|
||||
grman_resize(self->alt_grman, self->lines, lines, self->columns, columns);
|
||||
#undef setup_cursor
|
||||
|
||||
self->linebuf = is_main ? self->main_linebuf : self->alt_linebuf;
|
||||
/* printf("\nold_size: (%u, %u) new_size: (%u, %u)\n", self->columns, self->lines, columns, lines); */
|
||||
self->lines = lines; self->columns = columns;
|
||||
self->margin_top = 0; self->margin_bottom = self->lines - 1;
|
||||
|
||||
@ -186,18 +192,13 @@ screen_resize(Screen *self, unsigned int lines, unsigned int columns) {
|
||||
self->selection = EMPTY_SELECTION;
|
||||
self->url_range = EMPTY_SELECTION;
|
||||
self->selection_updated_once = false;
|
||||
|
||||
// Ensure cursor is on the correct line
|
||||
self->cursor->x = 0;
|
||||
if (cursor_on_last_content_line) {
|
||||
index_type delta;
|
||||
if (self->columns > old_columns) delta = 1;
|
||||
else delta = (old_columns / self->columns) + 1;
|
||||
self->cursor->y = num_content_lines > delta ? num_content_lines - delta : 0;
|
||||
} else self->cursor->y = num_content_lines;
|
||||
self->cursor->y = MIN(self->cursor->y, self->lines - 1);
|
||||
if (num_content_lines >= self->lines) screen_index(self);
|
||||
|
||||
/* printf("old_cursor: (%u, %u) new_cursor: (%u, %u) beyond_content: %d\n", self->cursor->x, self->cursor->y, cursor_x, cursor_y, cursor_is_beyond_content); */
|
||||
self->cursor->x = MIN(cursor_x, self->columns - 1);
|
||||
self->cursor->y = MIN(cursor_y, self->lines - 1);
|
||||
if (cursor_is_beyond_content) {
|
||||
self->cursor->y = num_content_lines;
|
||||
if (self->cursor->y >= self->lines) { self->cursor->y = self->lines - 1; screen_index(self); }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -217,13 +217,13 @@ class TestScreen(BaseTest):
|
||||
s = self.create_screen(scrollback=6)
|
||||
s.draw(''.join([str(i) * s.columns for i in range(s.lines)]))
|
||||
s.resize(3, 10)
|
||||
self.ae(str(s.line(0)), '2'*5 + '3'*5)
|
||||
self.ae(str(s.line(1)), '4'*5)
|
||||
self.ae(str(s.line(2)), ''*5)
|
||||
self.ae(str(s.line(0)), '0'*5 + '1'*5)
|
||||
self.ae(str(s.line(1)), '2'*5 + '3'*5)
|
||||
self.ae(str(s.line(2)), '4'*5)
|
||||
s.resize(5, 1)
|
||||
self.ae(str(s.line(0)), '4')
|
||||
hb = s.historybuf
|
||||
self.ae(str(hb), '4\n3\n3\n3\n3\n3')
|
||||
self.ae(str(hb), '3\n3\n3\n3\n3\n2')
|
||||
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')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user