diff --git a/csi.c b/csi.c index 49bb1eb7..50951781 100644 --- a/csi.c +++ b/csi.c @@ -96,7 +96,7 @@ csi_dispatch(struct terminal *term, uint8_t final) case 'J': { assert(term->vt.params.idx == 0); - int start = term->grid.cursor / term->grid.cols * term->grid.cols; + int start = grid_cursor_linear(&term->grid, term->grid.cursor.row, 0); int end = term->grid.cols * term->grid.rows; grid_erase(&term->grid, start, end); return true; @@ -104,10 +104,10 @@ csi_dispatch(struct terminal *term, uint8_t final) case 'K': { assert(term->vt.params.idx == 0); - int start = term->grid.cursor; - int end = (start + term->grid.cols - 1) / term->grid.cols * term->grid.cols - 1; - assert(start <= end); - assert((end + 1) % term->grid.cols == 0); + int start = term->grid.linear_cursor; + int end = grid_cursor_linear( + &term->grid, term->grid.cursor.row, term->grid.cols - 1); + LOG_DBG("K: %d -> %d", start, end); grid_erase(&term->grid, start, end); return true; @@ -115,13 +115,13 @@ csi_dispatch(struct terminal *term, uint8_t final) case 'C': { int count = term->vt.params.idx > 0 ? term->vt.params.v[0].value : 1; - grid_cursor_move(&term->grid, count); + grid_cursor_right(&term->grid, count); return true; } case 'D': { int count = term->vt.params.idx > 0 ? term->vt.params.v[0].value : 1; - grid_cursor_move(&term->grid, -count); + grid_cursor_left(&term->grid, count); return true; } diff --git a/grid.c b/grid.c index 3954b64f..02ec24a5 100644 --- a/grid.c +++ b/grid.c @@ -1,6 +1,10 @@ #include "grid.h" #include +#include + +#define min(x, y) ((x) < (y) ? (x) : (y)) +#define max(x, y) ((x) > (y) ? (x) : (y)) void grid_erase(struct grid *grid, int start, int end) @@ -17,19 +21,74 @@ grid_erase(struct grid *grid, int start, int end) } } -void -grid_cursor_move(struct grid *grid, int cols) +int +grid_cursor_linear(const struct grid *grid, int row, int col) { - int new_cursor = grid->cursor + cols; - grid->cells[grid->cursor].dirty = true; - grid->cells[new_cursor].dirty = true; - grid->cursor = new_cursor; + return row * grid->cols + col; +} + +void +grid_cursor_to(struct grid *grid, int row, int col) +{ + assert(row >= 0); + assert(row < grid->rows); + assert(col >= 0); + assert(col < grid->cols); + + int new_linear = row * grid->cols + col; + assert(new_linear >= 0); + assert(new_linear < grid->rows * grid->cols); + + grid->cells[grid->linear_cursor].dirty = true; + grid->cells[new_linear].dirty = true; + grid->dirty = true; + grid->print_needs_wrap = false; + + grid->linear_cursor = new_linear; + grid->cursor.col = col; + grid->cursor.row = row; +} + +void +grid_cursor_left(struct grid *grid, int count) +{ + int move_amount = min(grid->cursor.col, count); + int new_linear = grid->linear_cursor - move_amount; + int new_col = grid->cursor.col - move_amount; + + assert(new_linear >= 0); + assert(new_linear < grid->rows * grid->cols); + assert(new_col >= 0); + assert(new_col < grid->cols); + + grid->cells[grid->linear_cursor].dirty = true; + grid->cells[new_linear].dirty = true; + + grid->linear_cursor = new_linear; + grid->cursor.col = new_col; + grid->dirty = true; grid->print_needs_wrap = false; } void -grid_cursor_to(struct grid *grid, int pos) +grid_cursor_right(struct grid *grid, int count) { - grid_cursor_move(grid, pos - grid->cursor); + int move_amount = min(grid->cols - grid->cursor.col - 1, count); + int new_linear = grid->linear_cursor + move_amount; + int new_col = grid->cursor.col + move_amount; + + assert(new_linear >= 0); + assert(new_linear < grid->rows * grid->cols); + assert(new_col >= 0); + assert(new_col < grid->cols); + + grid->cells[grid->linear_cursor].dirty = true; + grid->cells[new_linear].dirty = true; + + grid->linear_cursor = new_linear; + grid->cursor.col = new_col; + + grid->dirty = true; + grid->print_needs_wrap = false; } diff --git a/grid.h b/grid.h index 3f347cff..032708ad 100644 --- a/grid.h +++ b/grid.h @@ -4,5 +4,11 @@ void grid_erase(struct grid *grid, int start, int end); -void grid_cursor_to(struct grid *grid, int pos); -void grid_cursor_move(struct grid *grid, int cols); +void grid_cursor_to(struct grid *grid, int row, int col); +void grid_cursor_left(struct grid *grid, int count); +void grid_cursor_right(struct grid *grid, int count); + +int grid_cursor_linear(const struct grid *grid, int row, int col); + +//void grid_cursor_to(struct grid *grid, int pos); +//void grid_cursor_move(struct grid *grid, int cols); diff --git a/main.c b/main.c index bc47420f..f11d6ee3 100644 --- a/main.c +++ b/main.c @@ -97,7 +97,7 @@ grid_render(struct context *c) cell->dirty = false; - bool has_cursor = c->term.grid.cursor == cell_idx; + bool has_cursor = c->term.grid.linear_cursor == cell_idx; int y_ofs = row * c->term.grid.cell_height + c->fextents.ascent; int x_ofs = col * c->term.grid.cell_width; diff --git a/terminal.h b/terminal.h index e6a2e1f2..efea5106 100644 --- a/terminal.h +++ b/terminal.h @@ -28,8 +28,13 @@ struct grid { int cell_width; int cell_height; - int cursor; + int linear_cursor; + struct { + int row; + int col; + } cursor; bool print_needs_wrap; + struct cell *cells; uint32_t foreground; diff --git a/vt.c b/vt.c index e1fe0f03..06d4a1a0 100644 --- a/vt.c +++ b/vt.c @@ -158,13 +158,11 @@ action(struct terminal *term, enum action action, uint8_t c) LOG_DBG("execute: 0x%02x", c); switch (c) { case '\r': - grid_cursor_to( - &term->grid, - term->grid.cursor / term->grid.cols * term->grid.cols); + grid_cursor_left(&term->grid, term->grid.cursor.col); break; case '\b': - grid_cursor_move(&term->grid, -1); + grid_cursor_left(&term->grid, 1); break; } @@ -179,9 +177,9 @@ action(struct terminal *term, enum action action, uint8_t c) case ACTION_PRINT: { if (term->grid.print_needs_wrap) - grid_cursor_move(&term->grid, 1); + grid_cursor_to(&term->grid, term->grid.cursor.row + 1, 0); - struct cell *cell = &term->grid.cells[term->grid.cursor]; + struct cell *cell = &term->grid.cells[term->grid.linear_cursor]; cell->dirty = true; @@ -197,8 +195,8 @@ action(struct terminal *term, enum action action, uint8_t c) cell->attrs = term->vt.attrs; - if ((term->grid.cursor + 1) % term->grid.cols) - grid_cursor_move(&term->grid, 1); + if (term->grid.cursor.col < term->grid.cols - 1) + grid_cursor_right(&term->grid, 1); else term->grid.print_needs_wrap = true;