From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Akib Azmain Turja via "Bug reports for GNU Emacs, the Swiss army knife of text editors" Newsgroups: gmane.emacs.bugs Subject: bug#57607: Feature request: Use the character cell on bottom-right corner of a terminal Date: Tue, 04 Oct 2022 19:05:21 +0600 Message-ID: <878rlveo32.fsf@disroot.org> References: <87wnakl5md.fsf@disroot.org> <87o7vt3s58.fsf@disroot.org> <87ilm04xzl.fsf@disroot.org> <875yi0v8r6.fsf@disroot.org> <874jxjhz9l.fsf@disroot.org> <87tu5i9kbg.fsf@disroot.org> <87r0zpi9za.fsf@disroot.org> <83y1twwv7w.fsf@gnu.org> <87edvohx2s.fsf@disroot.org> <83a66cvwob.fsf@gnu.org> <87lepver2e.fsf@disroot.org> Reply-To: Akib Azmain Turja Mime-Version: 1.0 Content-Type: multipart/signed; boundary="==-=-="; micalg=pgp-sha256; protocol="application/pgp-signature" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="10307"; mail-complaints-to="usenet@ciao.gmane.io" Cc: gerd.moellmann@gmail.com, 57607@debbugs.gnu.org To: Eli Zaretskii Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Tue Oct 04 15:50:36 2022 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1ofiJd-0002NY-7u for geb-bug-gnu-emacs@m.gmane-mx.org; Tue, 04 Oct 2022 15:50:33 +0200 Original-Received: from localhost ([::1]:46110 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ofiJc-0007Bb-17 for geb-bug-gnu-emacs@m.gmane-mx.org; Tue, 04 Oct 2022 09:50:32 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:56542) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ofheU-0005zE-Uv for bug-gnu-emacs@gnu.org; Tue, 04 Oct 2022 09:08:02 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:53830) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1ofheU-0008OJ-KF for bug-gnu-emacs@gnu.org; Tue, 04 Oct 2022 09:08:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1ofheU-0003rw-F0 for bug-gnu-emacs@gnu.org; Tue, 04 Oct 2022 09:08:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Akib Azmain Turja Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 04 Oct 2022 13:08:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 57607 X-GNU-PR-Package: emacs Original-Received: via spool by 57607-submit@debbugs.gnu.org id=B57607.166488884214825 (code B ref 57607); Tue, 04 Oct 2022 13:08:02 +0000 Original-Received: (at 57607) by debbugs.gnu.org; 4 Oct 2022 13:07:22 +0000 Original-Received: from localhost ([127.0.0.1]:52908 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ofhdp-0003r1-BL for submit@debbugs.gnu.org; Tue, 04 Oct 2022 09:07:22 -0400 Original-Received: from knopi.disroot.org ([178.21.23.139]:54820) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ofhdl-0003qq-6O for 57607@debbugs.gnu.org; Tue, 04 Oct 2022 09:07:19 -0400 Original-Received: from localhost (localhost [127.0.0.1]) by disroot.org (Postfix) with ESMTP id E4F7B4C639; Tue, 4 Oct 2022 15:07:15 +0200 (CEST) X-Virus-Scanned: SPAM Filter at disroot.org Original-Received: from knopi.disroot.org ([127.0.0.1]) by localhost (disroot.org [127.0.0.1]) (amavisd-new, port 10024) with UTF8SMTP id T-UMlYYk80Tt; Tue, 4 Oct 2022 15:07:13 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=disroot.org; s=mail; t=1664888779; bh=n4SNjnRaInOyUTMwtKKgdAFtj/mZzqLXMv4PXP8DBKc=; h=From:To:Cc:Subject:In-Reply-To:References:Date; b=WSCXYX1PxOirMmloXQ2N5afzh6lcwW+72ctZLiBoeNjwQ8CCii2MTS8t2aKOHp6uq DRMoInjCn9HkhDO7MPJOE/o9VAsddjhmXWvsN2B9rodD5ny3PF4Bf0MtnR7Ic9D9bo cKMSxWMdi4LYl7gVSJXuoUrvNqOINbIq8Tw9UouI5j1Hn5RYcM67mHIhqfyksmhiA7 3AK2s8zq33wwFnLd8RlOrD2Oj5tFO/ou9JDzeI9+3Gygg7bUWvqqlREYlWB8Gj6uh/ xOGlu74Idf+0VCQKcLOS8hPfdP+bYRdmPLBEOoepw9EUpjS50+Yt3cZrACwEvMYY+e EkVW6GcGo7f4w== In-Reply-To: <87lepver2e.fsf@disroot.org> (Akib Azmain Turja's message of "Tue, 04 Oct 2022 18:00:57 +0600") X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:244429 Archived-At: --==-=-= Content-Type: multipart/mixed; boundary="=-=-=" --=-=-= Content-Type: text/plain Content-Transfer-Encoding: quoted-printable Akib Azmain Turja writes: > Eli Zaretskii writes: > >>> From: Akib Azmain Turja >>> Cc: 57607@debbugs.gnu.org, gerd.moellmann@gmail.com >>> Date: Tue, 04 Oct 2022 13:22:51 +0600 >>>=20 >>> > Thanks. But could you please describe the idea of the patch in some >>> > comment? It is hard to follow the code, especially since the diff has >>> > many pure whitespace changes. >>>=20 >>> The idea is that you write the string just like before (for example, you >>> want to write "hello" in a five columns width terminal, so you write >>> only "hell", so that the line shows "hell "), then move a character >>> backward and write the last glyph (write "o", so that the line shows >>> "helo "), move a character backward again and arrange that after writing >>> the next glyph, the character on the current position will be pushed >>> towards right and write the glyph before the last one (write "l", now >>> the line shows "hello"). >>>=20 >>> Should I add the explanation to the function as comment? >> >> Yes, please. It would also help if the respective parts of the code >> were annotated with comments that explain their role in the algorithm. > > OK. Done. > >> >>> > Also, this: >>> > >>> >> + /* Go to the previous position. */ >>> >> + cmgoto (tty, curY (tty), curX (tty) - 1); >>> >> + cmplus (tty, 1); >>> > >>> > Seem to assume the last character takes just one column? What about >>> > characters whose width is 2 columns? >>>=20 >>> Yes, I assume that. I don't think any multi-char width glyph reach this >>> function (I think they are converted to single column width glyphs, for >>> example "^L" is converted to "^" and "L"). The reason of the assumption >>> is the following code: >>>=20 >>> --8<---------------cut here---------------start------------->8--- >>> if (AutoWrap (tty) >>> && curY (tty) + 1 =3D=3D FRAME_TOTAL_LINES (f) >>> && (curX (tty) + len) =3D=3D FRAME_COLS (f)) >>> len --; >>> --8<---------------cut here---------------end--------------->8--- >>>=20 >>> Which also assumes the same. >> >> Please try with some 2-column CJK characters, I'm not sure the example >> with ^L is relevant here. You can find the list of wide characters in >> characters.el (search for "width"); for example, characters in the >> U+FF00 block can be useful. > > Thanks, "CJK STROKE D" doesn't work as expected, and the result depends > on terminal in use. How can I determine the width of a glyph? > >> (And the existing code could have bugs, >> no need to assume it is always correct.) > > Yes, it can, but in most cases, my brain has more bugs. > >> >>> > And finally, it would be nice to avoid so much code duplication >>> > between tty_write_glyphs and tty_write_glyphs_with_face. Is that >>> > feasible? >>>=20 >>> Yes, I think so. I think it possible to just add a new argument >>> "face_id" to tty_write_glyphs would the trick. tty_write_glyph will try >>> to use "face_id" if it is specified, otherwise fallback to the face_id >>> in the string. But how to "not" specify a face_id? Would a NULL work? >> >> face_id is an integer, and zero is a valid value (it means the default >> face), so NULL won't do. But you can use -1 to mean "no face ID". >> Just make sure you never pass it to FACE_FROM_ID etc. >> >> Thanks. > > OK, I'll try that. Thanks. Done. Looks like Emacs still works. Here are the patches: --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0001-Write-on-the-bottom-right-character-cell-on-terminal.patch Content-Transfer-Encoding: quoted-printable Content-Description: PATCH 1/2 From=2072af00d8610bdc194062b246aab0e38f22174aeb 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. =2D-- 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 =2D-- 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); } =20 =2D +static struct glyph glyph_on_char_cell_before_last; =20 /* An implementation of write_glyphs for termcap frames. */ =20 @@ -727,7 +727,7 @@ tty_write_glyphs (struct frame *f, struct glyph *string= , int len) { unsigned char *conversion_buffer; struct coding_system *coding; =2D int n, stringlen; + int n, stringlen, write_on_last_cell; =20 struct tty_display_info *tty =3D FRAME_TTY (f); =20 @@ -737,55 +737,158 @@ tty_write_glyphs (struct frame *f, struct glyph *str= ing, 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. */ =20 =2D if (AutoWrap (tty) =2D && curY (tty) + 1 =3D=3D FRAME_TOTAL_LINES (f) =2D && (curX (tty) + len) =3D=3D FRAME_COLS (f)) + write_on_last_cell =3D (AutoWrap (tty) + && curY (tty) + 1 =3D=3D FRAME_TOTAL_LINES (f) + && (curX (tty) + len) =3D=3D FRAME_COLS (f)); + if (write_on_last_cell) len --; =2D if (len <=3D 0) =2D return; =20 =2D cmplus (tty, len); + if (FRAME_COLS (f) =3D=3D 1 + || !(tty->TS_ins_char || tty->TS_ins_multi_chars + || (tty->TS_insert_mode && tty->TS_end_insert_mode))) + write_on_last_cell =3D false; + + if (len <=3D 0 && !write_on_last_cell) + return; =20 /* 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. */ =2D coding =3D (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_E= NCODING_MASK + coding =3D ((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 &=3D ~CODING_MODE_LAST_BLOCK; =20 =2D for (stringlen =3D len; stringlen !=3D 0; stringlen -=3D n) + if (len > 0) { =2D /* Identify a run of glyphs with the same face. */ =2D int face_id =3D string->face_id; + cmplus (tty, len); + + if (write_on_last_cell) + glyph_on_char_cell_before_last =3D string[len - 1]; + + for (stringlen =3D len; stringlen !=3D 0; stringlen -=3D n) + { + /* Identify a run of glyphs with the same face. */ + int face_id =3D string->face_id; + + for (n =3D 1; n < stringlen; ++n) + if (string[n].face_id !=3D face_id) + break; + + /* Turn appearance modes of the face of the run on. */ + tty_highlight_if_desired (tty); + turn_on_face (f, face_id); =20 =2D for (n =3D 1; n < stringlen; ++n) =2D if (string[n].face_id !=3D face_id) =2D break; + if (n =3D=3D stringlen && !write_on_last_cell) + /* This is the last run. */ + coding->mode |=3D CODING_MODE_LAST_BLOCK; + conversion_buffer =3D 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 +=3D n; =20 =2D /* 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 =3D string->face_id; + + /* Turn appearance modes of the face. */ tty_highlight_if_desired (tty); turn_on_face (f, face_id); =20 =2D if (n =3D=3D stringlen) =2D /* This is the last run. */ =2D coding->mode |=3D CODING_MODE_LAST_BLOCK; =2D conversion_buffer =3D encode_terminal_code (string, n, coding); + conversion_buffer =3D encode_terminal_code (string, 1, coding); if (coding->produced > 0) { block_input (); =2D fwrite (conversion_buffer, 1, coding->produced, tty->output); + fwrite (conversion_buffer, 1, coding->produced, + tty->output); clearerr (tty->output); if (tty->termscript) =2D 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 =3D 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 !=3D 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 =3D 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 |=3D CODING_MODE_LAST_BLOCK; + conversion_buffer + =3D 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 (); } =2D string +=3D n; =20 /* Turn appearance modes off. */ turn_off_face (f, face_id); tty_turn_off_highlight (tty); + + tty_turn_off_insert (tty); } =20 cmcheckmagic (tty); @@ -799,6 +902,7 @@ tty_write_glyphs_with_face (register struct frame *f, r= egister struct glyph *str { unsigned char *conversion_buffer; struct coding_system *coding; + int write_on_last_cell; =20 struct tty_display_info *tty =3D FRAME_TTY (f); =20 @@ -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. */ =20 =2D if (AutoWrap (tty) =2D && curY (tty) + 1 =3D=3D FRAME_TOTAL_LINES (f) =2D && (curX (tty) + len) =3D=3D FRAME_COLS (f)) + write_on_last_cell =3D (AutoWrap (tty) + && curY (tty) + 1 =3D=3D FRAME_TOTAL_LINES (f) + && (curX (tty) + len) =3D=3D FRAME_COLS (f)); + if (write_on_last_cell) len --; =2D if (len <=3D 0) =2D return; =20 =2D cmplus (tty, len); + if (FRAME_COLS (f) =3D=3D 1 + || !(tty->TS_ins_char || tty->TS_ins_multi_chars + || (tty->TS_insert_mode && tty->TS_end_insert_mode))) + write_on_last_cell =3D false; + + if (len <=3D 0 && !write_on_last_cell) + return; =20 /* 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. */ =2D coding =3D (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_E= NCODING_MASK + coding =3D ((FRAME_TERMINAL_CODING (f)->common_flags + & CODING_REQUIRE_ENCODING_MASK) ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding); =2D /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at =2D the tail. */ + + /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only + at the tail. */ coding->mode &=3D ~CODING_MODE_LAST_BLOCK; =20 /* Turn appearance modes of the face. */ tty_highlight_if_desired (tty); turn_on_face (f, face_id); =20 =2D coding->mode |=3D CODING_MODE_LAST_BLOCK; =2D conversion_buffer =3D encode_terminal_code (string, len, coding); =2D if (coding->produced > 0) + if (len > 0) + { + cmplus (tty, len); + if (write_on_last_cell) + glyph_on_char_cell_before_last =3D string[len - 1]; + else + coding->mode |=3D CODING_MODE_LAST_BLOCK; + + conversion_buffer =3D 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) { =2D block_input (); =2D fwrite (conversion_buffer, 1, coding->produced, tty->output); =2D clearerr (tty->output); =2D if (tty->termscript) =2D fwrite (conversion_buffer, 1, coding->produced, tty->termscript); =2D unblock_input (); + /* Go to the previous position. */ + cmgoto (tty, curY (tty), curX (tty) - 1); + cmplus (tty, 1); + + conversion_buffer =3D 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 =3D 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 |=3D CODING_MODE_LAST_BLOCK; + conversion_buffer + =3D 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); } =20 /* Turn appearance modes off. */ =2D-=20 2.37.1 --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0002-Merge-tty_write_glyphs-and-tty_write_glyphs_with_fac.patch Content-Transfer-Encoding: quoted-printable Content-Description: PATCH 2/2 From=20b090cba28981d7a0e40f87211e9b8b065bfdf3e3 Mon Sep 17 00:00:00 2001 From: Akib Azmain Turja Date: Tue, 4 Oct 2022 18:54:58 +0600 Subject: [PATCH 2/2] Merge tty_write_glyphs and tty_write_glyphs_with_face * src/term.c (tty_write_glyphs_1, tty_write_glyphs) (tty_write_glyphs_with_face): Merge tty_write_glyphs and tty_write_glyphs_with_face into tty_write_glyphs_1. Define tty_write_glyphs as a wrapper of tty_write_glyphs_1. =2D-- src/term.c | 243 +++++++++++++++++------------------------------------ 1 file changed, 79 insertions(+), 164 deletions(-) diff --git a/src/term.c b/src/term.c index 283a65c4..db1dd2a4 100644 =2D-- a/src/term.c +++ b/src/term.c @@ -723,7 +723,8 @@ encode_terminal_code (struct glyph *src, int src_len, /* An implementation of write_glyphs for termcap frames. */ =20 static void =2Dtty_write_glyphs (struct frame *f, struct glyph *string, int len) +tty_write_glyphs_1 (struct frame *f, struct glyph *string, int len, + int face_id) { unsigned char *conversion_buffer; struct coding_system *coding; @@ -761,6 +762,13 @@ tty_write_glyphs (struct frame *f, struct glyph *strin= g, int len) the tail. */ coding->mode &=3D ~CODING_MODE_LAST_BLOCK; =20 + if (face_id >=3D 0) + { + /* Turn appearance modes of the face. */ + tty_highlight_if_desired (tty); + turn_on_face (f, face_id); + } + if (len > 0) { cmplus (tty, len); @@ -770,16 +778,27 @@ tty_write_glyphs (struct frame *f, struct glyph *stri= ng, int len) =20 for (stringlen =3D len; stringlen !=3D 0; stringlen -=3D n) { =2D /* Identify a run of glyphs with the same face. */ =2D int face_id =3D string->face_id; + int local_face_id; =20 =2D for (n =3D 1; n < stringlen; ++n) =2D if (string[n].face_id !=3D face_id) =2D break; + if (face_id >=3D 0) + { + /* This will be a problem when we run the loop another + time, but this is the only iteration. */ + n =3D stringlen; + } + else + { + /* Identify a run of glyphs with the same face. */ + local_face_id =3D string->face_id; =20 =2D /* Turn appearance modes of the face of the run on. */ =2D tty_highlight_if_desired (tty); =2D turn_on_face (f, face_id); + for (n =3D 1; n < stringlen; ++n) + if (string[n].face_id !=3D local_face_id) + break; + + /* Turn appearance modes of the face of the run on. */ + tty_highlight_if_desired (tty); + turn_on_face (f, local_face_id); + } =20 if (n =3D=3D stringlen && !write_on_last_cell) /* This is the last run. */ @@ -799,24 +818,41 @@ tty_write_glyphs (struct frame *f, struct glyph *stri= ng, int len) } string +=3D n; =20 =2D /* Turn appearance modes off. */ =2D turn_off_face (f, face_id); =2D tty_turn_off_highlight (tty); + if (face_id < 0) + { + /* Turn appearance modes off. */ + turn_off_face (f, local_face_id); + tty_turn_off_highlight (tty); + } } } =20 /* Write on the bottom-right corner. */ if (write_on_last_cell) { =2D /* Go to the previous position. */ + /* The algorithm here is: we write the whole string except the + last glyph, then move back to the beginning of previous + glyph, write the last glyph, move back again, and insert the + glyph before the last glyph in such a way that last glyph at + cursor' position gets pushed to the corner. */ + + /* Go to the beginning of previous glyph. */ + /* BUG: This assume the previous glyph is a single column width + glyph, so this won't work for multi column width, and the + result is terminal-dependent. */ cmgoto (tty, curY (tty), curX (tty) - 1); cmplus (tty, 1); =20 =2D int face_id =3D string->face_id; + int local_face_id; =20 =2D /* Turn appearance modes of the face. */ =2D tty_highlight_if_desired (tty); =2D turn_on_face (f, face_id); + if (face_id < 0) + { + local_face_id =3D string->face_id; + + /* Turn appearance modes of the face. */ + tty_highlight_if_desired (tty); + turn_on_face (f, local_face_id); + } =20 conversion_buffer =3D encode_terminal_code (string, 1, coding); if (coding->produced > 0) @@ -831,12 +867,15 @@ tty_write_glyphs (struct frame *f, struct glyph *stri= ng, int len) unblock_input (); } =20 =2D /* Go to the previous position. */ + /* Go to the beginning of previous glyph. */ + /* BUG: This assume the previous glyph is a single column width + glyph, so this won't work for multi column width, and the + result is terminal-dependent. */ cmgoto (tty, curY (tty), curX (tty) - 1); cmplus (tty, 1); =20 /* Arrange that after writing the next glyph, the glyph on the =2D current character cell is somehow pushed to the bottom-right + current character cell gets pushed to the bottom-right corner. */ if (tty->TS_ins_char) { @@ -854,17 +893,18 @@ tty_write_glyphs (struct frame *f, struct glyph *stri= ng, int len) tty_turn_on_insert (tty); } =20 =2D if (face_id !=3D glyph_on_char_cell_before_last.face_id) + if (face_id < 0 + && local_face_id !=3D glyph_on_char_cell_before_last.face_id) { =20 /* Turn appearance modes of the face. */ =2D turn_off_face (f, face_id); + turn_off_face (f, local_face_id); tty_turn_off_highlight (tty); =20 =2D face_id =3D glyph_on_char_cell_before_last.face_id; + local_face_id =3D glyph_on_char_cell_before_last.face_id; =20 tty_highlight_if_desired (tty); =2D turn_on_face (f, face_id); + turn_on_face (f, local_face_id); } =20 /* This is the last run. */ @@ -884,157 +924,32 @@ tty_write_glyphs (struct frame *f, struct glyph *str= ing, int len) unblock_input (); } =20 + if (face_id < 0) + { + /* Turn appearance modes off. */ + turn_off_face (f, local_face_id); + tty_turn_off_highlight (tty); + } + + tty_turn_off_insert (tty); + } + + if (face_id >=3D 0) + { /* Turn appearance modes off. */ turn_off_face (f, face_id); tty_turn_off_highlight (tty); =2D =2D tty_turn_off_insert (tty); } =20 cmcheckmagic (tty); } =20 =2D#ifndef DOS_NT =2D static void =2Dtty_write_glyphs_with_face (register struct frame *f, register struct gl= yph *string, =2D register int len, register int face_id) +tty_write_glyphs (struct frame *f, struct glyph *string, int len) { =2D unsigned char *conversion_buffer; =2D struct coding_system *coding; =2D int write_on_last_cell; =2D =2D struct tty_display_info *tty =3D FRAME_TTY (f); =2D =2D tty_turn_off_insert (tty); =2D tty_hide_cursor (tty); =2D =2D /* Don't dare write in last column of bottom line, if Auto-Wrap, =2D since that would scroll the whole frame on some terminals. */ =2D =2D write_on_last_cell =3D (AutoWrap (tty) =2D && curY (tty) + 1 =3D=3D FRAME_TOTAL_LINES (f) =2D && (curX (tty) + len) =3D=3D FRAME_COLS (f)); =2D if (write_on_last_cell) =2D len --; =2D =2D if (FRAME_COLS (f) =3D=3D 1 =2D || !(tty->TS_ins_char || tty->TS_ins_multi_chars =2D || (tty->TS_insert_mode && tty->TS_end_insert_mode))) =2D write_on_last_cell =3D false; =2D =2D if (len <=3D 0 && !write_on_last_cell) =2D return; =2D =2D /* If terminal_coding does any conversion, use it, otherwise use =2D safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here =2D because it always return 1 if the member src_multibyte is 1. */ =2D coding =3D ((FRAME_TERMINAL_CODING (f)->common_flags =2D & CODING_REQUIRE_ENCODING_MASK) =2D ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding); =2D =2D /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only =2D at the tail. */ =2D coding->mode &=3D ~CODING_MODE_LAST_BLOCK; =2D =2D /* Turn appearance modes of the face. */ =2D tty_highlight_if_desired (tty); =2D turn_on_face (f, face_id); =2D =2D if (len > 0) =2D { =2D cmplus (tty, len); =2D if (write_on_last_cell) =2D glyph_on_char_cell_before_last =3D string[len - 1]; =2D else =2D coding->mode |=3D CODING_MODE_LAST_BLOCK; =2D =2D conversion_buffer =3D encode_terminal_code (string, len, coding); =2D if (coding->produced > 0) =2D { =2D block_input (); =2D fwrite (conversion_buffer, 1, coding->produced, =2D tty->output); =2D clearerr (tty->output); =2D if (tty->termscript) =2D fwrite (conversion_buffer, 1, coding->produced, =2D tty->termscript); =2D unblock_input (); =2D } =2D } =2D =2D /* Write on the bottom-right corner. */ =2D if (write_on_last_cell) =2D { =2D /* Go to the previous position. */ =2D cmgoto (tty, curY (tty), curX (tty) - 1); =2D cmplus (tty, 1); =2D =2D conversion_buffer =3D encode_terminal_code (string, 1, coding); =2D if (coding->produced > 0) =2D { =2D block_input (); =2D fwrite (conversion_buffer, 1, coding->produced, =2D tty->output); =2D clearerr (tty->output); =2D if (tty->termscript) =2D fwrite (conversion_buffer, 1, coding->produced, =2D tty->termscript); =2D unblock_input (); =2D } =2D =2D /* Go to the previous position. */ =2D cmgoto (tty, curY (tty), curX (tty) - 1); =2D cmplus (tty, 1); =2D =2D /* Arrange that after writing the next glyph, the glyph on the =2D current character cell is somehow pushed to the bottom-right =2D corner. */ =2D if (tty->TS_ins_char) =2D { =2D OUTPUT1 (tty, tty->TS_ins_char); =2D } =2D else if (tty->TS_ins_multi_chars) =2D { =2D char *buf =3D tparam (tty->TS_ins_multi_chars, 0, 0, 1, =2D 0, 0, 0); =2D OUTPUT1 (tty, buf); =2D xfree (buf); =2D } =2D else =2D { =2D tty_turn_on_insert (tty); =2D } =2D =2D /* This is the last run. */ =2D coding->mode |=3D CODING_MODE_LAST_BLOCK; =2D conversion_buffer =2D =3D encode_terminal_code (&glyph_on_char_cell_before_last, 1, =2D coding); =2D if (coding->produced > 0) =2D { =2D block_input (); =2D fwrite (conversion_buffer, 1, coding->produced, =2D tty->output); =2D clearerr (tty->output); =2D if (tty->termscript) =2D fwrite (conversion_buffer, 1, coding->produced, =2D tty->termscript); =2D unblock_input (); =2D } =2D =2D tty_turn_off_insert (tty); =2D } =2D =2D /* Turn appearance modes off. */ =2D turn_off_face (f, face_id); =2D tty_turn_off_highlight (tty); =2D =2D cmcheckmagic (tty); + tty_write_glyphs_1 (f, string, len, -1); } =20 =2D#endif =2D /* An implementation of insert_glyphs for termcap frames. */ =20 static void @@ -2615,8 +2530,8 @@ tty_draw_row_with_mouse_face (struct window *w, struc= t glyph_row *row, cursor_to (f, pos_y, pos_x); =20 if (draw =3D=3D DRAW_MOUSE_FACE) =2D tty_write_glyphs_with_face (f, row->glyphs[TEXT_AREA] + start_hpos, =2D nglyphs, face_id); + tty_write_glyphs_1 (f, row->glyphs[TEXT_AREA] + start_hpos, + nglyphs, face_id); else if (draw =3D=3D DRAW_NORMAL_TEXT) write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs); =20 =2D-=20 2.37.1 --=-=-= Content-Type: text/plain Content-Transfer-Encoding: quoted-printable =2D-=20 Akib Azmain Turja Find me on Mastodon at @akib@hostux.social. This message is signed by me with my GnuPG key. Its fingerprint is: 7001 8CE5 819F 17A3 BBA6 66AF E74F 0EFA 922A E7F5 --=-=-=-- --==-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAEBCAAdFiEEyVTKmrtL6kNBe3FRVTX89U2IYWsFAmM8L5EACgkQVTX89U2I YWspHg/9GP+951K+Ly2rpsPxpgHyH7bPfA6ZQ0b6Bb+nrlwR6c/8akN4/f8IdUbk F6ChnQ6FMbGHkY2RQA2sFPKo1wTv+GESgV6f7oN1K0tmsZLckGD8iLSFHEHkV2NT 8j93gsxroe8sMKE2q8sGM3YCGl64ZP2+kUpYQXx1rrZ+VW+2SdCDY1tY/El8GptM LVBtj6PlBYrQ/m+Ysp/VOWlMrsKhye811b+N8Q7PfJHam4c+KFqH8Pd8aRrvhXoI gzyO3A2lq6QINa7Bq5KjbMsRXUQP6S/yZJP6vL8kqzG+eIPt+euBo3E+RgQ/K00Y 9TICQ3QVAGGQwD30ZyZd+/h/SaJvKBylfNy99zpZ3riiX0Rj3ETD65Lfo/qy3ryF n17XI5PAEPzlpQxQ6gQu9lNLC/f7XgWvPFg3ODkwj3U6wveVsyuzouuQjpqHue8a QTHOx6shn/3H6TLWC2PYjwm0FhHnCoCxJqCJ1n12wDMj8fTzLEk4L4SwSRPlsShC H0fqc/epkrXOZqvg+ebE1tl4C9ZI3pDeCBacsB6Ixp89XkuljsxkZrU7lQN0gOrf YqgsyLZsG4RXHfZvERdEUMV2HsVqSZhVMQ4IJyMOaqfG1Qln/c050IOTBHjvpIXk qN6i+4jKBaVP3qwoPQ1WOAbcTspbDVjwI7fPzVDHBzqWSx5JiX4= =oAel -----END PGP SIGNATURE----- --==-=-=--