mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
When scrolling the viewport up, we need to ensure we don’t go past the scrollback wrap around. This was previously done using “custom” logic that tried to calculate many rows away from the scrollback start the current viewport is. But this is *exactly* what grid_row_abs_to_sb() does, except it doesn’t account for uninitialized scrollback. So, copy the logic from grid_row_abs_to_sb(), but ensure scrollback start points to valid scrollback data. The maximum number of rows we’re allowed to scroll is now the same as the current viewport’s sb-relative coordinate. Maybe closes #1074
124 lines
3.3 KiB
C
124 lines
3.3 KiB
C
#include "commands.h"
|
||
|
||
#define LOG_MODULE "commands"
|
||
#define LOG_ENABLE_DBG 0
|
||
#include "log.h"
|
||
#include "grid.h"
|
||
#include "render.h"
|
||
#include "selection.h"
|
||
#include "terminal.h"
|
||
#include "url-mode.h"
|
||
#include "util.h"
|
||
|
||
void
|
||
cmd_scrollback_up(struct terminal *term, int rows)
|
||
{
|
||
if (term->grid == &term->alt)
|
||
return;
|
||
if (urls_mode_is_active(term))
|
||
return;
|
||
|
||
const struct grid *grid = term->grid;
|
||
const int offset = grid->offset;
|
||
const int view = grid->view;
|
||
const int grid_rows = grid->num_rows;
|
||
const int screen_rows = term->rows;
|
||
|
||
int scrollback_start = (offset + screen_rows) & (grid_rows - 1);
|
||
|
||
/* Part of the scrollback may be uninitialized */
|
||
while (grid->rows[scrollback_start] == NULL) {
|
||
scrollback_start++;
|
||
scrollback_start &= grid_rows - 1;
|
||
}
|
||
|
||
/* The view row number in scrollback relative coordinates. This is
|
||
* the maximum number of rows we’re allowed to scroll */
|
||
int view_sb_rel = view - scrollback_start + grid_rows;
|
||
view_sb_rel &= grid_rows - 1;
|
||
|
||
rows = min(rows, view_sb_rel);
|
||
if (rows == 0)
|
||
return;
|
||
|
||
int new_view = (view + grid_rows) - rows;
|
||
new_view &= grid_rows - 1;
|
||
|
||
xassert(new_view != view);
|
||
xassert(grid->rows[new_view] != NULL);
|
||
#if defined(_DEBUG)
|
||
for (int r = 0; r < term->rows; r++)
|
||
xassert(grid->rows[(new_view + r) & (grid->num_rows - 1)] != NULL);
|
||
#endif
|
||
|
||
LOG_DBG("scrollback UP: %d -> %d (offset = %d, rows = %d)",
|
||
view, new_view, offset, grid_rows);
|
||
|
||
selection_view_up(term, new_view);
|
||
term->grid->view = new_view;
|
||
|
||
if (rows < term->rows) {
|
||
term_damage_scroll(
|
||
term, DAMAGE_SCROLL_REVERSE_IN_VIEW,
|
||
(struct scroll_region){0, term->rows}, rows);
|
||
term_damage_rows_in_view(term, 0, rows - 1);
|
||
} else
|
||
term_damage_view(term);
|
||
|
||
render_refresh_urls(term);
|
||
render_refresh(term);
|
||
}
|
||
|
||
void
|
||
cmd_scrollback_down(struct terminal *term, int rows)
|
||
{
|
||
if (term->grid == &term->alt)
|
||
return;
|
||
if (urls_mode_is_active(term))
|
||
return;
|
||
|
||
const struct grid *grid = term->grid;
|
||
const int offset = grid->offset;
|
||
const int view = grid->view;
|
||
const int grid_rows = grid->num_rows;
|
||
const int screen_rows = term->rows;
|
||
|
||
const int scrollback_end = offset;
|
||
|
||
/* Number of rows to scroll, without going past the scrollback end */
|
||
int max_rows = 0;
|
||
if (view <= scrollback_end)
|
||
max_rows = scrollback_end - view;
|
||
else
|
||
max_rows = offset + (grid_rows - view);
|
||
|
||
rows = min(rows, max_rows);
|
||
if (rows == 0)
|
||
return;
|
||
|
||
int new_view = (view + rows) & (grid_rows - 1);
|
||
|
||
xassert(new_view != view);
|
||
xassert(grid->rows[new_view] != NULL);
|
||
#if defined(_DEBUG)
|
||
for (int r = 0; r < term->rows; r++)
|
||
xassert(grid->rows[(new_view + r) & (grid_rows - 1)] != NULL);
|
||
#endif
|
||
|
||
LOG_DBG("scrollback DOWN: %d -> %d (offset = %d, rows = %d)",
|
||
view, new_view, offset, grid_rows);
|
||
|
||
selection_view_down(term, new_view);
|
||
term->grid->view = new_view;
|
||
|
||
if (rows < term->rows) {
|
||
term_damage_scroll(
|
||
term, DAMAGE_SCROLL_IN_VIEW,
|
||
(struct scroll_region){0, term->rows}, rows);
|
||
term_damage_rows_in_view(term, term->rows - rows, screen_rows - 1);
|
||
} else
|
||
term_damage_view(term);
|
||
|
||
render_refresh_urls(term);
|
||
render_refresh(term);
|
||
}
|