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:
Kovid Goyal 2018-02-02 12:05:52 +05:30
parent 4c53a74fa9
commit 2ee9844c2b
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
6 changed files with 43 additions and 34 deletions

View File

@ -279,8 +279,9 @@ void historybuf_rewrap(HistoryBuf *self, HistoryBuf *other) {
return; return;
} }
other->count = 0; other->start_of_data = 0; other->count = 0; other->start_of_data = 0;
index_type x = 0, y = 0;
if (self->count > 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; for (index_type i = 0; i < other->count; i++) other->line_attrs[(other->start_of_data + i) % other->ynum] |= TEXT_DIRTY_MASK;
} }
} }

View File

@ -494,7 +494,7 @@ copy_old(LineBuf *self, PyObject *y) {
#include "rewrap.h" #include "rewrap.h"
void 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; index_type first, i;
bool is_empty = true; bool is_empty = true;
@ -523,7 +523,7 @@ linebuf_rewrap(LineBuf *self, LineBuf *other, index_type *num_content_lines_befo
return; 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; *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] |= TEXT_DIRTY_MASK;
*num_content_lines_before = first + 1; *num_content_lines_before = first + 1;
@ -536,7 +536,8 @@ rewrap(LineBuf *self, PyObject *args) {
unsigned int nclb, ncla; unsigned int nclb, ncla;
if (!PyArg_ParseTuple(args, "O!O!", &LineBuf_Type, &other, &HistoryBuf_Type, &historybuf)) return NULL; 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); return Py_BuildValue("II", nclb, ncla);
} }

View File

@ -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_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_delete_lines(LineBuf *self, index_type num, index_type y, index_type bottom);
void linebuf_set_attribute(LineBuf *, unsigned int , unsigned int ); 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_dirty(LineBuf *self, index_type y);
void linebuf_mark_line_clean(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); unsigned int linebuf_char_width_at(LineBuf *self, index_type x, index_type y);

View File

@ -48,12 +48,13 @@ copy_range(Line *src, index_type src_at, Line* dest, index_type dest_at, index_t
static void 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; 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; index_type src_y = 0, src_x = 0, dest_x = 0, dest_y = 0, num = 0, src_x_limit = 0;
first_dest_line; first_dest_line;
do { do {
bool is_tracked_line = src_y == *track_y;
init_src_line(src_y); init_src_line(src_y);
src_line_is_continued = is_src_line_continued(src_y); src_line_is_continued = is_src_line_continued(src_y);
src_x_limit = src->xnum; 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--; 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) { while (src_x < src_x_limit) {
if (dest_x >= dest->xnum) { next_dest_line(true); dest_x = 0; } if (dest_x >= dest->xnum) { next_dest_line(true); dest_x = 0; }
num = MIN(src->line->xnum - src_x, dest->xnum - dest_x); num = MIN(src->line->xnum - src_x, dest->xnum - dest_x);
copy_range(src->line, src_x, dest->line, dest_x, num); 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_x += num; dest_x += num;
} }
src_y++; src_x = 0; src_y++; src_x = 0;

View File

@ -135,10 +135,10 @@ realloc_hb(HistoryBuf *old, unsigned int lines, unsigned int columns) {
} }
static inline LineBuf* 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); LineBuf *ans = alloc_linebuf(lines, columns);
if (ans == NULL) { PyErr_NoMemory(); return NULL; } 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; return ans;
} }
@ -147,31 +147,37 @@ screen_resize(Screen *self, unsigned int lines, unsigned int columns) {
lines = MAX(1, lines); columns = MAX(1, columns); lines = MAX(1, lines); columns = MAX(1, columns);
bool is_main = self->linebuf == self->main_linebuf; bool is_main = self->linebuf == self->main_linebuf;
index_type num_content_lines_before, num_content_lines_after; index_type num_content_lines_before, num_content_lines_after, num_content_lines;
index_type num_content_lines = 0, old_columns = self->columns; unsigned int cursor_x = 0, cursor_y = 0;
bool cursor_on_last_content_line = false; 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 // Resize main linebuf
HistoryBuf *nh = realloc_hb(self->historybuf, self->historybuf->ynum, columns); HistoryBuf *nh = realloc_hb(self->historybuf, self->historybuf->ynum, columns);
if (nh == NULL) return false; if (nh == NULL) return false;
Py_CLEAR(self->historybuf); self->historybuf = nh; 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; if (n == NULL) return false;
Py_CLEAR(self->main_linebuf); self->main_linebuf = n; Py_CLEAR(self->main_linebuf); self->main_linebuf = n;
if (is_main) { if (is_main) setup_cursor();
num_content_lines = num_content_lines_after;
cursor_on_last_content_line = num_content_lines_before == self->cursor->y + 1 || !num_content_lines_before;
}
grman_resize(self->main_grman, self->lines, lines, self->columns, columns); grman_resize(self->main_grman, self->lines, lines, self->columns, columns);
// Resize alt linebuf // 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; if (n == NULL) return false;
Py_CLEAR(self->alt_linebuf); self->alt_linebuf = n; 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); grman_resize(self->alt_grman, self->lines, lines, self->columns, columns);
#undef setup_cursor
self->linebuf = is_main ? self->main_linebuf : self->alt_linebuf; 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->lines = lines; self->columns = columns;
self->margin_top = 0; self->margin_bottom = self->lines - 1; 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->selection = EMPTY_SELECTION;
self->url_range = EMPTY_SELECTION; self->url_range = EMPTY_SELECTION;
self->selection_updated_once = false; self->selection_updated_once = false;
/* 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); */
// Ensure cursor is on the correct line self->cursor->x = MIN(cursor_x, self->columns - 1);
self->cursor->x = 0; self->cursor->y = MIN(cursor_y, self->lines - 1);
if (cursor_on_last_content_line) { if (cursor_is_beyond_content) {
index_type delta; self->cursor->y = num_content_lines;
if (self->columns > old_columns) delta = 1; if (self->cursor->y >= self->lines) { self->cursor->y = self->lines - 1; screen_index(self); }
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);
return true; return true;
} }

View File

@ -217,13 +217,13 @@ class TestScreen(BaseTest):
s = self.create_screen(scrollback=6) s = self.create_screen(scrollback=6)
s.draw(''.join([str(i) * s.columns for i in range(s.lines)])) s.draw(''.join([str(i) * s.columns for i in range(s.lines)]))
s.resize(3, 10) s.resize(3, 10)
self.ae(str(s.line(0)), '2'*5 + '3'*5) self.ae(str(s.line(0)), '0'*5 + '1'*5)
self.ae(str(s.line(1)), '4'*5) self.ae(str(s.line(1)), '2'*5 + '3'*5)
self.ae(str(s.line(2)), ''*5) self.ae(str(s.line(2)), '4'*5)
s.resize(5, 1) s.resize(5, 1)
self.ae(str(s.line(0)), '4') self.ae(str(s.line(0)), '4')
hb = s.historybuf 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 = self.create_screen(scrollback=20)
s.draw(''.join(str(i) * s.columns for i in range(s.lines*2))) s.draw(''.join(str(i) * s.columns for i in range(s.lines*2)))
self.ae(str(s.linebuf), '55555\n66666\n77777\n88888\n99999') self.ae(str(s.linebuf), '55555\n66666\n77777\n88888\n99999')