GhosttyからSSH接続した先でVimを使ってテキスト編集していると、
- 挿入モードで文字入力して
- ノーマルモードに戻ることを期待して
Ctrl-[押下すると - 挿入した文字列がすべて取り消される
問題に遭遇しました。
これが生じる環境は限られています。
- クライアント: macOS + Ghostty
- 接続方法:
sshで計算機Aに接続- なお、計算機Aは相当古い
- エディタ: Vim
- 計算機Aにインストールされていて、バージョンが古い
異なる計算機に接続したり、接続方法を変更すると、この問題を生じません。
| クライアント | 接続先 |
Ctrl-[ の挙動 |
|---|---|---|
| Ghostty(macOS) | 計算機B |
Esc と同じ |
| macOS標準Terminal | 計算機A |
Esc と同じ |
| MobaXterm(Windows) | 計算機A |
Esc と同じ |
Ghosttyと計算機Aの組み合わせ(だけ)が、期待した動作をしません。
送信されるキー列を確認する
この振る舞いを理解するために、Ctrl-[ がどのように扱われるかを調べます。
cat -v
を実行して、Ctrl-[ を押下すると、キー入力が(非表示文字を含めて)表示されます(Ctrl-C で終了)。
例えば、macOS標準Terminalでは、次のように表示されます。
^[
一方Ghosttyでは、次のように表示されます。
^[[91;5u
これは「拡張(エスケープ)シーケンス」(後述)と呼ばれるものです。
なお、どちらのターミナルでも Esc は ^[ です。
Vimからも確認します。Vimを起動して、
:echo getchar()
として、一文字タイプすると、そのASCIIコードが表示されます。Esc は 27 です。
ところが問題が生じる環境では、Ctrl-[ を押下すると、以下のように表示されました。
Already at oldest change
拡張シーケンスとは: Ctrl-[ と Esc を区別する
【参考】Comprehensive keyboard handling in terminals
Ghosttyは、 Ctrl-[ を従来の Esc 文字ではなく、拡張シーケンスとして送信しています。それが、
^[[91;5u
です。Esc 相当の ^[ の後ろに、 [91;5u が続きます。
従来の端末(例えば、macOS標準Terminal)では、Esc と Ctrl-[ を区別しません。その上で動作するアプリケーション(ここではVim)は、 Esc と Ctrl-[ を区別できません。どちらを使っても効果は同じです。
Tab と Ctrl-i の関係も同様です。
拡張シーケンスは、これらを区別するために用意されました。Ghosttyは Ctrl-[ を Esc と区別するために、拡張シーケンスを送信する場合があります。
^[[91;5u の意味
^[[91;5u は、Ctrl-[ を表すCSI u 形式のキーシーケンスです。(CSI: Control Sequence Introducer)
ESC [ 91 ; 5 u
各部分の意味は次の通りです。
| 部分 | 意味 |
|---|---|
ESC [ |
CSIの開始 |
91 |
[ のASCII/Unicodeコードポイント(10進数) |
5 |
Ctrl修飾キー |
u |
CSI u 形式の終端 |
すなわち、
CSI 91;5u = Ctrl+[
です。
拡張シーケンス非対応のVimの動作を考察する
(新しい Vim は、拡張シーケンスに対応しています。)
Ghosttyから送信される
ESC [ 91 ; 5 u
は、拡張シーケンスに対応していない場合、以下のように解釈されます。
-
ESC: ノーマルモードに移行 -
[ 9 1 ;: 解釈に失敗(効力なし) -
5: カウンタ -
u: undo
すなわち、ノーマルモードに移行して、5回 undoされます。冒頭で述べた例では文字入力はなかったことになり(undo 1回分)、さらにその前の4回分の操作が(あれば)取り消されます。
対処法: GhosttyでCtrl-[の拡張シーケンスを使わない
最も手軽な対処は、Ghostty側で拡張シーケンスを使わずに、 Ctrl-[ を Esc 文字として送ることです。
~/.config/ghostty/config に以下を追加します。設定を反映するためには、Ghosttyの再起動が必要です。
keybind = ctrl+[=text:\x1b
(16進数 1b は、10進数の 27 です; Esc のASCIIコード。)
まとめ
拡張シーケンスが策定されていて、Ghosttyはこれを積極的に実装しています。古い環境へのsshでは、拡張シーケンスが意図しない動作を引き起こすことがあります。
現時点では、Ctrl-[ を Esc と区別するメリットは乏しいので、 Ctrl-[ を text:\x1b に割り当てることにします。
同様に、Ctrl-i を Tab として利用する場合は、以下の設定も追加します。
keybind = ctrl+i=text:\x09
Ctrl-i を表すCSI u 形式のキーシーケンスは ^[[105;5u です。
| 部分 | 意味 |
|---|---|
ESC [ |
CSIの開始 |
105 |
i のASCII/Unicodeコードポイント(10進数) |
5 |
Ctrl修飾キー |
u |
CSI u 形式の終端 |