term: do not allow codepoint merging into grapheme clusters directly after a cursor move

That is, only do grapheme clustering when printing codepoints in
sequence, without any cursor movements in between.

Closes #2383
This commit is contained in:
Daniel Eklöf 2026-06-12 15:34:12 +02:00
parent f66a020bba
commit d7742d0312
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
3 changed files with 21 additions and 1 deletions

View file

@ -73,6 +73,13 @@
## Unreleased
### Added
### Changed
* Do not allow codepoints to be merged into grapheme clusters directly
after a cursor move ([#2383][2383]).
[2383]: https://codeberg.org/dnkl/foot/issues/2383
### Deprecated
### Removed
### Fixed

View file

@ -4086,6 +4086,10 @@ term_print(struct terminal *term, char32_t wc, int width, bool insert_mode_disab
xassert(!grid->cursor.lcf);
grid->cursor.point.col = col;
#if defined(FOOT_GRAPHEME_CLUSTERING)
term->vt.codepoint_merging_ok = true;
#endif
}
static void
@ -4126,6 +4130,9 @@ ascii_printer_fast(struct terminal *term, char32_t wc)
xassert(!grid->cursor.lcf);
grid->cursor.point.col = col;
#if defined(FOOT_GRAPHEME_CLUSTERING)
term->vt.codepoint_merging_ok = true;
#endif
if (unlikely(row->extra != NULL)) {
grid_row_uri_range_erase(row, uri_start, uri_start);
@ -4210,7 +4217,11 @@ term_process_and_print_non_ascii(struct terminal *term, char32_t wc)
{
int width = c32width(wc);
bool insert_mode_disable = false;
const bool grapheme_clustering = term->grapheme_shaping;
const bool grapheme_clustering = term->grapheme_shaping
#if defined(FOOT_GRAPHEME_CLUSTERING)
&& term->vt.codepoint_merging_ok
#endif
;
#if !defined(FOOT_GRAPHEME_CLUSTERING)
xassert(!grapheme_clustering);

View file

@ -264,6 +264,7 @@ struct vt {
char32_t last_printed;
#if defined(FOOT_GRAPHEME_CLUSTERING)
utf8proc_int32_t grapheme_state;
bool codepoint_merging_ok;
#endif
char32_t utf8;
struct {
@ -994,5 +995,6 @@ static inline void term_reset_grapheme_state(struct terminal *term)
{
#if defined(FOOT_GRAPHEME_CLUSTERING)
term->vt.grapheme_state = 0;
term->vt.codepoint_merging_ok = false;
#endif
}