From 031e8f59877f4ad25a5a4116342d66f9aac56c20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 29 Jun 2021 18:45:27 +0200 Subject: [PATCH 1/3] vt: limit grapheme width to 2 cells MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All emoji graphemes are double-width. Foot doesn’t support non-latin scripts. Ergo, this should result in the Right Thing, even though we’re not doing it the Right Way. Note that we’re now breaking cursor synchronization with nearly all applications. But the way I see it, the applications need to be updated. --- vt.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/vt.c b/vt.c index 900ffd9d..5f2b3c0d 100644 --- a/vt.c +++ b/vt.c @@ -766,11 +766,9 @@ action_utf8_print(struct terminal *term, wchar_t wc) int grapheme_width = composed != NULL ? composed->width : base_width; - if (wc == 0xfe0f && grapheme_width < 2) - grapheme_width = 2; - else - grapheme_width += width; - new_cc->width = grapheme_width; + if (wc == 0xfe0f) + width = 2; + new_cc->width = min(max(grapheme_width, width), 2); term->composed_count++; composed_insert(&term->composed, new_cc); From 9817e44c325f5d44f64bfa768107998134ea7f59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 30 Jun 2021 18:00:33 +0200 Subject: [PATCH 2/3] config: add tweak.grapheme-width-method=wcswidth|at-most-2 --- CHANGELOG.md | 3 +++ config.c | 10 ++++++++++ config.h | 1 + doc/foot.ini.5.scd | 18 ++++++++++++++++++ vt.c | 19 ++++++++++++++----- 5 files changed, 46 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78016bae..9337652b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,9 @@ terminfo entries. This should make 24-bit RGB colors work in tmux and neovim, without the need for config hacks or detection heuristics (https://codeberg.org/dnkl/foot/issues/615). +* `[tweak].grapheme-width-method=wcswidth|at-most-2` option to + `foot.ini`. + ### Changed ### Deprecated diff --git a/config.c b/config.c index 372e9f9c..cb407c24 100644 --- a/config.c +++ b/config.c @@ -2255,6 +2255,15 @@ parse_section_tweak( LOG_WARN("tweak: grapheme shaping"); } + else if (strcmp(key, "grapheme-width-method") == 0) { + if (strcmp(value, "at-most-2") == 0) + conf->tweak.grapheme_width_method = GRAPHEME_WIDTH_MAX_2; + else if (strcmp(value, "wcswidth") == 0) + conf->tweak.grapheme_width_method = GRAPHEME_WIDTH_WCSWIDTH; + + LOG_WARN("%s:%d [tweak]: grapheme-width-method=%s", path, lineno, value); + } + else if (strcmp(key, "render-timer") == 0) { if (strcmp(value, "none") == 0) { conf->tweak.render_timer_osd = false; @@ -2823,6 +2832,7 @@ config_load(struct config *conf, const char *conf_path, .fcft_filter = FCFT_SCALING_FILTER_LANCZOS3, .allow_overflowing_double_width_glyphs = true, .grapheme_shaping = false, + .grapheme_width_method = GRAPHEME_WIDTH_MAX_2, .delayed_render_lower_ns = 500000, /* 0.5ms */ .delayed_render_upper_ns = 16666666 / 2, /* half a frame period (60Hz) */ .max_shm_pool_size = 512 * 1024 * 1024, diff --git a/config.h b/config.h index ee427267..57305b22 100644 --- a/config.h +++ b/config.h @@ -246,6 +246,7 @@ struct config { enum fcft_scaling_filter fcft_filter; bool allow_overflowing_double_width_glyphs; bool grapheme_shaping; + enum {GRAPHEME_WIDTH_WCSWIDTH, GRAPHEME_WIDTH_MAX_2} grapheme_width_method; bool render_timer_osd; bool render_timer_log; bool damage_whole_window; diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index 2e408b3a..a0829ad7 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -997,8 +997,26 @@ any of these options. but is necessary to not break cursor synchronization with the application running in foot. + See also: *grapheme-width-method*. + Default: _no_ +*grapheme-width-method* + Selects which method to use when calculating the width + (i.e. number of columns) of a grapheme cluster. One of *at-most-2* + and *wcswidth*. + + *wcswidth* simply adds together the individual width of all + codepoints making up the cluster. + + *at-most-2* does the same, but limits the maximum number of + columns to 2. This is more correct, but is likely to break + applications since applications typically use *wcswidth*(3) + internally to calculate the width. This results in cursor + de-synchronization issues. + + Default: _at-most-2_ + *max-shm-pool-size-mb* This option controls the amount of virtual address space used by the pixmap memory to which the terminal screen content is diff --git a/vt.c b/vt.c index 5f2b3c0d..6ef2b782 100644 --- a/vt.c +++ b/vt.c @@ -764,17 +764,26 @@ action_utf8_print(struct terminal *term, wchar_t wc) (wanted_count - 2) * sizeof(new_cc->chars[0])); } - int grapheme_width = composed != NULL ? composed->width : base_width; + const int grapheme_width = + composed != NULL ? composed->width : base_width; - if (wc == 0xfe0f) - width = 2; - new_cc->width = min(max(grapheme_width, width), 2); + switch (term->conf->tweak.grapheme_width_method) { + case GRAPHEME_WIDTH_MAX_2: + if (unlikely(wc == 0xfe0f)) + width = 2; + new_cc->width = min(grapheme_width + width, 2); + break; + + case GRAPHEME_WIDTH_WCSWIDTH: + new_cc->width = grapheme_width + width; + break; + } term->composed_count++; composed_insert(&term->composed, new_cc); wc = CELL_COMB_CHARS_LO + key; - width = grapheme_width; + width = new_cc->width; xassert(wc >= CELL_COMB_CHARS_LO); xassert(wc <= CELL_COMB_CHARS_HI); From 5138f022146e447d8bb0be56a06e9065b35b6489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 1 Jul 2021 08:00:23 +0200 Subject: [PATCH 3/3] config: rename at-most-2 (value for grapheme-width-method) to double-width --- CHANGELOG.md | 2 +- config.c | 6 +++--- config.h | 2 +- doc/foot.ini.5.scd | 8 ++++---- vt.c | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9337652b..0b79b0ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,7 @@ terminfo entries. This should make 24-bit RGB colors work in tmux and neovim, without the need for config hacks or detection heuristics (https://codeberg.org/dnkl/foot/issues/615). -* `[tweak].grapheme-width-method=wcswidth|at-most-2` option to +* `[tweak].grapheme-width-method=wcswidth|double-width` option to `foot.ini`. diff --git a/config.c b/config.c index cb407c24..e02ca3de 100644 --- a/config.c +++ b/config.c @@ -2256,8 +2256,8 @@ parse_section_tweak( } else if (strcmp(key, "grapheme-width-method") == 0) { - if (strcmp(value, "at-most-2") == 0) - conf->tweak.grapheme_width_method = GRAPHEME_WIDTH_MAX_2; + if (strcmp(value, "double-width") == 0) + conf->tweak.grapheme_width_method = GRAPHEME_WIDTH_DOUBLE; else if (strcmp(value, "wcswidth") == 0) conf->tweak.grapheme_width_method = GRAPHEME_WIDTH_WCSWIDTH; @@ -2832,7 +2832,7 @@ config_load(struct config *conf, const char *conf_path, .fcft_filter = FCFT_SCALING_FILTER_LANCZOS3, .allow_overflowing_double_width_glyphs = true, .grapheme_shaping = false, - .grapheme_width_method = GRAPHEME_WIDTH_MAX_2, + .grapheme_width_method = GRAPHEME_WIDTH_DOUBLE, .delayed_render_lower_ns = 500000, /* 0.5ms */ .delayed_render_upper_ns = 16666666 / 2, /* half a frame period (60Hz) */ .max_shm_pool_size = 512 * 1024 * 1024, diff --git a/config.h b/config.h index 57305b22..2300a0ad 100644 --- a/config.h +++ b/config.h @@ -246,7 +246,7 @@ struct config { enum fcft_scaling_filter fcft_filter; bool allow_overflowing_double_width_glyphs; bool grapheme_shaping; - enum {GRAPHEME_WIDTH_WCSWIDTH, GRAPHEME_WIDTH_MAX_2} grapheme_width_method; + enum {GRAPHEME_WIDTH_WCSWIDTH, GRAPHEME_WIDTH_DOUBLE} grapheme_width_method; bool render_timer_osd; bool render_timer_log; bool damage_whole_window; diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index a0829ad7..684497ca 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -1003,19 +1003,19 @@ any of these options. *grapheme-width-method* Selects which method to use when calculating the width - (i.e. number of columns) of a grapheme cluster. One of *at-most-2* - and *wcswidth*. + (i.e. number of columns) of a grapheme cluster. One of + *double-width* and *wcswidth*. *wcswidth* simply adds together the individual width of all codepoints making up the cluster. - *at-most-2* does the same, but limits the maximum number of + *double-width* does the same, but limits the maximum number of columns to 2. This is more correct, but is likely to break applications since applications typically use *wcswidth*(3) internally to calculate the width. This results in cursor de-synchronization issues. - Default: _at-most-2_ + Default: _double-width_ *max-shm-pool-size-mb* This option controls the amount of virtual address space used by diff --git a/vt.c b/vt.c index 6ef2b782..b9a4f4b0 100644 --- a/vt.c +++ b/vt.c @@ -768,7 +768,7 @@ action_utf8_print(struct terminal *term, wchar_t wc) composed != NULL ? composed->width : base_width; switch (term->conf->tweak.grapheme_width_method) { - case GRAPHEME_WIDTH_MAX_2: + case GRAPHEME_WIDTH_DOUBLE: if (unlikely(wc == 0xfe0f)) width = 2; new_cc->width = min(grapheme_width + width, 2);