Guess emoji width via system wcwidth

Since Unicode 9, the width of some characters changed to 2.

Depending on the system, it might have support for it, or it might
not.

Instead of hardcoding specific glibc etc versions, we check what the
system wcwidth says to "😃", U+1F603 "Grinning Face With Big Eyes".

The intention is to, in most cases, make setting $fish_emoji_width
unnecessary, but since it sets the "guessed_emoji_width", that variable still takes precedence if it is set.

Unfortunately this approach has some caveats:

- It relies on the locale being set to a unicode-supporting one.
  (C.UTF-8 is unfortunately not standard, so we can't use it)
- It relies on the terminal's wcwidth having unicode9 support IFF the
  system wcwidth does.

This is like #5722, but at runtime.

The additional caveat is that we don't try to achieve a unicode
locale, but since we re-run the heuristic when the locale changes (and
we try to get a unicode locale), we should still often get the correct
value.

Plus if you use a C locale and your terminal still displays emoji,
you've misconfigured your system.

Fixes #5722.
This commit is contained in:
Fabian Homborg 2019-03-06 22:07:03 +01:00
parent 60ce10ad84
commit c633c06e11

View File

@ -561,16 +561,22 @@ static void guess_emoji_width() {
version = strtod(narrow_version.c_str(), NULL);
}
// iTerm2 defaults to Unicode 8 sizes.
// See https://gitlab.com/gnachman/iterm2/wikis/unicodeversionswitching
if (term == L"Apple_Terminal" && version >= 400) {
// Apple Terminal on High Sierra
g_guessed_fish_emoji_width = 2;
debug(2, "default emoji width: 2 for %ls", term.c_str());
} else {
} else if (term == L"iTerm.app") {
// iTerm2 defaults to Unicode 8 sizes.
// See https://gitlab.com/gnachman/iterm2/wikis/unicodeversionswitching
g_guessed_fish_emoji_width = 1;
debug(2, "default emoji width: 1");
} else {
// Default to whatever system wcwidth says to U+1F603,
// but only if it's at least 1.
int w = wcwidth(L'😃');
g_guessed_fish_emoji_width = w > 0 ? w : 1;
debug(2, "default emoji width: %d", g_guessed_fish_emoji_width);
}
}
@ -849,6 +855,8 @@ static void handle_locale_change(const wcstring &op, const wcstring &var_name, e
UNUSED(op);
UNUSED(var_name);
init_locale(vars);
// We need to re-guess emoji width because the locale might have changed to a multibyte one.
guess_emoji_width();
}
static void handle_curses_change(const wcstring &op, const wcstring &var_name, env_stack_t &vars) {