From 72af00d8610bdc194062b246aab0e38f22174aeb Mon Sep 17 00:00:00 2001 From: Akib Azmain Turja Date: Mon, 3 Oct 2022 14:18:59 +0600 Subject: [PATCH 1/2] Write on the bottom-right character cell on terminal Correctly write on the bottom-right character cell on text terminals if the terminal allows to do this. Also fixes bug#57728. * src/term.c (tty_write_glyphs, tty_write_glyphs_with_face): Write on the bottom-right character cell if the terminal supports it. * src/term.c (glyph_on_char_cell_before_last): New static variable to hold the current glyph on the character cell before the cell on the bottom-right corner. --- src/term.c | 266 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 225 insertions(+), 41 deletions(-) diff --git a/src/term.c b/src/term.c index 2e43d892..283a65c4 100644 --- a/src/term.c +++ b/src/term.c @@ -718,7 +718,7 @@ encode_terminal_code (struct glyph *src, int src_len, return (encode_terminal_dst); } - +static struct glyph glyph_on_char_cell_before_last; /* An implementation of write_glyphs for termcap frames. */ @@ -727,7 +727,7 @@ tty_write_glyphs (struct frame *f, struct glyph *string, int len) { unsigned char *conversion_buffer; struct coding_system *coding; - int n, stringlen; + int n, stringlen, write_on_last_cell; struct tty_display_info *tty = FRAME_TTY (f); @@ -737,55 +737,158 @@ tty_write_glyphs (struct frame *f, struct glyph *string, int len) /* Don't dare write in last column of bottom line, if Auto-Wrap, since that would scroll the whole frame on some terminals. */ - if (AutoWrap (tty) - && curY (tty) + 1 == FRAME_TOTAL_LINES (f) - && (curX (tty) + len) == FRAME_COLS (f)) + write_on_last_cell = (AutoWrap (tty) + && curY (tty) + 1 == FRAME_TOTAL_LINES (f) + && (curX (tty) + len) == FRAME_COLS (f)); + if (write_on_last_cell) len --; - if (len <= 0) - return; - cmplus (tty, len); + if (FRAME_COLS (f) == 1 + || !(tty->TS_ins_char || tty->TS_ins_multi_chars + || (tty->TS_insert_mode && tty->TS_end_insert_mode))) + write_on_last_cell = false; + + if (len <= 0 && !write_on_last_cell) + return; /* If terminal_coding does any conversion, use it, otherwise use safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here because it always return 1 if the member src_multibyte is 1. */ - coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK + coding = ((FRAME_TERMINAL_CODING (f)->common_flags + & CODING_REQUIRE_ENCODING_MASK) ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding); /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at the tail. */ coding->mode &= ~CODING_MODE_LAST_BLOCK; - for (stringlen = len; stringlen != 0; stringlen -= n) + if (len > 0) { - /* Identify a run of glyphs with the same face. */ - int face_id = string->face_id; + cmplus (tty, len); + + if (write_on_last_cell) + glyph_on_char_cell_before_last = string[len - 1]; + + for (stringlen = len; stringlen != 0; stringlen -= n) + { + /* Identify a run of glyphs with the same face. */ + int face_id = string->face_id; + + for (n = 1; n < stringlen; ++n) + if (string[n].face_id != face_id) + break; + + /* Turn appearance modes of the face of the run on. */ + tty_highlight_if_desired (tty); + turn_on_face (f, face_id); - for (n = 1; n < stringlen; ++n) - if (string[n].face_id != face_id) - break; + if (n == stringlen && !write_on_last_cell) + /* This is the last run. */ + coding->mode |= CODING_MODE_LAST_BLOCK; + conversion_buffer = encode_terminal_code (string, n, + coding); + if (coding->produced > 0) + { + block_input (); + fwrite (conversion_buffer, 1, coding->produced, + tty->output); + clearerr (tty->output); + if (tty->termscript) + fwrite (conversion_buffer, 1, coding->produced, + tty->termscript); + unblock_input (); + } + string += n; - /* Turn appearance modes of the face of the run on. */ + /* Turn appearance modes off. */ + turn_off_face (f, face_id); + tty_turn_off_highlight (tty); + } + } + + /* Write on the bottom-right corner. */ + if (write_on_last_cell) + { + /* Go to the previous position. */ + cmgoto (tty, curY (tty), curX (tty) - 1); + cmplus (tty, 1); + + int face_id = string->face_id; + + /* Turn appearance modes of the face. */ tty_highlight_if_desired (tty); turn_on_face (f, face_id); - if (n == stringlen) - /* This is the last run. */ - coding->mode |= CODING_MODE_LAST_BLOCK; - conversion_buffer = encode_terminal_code (string, n, coding); + conversion_buffer = encode_terminal_code (string, 1, coding); if (coding->produced > 0) { block_input (); - fwrite (conversion_buffer, 1, coding->produced, tty->output); + fwrite (conversion_buffer, 1, coding->produced, + tty->output); clearerr (tty->output); if (tty->termscript) - fwrite (conversion_buffer, 1, coding->produced, tty->termscript); + fwrite (conversion_buffer, 1, coding->produced, + tty->termscript); + unblock_input (); + } + + /* Go to the previous position. */ + cmgoto (tty, curY (tty), curX (tty) - 1); + cmplus (tty, 1); + + /* Arrange that after writing the next glyph, the glyph on the + current character cell is somehow pushed to the bottom-right + corner. */ + if (tty->TS_ins_char) + { + OUTPUT1 (tty, tty->TS_ins_char); + } + else if (tty->TS_ins_multi_chars) + { + char *buf = tparam (tty->TS_ins_multi_chars, 0, 0, 1, 0, + 0, 0); + OUTPUT1 (tty, buf); + xfree (buf); + } + else + { + tty_turn_on_insert (tty); + } + + if (face_id != glyph_on_char_cell_before_last.face_id) + { + + /* Turn appearance modes of the face. */ + turn_off_face (f, face_id); + tty_turn_off_highlight (tty); + + face_id = glyph_on_char_cell_before_last.face_id; + + tty_highlight_if_desired (tty); + turn_on_face (f, face_id); + } + + /* This is the last run. */ + coding->mode |= CODING_MODE_LAST_BLOCK; + conversion_buffer + = encode_terminal_code (&glyph_on_char_cell_before_last, 1, + coding); + if (coding->produced > 0) + { + block_input (); + fwrite (conversion_buffer, 1, coding->produced, + tty->output); + clearerr (tty->output); + if (tty->termscript) + fwrite (conversion_buffer, 1, coding->produced, + tty->termscript); unblock_input (); } - string += n; /* Turn appearance modes off. */ turn_off_face (f, face_id); tty_turn_off_highlight (tty); + + tty_turn_off_insert (tty); } cmcheckmagic (tty); @@ -799,6 +902,7 @@ tty_write_glyphs_with_face (register struct frame *f, register struct glyph *str { unsigned char *conversion_buffer; struct coding_system *coding; + int write_on_last_cell; struct tty_display_info *tty = FRAME_TTY (f); @@ -808,38 +912,118 @@ tty_write_glyphs_with_face (register struct frame *f, register struct glyph *str /* Don't dare write in last column of bottom line, if Auto-Wrap, since that would scroll the whole frame on some terminals. */ - if (AutoWrap (tty) - && curY (tty) + 1 == FRAME_TOTAL_LINES (f) - && (curX (tty) + len) == FRAME_COLS (f)) + write_on_last_cell = (AutoWrap (tty) + && curY (tty) + 1 == FRAME_TOTAL_LINES (f) + && (curX (tty) + len) == FRAME_COLS (f)); + if (write_on_last_cell) len --; - if (len <= 0) - return; - cmplus (tty, len); + if (FRAME_COLS (f) == 1 + || !(tty->TS_ins_char || tty->TS_ins_multi_chars + || (tty->TS_insert_mode && tty->TS_end_insert_mode))) + write_on_last_cell = false; + + if (len <= 0 && !write_on_last_cell) + return; /* If terminal_coding does any conversion, use it, otherwise use safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here because it always return 1 if the member src_multibyte is 1. */ - coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK + coding = ((FRAME_TERMINAL_CODING (f)->common_flags + & CODING_REQUIRE_ENCODING_MASK) ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding); - /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at - the tail. */ + + /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only + at the tail. */ coding->mode &= ~CODING_MODE_LAST_BLOCK; /* Turn appearance modes of the face. */ tty_highlight_if_desired (tty); turn_on_face (f, face_id); - coding->mode |= CODING_MODE_LAST_BLOCK; - conversion_buffer = encode_terminal_code (string, len, coding); - if (coding->produced > 0) + if (len > 0) + { + cmplus (tty, len); + if (write_on_last_cell) + glyph_on_char_cell_before_last = string[len - 1]; + else + coding->mode |= CODING_MODE_LAST_BLOCK; + + conversion_buffer = encode_terminal_code (string, len, coding); + if (coding->produced > 0) + { + block_input (); + fwrite (conversion_buffer, 1, coding->produced, + tty->output); + clearerr (tty->output); + if (tty->termscript) + fwrite (conversion_buffer, 1, coding->produced, + tty->termscript); + unblock_input (); + } + } + + /* Write on the bottom-right corner. */ + if (write_on_last_cell) { - block_input (); - fwrite (conversion_buffer, 1, coding->produced, tty->output); - clearerr (tty->output); - if (tty->termscript) - fwrite (conversion_buffer, 1, coding->produced, tty->termscript); - unblock_input (); + /* Go to the previous position. */ + cmgoto (tty, curY (tty), curX (tty) - 1); + cmplus (tty, 1); + + conversion_buffer = encode_terminal_code (string, 1, coding); + if (coding->produced > 0) + { + block_input (); + fwrite (conversion_buffer, 1, coding->produced, + tty->output); + clearerr (tty->output); + if (tty->termscript) + fwrite (conversion_buffer, 1, coding->produced, + tty->termscript); + unblock_input (); + } + + /* Go to the previous position. */ + cmgoto (tty, curY (tty), curX (tty) - 1); + cmplus (tty, 1); + + /* Arrange that after writing the next glyph, the glyph on the + current character cell is somehow pushed to the bottom-right + corner. */ + if (tty->TS_ins_char) + { + OUTPUT1 (tty, tty->TS_ins_char); + } + else if (tty->TS_ins_multi_chars) + { + char *buf = tparam (tty->TS_ins_multi_chars, 0, 0, 1, + 0, 0, 0); + OUTPUT1 (tty, buf); + xfree (buf); + } + else + { + tty_turn_on_insert (tty); + } + + /* This is the last run. */ + coding->mode |= CODING_MODE_LAST_BLOCK; + conversion_buffer + = encode_terminal_code (&glyph_on_char_cell_before_last, 1, + coding); + if (coding->produced > 0) + { + block_input (); + fwrite (conversion_buffer, 1, coding->produced, + tty->output); + clearerr (tty->output); + if (tty->termscript) + fwrite (conversion_buffer, 1, coding->produced, + tty->termscript); + unblock_input (); + } + + tty_turn_off_insert (tty); } /* Turn appearance modes off. */ -- 2.37.1