aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/tui
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2024-08-08 10:42:08 +0200
committerbfredl <bjorn.linse@gmail.com>2024-08-30 11:49:09 +0200
commitcfdf68a7acde16597fbd896674af68c42361102c (patch)
tree6113193fda7a7c0f94577a464e39964e74311583 /src/nvim/tui
parent4353996d0fa8e5872a334d68196d8088391960cf (diff)
downloadrneovim-cfdf68a7acde16597fbd896674af68c42361102c.tar.gz
rneovim-cfdf68a7acde16597fbd896674af68c42361102c.tar.bz2
rneovim-cfdf68a7acde16597fbd896674af68c42361102c.zip
feat(mbyte): support extended grapheme clusters including more emoji
Use the grapheme break algorithm from utf8proc to support grapheme clusters from recent unicode versions. Handle variant selector VS16 turning some codepoints into double-width emoji. This means we need to use ptr2cells rather than char2cells when possible.
Diffstat (limited to 'src/nvim/tui')
-rw-r--r--src/nvim/tui/tui.c17
-rw-r--r--src/nvim/tui/tui_defs.h1
2 files changed, 16 insertions, 2 deletions
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 1866a4a592..7e1068ed56 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -109,6 +109,7 @@ struct TUIData {
bool set_cursor_color_as_str;
bool cursor_color_changed;
bool is_starting;
+ bool did_set_grapheme_cluster_mode;
FILE *screenshot;
cursorentry_T cursor_shapes[SHAPE_IDX_COUNT];
HlAttrs clear_attrs;
@@ -220,6 +221,7 @@ static void tui_set_term_mode(TUIData *tui, TermMode mode, bool set)
void tui_handle_term_mode(TUIData *tui, TermMode mode, TermModeState state)
FUNC_ATTR_NONNULL_ALL
{
+ bool is_set = false;
switch (state) {
case kTermModeNotRecognized:
case kTermModePermanentlySet:
@@ -228,6 +230,8 @@ void tui_handle_term_mode(TUIData *tui, TermMode mode, TermModeState state)
// then there is nothing to do
break;
case kTermModeSet:
+ is_set = true;
+ FALLTHROUGH;
case kTermModeReset:
// The terminal supports changing the given mode
switch (mode) {
@@ -240,6 +244,12 @@ void tui_handle_term_mode(TUIData *tui, TermMode mode, TermModeState state)
signal_watcher_stop(&tui->winch_handle);
tui_set_term_mode(tui, mode, true);
break;
+ case kTermModeGraphemeClusters:
+ if (!is_set) {
+ tui_set_term_mode(tui, mode, true);
+ tui->did_set_grapheme_cluster_mode = true;
+ }
+ break;
}
}
}
@@ -434,6 +444,7 @@ static void terminfo_start(TUIData *tui)
if (!nsterm) {
tui_request_term_mode(tui, kTermModeSynchronizedOutput);
tui_request_term_mode(tui, kTermModeResizeEvents);
+ tui_request_term_mode(tui, kTermModeGraphemeClusters);
}
// Don't use DECRQSS in screen or tmux, as they behave strangely when receiving it.
@@ -494,7 +505,9 @@ static void terminfo_stop(TUIData *tui)
// Disable resize events
tui_set_term_mode(tui, kTermModeResizeEvents, false);
-
+ if (tui->did_set_grapheme_cluster_mode) {
+ tui_set_term_mode(tui, kTermModeGraphemeClusters, false);
+ }
// May restore old title before exiting alternate screen.
tui_set_title(tui, NULL_STRING);
if (ui_client_exit_status == 0) {
@@ -1010,7 +1023,7 @@ static void print_cell_at_pos(TUIData *tui, int row, int col, UCell *cell, bool
char buf[MAX_SCHAR_SIZE];
schar_get(buf, cell->data);
int c = utf_ptr2char(buf);
- bool is_ambiwidth = utf_ambiguous_width(c);
+ bool is_ambiwidth = utf_ambiguous_width(buf);
if (is_doublewidth && (is_ambiwidth || utf_char2cells(c) == 1)) {
// If the server used setcellwidths() to treat a single-width char as double-width,
// it needs to be treated like an ambiguous-width char.
diff --git a/src/nvim/tui/tui_defs.h b/src/nvim/tui/tui_defs.h
index 46913e07a2..bd99d6b0ad 100644
--- a/src/nvim/tui/tui_defs.h
+++ b/src/nvim/tui/tui_defs.h
@@ -4,6 +4,7 @@ typedef struct TUIData TUIData;
typedef enum {
kTermModeSynchronizedOutput = 2026,
+ kTermModeGraphemeClusters = 2027,
kTermModeResizeEvents = 2048,
} TermMode;