diff --git a/terminal/terminal.c b/terminal/terminal.c index 002d1528..5a113027 100644 --- a/terminal/terminal.c +++ b/terminal/terminal.c @@ -3997,7 +3997,10 @@ static void term_out(Terminal *term, bool called_from_term_data) break; } case '\b': /* BS: Back space */ - if (term->curs.x == 0 && (term->curs.y == 0 || !term->wrap)) { + if (term->wrapnext) { + term->wrapnext = false; + } else if (term->curs.x == 0 && + (term->curs.y == 0 || !term->wrap)) { /* do nothing */ } else if (term->curs.x == 0 && term->curs.y > 0) { term->curs.x = term->cols - 1, term->curs.y--; @@ -4021,8 +4024,6 @@ static void term_out(Terminal *term, bool called_from_term_data) termline *ldata = scrlineptr(term->curs.y); if (term->curs.x > 0 && (ldata->lattr & LATTR_WRAPPED2)) term->curs.x--; - } else if (term->wrapnext) { - term->wrapnext = false; } else { term->curs.x--; } diff --git a/test/test_terminal.c b/test/test_terminal.c index de83f6ad..5c377280 100644 --- a/test/test_terminal.c +++ b/test/test_terminal.c @@ -326,6 +326,57 @@ static void test_wrap(Mock *mk) IEQUAL(mk->term->curs.x, 78); IEQUAL(mk->term->curs.y, 0); IEQUAL(mk->term->wrapnext, 0); + + /* + * Now test the special cases that arise when the terminal is only + * one column wide! + */ + + reset(mk); + term_size(mk->term, 24, 1, 0); + mk->term->curs.x = 0; + mk->term->curs.y = 0; + mk->term->wrap = true; + /* Printing a single-width character takes us into wrapnext immediately */ + term_datapl(mk->term, PTRLEN_LITERAL("a")); + IEQUAL(mk->term->curs.x, 0); + IEQUAL(mk->term->curs.y, 0); + IEQUAL(mk->term->wrapnext, 1); + IEQUAL(get_lineattr(mk->term, 0), 0); + IEQUAL(get_termchar(mk->term, 0, 0).chr, CSET_ASCII | 'a'); + /* Printing a second one wraps, and takes us _back_ to wrapnext */ + term_datapl(mk->term, PTRLEN_LITERAL("b")); + IEQUAL(mk->term->curs.x, 0); + IEQUAL(mk->term->curs.y, 1); + IEQUAL(mk->term->wrapnext, 1); + IEQUAL(get_lineattr(mk->term, 0), LATTR_WRAPPED); + IEQUAL(get_termchar(mk->term, 0, 0).chr, CSET_ASCII | 'a'); + IEQUAL(get_termchar(mk->term, 0, 1).chr, CSET_ASCII | 'b'); + /* Backspacing once clears the wrapnext flag, putting us on the b */ + term_datapl(mk->term, PTRLEN_LITERAL("\b")); + IEQUAL(mk->term->curs.x, 0); + IEQUAL(mk->term->curs.y, 1); + IEQUAL(mk->term->wrapnext, 0); + /* Backspacing again returns to the previous line, putting us on the a */ + term_datapl(mk->term, PTRLEN_LITERAL("\b")); + IEQUAL(mk->term->curs.x, 0); + IEQUAL(mk->term->curs.y, 0); + IEQUAL(mk->term->wrapnext, 0); + + /* And now try with a double-width character */ + reset(mk); + term_size(mk->term, 24, 1, 0); + mk->term->curs.x = 0; + mk->term->curs.y = 0; + mk->term->wrap = true; + /* DW character won't fit at all, so it transforms into U+FFFD + * REPLACEMENT CHARACTER and then behaves like a SW char */ + term_datapl(mk->term, PTRLEN_LITERAL("\xEA\xB0\x80")); + IEQUAL(mk->term->curs.x, 0); + IEQUAL(mk->term->curs.y, 0); + IEQUAL(mk->term->wrapnext, 1); + IEQUAL(get_lineattr(mk->term, 0), 0); + IEQUAL(get_termchar(mk->term, 0, 0).chr, 0xFFFD); } int main(void)