Re: [PATCH] emoji on TUI emacs
Eli Zaretskii <[email protected]> Fri, 31 Jul 2026 14:34:05 +0300
| Newsgroups | gmane.emacs.devel |
|---|---|
| Message-ID | <[email protected]> |
> Date: Fri, 31 Jul 2026 11:23:37 +0200 > Cc: [email protected] > From: Kai Ma <[email protected]> > > >>>> (string-width "\x26a1\xfe0f") ;; ==> 2 > >>> Yes, Emoji sequences which end in Variation Selector controls are one > >>> of a couple of cases which currently cannot be correctly displayed on > >>> text-only frames when auto-composition-mode is enabled. Please try > >>> disabling auto-composition-mode. > >> That's why I think there's something wrong with the current handling of > >> the composition. > > Not generally with compositions, but specifically with Emoji sequences > > that have VS controls or several Emoji codepoints that the terminal > > shows as a single glyph. > > The composite glyph is not only about emoji, (though personally my only > use is emoji). E.g. CJK characters can be composed as well: > > CJK Ideographic Variation Selector: "龜\xE0100" "龜\xE0103" (auto > composed, width = 2, which is correct) > > Korean Jamo: "\x1100\x1161\x11A8" (auto composed, width = 2, which > is correct) > > There are some cases that are not auto composed by emacs as well, > (though I think they should): > > CJK tone modifier: "一\x302A" (width = 4, should be 2) > > Ainu katakana: "\x31F7\x309A" (width = 4, should be 2) This is a separate issue. And some of your conclusions are wrong: . "一\x302A" does compose, if your fontset defines a font for han characters which supports both of these codepoints, because Emacs cannot compose characters unless they have glyphs in the font used for them. And when the composition does work, the width is 3, not 2, at least with the fonts I have on my system. And all that is on GUI frames; on TTY frames, Emacs cannot know whether these characters will be combined by the terminal, so if the terminal does combine them, cursor movement will be problematic. . same for "\x31F7\x309A": on GUI frames they are composed and displayed as single glyph whose width is close to 2, but on TTY frames Emacs cannot know they will be composed by the terminal, and thus string-width returns 4, which is a sum of widths of the two codepoints. I hope you agree that blindly adding 3 padding glyphs in these two cases for displaying them on TTY frames is not the right solution. > My understanding of the implementation is that, if a CHAR_GLYPH has > pixel_width > 1, append_glyph in term.c will add padding glyphs to make > room in the glyph matrix. So the proposed patch makes > append_composite_glyph do the same thing as append_glyph. Yes, but to do this correctly we need to know the actual width of the composed glyphs on display. And we cannot know that reliably on TTY frames, because we don't have any access to the fonts used by the terminal and their composition capabilities. That's why using auto-composition-mode on TTY frames will always have problems in some cases. > > The problem is with the value of N. How can Emacs know what is the > > width N of a composed sequence of codepoints? It's the terminal > > emulator that decides how to display them and with what font glyphs, > > and Emacs has no access to that information when it displays on a > > text-only terminal. On GUI frames, we access the font information and > > determine the metrics of the glyphs that are displayed as result of > > the composition, but on text-only frames we cannot do that. > > > > Try the Emoji sequence "\x1faf6\x1f3fc", for example. On terminals > > that support Emoji, it displays as a single glyph whose width is 2, > > but Emacs thinks there are 2 separate glyphs there whose combined > > pixel_width is 2 + 2 = 4. And sure enough, (string-width "\x1faf6\x1f3fc") > > returns 4 on a text-only frame, because Emacs doesn't think these two > > codepoints will be combined into one on display. How do you suggest > > to resolve these problems? > > The proposed patch does not fix this problem, and I think this is > orthogonal to the width calculation. That's why I mentioned the case of > correct widths. The "correct widths" case is a small minority. Moreover, we don't have any way of knowing when the width is correct and when it isn't, not on TTY frames. So using the proposed patch might solve a small number of lucky cases, but it will leave a large number unsolved, and in many cases will make the situation worse by adding too many padding glyphs! > My analysis of the situation is that there are two problems. One is the > width calculation, and another is the rendering of composite glyphs. > Both problems are not emoji-specific. See above: to make some progress, we must add padding glyphs only where we know that the result is wider than 1 column. In addition, I think we should never add more than 1 padding glyph for composed characters, because that is almost never correct. > >> Do you have other acceptable alternative solutions in mind? > > Not at the moment, no. But I'm open to ideas. For example, we could > > perhaps do better for Emoji sequences whose first codepoint has a > > width of 2, by adding a padding glyphs. But that's a partial solution > > in any case. And adding padding glyphs according to pixel_width of a > > composite glyph is incorrect in general, because on text-mode frames > > that value is in many cases incorrect. > > I'm following the case of append_glyph. Does it mean CHAR_GLYPHs always > have pixel_width no more than 2? Yes. You can see it yourself in char-width-table: no value is greater than 2. > If so, do you think it's acceptable to add only one padding glyph? That > could bring it closer to append_glyph. We should only add one padding glyph if we are sure the combined glyph is wider than 1. > add_one_composite_glyph(); > > if (pixel_width >= 2) add_one_padding_glyph(); That's the wrong condition. pixel_width gives the best guess about the width of the combined glyph, and it is wrong in many cases. We should instead do something like if (pixel_width >= 2 && char_width (first_character) >= 2) add_one_padding_glyph(); where first_character is the first character of the composed sequence, which you can get by LGLYPH_CHAR (LGSTRING_GLYPH (gstring, 0)) and where GSTRING is the glyph string obtained from composition's ID. Or just get the first character of the composed sequence and call CHAR_WIDTH on it. > I tested this approach just now and it does feel like an improvement. There are many cases where a sequence of characters whose pixel_width on TTY frames is 2 or more will be eventually displayed as a single-column glyph, and in those cases the first character of the composed sequence will generally have char-width of 1. In those cases we should NOT add padding glyphs. I guess you haven't tried such cases.