weztermのEmojiがなんか思ってたのと違うな...というときの設定の仕方
TL;DR
Emojiが含まれている合成フォントを使いたいときはこう書くといい
return {
font = wezterm.font_with_fallback({
{ family = "Cica" },
{ family = "Cica", assume_emoji_presentation = true },
})
}
最近、paizaのエンジニア間でじわじわとweztermが流行っています。
ずっとalacritty + tmuxを使っていたんですが、みんなよさげよさげと言うので私も使い始めてみました。
macではhomebrewでweztermをインストールできます。
$ brew install --cask wezterm
fontの設定
私はCica fontが好きなので、エディタにもターミナルにもCicaを設定しています。当然alacrittyでもCicaを使っており、weztermもCicaで行こうとおもいます。
Cicaもhomebrewからインストールできます。
$ brew install --cask font-cica
これをweztermで使うように設定します。
return {
font = wezterm.font 'Cica',
}
CicaはNerd FontsやNoto EmojiやIcons for Devsが合成されたフォントなのでこれらのGlyphも持っており、これ一つでいい感じに絵文字を表示してくれる素敵なフォントです。
Powerlineもstarshipもこれでいい感じに決まるはず。
なんかいつもと違くない...?
これはstarshipで表示しているpromptです。
上がwezterm、下がalacrittyの表示になります。(カラースキームやフォントレンダリングの微妙な違いがありますがいったん気にしないことにします)
Emojiが違う...どうして...
alacrittyの方で表示されているemojiはCicaに合成されたNerd Fontに含まれているものですが、weztermの方ではNoto Color Emoji
のものが表示されてしまっているようです。
fontのfallbackを確認する
多くのエディタやターミナルではfallback fontを設定することで、「Primaryのfontに存在しない文字はSecondaryのfontを利用する」という設定が可能です。
weztermもfont fallbackに対応しているので、(Cicaに含まれているからCicaから使われるはず...と思いながらも)まずはfont fallbackの状況を確認してみます。
weztermではcliから wezterm ls-fonts
コマンドでどのフォントが表示に選択されているかのfallback状況を確認することができます。
以下は wezterm ls-font
の出力からPrimary fontの部分を抜粋しました。
$ wezterm ls-fonts
Primary font:
wezterm.font_with_fallback({
-- /Users/akira.shinohara/Library/Fonts/Cica-Regular.ttf, CoreText
{family="Cica"},
-- <built-in>, BuiltIn
"JetBrains Mono",
-- <built-in>, BuiltIn
-- Assumed to have Emoji Presentation
-- Pixel sizes: [128]
"Noto Color Emoji",
-- <built-in>, BuiltIn
"Symbols Nerd Font Mono",
})
これを見る限りだとCicaが最優先になっているものの、Emojiの表示にはCicaをすっ飛ばして Noto Color Emoji
にfallbackされてしまっていそうです。
明示的にNerd Fontのfallbackを設定してみる
先の通り、何故かCicaからはEmojiが使われないことがわかったので一旦 Noto Color Emoji
よりNerd Fontを優先すべく明示的にfallback設定をしてみます。
return {
font = wezterm.font_with_fallback({
{ family = "Cica" },
{ family = "Symbols Nerd Font Mono" },
}
}
(Symbols Nerd Font Mono
はweztermに組み込まれているfontなので、マシンへのインストールをせずに利用できます)
結果は...
変わらん...
wezterm ls-font
の出力を見ると、ちゃんとNerd Fontのほうが優先されているみたいですが...
wezterm ls-fonts
Primary font:
wezterm.font_with_fallback({
-- /Users/akira.shinohara/Library/Fonts/Cica-Regular.ttf, CoreText
"Cica",
-- <built-in>, BuiltIn
"Symbols Nerd Font Mono",
-- <built-in>, BuiltIn
"JetBrains Mono",
-- <built-in>, BuiltIn
-- Assumed to have Emoji Presentation
-- Pixel sizes: [128]
"Noto Color Emoji",
})
どうして...
別のEmoji Fontをfallbackに設定してみる
切り分けのために別のEmoji対応fontをfallbackに設定してみます。
今回はTwemoji Mozilla
を設定してみました。
return {
font = wezterm.font_with_fallback({
{ family = "Cica" },
{ family = "Symbols Nerd Font Mono" },
{ family = "Twemoji Mozilla" },
}
}
変わった!
wezterm ls-font
の出力は以下のとおりです。
Primary font:
wezterm.font_with_fallback({
-- /Users/akira.shinohara/Library/Fonts/Cica-Regular.ttf, CoreText
"Cica",
-- <built-in>, BuiltIn
"Symbols Nerd Font Mono",
-- /Users/akira.shinohara/Library/Fonts/Twemoji.Mozilla.ttf, CoreText
-- Assumed to have Emoji Presentation
"Twemoji Mozilla",
-- <built-in>, BuiltIn
"JetBrains Mono",
-- <built-in>, BuiltIn
-- Assumed to have Emoji Presentation
-- Pixel sizes: [128]
"Noto Color Emoji",
})
CicaとNerd Fontをすっ飛ばした上でTwemoji Mozilla
が選択されているようですね。
つまり、「特定のフォントをEmojiの表示に利用するか」には何らかの条件があるようです。
weztermがEmoji表示用fontを選択する仕組み
weztermのソースコードを読んでみました。
// If they explicitly list an emoji font, assume that they
// want it to be used for emoji presentation.
// We match on "moji" rather than "emoji" as there are
// emoji fonts that are moji rather than emoji :-/
// This heuristic is awful, TBH.
if !self.is_built_in_fallback
&& !attr.is_synthetic
&& self.names.full_name.to_lowercase().contains("moji")
{
self.assume_emoji_presentation = true;
}
どうやらweztermではfontの名前に case unsensitiveで moji
が含まれているときにそのfontをEmoji表示のために選択するようです。 これじゃ〜ん!
これで「Cica」と「Nerd Font」が無視されて「Twemoji Mozilla」にfallbackされた理由がわかりました。
明示的にCicaをEmoji用fontとしてfallbackに設定する
先の通り、命名に「moji」が含まれていないと自動的には絵文字表示に利用してくれないことがわかりました。
weztermでfont fallbackに設定できる項目に assume_emoji_presentation
というプロパティがあります。これをtrueに設定することで明示的にEmoji用fontとして認識させることができるようです。(ドキュメントにバッチリ書いてあったのを見落としてた...)
assume_emoji_presentation = true or assume_emoji_presentation = false to control whether a font is considered to have emoji (rather than text) presentation glyphs for emoji. (Since: 20220807-113146-c2fee766)
https://wezfurlong.org/wezterm/config/lua/wezterm/font_with_fallback.html?highlight=assume_emoji_presentation#weztermfont_with_fallbackfamilies--attributes
このようにweztermに設定します。(Emoji用fontはテキスト表示用fontとは独立しているようで、両方記述してfallbackさせないとダメでした)
return {
font = wezterm.font_with_fallback({
{ family = "Cica" },
{ family = "Cica", assume_emoji_presentation = true },
})
}
こちらがこの設定でのターミナルの表示です。
完璧
おかえり...
before
after
(このサメくんはCicaには存在しないGlyphなので、weztermデフォルトの Noto Color Emoji
にfallbackされて表示されています)
これでお気に入りのpromptが帰ってきたのでハッピーで埋め尽くしてレストインピースまで行けるようになりました。
weztermのfont fallbackはfontごとにscaleが変更できたり(英字fontから和文fontへfallbackさせたいときに微妙なサイズのズレを調整できます)結構かゆいところに手が届くのでとてもよいですね。
luaでシンプルに設定が書けて、仮に足りなくても自分でそういう機能を書いちゃおうというのがweztermの素敵なところです。個人的にもtmuxにもたせていた機能をどんどん移行していってるのでこのままweztermを使っていこうという機運が高まりました。
とてもおすすめのターミナルなので、「思ったとおりにfontが出ないからなあ...」と諦めていた方はぜひ触ってみてください。あとドキュメントはちゃんと読もう。
Discussion