Re: [PATCH] emoji on TUI emacs
Kai Ma <[email protected]> Thu, 30 Jul 2026 18:52:18 +0200
| Newsgroups | gmane.emacs.devel |
|---|---|
| Message-ID | <[email protected]> |
On 7/30/2026 6:13 PM, Eli Zaretskii wrote: >> Date: Thu, 30 Jul 2026 17:03:58 +0200 >> From: Kai Ma <[email protected]> >> >> Today I took some time to look into the emoji problem on TUI emacs. >> There were some previous bug reports, for example, 79517, 81052. This >> is a super annoying problem which makes it almost unusable to edit >> files containing emojis. (Brief description: pressing C-n/C-p can >> cause duplicate rendered lines or empty lines, and it's not possible >> to clear it easily with C-l or redisplay.) > The way to make it possible to edit text with Emoji on text-only > frames is by disabling auto-composition-mode. Did you try that? If > you tried that, and you still find that "almost unusable", please tell > the details of what you see and preferably also show a simple recipe > to reproduce the problems you see. Yes. I'm aware of this workaround. Sorry for not mentioning it in the original mail. There are two drawbacks for this workaround: 1. This breaks textual layout. 2. This makes it other composition no longer work. >> Previous discussions are usually about the width of a grapheme >> cluster. But to my surprise, I found that the problem occurs even if >> the width is correct. For example, ⚡ (#x26a1) composed with #fe0f >> has width 2, >> >> (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. >> and it still causes garbled lines. Therefore, the incorrect width of >> an emoji is not the _only_ problem. > It isn't the width of the Emoji, it's the fact that > > (string-width "\x26a1") ;; ==> 2 > > IOW, adding the VS-15 control leaves the width unaltered. I'm talking about the composition. The impression I got from previous discussions and etc/PROBLEMS are that the problem is *solely* about width calculation. That is not true! The example in my original mail shows that even if the width is correct, the rendering issue still happens. >> Upon further inspection, I'm >> pretty sure it's related to composition strings, and it's due to the >> wrong x index of the next glyph: even if the composition itself has >> pixel_width=2, the next glyph's index just increases by 1. So this >> looks like a genuine problem. > Sorry, you lost me here: which code and in what function do you allude > here? See below. But please correct my misunderstandings. >> Looking into the source code, in term.c, append_composite_glyph only >> appends one glyph, but in append_glyph, it appends pixel_width glyphs. >> Therefore, the attached patch simply copies the existing approach. I >> have tested it on files containing many emojis, margins, and bidi >> texts, and observed no problems so far, but I might miss something so >> review is appreciated. > I don't understand why these changes are needed, or what is wrong with > the original code. There are clearly two coordinate systems, the terminal one for cells (denoted T) and the emacs internal matrix one (denoted E). E is generated by append_composite_glyph filling in the glyph row, and T is generated by the tty_* functions. Let's say the buffer contains an emoji ⚡ and there's a character 'a' follows it. The current append_composite_glyph assigns coordinates: '⚡' E(line,col) and 'a' E(line,col+1). When it's being output to the terminal, cmplus is used to maintain the T coordinates. cmplus is used (in term.c) to advance the tty cursor, but 'len' argument of 'tty_write_glyphs' etc is determined from the glyph matrix. See, for example, in update_text_area in dispnew.c: if (desired_row->used[TEXT_AREA]) rif->write_glyphs (w, updated_row, desired_row->glyphs[TEXT_AREA], TEXT_AREA, desired_row->used[TEXT_AREA]); The last argument is the number of cells of this write. In the current implementation, '⚡' at E(line,col) is emitted at T(line,col) (assuming nothing precedes it), but 'a' at T(line,col+1), despite the fact that _Emacs itself_ thinks ⚡ has width 2. So IMO this is an internal invariant violation. > In general, it is wrong to produce as many glyphs as pixel_width for a > composite glyph, because Emacs cannot know the actual width of the > composed glyph on display, as shown on text-only frames. The value of > pixel_width in this case is a guess based on what characters were > composed. So your changes might work for some codepoints and on some > specific terminal emulators, but they will not work correctly in > general. Pardon my ignorance. I don't follow you here. Let's say the composition has Emacs width N, printed at T(0,0), where should the next glyph be? I think it's fair to assume T(0,N). >> Also, if it's considered a safe fix, is it possible to install this >> patch on emacs-31, considering how annoying the problem is? > Sorry, I don't think the changes are correct, let alone safe. Please > try disabling auto-composition-mode instead. Do you have other acceptable alternative solutions in mind?