Vimのu/Uキーがアンドゥと大文字小文字変換の二重の意味を持つ理由
大文字化しようとしてUを押したら、変換されるどころか行が丸ごと元に戻りました。ビジュアルモードに入っていたつもりが、実際はノーマルモードのままだった、というのはVimでありがちな事故です。原因はu/Uが、モードによってまったく違う意味を持つキーだからです。
目次(9項目)
同じキーでも、モードで意味が変わる
| キー | ノーマルモード | ビジュアルモード |
|---|---|---|
| u | アンドゥ | 選択範囲を小文字化 |
| U | 直近に変更した行をまとめてアンドゥ | 選択範囲を大文字化 |
ビジュアルモードで範囲を選択してからUを押すと、その範囲を大文字化します。
hello world
HELLO world
ノーマルモードのUは「アンドゥ」と聞くと意外に感じるかもしれませんが、正確には「直近に一括で変更された行の内容を、変更前に戻す」コマンドで、u(1手ずつ戻す一般的なアンドゥ)とは少し性質が違います。いずれにせよビジュアルモードの変換とは無関係な機能です。
なぜこの割り当てになっているのか
ノーマルモードのu/UはVi時代から存在するアンドゥ系のコマンドで、ビジュアルモードはVimになってから追加された機能です。ビジュアルモードでは、範囲を選択した状態でu/Uを押すという操作自体がアンドゥとして意味を持たないため、そこに大文字小文字変換という別の機能を割り当てても衝突しません。Vimの多くのキーはこうして「モードが変われば同じキーでも別の役割を持てる」という前提で設計されています。
他のモードではどうか
ノーマルモード・ビジュアルモード以外でもu系のキーは登場します。挿入モード中にCtrl-o uのように一時的にノーマルモードへ抜けて実行すれば、そこではやはりアンドゥとして働きます。モードをまたいで同じキーが使い回されているという前提さえ頭に入っていれば、どの文脈でも動作を予測しやすくなります。
混同を避けるコツ
一番確実なのは、変換前に画面下部を見てビジュアルモードに入っているか確認する癖をつけることです。ノーマルモードなら何も表示されず、ビジュアルモードなら-- VISUAL --のような表示が出ます。急いで操作しているときほど確認を飛ばしがちなので、意識してワンテンポ置くと安心です。
もう1つの回避策は、大文字小文字変換にビジュアルモードのU/uではなく、ノーマルモードのオペレータgU/guを使う習慣に切り替えることです。こちらはアンドゥのキーと文字が重ならないため、そもそも混同しようがありません。具体的な使い方は大文字小文字変換まとめで扱っています。
急いでいるときに何度か行アンドゥとの取り違えをやらかしてから、大文字小文字変換はgU/guに切り替えました。ビジュアルモードのU/uより1文字多いですが、間違えて行が消える心配がなくなったので、結果的にこちらのほうが速く安心して使えています。
U はもう一度押すと元に戻る
ノーマルモードの U は「直前に変更した行を変更前の状態に戻す」コマンドですが、その U 自体も変更として記録されます。そのためもう一度 U を押すと、戻す前の状態に戻ります。
手元のVim 9.1.1752で one two three の行頭で x を2回押して e two three にしたあと、U で one two three に戻り、もう一度 U を押すと e two three に戻りました。
xx " e two three
U " one two three(行の変更をまとめて戻す)
U " e two three(U を取り消す)
押し間違えても同じキーで戻れるので、U は思ったより安全なキーです。ただし別の行へ移った時点で対象が変わるので、戻したい行から離れる前に押す必要があります。
取り消しの履歴は枝分かれする
Vimの取り消しは一直線ではありません。u で戻したあとに別の編集をすると、そこで履歴が枝分かれします。Ctrl-r では消えたほうの枝に戻れませんが、時系列でたどるキーなら行き来できます。
:undolist " 枝の一覧を見る
g- " 時系列で1つ前の状態へ
g+ " 時系列で1つ後の状態へ
:earlier 10m " 10分前の状態へ
「戻しすぎたあとに打ってしまって、さっきの内容が消えた」と思ったときは、たいてい g- で戻せます。undofile を有効にしておけば、Vimを閉じたあとでもこの履歴が残ります。
gU と gu に寄せると迷わない
大文字小文字の変換をビジュアルモードの U u ではなく、ノーマルモードのオペレータ gU gu に寄せてしまえば、取り消しのキーと文字が重なりません。
gUiw " 単語を大文字に
guiw " 単語を小文字に
gUU " 行全体を大文字に
g~~ " 行全体の大小を入れ替える
1文字多く打つことになりますが、モードを確かめる手間が消えるぶん結果的に速くなります。オペレータなのでテキストオブジェクトも使えて、gUap のような大きい範囲も指定できます。詳しい使い方は大文字と小文字の変換にまとめています。
まとめ
u/Uはノーマルモードとビジュアルモードで役割が完全に別物になります。混同が不安な人は、大文字小文字変換をgU/guに寄せてしまうと事故を根本的に避けられます。ノーマルモードのuのほう、つまりアンドゥの詳しい挙動はundoとredoの記事で扱っています。
ここで扱ったキーは、ブラウザ上で動くVim道場の大文字と小文字を変えるでそのまま試せます。インストールもログインも要りません。