foot/commands.c
Daniel Eklöf 6726494f4c
url-mode: store absolute row numbers in start/end coordinates
This allows us to update the jump label positions when the viewport
changes.

This in turn allows us to stay in URL mode while the user is using the
mouse to scroll in the scrollback history.

Scrolling with the keyboard is currently not possible, since input
handling in URL mode does not recognize “regular” key bindings. We
_could_ add scrollback up/down bindings to URL mode too, but lets not,
for the time being.

(Note: an alternative to this patch is to disallow mouse scrolling
too. Then we could have kept the URL start/end as viewport local
coordinates).
2021-02-07 16:33:34 +01:00

163 lines
4.8 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 "util.h"
void
cmd_scrollback_up(struct terminal *term, int rows)
{
if (term->grid == &term->alt)
return;
if (term->mouse_tracking != MOUSE_NONE)
return;
rows = min(rows, term->rows);
xassert(term->grid->offset >= 0);
int new_view = term->grid->view - rows;
while (new_view < 0)
new_view += term->grid->num_rows;
new_view %= term->grid->num_rows;
xassert(new_view >= 0);
xassert(new_view < term->grid->num_rows);
/* Avoid scrolling in uninitialized rows */
while (term->grid->rows[new_view] == NULL)
new_view = (new_view + 1) % term->grid->num_rows;
if (new_view == term->grid->view) {
/*
* This happens when scrolling up in a newly opened terminal;
* every single line (except those already visible) are
* uninitialized, and the loop above will bring us back to
* where we started.
*/
return;
}
/* Don't scroll past scrollback history */
int end = (term->grid->offset + term->rows - 1) % term->grid->num_rows;
if (end >= term->grid->offset) {
/* Not wrapped */
if (new_view >= term->grid->offset && new_view <= end)
new_view = (end + 1) % term->grid->num_rows;
} else {
if (new_view >= term->grid->offset || new_view <= end)
new_view = (end + 1) % term->grid->num_rows;
}
while (term->grid->rows[new_view] == NULL)
new_view = (new_view + 1) % term->grid->num_rows;
#if defined(_DEBUG)
for (int r = 0; r < term->rows; r++)
xassert(term->grid->rows[(new_view + r) % term->grid->num_rows] != NULL);
#endif
LOG_DBG("scrollback UP: %d -> %d (offset = %d, end = %d, rows = %d)",
term->grid->view, new_view, term->grid->offset, end, term->grid->num_rows);
if (new_view == term->grid->view)
return;
int diff = -1;
if (new_view < term->grid->view)
diff = term->grid->view - new_view;
else
diff = (term->grid->num_rows - new_view) + term->grid->view;
selection_view_up(term, new_view);
term->grid->view = new_view;
if (diff >= 0 && diff < term->rows) {
term_damage_scroll(term, DAMAGE_SCROLL_REVERSE_IN_VIEW, (struct scroll_region){0, term->rows}, diff);
term_damage_rows_in_view(term, 0, diff - 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 (term->mouse_tracking != MOUSE_NONE)
return;
if (term->grid->view == term->grid->offset)
return;
rows = min(rows, term->rows);
xassert(term->grid->offset >= 0);
int new_view = (term->grid->view + rows) % term->grid->num_rows;
xassert(new_view >= 0);
xassert(new_view < term->grid->num_rows);
/* Prevent scrolling in uninitialized rows */
bool all_initialized = false;
do {
all_initialized = true;
for (int i = 0; i < term->rows; i++) {
int row_no = (new_view + i) % term->grid->num_rows;
if (term->grid->rows[row_no] == NULL) {
all_initialized = false;
new_view--;
break;
}
}
} while (!all_initialized);
/* Don't scroll past scrollback history */
int end = (term->grid->offset + term->rows - 1) % term->grid->num_rows;
if (end >= term->grid->offset) {
/* Not wrapped */
if (new_view >= term->grid->offset && new_view <= end)
new_view = term->grid->offset;
} else {
if (new_view >= term->grid->offset || new_view <= end)
new_view = term->grid->offset;
}
#if defined(_DEBUG)
for (int r = 0; r < term->rows; r++)
xassert(term->grid->rows[(new_view + r) % term->grid->num_rows] != NULL);
#endif
LOG_DBG("scrollback DOWN: %d -> %d (offset = %d, end = %d, rows = %d)",
term->grid->view, new_view, term->grid->offset, end, term->grid->num_rows);
if (new_view == term->grid->view)
return;
int diff = -1;
if (new_view > term->grid->view)
diff = new_view - term->grid->view;
else
diff = (term->grid->num_rows - term->grid->view) + new_view;
selection_view_down(term, new_view);
term->grid->view = new_view;
if (diff >= 0 && diff < term->rows) {
term_damage_scroll(term, DAMAGE_SCROLL_IN_VIEW, (struct scroll_region){0, term->rows}, diff);
term_damage_rows_in_view(term, term->rows - diff, term->rows - 1);
} else
term_damage_view(term);
render_refresh_urls(term);
render_refresh(term);
}