課題:ブラウザで文字を大きくすると、カーソルが数文字ずれる
ブラウザで開いた AI の画面。文字が小さくて読みにくいので、Ctrl と + を押します。大きくなりました。
そのあと長いコマンドを打っていて、途中を直そうとカーソルを戻します。カーソルが、直したい場所より三文字ずれた位置にいます。Ctrl + L で画面を消しても、画面の端にゴミが残っています。
タブを再読み込みすると直りますが、また少し時間がたつと同じことが起きます。
ターミナルには「桁数」と「行数」がある
原因は、ターミナルの仕組みにあります。
ターミナルは文字の格子です。80 桁 × 24 行のような格子で、その数字を中のプログラム(シェルや Claude Code)も知っています。この数字を使って、
- 長い行をどこで折り返すか
- カーソルを何文字戻すか
clearで何行消すかvimが画面のどこに何を描くか
を決めています。桁数と行数が合っていることが前提の仕組みです。
Unix の API では TIOCGWINSZ という ioctl で取得する値で、SIGWINCH というシグナルでプロセスに「変わった」ことを知らせます。
ブラウザのズームは、その数字を知らせない
ブラウザのズームは、ターミナルに何も言わずにページを大きくします。文字が大きくなった分、同じ幅に入る桁数は減ります。80 桁だったところが 70 桁になる。
でも中のプログラムは、80 桁のままだと思っています。TIOCGWINSZ の値は変わらないし、SIGWINCH も送られません。
70 文字目で折り返されるのに 80 文字目だと思って計算するので、
- カーソルを戻す量が合わない(3〜10 文字ずれる)
- 消す行数が合わない(画面にゴミが残る)
- 色のエスケープシーケンスが途中で切れる
拡大コピーした図面の隅の縮尺がそのままになっているのと、同じ構造の事故です。
既存の回避策とそのコスト
ブラウザのズームを使わない
一番素朴な回避策です。ただしブラウザは普段からズームする道具なので、「ターミナルのタブだけはズームしない」を忘れずに守る必要があります。
AI の画面を長時間見るときは、ちょっと大きくしたい、が普通に起きます。禁止ルールで運用するのは現実的ではありません。
ブラウザ全体を 125% にする
Chrome や Edge のゾーン設定でそのドメインだけ 125% にすると、タブごとのズーム忘れは減ります。ただし、
- MulmoTerminal の UI(設定モーダル、サイドバー、グリッド)まで一緒に拡大される
- 125% を超えると UI が窮屈になる
- タブや Space をまたいで同じ MulmoTerminal を開くと、片方だけズームされていない
UI と中身を別々に拡大したい、という普通の要求に応えられません。
CSS の font-size で xterm のフォントを直接いじる
ユーザースクリプトで xterm のフォント CSS を書き換えるアプローチもあります。見た目は大きくなります。ただし xterm.js は内部で文字サイズを測って桁数を計算しているので、CSS だけ書き換えると xterm.js の内部状態とターミナルプロセスの TIOCGWINSZ の両方がずれ、同じ事故が別の経路で起きます。
ターミナルを測り直して、新しい桁数をプロセスに送るという手順をどこかで踏まないと、ずれは直りません。
MulmoTerminal の解決:fontSize を変えたら、桁数を数え直してプロセスに伝える
MulmoTerminal には fontSize という設定があります。ターミナルの文字サイズを px で指定します。
{ "fontSize": 16 }
ブラウザのズームと違うのは、fontSize を変えたときにターミナルを再フィットして、新しい桁数と行数を中のプロセスに SIGWINCH で知らせるところです。
- 文字を大きくする(xterm.js に px を伝える)
- 新しい入り数を数える(xterm.js の
fitアドオン) - プロセスに「今は 70 桁 24 行だ」と送る(
SIGWINCH)
この手順を踏むので、折り返しもカーソル移動も clear も、全部正しく動きます。拡大コピーしたときに、隅の縮尺もちゃんと書き直す、という挙動です。
詳細
範囲外の値は近い端に丸める
有効な範囲は 8〜32 px です。範囲外の値はエラーにせず、近い端に丸めます。
| 書いた値 | 実際の値 |
|---|---|
6 |
8(下端に丸め) |
99 |
32(上端に丸め) |
"large" |
無視。設定モーダルの値が使われる |
意図のある挙動です。99 は「大きくしたい」という意図が読めるので、できる範囲でやる。"large" は意図が読めないので何もしない。設定したのに何も変わらない、が起きにくい作りです。
プロジェクトごとに文字サイズを変える意味
fontSize はプロジェクト単位の設定なので、マスによって文字サイズを変えられます。これは見栄えの話ではなく、中身の違いに合わせるためです。
| プロジェクト | 文字サイズ | 理由 |
|---|---|---|
| ログを眺めるマス | 小さめ(12〜14 px) | 一画面に多く入れたい |
| コードを読みながら指示するマス | 大きめ(16〜18 px) | 読み間違えない |
| 日本語が多いマス | 大きめ(16 px〜) | 全角が潰れないように |
| スマホから開くマス | 18〜20 px | 画面が小さいので |
九枚のマスが全部同じサイズである必要はありません。
保存場所:ブラウザ単位の既定と、プロジェクト単位の上書き
| 書く場所 | スコープ | 書き方 |
|---|---|---|
| 設定モーダルの Terminal font size | このブラウザの全マスの既定 | スライダー(8〜32) |
プロジェクトの .mulmoterminal.json |
そのプロジェクトのマス | "fontSize": 16 |
ブラウザ単位にしてある理由は、スマホと PC で別の値を持ちたいからです。スマホは 20 px、PC は 14 px、を同じアカウントで維持できます。
プロジェクト単位があるのは、上の表のとおり中身の違いで変えたいケースがあるからです。
反映のタイミング
| 変更の仕方 | 反映タイミング |
|---|---|
| 設定モーダルのスライダーを動かす | 即時(ブラウザごとの既定) |
AI にファイルを書かせて fontSize を変える |
即時 |
エディタで .mulmoterminal.json を手で書き換える |
タブを再読み込みするまで古いまま |
ファイルを見張っているわけではないので、手で書いたときはタブを更新します。ここが「設定したのに効かない」の典型的な原因です。
fontFamily も同じファイルで変えられる
fontSize と同じ場所に fontFamily も書けます。日本語が多いプロジェクトでは、両方を一緒に指定するのが実用的です(→ MulmoTerminal の日本語フォント設定)。
{
"fontSize": 16,
"fontFamily": "'Cica', 'MS ゴシック', monospace"
}
使ってみる
既存の MulmoTerminal 環境があれば、設定を書き足すだけで動きます。はじめての方は、MulmoTerminal 完全ガイド の「使い方 3 ステップ」から。
動作確認の最小シナリオ
- 適当なプロジェクトの
.mulmoterminal.jsonに"fontSize": 20を書く - そのプロジェクトのマスで長いコマンドを打つ(画面幅ギリギリまで)
- カーソルを行頭に戻し、修正してみる — カーソル位置と修正位置がずれていなければ成功
- 比較のため、別のマスでブラウザのズーム(Ctrl + +)だけで同じサイズまで拡大し、同じ長いコマンドを打つ — カーソルがずれるはず
同じ「文字を大きくする」でも、手順を踏んでいるかどうかで振る舞いが変わります。この差が、専用の設定を使う理由です。
覚えることは一つだけ
この記事を一行にすると、ブラウザのズームは使わない、fontSize を書く、になります。
数字を覚える必要もありません。「ターミナルの文字を大きくして」と AI に頼めば書いてくれます。範囲外を書いても丸めてくれるので、やり直しも要りません。
やめるときは .mulmoterminal.json からその項目を消すか、ファイルごと消せば戻ります。
まとめ
- ターミナルは桁数と行数を前提に、折り返し・カーソル移動・画面消去を計算する
- ブラウザのズームはその数字を更新しないので、文字が大きくなった分だけずれが積み重なる
fontSizeは再フィットして新しい桁数をプロセスに送るので、ずれない- 範囲 8〜32 外は端に丸める。数値でない値は無視する(設定したのに変わらない、を起こさない)
- プロジェクトごとに変えられるのは、中身の違い(ログ中心・日本語中心)に合わせるため
関連: MulmoTerminal 公式ガイドの fontSize 設定 / MulmoTerminal の日本語フォント設定 / MulmoTerminal の xterm カラー — 中身を染める / Cursor の代替としての MulmoTerminal
