diff --git a/CHANGELOG.md b/CHANGELOG.md index 67d38093..7b247ec9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,13 @@ ## Unreleased ### Added + +* Implement reverse auto-wrap (_auto\_left\_margin_, _bw_, in + terminfo). This mode can be enabled/disabled with `CSI ? 45 h` and + `CSI `45 l`. It is **enabled** by default + (https://codeberg.org/dnkl/foot/issues/150). + + ### Changed * Default value of the **scrollback.multiplier** option in `foot.ini` diff --git a/csi.c b/csi.c index 53a90805..9a8d7a38 100644 --- a/csi.c +++ b/csi.c @@ -399,6 +399,10 @@ decset_decrst(struct terminal *term, unsigned param, bool enable) term->hide_cursor = !enable; break; + case 45: + term->reverse_wrap = enable; + break; + case 1000: if (enable) term->mouse_tracking = MOUSE_CLICK; @@ -576,6 +580,7 @@ xtsave(struct terminal *term, unsigned param) } case 25: term->xtsave.show_cursor = !term->hide_cursor; break; + case 45: term->xtsave.reverse_wrap = term->reverse_wrap; break; case 1000: term->xtsave.mouse_click = term->mouse_tracking == MOUSE_CLICK; break; case 1001: break; case 1002: term->xtsave.mouse_drag = term->mouse_tracking == MOUSE_DRAG; break; @@ -606,6 +611,7 @@ xtrestore(struct terminal *term, unsigned param) case 9: /* enable = term->xtsave.mouse_x10; break; */ return; case 12: enable = term->xtsave.cursor_blink; break; case 25: enable = term->xtsave.show_cursor; break; + case 45: enable = term->xtsave.reverse_wrap; break; case 1000: enable = term->xtsave.mouse_click; break; case 1001: return; case 1002: enable = term->xtsave.mouse_drag; break; diff --git a/foot.info b/foot.info index 62eb2beb..c7a05653 100644 --- a/foot.info +++ b/foot.info @@ -14,6 +14,7 @@ foot-direct|foot with direct color indexing, foot+base|foot base fragment, am, bce, + bw, ccc, km, mir, diff --git a/terminal.c b/terminal.c index 0840a45c..a171b182 100644 --- a/terminal.c +++ b/terminal.c @@ -904,6 +904,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper, : FCFT_SUBPIXEL_NONE), .cursor_keys_mode = CURSOR_KEYS_NORMAL, .keypad_keys_mode = KEYPAD_NUMERICAL, + .reverse_wrap = true, .auto_margin = true, .window_title_stack = tll_init(), .scale = 1, @@ -1394,6 +1395,7 @@ term_reset(struct terminal *term, bool hard) term->keypad_keys_mode = KEYPAD_NUMERICAL; term->reverse = false; term->hide_cursor = false; + term->reverse_wrap = true; term->auto_margin = true; term->insert_mode = false; term->bracketed_paste = false; @@ -1728,9 +1730,44 @@ term_cursor_home(struct terminal *term) void term_cursor_left(struct terminal *term, int count) { - int move_amount = min(term->grid->cursor.point.col, count); - term->grid->cursor.point.col -= move_amount; - assert(term->grid->cursor.point.col >= 0); + assert(count >= 0); + int new_col = term->grid->cursor.point.col - count; + + /* Reverse wrap */ + if (unlikely(new_col < 0)) { + if (unlikely(term->reverse_wrap && term->auto_margin)) { + + /* Number of rows to reverse wrap through */ + int row_count = (abs(new_col) - 1) / term->cols + 1; + + /* Row number cursor will end up on */ + int new_row_no = term->grid->cursor.point.row - row_count; + + /* New column number */ + new_col = term->cols - ((abs(new_col) - 1) % term->cols + 1); + assert(new_col >= 0 && new_col < term->cols); + + /* Don't back up past the scroll region */ + /* TODO: should this be allowed? */ + if (new_row_no < term->scroll_region.start) { + new_row_no = term->scroll_region.start; + new_col = 0; + } + + struct row *new_row = grid_row(term->grid, new_row_no); + term->grid->cursor.point.col = new_col; + term->grid->cursor.point.row = new_row_no; + term->grid->cursor.lcf = false; + term->grid->cur_row = new_row; + return; + } + + /* Reverse wrap disabled - don't let cursor move past first column */ + new_col = 0; + } + + assert(new_col >= 0); + term->grid->cursor.point.col = new_col; term->grid->cursor.lcf = false; } diff --git a/terminal.h b/terminal.h index 60a4aba4..817ee8ba 100644 --- a/terminal.h +++ b/terminal.h @@ -237,6 +237,7 @@ struct terminal { enum keypad_keys keypad_keys_mode; bool reverse; bool hide_cursor; + bool reverse_wrap; bool auto_margin; bool insert_mode; bool bracketed_paste; @@ -256,6 +257,7 @@ struct terminal { uint32_t application_cursor_keys:1; uint32_t reverse:1; uint32_t show_cursor:1; + uint32_t reverse_wrap:1; uint32_t auto_margin:1; uint32_t cursor_blink:1; uint32_t insert_mode:1; diff --git a/vt.c b/vt.c index 6b6bbd0b..6cd5ead7 100644 --- a/vt.c +++ b/vt.c @@ -130,7 +130,10 @@ action_execute(struct terminal *term, uint8_t c) case '\b': /* backspace */ - term_cursor_left(term, 1); + if (term->grid->cursor.lcf) + term->grid->cursor.lcf = false; + else + term_cursor_left(term, 1); break; case '\t': {