#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(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(term); }