GNU bug report logs -
#57607
Feature request: Use the character cell on bottom-right corner of a terminal
Previous Next
Reported by: Akib Azmain Turja <akib <at> disroot.org>
Date: Tue, 6 Sep 2022 07:10:02 UTC
Severity: wishlist
Fixed in version 31.1
Done: Gerd Möllmann <gerd.moellmann <at> gmail.com>
Bug is archived. No further changes may be made.
To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 57607 in the body.
You can then email your comments to 57607 AT debbugs.gnu.org in the normal way.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Tue, 06 Sep 2022 07:10:02 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
Akib Azmain Turja <akib <at> disroot.org>
:
New bug report received and forwarded. Copy sent to
bug-gnu-emacs <at> gnu.org
.
(Tue, 06 Sep 2022 07:10:02 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Forwarding to bug-gnu-emacs list.
Akib Azmain Turja <akib <at> disroot.org> writes:
> Emacs never writes to the bottom-right corner of a terminal, because the
> terminal might open a new line at bottom of screen. But terminals
> having any of 'ich', 'ich1' and 'smir' capabilities can write to the
> bottom-right corner of the terminal. Almost all terminals have at least
> one of the aforementioned capabilities. Why doesn't Emacs make use of
> that?
--
Akib Azmain Turja
Find me on Mastodon at @akib <at> 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
[signature.asc (application/pgp-signature, inline)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Tue, 06 Sep 2022 08:04:02 GMT)
Full text and
rfc822 format available.
Message #8 received at 57607 <at> debbugs.gnu.org (full text, mbox):
Akib Azmain Turja <akib <at> disroot.org> writes:
> Forwarding to bug-gnu-emacs list.
>
> Akib Azmain Turja <akib <at> disroot.org> writes:
>
>> Emacs never writes to the bottom-right corner of a terminal, because the
>> terminal might open a new line at bottom of screen. But terminals
>> having any of 'ich', 'ich1' and 'smir' capabilities can write to the
>> bottom-right corner of the terminal. Almost all terminals have at least
>> one of the aforementioned capabilities. Why doesn't Emacs make use of
>> that?
I don't know. And I don't know if that would work, it would require
investigation.
Emacs already writes to the bottom-right corner in case neither "am" nor
"xn" are defined for the terminal in question. vt100 and xterm, for
instance, have "am" defined here, so Emacs doesn't write to the
bottom-right corner.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Tue, 06 Sep 2022 11:08:01 GMT)
Full text and
rfc822 format available.
Message #11 received at 57607 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Gerd Möllmann <gerd.moellmann <at> gmail.com> writes:
> Akib Azmain Turja <akib <at> disroot.org> writes:
>
>> Forwarding to bug-gnu-emacs list.
>>
>> Akib Azmain Turja <akib <at> disroot.org> writes:
>>
>>> Emacs never writes to the bottom-right corner of a terminal, because the
>>> terminal might open a new line at bottom of screen. But terminals
>>> having any of 'ich', 'ich1' and 'smir' capabilities can write to the
>>> bottom-right corner of the terminal. Almost all terminals have at least
>>> one of the aforementioned capabilities. Why doesn't Emacs make use of
>>> that?
>
> I don't know. And I don't know if that would work, it would require
> investigation.
There must be a way reliably way to do so, because ncurses can write to
the last character cell on terminal on linux console and xterm-like
terminal emulators.
>
> Emacs already writes to the bottom-right corner in case neither "am" nor
> "xn" are defined for the terminal in question. vt100 and xterm, for
> instance, have "am" defined here, so Emacs doesn't write to the
> bottom-right corner.
I repeat: vt100 and xterm-like terminal having any of 'ich', 'ich1',
'il' and 'il1' or both 'smir' and 'rmir' can write to the last character
cell reliably without scrolling.
Here is what Emacs can do IMHO:
Glyph matrix (or whatever):
+------------------------+
|foo |
|bar |
|baz |
| --- *scratch* ---------|
|A very looooong message.|
+------------------------+
* Case: Any of 'ich', 'ich1', or both 'smir' and 'rmir' defined.
*Note*: Won't work on displays with only a single column.
Write to all character cells except the last two:
+------------------------+
|foo |
|bar |
|baz |
| --- *scratch* ---------|
|A very looooong messag | <-- cursor
+------------------------+
^
|
cursor
* Case: 'ich1' defined.
Write the glyph to be placed on the last character cell.
+------------------------+
|foo |
|bar |
|baz |
| --- *scratch* ---------|
|A very looooong messag. | <-- cursor
+------------------------+
^
|
cursor
Move to the character cell on the left side (cub1):
+------------------------+
|foo |
|bar |
|baz |
| --- *scratch* ---------|
|A very looooong messag. | <-- cursor
+------------------------+
^
|
cursor
Invoke (or write or whatever) 'ich1':
+------------------------+
|foo |
|bar |
|baz |
| --- *scratch* ---------|
|A very looooong messag .| <-- cursor
+------------------------+
^
|
cursor
Write the glyph to be placed on the character cell before the last
character cell:
+------------------------+
|foo |
|bar |
|baz |
| --- *scratch* ---------|
|A very looooong message.| <-- cursor
+------------------------+
^
|
cursor
* Case: 'ich' defined.
Same as the 'ich1' case, but invoke 'ich' with parameter '1' instead
of 'ich1'.
* Case: 'smir' and 'rmir' defined.
Write the glyph to be placed on the last character cell.
+------------------------+
|foo |
|bar |
|baz |
| --- *scratch* ---------|
|A very looooong messag. | <-- cursor
+------------------------+
^
|
cursor
Move to the character cell on the left side (cub1):
+------------------------+
|foo |
|bar |
|baz |
| --- *scratch* ---------|
|A very looooong messag. | <-- cursor
+------------------------+
^
|
cursor
Invoke 'smir'.
Write the glyph to be placed on the character cell before the last
character cell:
+------------------------+
|foo |
|bar |
|baz |
| --- *scratch* ---------|
|A very looooong message.| <-- cursor
+------------------------+
^
|
cursor
Invoke 'rmir'.
* Case: 'il' or 'il1' defined.
*Note*: Won't work on displays with only a single line.
Write to all lines except the last two:
+------------------------+
|foo |
|bar |
|baz |
| | <-- cursor
| |
+------------------------+
^
|
cursor
Write the glyphs to be placed on the last line.
+------------------------+
|foo |
|bar |
|baz |
|A very looooong message.|
| | <-- cursor
+------------------------+
^
|
cursor
Move to the character cell above (cuu1):
+------------------------+
|foo |
|bar |
|baz |
|A very looooong message.| <-- cursor
| |
+------------------------+
^
|
cursor
* Case: 'il1' defined.
Invoke 'il1'.
* Case: 'il' defined.
Invoke 'il1' with parameter '1'.
+------------------------+
|foo |
|bar |
|baz |
| | <-- cursor
|A very looooong message.|
+------------------------+
^
|
cursor
Insert the glyphs to be placed on the line before the last line:
+------------------------+
|foo |
|bar |
|baz |
| --- *scratch* ---------|
|A very looooong message.| <-- cursor
+------------------------+
^
|
cursor
--
Akib Azmain Turja
Find me on Mastodon at @akib <at> 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
[signature.asc (application/pgp-signature, inline)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Tue, 06 Sep 2022 12:02:02 GMT)
Full text and
rfc822 format available.
Message #14 received at 57607 <at> debbugs.gnu.org (full text, mbox):
Akib Azmain Turja <akib <at> disroot.org> writes:
> Gerd Möllmann <gerd.moellmann <at> gmail.com> writes:
>
>> Emacs already writes to the bottom-right corner in case neither "am" nor
>> "xn" are defined for the terminal in question. vt100 and xterm, for
>> instance, have "am" defined here, so Emacs doesn't write to the
>> bottom-right corner.
>
> I repeat: vt100 and xterm-like terminal having any of 'ich', 'ich1',
> 'il' and 'il1' or both 'smir' and 'rmir' can write to the last character
> cell reliably without scrolling.
>
> Here is what Emacs can do IMHO:
>
I know that, I can edit text :-).
I guess no-one else before felt motifvated enough to implement this. Do
you feel motivated? I could show you where to look, if you like.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Tue, 06 Sep 2022 15:20:02 GMT)
Full text and
rfc822 format available.
Message #17 received at 57607 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Gerd Möllmann <gerd.moellmann <at> gmail.com> writes:
> Akib Azmain Turja <akib <at> disroot.org> writes:
>
>> Gerd Möllmann <gerd.moellmann <at> gmail.com> writes:
>>
>>> Emacs already writes to the bottom-right corner in case neither "am" nor
>>> "xn" are defined for the terminal in question. vt100 and xterm, for
>>> instance, have "am" defined here, so Emacs doesn't write to the
>>> bottom-right corner.
>>
>> I repeat: vt100 and xterm-like terminal having any of 'ich', 'ich1',
>> 'il' and 'il1' or both 'smir' and 'rmir' can write to the last character
>> cell reliably without scrolling.
>>
>> Here is what Emacs can do IMHO:
>>
>
> I know that, I can edit text :-).
>
> I guess no-one else before felt motifvated enough to implement this. Do
> you feel motivated?
A little.
> I could show you where to look, if you like.
It's good to know, in case I (or someone else) try to do this.
--
Akib Azmain Turja
Find me on Mastodon at @akib <at> 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
[signature.asc (application/pgp-signature, inline)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Wed, 07 Sep 2022 04:59:01 GMT)
Full text and
rfc822 format available.
Message #20 received at 57607 <at> debbugs.gnu.org (full text, mbox):
Akib Azmain Turja <akib <at> disroot.org> writes:
>> I guess no-one else before felt motifvated enough to implement this. Do
>> you feel motivated?
>
> A little.
I've added something to etc/TODO.
I guess there's not much else to do, so I'm closing this for now.
bug marked as fixed in version 29.1, send any further explanations to
57607 <at> debbugs.gnu.org and Akib Azmain Turja <akib <at> disroot.org>
Request was from
Gerd Möllmann <gerd.moellmann <at> gmail.com>
to
control <at> debbugs.gnu.org
.
(Wed, 07 Sep 2022 05:00:03 GMT)
Full text and
rfc822 format available.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Wed, 07 Sep 2022 12:53:02 GMT)
Full text and
rfc822 format available.
Message #25 received at 57607 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Gerd Möllmann <gerd.moellmann <at> gmail.com> writes:
> Akib Azmain Turja <akib <at> disroot.org> writes:
>
>>> I guess no-one else before felt motifvated enough to implement this. Do
>>> you feel motivated?
>>
>> A little.
>
> I've added something to etc/TODO.
>
> I guess there's not much else to do, so I'm closing this for now.
>
>
>
OK, but what to change in Emacs???
--
Akib Azmain Turja
Find me on Mastodon at @akib <at> 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
[signature.asc (application/pgp-signature, inline)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Wed, 07 Sep 2022 12:59:02 GMT)
Full text and
rfc822 format available.
Message #28 received at 57607 <at> debbugs.gnu.org (full text, mbox):
Akib Azmain Turja <akib <at> disroot.org> writes:
> OK, but what to change in Emacs???
I guess I'm missing something. What do you mean?
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Wed, 07 Sep 2022 15:57:02 GMT)
Full text and
rfc822 format available.
Message #31 received at 57607 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Gerd Möllmann <gerd.moellmann <at> gmail.com> writes:
> Akib Azmain Turja <akib <at> disroot.org> writes:
>
>>> I guess no-one else before felt motifvated enough to implement this. Do
>>> you feel motivated?
>>
>> A little.
>
> I've added something to etc/TODO.
>
> I guess there's not much else to do, so I'm closing this for now.
OK, but what to change?
--
Akib Azmain Turja
Find me on Mastodon at @akib <at> 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
[signature.asc (application/pgp-signature, inline)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Wed, 07 Sep 2022 17:30:02 GMT)
Full text and
rfc822 format available.
Message #34 received at 57607 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Gerd Möllmann <gerd.moellmann <at> gmail.com> writes:
I mean, what files to change in order to do this? I think it's
tty_write_glyphs and tty_write_glyphs_with_face in term.c.
--
Akib Azmain Turja
Find me on Mastodon at @akib <at> 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
[signature.asc (application/pgp-signature, inline)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Thu, 08 Sep 2022 05:50:02 GMT)
Full text and
rfc822 format available.
Message #37 received at 57607 <at> debbugs.gnu.org (full text, mbox):
Akib Azmain Turja <akib <at> disroot.org> writes:
> Gerd Möllmann <gerd.moellmann <at> gmail.com> writes:
>
> I mean, what files to change in order to do this? I think it's
> tty_write_glyphs and tty_write_glyphs_with_face in term.c.
Are you interested in implementing something? You could re-open this
bug then, no problem. Or are you maybe just evaluating if you'd like to
do it? Please give a hint.
The places you mention sound right. It's probably all in term.c. But
I'd like to add, that in principle all places writing to the terminal
have to be checked at least.
And corner cases have to be taken into consideration :-). Pulling
something out of thin air: What happens if we write RGRG to the
bottom-right corner, where R is one red char, and G is 1 green char,
say.
And maybe we have to check for characters that are more than 1 column
wide? I don't remember something like that from when I last worked in
this area, but I'd check what the situation is nowadays.
That's all I can say without studying the code more in detail, which I'm
trying to avoid :-).
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Thu, 08 Sep 2022 12:11:01 GMT)
Full text and
rfc822 format available.
Message #40 received at 57607 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Gerd Möllmann <gerd.moellmann <at> gmail.com> writes:
> Akib Azmain Turja <akib <at> disroot.org> writes:
>
>> Gerd Möllmann <gerd.moellmann <at> gmail.com> writes:
>>
>> I mean, what files to change in order to do this? I think it's
>> tty_write_glyphs and tty_write_glyphs_with_face in term.c.
>
> Are you interested in implementing something? You could re-open this
> bug then, no problem. Or are you maybe just evaluating if you'd like to
> do it? Please give a hint.
Yes, I'm interested, because I think it would help me understand how
Emacs renders text in terminal, which would help me to implement child
frame in terminal. But I don't have the time to do it right now. I
hope I can start doing this by late October.
>
> The places you mention sound right. It's probably all in term.c. But
> I'd like to add, that in principle all places writing to the terminal
> have to be checked at least.
>
> And corner cases have to be taken into consideration :-). Pulling
> something out of thin air: What happens if we write RGRG to the
> bottom-right corner, where R is one red char, and G is 1 green char,
> say.
I think you meant the following in Bash:
--8<---------------cut here---------------start------------->8---
printf "%$((COLUMNS - 4))s\e[31mr\e[32mg\e7\e[32mg\e8\e[@\e[31mr\e[m" "" ; sleep 1 ; printf '\n'
--8<---------------cut here---------------end--------------->8---
And it works on St, Kitty, Coterm, Term, etc.
>
> And maybe we have to check for characters that are more than 1 column
> wide? I don't remember something like that from when I last worked in
> this area, but I'd check what the situation is nowadays.
>
> That's all I can say without studying the code more in detail, which I'm
> trying to avoid :-).
>
--
Akib Azmain Turja
Find me on Mastodon at @akib <at> 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
[signature.asc (application/pgp-signature, inline)]
bug No longer marked as fixed in versions 29.1 and reopened.
Request was from
Debbugs Internal Request <help-debbugs <at> gnu.org>
to
internal_control <at> debbugs.gnu.org
.
(Thu, 08 Sep 2022 12:32:02 GMT)
Full text and
rfc822 format available.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Thu, 08 Sep 2022 12:36:01 GMT)
Full text and
rfc822 format available.
Message #45 received at 57607 <at> debbugs.gnu.org (full text, mbox):
Akib Azmain Turja <akib <at> disroot.org> writes:
> Yes, I'm interested, because I think it would help me understand how
> Emacs renders text in terminal, which would help me to implement child
> frame in terminal. But I don't have the time to do it right now. I
> hope I can start doing this by late October.
Great! I've re-opened this issue.
>
>>
>> The places you mention sound right. It's probably all in term.c. But
>> I'd like to add, that in principle all places writing to the terminal
>> have to be checked at least.
>>
>> And corner cases have to be taken into consideration :-). Pulling
>> something out of thin air: What happens if we write RGRG to the
>> bottom-right corner, where R is one red char, and G is 1 green char,
>> say.
>
> I think you meant the following in Bash:
>
> printf "%$((COLUMNS - 4))s\e[31mr\e[32mg\e7\e[32mg\e8\e[@\e[31mr\e[m" "" ; sleep 1 ; printf '\n'
>
> And it works on St, Kitty, Coterm, Term, etc.
What I was thinking of is the Emacs side of things, i.e. can we always
do our magic locally in tty_write... etc., or is it sometimes necessary
to reorder writes at the caller.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Thu, 08 Sep 2022 14:51:01 GMT)
Full text and
rfc822 format available.
Message #48 received at 57607 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Gerd Möllmann <gerd.moellmann <at> gmail.com> writes:
> Akib Azmain Turja <akib <at> disroot.org> writes:
>
>> Yes, I'm interested, because I think it would help me understand how
>> Emacs renders text in terminal, which would help me to implement child
>> frame in terminal. But I don't have the time to do it right now. I
>> hope I can start doing this by late October.
>
> Great! I've re-opened this issue.
>
>>
>>>
>>> The places you mention sound right. It's probably all in term.c. But
>>> I'd like to add, that in principle all places writing to the terminal
>>> have to be checked at least.
>>>
>>> And corner cases have to be taken into consideration :-). Pulling
>>> something out of thin air: What happens if we write RGRG to the
>>> bottom-right corner, where R is one red char, and G is 1 green char,
>>> say.
>>
>> I think you meant the following in Bash:
>>
>> printf "%$((COLUMNS - 4))s\e[31mr\e[32mg\e7\e[32mg\e8\e[@\e[31mr\e[m" "" ; sleep 1 ; printf '\n'
>>
>> And it works on St, Kitty, Coterm, Term, etc.
>
> What I was thinking of is the Emacs side of things, i.e. can we always
> do our magic locally in tty_write... etc., or is it sometimes necessary
> to reorder writes at the caller.
We would need to remember the glyph in the character cell before the
last one, because modifying the last character cell needs to rewrite to
that cell.
--
Akib Azmain Turja
Find me on Mastodon at @akib <at> 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
[signature.asc (application/pgp-signature, inline)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Sun, 11 Sep 2022 09:05:02 GMT)
Full text and
rfc822 format available.
Message #51 received at 57607 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Akib Azmain Turja <akib <at> disroot.org> writes:
> Gerd Möllmann <gerd.moellmann <at> gmail.com> writes:
>
>> Akib Azmain Turja <akib <at> disroot.org> writes:
>>
>>> Yes, I'm interested, because I think it would help me understand how
>>> Emacs renders text in terminal, which would help me to implement child
>>> frame in terminal. But I don't have the time to do it right now. I
>>> hope I can start doing this by late October.
>>
>> Great! I've re-opened this issue.
>>
>>>
>>>>
>>>> The places you mention sound right. It's probably all in term.c. But
>>>> I'd like to add, that in principle all places writing to the terminal
>>>> have to be checked at least.
>>>>
>>>> And corner cases have to be taken into consideration :-). Pulling
>>>> something out of thin air: What happens if we write RGRG to the
>>>> bottom-right corner, where R is one red char, and G is 1 green char,
>>>> say.
>>>
>>> I think you meant the following in Bash:
>>>
>>> printf "%$((COLUMNS - 4))s\e[31mr\e[32mg\e7\e[32mg\e8\e[@\e[31mr\e[m" "" ; sleep 1 ; printf '\n'
>>>
>>> And it works on St, Kitty, Coterm, Term, etc.
>>
>> What I was thinking of is the Emacs side of things, i.e. can we always
>> do our magic locally in tty_write... etc., or is it sometimes necessary
>> to reorder writes at the caller.
>
> We would need to remember the glyph in the character cell before the
> last one, because modifying the last character cell needs to rewrite to
> that cell.
Just to add, terminal is with 'smam' (enable automatic margin) and
'rmam' (disable automatic margin) can disable automatic margin, thus can
write the last character cell.
And, Emacs currently often writes to the last character possibly by
mistake. I'm not sure whether this is a bug or not. To reproduce, run
emacs -Q, hit M-: (eval-expression), write some garbage until the
minibuffer window scrolls (I used (+ (% (random) 26) ?a) to generate
the garbage), and hit C-p until you scroll down a line. You should now
see that the last character cell contains a continuation ('\') glyph. I
think this is probably due to the use of 'il' or 'il1' or 'rin'
capability. Should I report this as a bug?
--
Akib Azmain Turja
Find me on Mastodon at @akib <at> 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
[signature.asc (application/pgp-signature, inline)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Sun, 11 Sep 2022 10:09:01 GMT)
Full text and
rfc822 format available.
Message #54 received at 57607 <at> debbugs.gnu.org (full text, mbox):
On 22-09-11 11:00 , Akib Azmain Turja wrote:
> Should I report this as a bug?
Yes, please. Someone should take a look at this.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Sun, 11 Sep 2022 10:41:01 GMT)
Full text and
rfc822 format available.
Message #57 received at 57607 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Gerd Möllmann <gerd.moellmann <at> gmail.com> writes:
> On 22-09-11 11:00 , Akib Azmain Turja wrote:
>> Should I report this as a bug?
>
> Yes, please. Someone should take a look at this.
>
Done, see bug#57728.
--
Akib Azmain Turja
Find me on Mastodon at @akib <at> 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
[signature.asc (application/pgp-signature, inline)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Mon, 03 Oct 2022 09:22:01 GMT)
Full text and
rfc822 format available.
Message #60 received at submit <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Akib Azmain Turja via "Bug reports for GNU Emacs, the Swiss army knife
of text editors" <bug-gnu-emacs <at> gnu.org> writes:
> Gerd Möllmann <gerd.moellmann <at> gmail.com> writes:
>
>> Akib Azmain Turja <akib <at> disroot.org> writes:
>>
>>> Gerd Möllmann <gerd.moellmann <at> gmail.com> writes:
>>>
>>> I mean, what files to change in order to do this? I think it's
>>> tty_write_glyphs and tty_write_glyphs_with_face in term.c.
>>
>> Are you interested in implementing something? You could re-open this
>> bug then, no problem. Or are you maybe just evaluating if you'd like to
>> do it? Please give a hint.
>
> Yes, I'm interested, because I think it would help me understand how
> Emacs renders text in terminal, which would help me to implement child
> frame in terminal. But I don't have the time to do it right now. I
> hope I can start doing this by late October.
>
I have implemented it. Implementing it was easier than I thought. Here
is the patch:
[0001-Write-on-the-bottom-right-character-cell-on-terminal.patch (text/x-patch, inline)]
From 72af00d8610bdc194062b246aab0e38f22174aeb Mon Sep 17 00:00:00 2001
From: Akib Azmain Turja <akib <at> disroot.org>
Date: Mon, 3 Oct 2022 14:18:59 +0600
Subject: [PATCH] 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
[Message part 3 (text/plain, inline)]
>>
>> The places you mention sound right. It's probably all in term.c. But
>> I'd like to add, that in principle all places writing to the terminal
>> have to be checked at least.
>>
>> And corner cases have to be taken into consideration :-). Pulling
>> something out of thin air: What happens if we write RGRG to the
>> bottom-right corner, where R is one red char, and G is 1 green char,
>> say.
I tried "RGRG\", where "R" is red, "G" is green, and "\" is the (white)
continuation glyph. Looks like this patch also fixes bug#57728.
--
Akib Azmain Turja
Find me on Mastodon at @akib <at> 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
[signature.asc (application/pgp-signature, inline)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Mon, 03 Oct 2022 09:22:02 GMT)
Full text and
rfc822 format available.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Mon, 03 Oct 2022 19:42:02 GMT)
Full text and
rfc822 format available.
Message #66 received at 57607 <at> debbugs.gnu.org (full text, mbox):
> Cc: gerd.moellmann <at> gmail.com
> Date: Mon, 03 Oct 2022 14:31:53 +0600
> From: Akib Azmain Turja via "Bug reports for GNU Emacs,
> the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org>
>
> I have implemented it. Implementing it was easier than I thought. Here
> is the patch:
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.
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?
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?
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Tue, 04 Oct 2022 07:27:02 GMT)
Full text and
rfc822 format available.
Message #69 received at 57607 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Eli Zaretskii <eliz <at> gnu.org> writes:
>> Cc: gerd.moellmann <at> gmail.com
>> Date: Mon, 03 Oct 2022 14:31:53 +0600
>> From: Akib Azmain Turja via "Bug reports for GNU Emacs,
>> the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org>
>>
>> I have implemented it. Implementing it was easier than I thought. Here
>> is the patch:
>
> 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.
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").
Should I add the explanation to the function as comment?
>
> 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?
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:
--8<---------------cut here---------------start------------->8---
if (AutoWrap (tty)
&& curY (tty) + 1 == FRAME_TOTAL_LINES (f)
&& (curX (tty) + len) == FRAME_COLS (f))
len --;
--8<---------------cut here---------------end--------------->8---
Which also assumes the same.
>
> 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?
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?
--
Akib Azmain Turja
Find me on Mastodon at @akib <at> 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
[signature.asc (application/pgp-signature, inline)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Tue, 04 Oct 2022 08:08:02 GMT)
Full text and
rfc822 format available.
Message #72 received at 57607 <at> debbugs.gnu.org (full text, mbox):
> From: Akib Azmain Turja <akib <at> disroot.org>
> Cc: 57607 <at> debbugs.gnu.org, gerd.moellmann <at> gmail.com
> Date: Tue, 04 Oct 2022 13:22:51 +0600
>
> > 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.
>
> 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").
>
> 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.
> > 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?
>
> 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:
>
> --8<---------------cut here---------------start------------->8---
> if (AutoWrap (tty)
> && curY (tty) + 1 == FRAME_TOTAL_LINES (f)
> && (curX (tty) + len) == FRAME_COLS (f))
> len --;
> --8<---------------cut here---------------end--------------->8---
>
> 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. (And the existing code could have bugs,
no need to assume it is always correct.)
> > 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?
>
> 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.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Tue, 04 Oct 2022 12:05:02 GMT)
Full text and
rfc822 format available.
Message #75 received at 57607 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Eli Zaretskii <eliz <at> gnu.org> writes:
>> From: Akib Azmain Turja <akib <at> disroot.org>
>> Cc: 57607 <at> debbugs.gnu.org, gerd.moellmann <at> gmail.com
>> Date: Tue, 04 Oct 2022 13:22:51 +0600
>>
>> > 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.
>>
>> 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").
>>
>> 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.
>
>> > 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?
>>
>> 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:
>>
>> --8<---------------cut here---------------start------------->8---
>> if (AutoWrap (tty)
>> && curY (tty) + 1 == FRAME_TOTAL_LINES (f)
>> && (curX (tty) + len) == FRAME_COLS (f))
>> len --;
>> --8<---------------cut here---------------end--------------->8---
>>
>> 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?
>>
>> 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.
--
Akib Azmain Turja
Find me on Mastodon at @akib <at> 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
[signature.asc (application/pgp-signature, inline)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Tue, 04 Oct 2022 12:56:01 GMT)
Full text and
rfc822 format available.
Message #78 received at 57607 <at> debbugs.gnu.org (full text, mbox):
> From: Akib Azmain Turja <akib <at> disroot.org>
> Cc: 57607 <at> debbugs.gnu.org, gerd.moellmann <at> gmail.com
> Date: Tue, 04 Oct 2022 18:00:57 +0600
>
> > 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?
Like this:
(char-width CHAR)
where CHAR is the character you are interested in. For example:
(char-width #x31D4)
=> 2
From C, you can call char_width, like Fchar_width (which see) does.
One other subtle point: the argument STRING to tty_write_glyphs is a
string of 'struct glyph' objects, not a string of characters. Each
struct glyph has the code of the character to display in its u.ch
member, if the glyph is a simple character glyph; for the full story
see encode_terminal_code.
> > (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.
Indeed, that the existing code has bugs should not be our first
hypothesis. But it shouldn't be axiomatic that there are no bugs
there ;-)
> > 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.
TIA
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Tue, 04 Oct 2022 13:08:02 GMT)
Full text and
rfc822 format available.
Message #81 received at 57607 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Akib Azmain Turja <akib <at> disroot.org> writes:
> Eli Zaretskii <eliz <at> gnu.org> writes:
>
>>> From: Akib Azmain Turja <akib <at> disroot.org>
>>> Cc: 57607 <at> debbugs.gnu.org, gerd.moellmann <at> gmail.com
>>> Date: Tue, 04 Oct 2022 13:22:51 +0600
>>>
>>> > 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.
>>>
>>> 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").
>>>
>>> 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?
>>>
>>> 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:
>>>
>>> --8<---------------cut here---------------start------------->8---
>>> if (AutoWrap (tty)
>>> && curY (tty) + 1 == FRAME_TOTAL_LINES (f)
>>> && (curX (tty) + len) == FRAME_COLS (f))
>>> len --;
>>> --8<---------------cut here---------------end--------------->8---
>>>
>>> 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?
>>>
>>> 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:
[0001-Write-on-the-bottom-right-character-cell-on-terminal.patch (text/x-patch, inline)]
From 72af00d8610bdc194062b246aab0e38f22174aeb Mon Sep 17 00:00:00 2001
From: Akib Azmain Turja <akib <at> disroot.org>
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
[0002-Merge-tty_write_glyphs-and-tty_write_glyphs_with_fac.patch (text/x-patch, inline)]
From b090cba28981d7a0e40f87211e9b8b065bfdf3e3 Mon Sep 17 00:00:00 2001
From: Akib Azmain Turja <akib <at> disroot.org>
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.
---
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
--- 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. */
static void
-tty_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 *string, int len)
the tail. */
coding->mode &= ~CODING_MODE_LAST_BLOCK;
+ if (face_id >= 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 *string, int len)
for (stringlen = len; stringlen != 0; stringlen -= n)
{
- /* Identify a run of glyphs with the same face. */
- int face_id = string->face_id;
+ int local_face_id;
- for (n = 1; n < stringlen; ++n)
- if (string[n].face_id != face_id)
- break;
+ if (face_id >= 0)
+ {
+ /* This will be a problem when we run the loop another
+ time, but this is the only iteration. */
+ n = stringlen;
+ }
+ else
+ {
+ /* Identify a run of glyphs with the same face. */
+ local_face_id = string->face_id;
- /* 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 != 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);
+ }
if (n == stringlen && !write_on_last_cell)
/* This is the last run. */
@@ -799,24 +818,41 @@ tty_write_glyphs (struct frame *f, struct glyph *string, int len)
}
string += n;
- /* Turn appearance modes off. */
- turn_off_face (f, face_id);
- 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);
+ }
}
}
/* Write on the bottom-right corner. */
if (write_on_last_cell)
{
- /* 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);
- int face_id = string->face_id;
+ int local_face_id;
- /* Turn appearance modes of the face. */
- tty_highlight_if_desired (tty);
- turn_on_face (f, face_id);
+ if (face_id < 0)
+ {
+ local_face_id = string->face_id;
+
+ /* Turn appearance modes of the face. */
+ tty_highlight_if_desired (tty);
+ turn_on_face (f, local_face_id);
+ }
conversion_buffer = encode_terminal_code (string, 1, coding);
if (coding->produced > 0)
@@ -831,12 +867,15 @@ tty_write_glyphs (struct frame *f, struct glyph *string, int len)
unblock_input ();
}
- /* 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);
/* Arrange that after writing the next glyph, the glyph on the
- 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 *string, int len)
tty_turn_on_insert (tty);
}
- if (face_id != glyph_on_char_cell_before_last.face_id)
+ if (face_id < 0
+ && local_face_id != glyph_on_char_cell_before_last.face_id)
{
/* Turn appearance modes of the face. */
- turn_off_face (f, face_id);
+ turn_off_face (f, local_face_id);
tty_turn_off_highlight (tty);
- face_id = glyph_on_char_cell_before_last.face_id;
+ local_face_id = glyph_on_char_cell_before_last.face_id;
tty_highlight_if_desired (tty);
- turn_on_face (f, face_id);
+ turn_on_face (f, local_face_id);
}
/* This is the last run. */
@@ -884,157 +924,32 @@ tty_write_glyphs (struct frame *f, struct glyph *string, int len)
unblock_input ();
}
+ 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 >= 0)
+ {
/* Turn appearance modes off. */
turn_off_face (f, face_id);
tty_turn_off_highlight (tty);
-
- tty_turn_off_insert (tty);
}
cmcheckmagic (tty);
}
-#ifndef DOS_NT
-
static void
-tty_write_glyphs_with_face (register struct frame *f, register struct glyph *string,
- register int len, register int face_id)
+tty_write_glyphs (struct frame *f, struct glyph *string, int len)
{
- unsigned char *conversion_buffer;
- struct coding_system *coding;
- int write_on_last_cell;
-
- struct tty_display_info *tty = FRAME_TTY (f);
-
- tty_turn_off_insert (tty);
- tty_hide_cursor (tty);
-
- /* Don't dare write in last column of bottom line, if Auto-Wrap,
- since that would scroll the whole frame on some terminals. */
-
- 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 (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)
- ? 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;
-
- /* Turn appearance modes of the face. */
- tty_highlight_if_desired (tty);
- turn_on_face (f, face_id);
-
- 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)
- {
- /* 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. */
- turn_off_face (f, face_id);
- tty_turn_off_highlight (tty);
-
- cmcheckmagic (tty);
+ tty_write_glyphs_1 (f, string, len, -1);
}
-#endif
-
/* An implementation of insert_glyphs for termcap frames. */
static void
@@ -2615,8 +2530,8 @@ tty_draw_row_with_mouse_face (struct window *w, struct glyph_row *row,
cursor_to (f, pos_y, pos_x);
if (draw == DRAW_MOUSE_FACE)
- tty_write_glyphs_with_face (f, row->glyphs[TEXT_AREA] + start_hpos,
- nglyphs, face_id);
+ tty_write_glyphs_1 (f, row->glyphs[TEXT_AREA] + start_hpos,
+ nglyphs, face_id);
else if (draw == DRAW_NORMAL_TEXT)
write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
--
2.37.1
[Message part 4 (text/plain, inline)]
--
Akib Azmain Turja
Find me on Mastodon at @akib <at> 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
[signature.asc (application/pgp-signature, inline)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Fri, 07 Oct 2022 13:20:01 GMT)
Full text and
rfc822 format available.
Message #84 received at 57607 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Eli Zaretskii <eliz <at> gnu.org> writes:
>> From: Akib Azmain Turja <akib <at> disroot.org>
>> Cc: 57607 <at> debbugs.gnu.org, gerd.moellmann <at> gmail.com
>> Date: Tue, 04 Oct 2022 18:00:57 +0600
>>
>> > 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?
>
> Like this:
>
> (char-width CHAR)
>
> where CHAR is the character you are interested in. For example:
>
> (char-width #x31D4)
> => 2
>
> From C, you can call char_width, like Fchar_width (which see) does.
>
> One other subtle point: the argument STRING to tty_write_glyphs is a
> string of 'struct glyph' objects, not a string of characters. Each
> struct glyph has the code of the character to display in its u.ch
> member, if the glyph is a simple character glyph; for the full story
> see encode_terminal_code.
Thanks.
I just discovered new type of glyph: padding glyph. What's this? Is
this a nop glyph? I guess it's used to make string of width N use N
numbers of glyph. But how? Is this like [CJK PAD] or [PAD CJK]?
>
>> > (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.
>
> Indeed, that the existing code has bugs should not be our first
> hypothesis. But it shouldn't be axiomatic that there are no bugs
> there ;-)
>
>> > 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.
>
> TIA
--
Akib Azmain Turja
Find me on Mastodon at @akib <at> 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
[signature.asc (application/pgp-signature, inline)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Fri, 07 Oct 2022 19:31:02 GMT)
Full text and
rfc822 format available.
Message #87 received at 57607 <at> debbugs.gnu.org (full text, mbox):
> From: Akib Azmain Turja <akib <at> disroot.org>
> Cc: 57607 <at> debbugs.gnu.org, gerd.moellmann <at> gmail.com
> Date: Fri, 07 Oct 2022 19:10:08 +0600
>
> I just discovered new type of glyph: padding glyph. What's this?
See the commentary in dispextern.h for the padding_p flag of 'struct
glyph'.
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#57607
; Package
emacs
.
(Sun, 09 Mar 2025 11:34:02 GMT)
Full text and
rfc822 format available.
Message #90 received at 57607 <at> debbugs.gnu.org (full text, mbox):
Akib, sorry for effectively loosing this in time. I guess I thought
others would take this up.
I fixed this now in master, in a different form because your patches did
no longer apply due to the new tty child frame stuff. It was easier that
way for me.
And closing.
bug marked as fixed in version 31.1, send any further explanations to
57607 <at> debbugs.gnu.org and Akib Azmain Turja <akib <at> disroot.org>
Request was from
Gerd Möllmann <gerd.moellmann <at> gmail.com>
to
control <at> debbugs.gnu.org
.
(Sun, 09 Mar 2025 11:34:03 GMT)
Full text and
rfc822 format available.
bug archived.
Request was from
Debbugs Internal Request <help-debbugs <at> gnu.org>
to
internal_control <at> debbugs.gnu.org
.
(Mon, 07 Apr 2025 11:24:05 GMT)
Full text and
rfc822 format available.
This bug report was last modified 34 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.