From 4813b79336a936abf2946dc3cacc3da1d16e592b Mon Sep 17 00:00:00 2001 From: Adam Saponara Date: Sat, 13 Apr 2024 15:06:23 -0400 Subject: [PATCH] replace `viewport_y` with `viewport_mark->bline->line_index` way back in the beginning, there was `viewport_y`. then in commit ad84c0f, `viewport_bline` was added as a perf shortcut for accessing the bline at `viewport_y`. in commit 2273cde, `viewport_mark` replaced `viewport_bline` to prevent use-after-free errors. and today we remove `viewport_y` entirely as it's redundant, and was causing a viewport bug described below. open a buffer with output from `seq 1 ` where N is greater than your terminal's line count. split the buffer and move the cursor to eof in the split. switch back to the original buffer. now start deleting lines from the top of the buffer. you'll notice the split will start rendering incorrectly around eof. this was due to `viewport_y` falling out of sync with `viewport_mark`. currently, we don't have a way to write viewport tests as tests run in headless mode. in the future we could do something similar to the termbox2 tests. --- bview.c | 18 +++++++++++------- cursor.c | 2 +- editor.c | 4 ++-- mle.h | 1 - 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/bview.c b/bview.c index fe94e69..114cd4c 100644 --- a/bview.c +++ b/bview.c @@ -340,9 +340,8 @@ int bview_set_viewport_y(bview_t *self, bint_t y, int do_rectify) { } else if (y >= self->buffer->line_count) { y = self->buffer->line_count - 1; } - self->viewport_y = y; + mark_move_to(self->viewport_mark, y, 0); if (do_rectify) bview_rectify_viewport(self); - mark_move_to(self->viewport_mark, self->viewport_y, 0); return MLE_OK; } @@ -370,17 +369,20 @@ int bview_max_viewport_y(bview_t *self) { // Rectify the viewport int bview_rectify_viewport(bview_t *self) { mark_t *mark; + bint_t viewport_y; + mark = self->active_cursor->mark; + viewport_y = self->viewport_mark->bline->line_index; // Rectify each dimension of the viewport MLBUF_BLINE_ENSURE_CHARS(mark->bline); _bview_rectify_viewport_dim(self, mark->bline, MLE_MARK_COL_TO_VCOL(mark), self->viewport_scope_x, self->rect_buffer.w, &self->viewport_x_vcol); bline_get_col_from_vcol(mark->bline, self->viewport_x_vcol, &(self->viewport_x)); - if (_bview_rectify_viewport_dim(self, mark->bline, mark->bline->line_index, self->viewport_scope_y, self->rect_buffer.h, &self->viewport_y)) { + if (_bview_rectify_viewport_dim(self, mark->bline, mark->bline->line_index, self->viewport_scope_y, self->rect_buffer.h, &viewport_y)) { // TODO viewport_y_vrow (soft-wrapped lines, code folding, etc) // Adjust viewport_mark - mark_move_to(self->viewport_mark, self->viewport_y, 0); + mark_move_to(self->viewport_mark, viewport_y, 0); } return MLE_OK; @@ -960,6 +962,7 @@ static void _bview_draw_edit(bview_t *self, int x, int y, int w, int h) { int fg_attr; int bg_attr; bline_t *bline; + bint_t viewport_y; // Handle split if (self->split_child) { @@ -1008,15 +1011,16 @@ static void _bview_draw_edit(bview_t *self, int x, int y, int w, int h) { // Render lines and margins bline = self->viewport_mark->bline; + viewport_y = bline->line_index; for (rect_y = 0; rect_y < self->rect_buffer.h; rect_y++) { - if (self->viewport_y + rect_y < 0 || self->viewport_y + rect_y >= self->buffer->line_count || !bline) { // "|| !bline" See TODOs below + if (viewport_y + rect_y < 0 || viewport_y + rect_y >= self->buffer->line_count) { // Draw pre/post blank tb_printf_rect(self->rect_lines, 0, rect_y, 0, 0, "%*c", self->linenum_width, '~'); tb_printf_rect(self->rect_margin_left, 0, rect_y, 0, 0, "%c", ' '); tb_printf_rect(self->rect_margin_right, 0, rect_y, 0, 0, "%c", ' '); tb_printf_rect(self->rect_buffer, 0, rect_y, 0, 0, "%-*.*s", self->rect_buffer.w, self->rect_buffer.w, " "); } else { - // Draw bline at self->rect_buffer self->viewport_y + rect_y + // Draw bline at self->rect_buffer self->viewport_mark + rect_y _bview_draw_bline(self, bline, rect_y, &bline, &rect_y); bline = bline->next; } @@ -1217,7 +1221,7 @@ int bview_screen_to_bline_col(bview_t *self, int x, int y, bview_t **ret_bview, && y >= self->rect_buffer.y && y < self->rect_buffer.y + self->rect_buffer.h ) { - line_index = self->viewport_y + (y - self->rect_buffer.y); + line_index = self->viewport_mark->bline->line_index + (y - self->rect_buffer.y); buffer_get_bline_w_hint(self->buffer, line_index, self->viewport_mark->bline, ret_bline); if (*ret_bline) { vcol = _bview_get_viewport_x(self, *ret_bline) + (x - self->rect_buffer.x); diff --git a/cursor.c b/cursor.c index 3f9e577..9b5c23e 100644 --- a/cursor.c +++ b/cursor.c @@ -331,7 +331,7 @@ int cursor_replace(cursor_t *cursor, int interactive, char *opt_regex, char *opt search_mark_end = buffer_add_mark(cursor->bview->buffer, NULL, 0); mark_join(search_mark, cursor->mark); mark_join(orig_mark, cursor->mark); - orig_viewport_y = cursor->bview->viewport_y; + orig_viewport_y = cursor->bview->viewport_mark->bline->line_index; orig_mark->lefty = 1; // lefty==1 avoids moving when text is inserted at mark lo_mark->lefty = 1; if (cursor->is_anchored) { diff --git a/editor.c b/editor.c index 73aba62..cd0a405 100644 --- a/editor.c +++ b/editor.c @@ -849,12 +849,12 @@ static int _editor_prompt_isearch_prev(cmd_context_t *ctx) { // Invoked when user hits up in a prompt_isearch static int _editor_prompt_isearch_viewport_up(cmd_context_t *ctx) { - return bview_set_viewport_y(ctx->editor->active_edit, ctx->editor->active_edit->viewport_y - 5, 0); + return bview_set_viewport_y(ctx->editor->active_edit, ctx->editor->active_edit->viewport_mark->bline->line_index - 5, 0); } // Invoked when user hits up in a prompt_isearch static int _editor_prompt_isearch_viewport_down(cmd_context_t *ctx) { - return bview_set_viewport_y(ctx->editor->active_edit, ctx->editor->active_edit->viewport_y + 5, 0); + return bview_set_viewport_y(ctx->editor->active_edit, ctx->editor->active_edit->viewport_mark->bline->line_index + 5, 0); } // Drops a cursor on each isearch match diff --git a/mle.h b/mle.h index 3c389e2..5d2fa45 100644 --- a/mle.h +++ b/mle.h @@ -185,7 +185,6 @@ struct bview_s { buffer_t *buffer; bint_t viewport_x; bint_t viewport_x_vcol; - bint_t viewport_y; mark_t *viewport_mark; int viewport_scope_x; int viewport_scope_y;