From a51dbf3f08bbb7980ff31d498c15915bb46eaee7 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 18 May 2018 14:16:11 +0100 Subject: [PATCH] terminal.c: factor out the graphic-character display. I'm about to want to implement an escape sequence that causes a graphic character to be printed, which means I'll need the code that does so to be in a separate routine that I can call easily, instead of buried a few loops deep in the middle of the main state machine. --- terminal.c | 280 ++++++++++++++++++++++++++--------------------------- 1 file changed, 138 insertions(+), 142 deletions(-) diff --git a/terminal.c b/terminal.c index 667a29b3..cfef4415 100644 --- a/terminal.c +++ b/terminal.c @@ -2827,6 +2827,143 @@ static void term_print_finish(Terminal *term) term->printing = term->only_printing = FALSE; } +static void term_display_graphic_char(Terminal *term, unsigned long c) +{ + termline *cline = scrlineptr(term->curs.y); + int width = 0; + if (DIRECT_CHAR(c)) + width = 1; + if (!width) + width = (term->cjk_ambig_wide ? + mk_wcwidth_cjk((unsigned int) c) : + mk_wcwidth((unsigned int) c)); + + if (term->wrapnext && term->wrap && width > 0) { + cline->lattr |= LATTR_WRAPPED; + if (term->curs.y == term->marg_b) + scroll(term, term->marg_t, term->marg_b, 1, TRUE); + else if (term->curs.y < term->rows - 1) + term->curs.y++; + term->curs.x = 0; + term->wrapnext = FALSE; + cline = scrlineptr(term->curs.y); + } + if (term->insert && width > 0) + insch(term, width); + if (term->selstate != NO_SELECTION) { + pos cursplus = term->curs; + incpos(cursplus); + check_selection(term, term->curs, cursplus); + } + if (((c & CSET_MASK) == CSET_ASCII || + (c & CSET_MASK) == 0) && term->logctx) + logtraffic(term->logctx, (unsigned char) c, LGTYP_ASCII); + + switch (width) { + case 2: + /* + * If we're about to display a double-width character starting + * in the rightmost column, then we do something special + * instead. We must print a space in the last column of the + * screen, then wrap; and we also set LATTR_WRAPPED2 which + * instructs subsequent cut-and-pasting not only to splice + * this line to the one after it, but to ignore the space in + * the last character position as well. (Because what was + * actually output to the terminal was presumably just a + * sequence of CJK characters, and we don't want a space to be + * pasted in the middle of those just because they had the + * misfortune to start in the wrong parity column. xterm + * concurs.) + */ + check_boundary(term, term->curs.x, term->curs.y); + check_boundary(term, term->curs.x+2, term->curs.y); + if (term->curs.x == term->cols-1) { + copy_termchar(cline, term->curs.x, + &term->erase_char); + cline->lattr |= LATTR_WRAPPED | LATTR_WRAPPED2; + if (term->curs.y == term->marg_b) + scroll(term, term->marg_t, term->marg_b, + 1, TRUE); + else if (term->curs.y < term->rows - 1) + term->curs.y++; + term->curs.x = 0; + cline = scrlineptr(term->curs.y); + /* Now we must check_boundary again, of course. */ + check_boundary(term, term->curs.x, term->curs.y); + check_boundary(term, term->curs.x+2, term->curs.y); + } + + /* FULL-TERMCHAR */ + clear_cc(cline, term->curs.x); + cline->chars[term->curs.x].chr = c; + cline->chars[term->curs.x].attr = term->curr_attr; + cline->chars[term->curs.x].truecolour = + term->curr_truecolour; + + term->curs.x++; + + /* FULL-TERMCHAR */ + clear_cc(cline, term->curs.x); + cline->chars[term->curs.x].chr = UCSWIDE; + cline->chars[term->curs.x].attr = term->curr_attr; + cline->chars[term->curs.x].truecolour = + term->curr_truecolour; + + break; + case 1: + check_boundary(term, term->curs.x, term->curs.y); + check_boundary(term, term->curs.x+1, term->curs.y); + + /* FULL-TERMCHAR */ + clear_cc(cline, term->curs.x); + cline->chars[term->curs.x].chr = c; + cline->chars[term->curs.x].attr = term->curr_attr; + cline->chars[term->curs.x].truecolour = + term->curr_truecolour; + + break; + case 0: + if (term->curs.x > 0) { + int x = term->curs.x - 1; + + /* If we're in wrapnext state, the character to combine + * with is _here_, not to our left. */ + if (term->wrapnext) + x++; + + /* + * If the previous character is UCSWIDE, back up another + * one. + */ + if (cline->chars[x].chr == UCSWIDE) { + assert(x > 0); + x--; + } + + add_cc(cline, x, c); + seen_disp_event(term); + } + return; + default: + return; + } + term->curs.x++; + if (term->curs.x == term->cols) { + term->curs.x--; + term->wrapnext = TRUE; + if (term->wrap && term->vt52_mode) { + cline->lattr |= LATTR_WRAPPED; + if (term->curs.y == term->marg_b) + scroll(term, term->marg_t, term->marg_b, 1, TRUE); + else if (term->curs.y < term->rows - 1) + term->curs.y++; + term->curs.x = 0; + term->wrapnext = FALSE; + } + } + seen_disp_event(term); +} + /* * Remove everything currently in `inbuf' and stick it up on the * in-memory display. There's a big state machine in here to @@ -3241,148 +3378,7 @@ static void term_out(Terminal *term) case TOPLEVEL: /* Only graphic characters get this far; * ctrls are stripped above */ - { - termline *cline = scrlineptr(term->curs.y); - int width = 0; - if (DIRECT_CHAR(c)) - width = 1; - if (!width) - width = (term->cjk_ambig_wide ? - mk_wcwidth_cjk((unsigned int) c) : - mk_wcwidth((unsigned int) c)); - - if (term->wrapnext && term->wrap && width > 0) { - cline->lattr |= LATTR_WRAPPED; - if (term->curs.y == term->marg_b) - scroll(term, term->marg_t, term->marg_b, 1, TRUE); - else if (term->curs.y < term->rows - 1) - term->curs.y++; - term->curs.x = 0; - term->wrapnext = FALSE; - cline = scrlineptr(term->curs.y); - } - if (term->insert && width > 0) - insch(term, width); - if (term->selstate != NO_SELECTION) { - pos cursplus = term->curs; - incpos(cursplus); - check_selection(term, term->curs, cursplus); - } - if (((c & CSET_MASK) == CSET_ASCII || - (c & CSET_MASK) == 0) && - term->logctx) - logtraffic(term->logctx, (unsigned char) c, - LGTYP_ASCII); - - switch (width) { - case 2: - /* - * If we're about to display a double-width - * character starting in the rightmost - * column, then we do something special - * instead. We must print a space in the - * last column of the screen, then wrap; - * and we also set LATTR_WRAPPED2 which - * instructs subsequent cut-and-pasting not - * only to splice this line to the one - * after it, but to ignore the space in the - * last character position as well. - * (Because what was actually output to the - * terminal was presumably just a sequence - * of CJK characters, and we don't want a - * space to be pasted in the middle of - * those just because they had the - * misfortune to start in the wrong parity - * column. xterm concurs.) - */ - check_boundary(term, term->curs.x, term->curs.y); - check_boundary(term, term->curs.x+2, term->curs.y); - if (term->curs.x == term->cols-1) { - copy_termchar(cline, term->curs.x, - &term->erase_char); - cline->lattr |= LATTR_WRAPPED | LATTR_WRAPPED2; - if (term->curs.y == term->marg_b) - scroll(term, term->marg_t, term->marg_b, - 1, TRUE); - else if (term->curs.y < term->rows - 1) - term->curs.y++; - term->curs.x = 0; - cline = scrlineptr(term->curs.y); - /* Now we must check_boundary again, of course. */ - check_boundary(term, term->curs.x, term->curs.y); - check_boundary(term, term->curs.x+2, term->curs.y); - } - - /* FULL-TERMCHAR */ - clear_cc(cline, term->curs.x); - cline->chars[term->curs.x].chr = c; - cline->chars[term->curs.x].attr = term->curr_attr; - cline->chars[term->curs.x].truecolour = - term->curr_truecolour; - - term->curs.x++; - - /* FULL-TERMCHAR */ - clear_cc(cline, term->curs.x); - cline->chars[term->curs.x].chr = UCSWIDE; - cline->chars[term->curs.x].attr = term->curr_attr; - cline->chars[term->curs.x].truecolour = - term->curr_truecolour; - - break; - case 1: - check_boundary(term, term->curs.x, term->curs.y); - check_boundary(term, term->curs.x+1, term->curs.y); - - /* FULL-TERMCHAR */ - clear_cc(cline, term->curs.x); - cline->chars[term->curs.x].chr = c; - cline->chars[term->curs.x].attr = term->curr_attr; - cline->chars[term->curs.x].truecolour = - term->curr_truecolour; - - break; - case 0: - if (term->curs.x > 0) { - int x = term->curs.x - 1; - - /* If we're in wrapnext state, the character - * to combine with is _here_, not to our left. */ - if (term->wrapnext) - x++; - - /* - * If the previous character is - * UCSWIDE, back up another one. - */ - if (cline->chars[x].chr == UCSWIDE) { - assert(x > 0); - x--; - } - - add_cc(cline, x, c); - seen_disp_event(term); - } - continue; - default: - continue; - } - term->curs.x++; - if (term->curs.x == term->cols) { - term->curs.x--; - term->wrapnext = TRUE; - if (term->wrap && term->vt52_mode) { - cline->lattr |= LATTR_WRAPPED; - if (term->curs.y == term->marg_b) - scroll(term, term->marg_t, term->marg_b, 1, TRUE); - else if (term->curs.y < term->rows - 1) - term->curs.y++; - term->curs.x = 0; - term->wrapnext = FALSE; - } - } - seen_disp_event(term); - } + term_display_graphic_char(term, c); break; case OSC_MAYBE_ST: