強まっていこう

あっちゃこっちゃへ強まっていくためのブログです。

さっさと帰りたい怠け者エンジニアは vim をマスターしましょう その1 - 基本と移動

コードを書いている時間と言うのはエンジニア人生の中でかなりの部分を占めます。ですが、その時間というのは残念ながら大半が無駄なものです。一発でバキッと仕上がる事なんてないので、書いちゃ消し、試しちゃ消し、とキーを叩きまくります。このキーを叩いている時間と言うのは 100% 無駄な時間であり極力減らすべきものです。

エンジニアがやりたい事はキーを叩くことではなくてきっちり動くコードを書くことですからね。仕事をしているふりをしているような人間であればエンターキーを「ターーン!」と爽快に押して無駄な時間を楽しめるかもしれませんがそんなことやってりゃレイオフまっしぐらです。

このエディット時間を究極に短くするためには vim を使うしかありません。このエディタに敵うエディタは人類史上ありませんから。

正直な話 vim を20年以上前に初めて触った時「何だこの狂ったエディタは!」なんて思ったもんです。

誰しも最初はそう思いますって、こんなもん。

ですがコイツは、サーバを触ると必ずセットで触ることになり「うぜぇーー!」と最初は文句を言いながら使うんですが、知れば知るほど「あれ?何これ超便利じゃん」とその狂った怠け者の世界に魅了され、どっぷりと浸かっていきました。

たった1回のキータイプ、それすらも減らしたい!そう言う概念の固まりが妙に心地よくなってくるんです。Unix道の権化みたいな代物ですからねコイツ。

狂っていますから、ものすごい数のショートカットが存在します。

普通の人はその数に圧倒されてしまい脳が拒絶してしまうのですが、そうならないように行動パターンに沿って徐々に身に付けていくことが大切になります。

このエディタは頭で考えて使うものではないです。私はギターを弾いていたのですが、ギターなどの楽器を使いこなす感覚に非常に良く似ています。

いきなりイングヴェイや、インペリテリ、ティモ・トルキ等の変態たちのフレーズを真似ようとしても死にます。

ディープ・パープルやガンズ等から始まりメタリカ、スレイヤー・・・って良くわからない話になるのでこれ以上はヤメときます。

一気に全部やろうとすると心がぶち折れるので徐々に出来ることを増やしていく。弾けるフレーズを徐々に増やすのが大事だってことを言いたいんです。

慣れてしまえば頭で思考しているものを待ち時間無しでそのままの速度で表現出来るようになります。超速弾きが出来るってわけです。このエディタの速度にかなうものは世界中探してもありません。


「そもそも楽器とか弾けねぇし弾く気ねぇよ!」と思いました?

この楽器を使いこなす感覚というのは、キーボードを見ずにタッチタイピングをする感覚、Windows を使う際にショートカットを押す感覚、ゲームをする際にキーを見ずに押す感覚、と似ているんです。

これらのこともちょっとずつ慣れていきましたよね?同じですよ、同じ。

今回は楽器の基本的な音の鳴らし方と、それを綺麗に鳴らすためのコツをお教えします。

入力が出来て、保存が出来て、移動が出来る、が基本的なことで、綺麗に鳴らすコツとして、vim の狂気の移動の世界を詳しくお教えします。

弾きたいフレーズじゃないと練習する気にならないでしょう。この「移動」は十分弾きたくなるフレーズなので是非マスターしてください。完全にハードコアパンクの世界ですから。

めげそうになるかもしれませんが、vim を使えるようになると言うことはいろんなメリットがあるので気張ってみてください。

・サーバで直接編集出来るので Windows -> FTP or Samba or etc が必要ない
・最初から入っている(vi しか入っていなくてもほぼ同じことが我慢できる範囲でできる)
emacs と違ってデフォルトの設定で使い物になる(emacs.emacs に色々書かないと使い物にならない)
・人前で編集すると"何が起こっているかわからない"と言われるぐらいの速度で編集ができる = カッコイイ = 女子高生にモテる
vim 使いこなせるだけで技術がすごい人っぽく見える

vim のモードと入力・保存について(モードを戻すときには esc を使うべからず)

まず基本中の基本から行きましょう。ピック握りしめネック掴んでフレット押さえていざピッキングです。

vim には、移動や削除、コピーなどを行うための「ノーマルモード」、文字入力するための「入力モード」があります。

最初 vim を開くと文字すら打てず「はぁ??????」となりますが、それはノーマルモードから始まるためです。

それとは別に、保存や終了などを行うための「コマンドモード」があります。

名前の通りで、基本 vimノーマルモードにいます。

入力モード <-> ノーマルモード <-> コマンドモード

こんな感じでノーマルモードを挟んで行ったり来たりします。

まず入力モードへ行く基本的な方法は

i カーソルの位置へ入力
a カーソルの次の文字から入力

です。

i insert
a append

と覚えてください。何故2種類もあるんだ?と思いますよね。

右に移動して i を押せば a と同じなんですが、その移動のキータイプ1つすら面倒くさい、その時間が勿体ない、それぐらいだったら覚えることを増やす、そう言うコンセプト丸出しの大発狂エディタが vim だからです。全体的にこの考え方で成り立っています。

そんなんどっちか一方だけで良いじゃん。バカなんじゃないの?と思うでしょ。

ですがね、必ず両方共使うようになるんです。しかも意識せずに。それが vim の呪いなんです。

この i と a を大文字にすると大げさな動きに変化します。

I 行頭から入力
A 行末から入力

どこにカーソルがあろうと、行頭と行末から入力が開始できます。相当便利なので積極的に使うことになります。

これを使っているうちに i と a の打ち分けが自然とできるようになっちゃうんですねぇ。

入力方法でもう1つ大事なものがあります。

o カーソルのある行の1つ下の行に空行を差し込んで入力開始
O カーソルのある行の1つ上の行に空行を差し込んで入力開始

これも相当使います。通常は下に入れる事が多いのでこれが標準で小文字になっています。大文字になるとそれがひっくり返って上に挿入されるようになります。

さて、入力モードからノーマルモードへと戻る方法ですが、あちこちの説明では「esc」で戻せ、とありますが、そんな遠いボタン押したらダメです。指が出張しすぎです。

vimホームポジションから殆ど手を動かさず使えるのがメリットだ!なんて言っているくせに esc ってなんだよ、と思いませんか。

ノーマルモードに戻すには「ctrl + c」で戻せます。これはコマンドモードからも同じです。

Windows の vi だろうが、大昔の Solaris の vi だろうが全てこれでイケます。決して esc を押す癖はつけないようにしましょう。それだけでエディット速度がバカみたいに落ちるんで。

お次は保存ですが、コマンドモードを利用します。コマンドモードは「:」を押すことで入ります。抜けるときには ctrl + c ですよ。

:w 保存
:q 閉じる
:wq 保存して閉じる

編集後に保存もなしに閉じたりしようとすると何か怒られます。「あーうるせぇ!黙って閉じろ!」となったら「!」をつければ問答無用でコマンドが実行されます。

:w! 強制的に保存
:q! 強制的に閉じる
:wq! 強制的に保存して閉じる

良いから黙ってやれっつってんだろ!の「!」です。

:wq! は ZZ でもいけます。が、保存したくない場合でも保存して閉じちゃうので、通常時 ZZ で保存して閉じる癖をつけちゃうと痛い目を見るかもしれませんから、あまりオススメはしません。

コマンドモードは補完が効きます。

例えば :co と押して tab を押してみてください。候補が出てきて tab で候補を次々切り替える事ができます。

さらに、コマンドは省略が出来ます。例えば、タブの幅を調整するコマンドは

:set tabstop=2

ですが、これは

:set ts=2

と書けたりします。

そしてこれらの設定は home に .vimrc と言うファイルを作って書いておくことで起動時に有効になるようになります。

ちなみに .vimrc に書く時 : は必要なくて

set ts=2

と書いてくださいね。ここらあたりの便利な設定はおいおい説明していきます。

vim の癖と概念

vim はコマンドを大文字にすると、殆どの場合、話が大げさになるか、動きが逆になるかの2択になる癖があります。

さっきの説明では入力の i と a が大文字にすることで話が大げさになりましたよね。そんな感じで動作が逆になるパターンもあるんです。

これは頭の片隅に置いておいてください。

さらに、vim はキーをプログラムのように組み合わせて使うことができます。それにより高速編集を可能にしていますしマクロを強力なものにしてくれます。

例えば、下への移動は j なのですが、10j とやると 10回下を押したのと同じになります。

dib で丸括弧の中身を全て削除、みたいな謎めいたことも出来ます(dib に関しては今後詳しく説明します)。

このエディタで大事な概念なので覚えておいてください。

基本的な移動

基本がわかったところで、ハードコアパンクな移動の話に移りましょうか。一気に色々出てきてパニックになるかもしれませんが、焦らず何度も反復して体に叩き込んでいきましょう。

基本的な移動は

h
j
k
l

で行います。なんでやねん!と思うでしょうね。そして vim がのっけから敬遠される原因の一つだったりします。

ですが、慣れてしまえばカーソルキーなんて遠くて押していられ無いほどになります。

と言うか Unix/Linux の世界はカーソルキーを押す必要が一切ないように出来ているので脱カーソルするべきです。作業効率がぐっと上がります。

この移動を覚えると vim 以外のものにも応用が効くんですよ。

例えば man、less、screen のコピーモード、などです。その他、無意識に使って「あれ?動く」というものが結構あります。

もちろん vim 上でも、単純移動だけではなく、ウィンドウ分割時の移動やウィンドウ自体の移動にも使うので、必ずマスターしましょう。

Unix/Linux 上ではこの移動パターンともう1パターンあります。その別のパターンは vim でも使うので両方セットで覚えてしまってください。

h ctrl + b
j ctrl + n
k ctrl + p
l ctrl + f

h j k l は左、右は忘れないですよね。下と上は、j の文字が下に伸びているということで下、と覚えておくと良いでしょう。

ctrl + bnpf の方は

ctrl + f forward
ctrl + b back
ctrl + n next
ctrl + p previous

と2つに分けて覚えましょう。こいつらは shell や emacs でカーソルキーの代わりとして使えます。

shell の場合、カーソルを前後に動かすのが ctrl + f、ctrl + b で、履歴を戻したり送ったりするのが ctrl + n、ctrl + p になります。

vim では高速移動と補完に使います。これらは追って説明していきます。

高速移動

気長に下を押しっぱなしだのマウスでスクロールバーを引っ張るだの、遠い pagedown ボタンを押すとかは暇人のやることです。シャシャっと移動しましょう。

ctrl + f 画面1つ分先へ
ctrl + b 画面1つ分戻る

ctrl + f を押すと、今表示されているものが全て消え、表示されていなかった部分の1行目から表示されます。

要するに超長いファイルを開いた場合、ctrl + f を押すとバンバン下にスクロールされるという事です。

大急ぎで上に戻したい場合は ctrl + b で戻します。まさに forward と back です。

ちょっと早すぎるな、と思ったら

ctrl + d 画面半分先へ
ctrl + u 画面半分戻る

を使うと良いでしょう。これらは、ctrl + f、b の半分の速度でスクロールができます。

高速移動である程度のところまで移動して、こいつらで微調整、みたいな使い方をします。

ctrl + d down
ctrl + u up

です。覚えやすいでしょ。

上下にカーソルを飛ばす

vim はカーソルを色んな場所へ飛ばせます。高速に編集するために非常に大切なので、必ず覚えましょう。

数字G 数字の行へ
1G または gg ファイルの先頭へ
G ファイルの最後尾へ

10行目に行きたい場合は 10G です。行ジャンプは死ぬほど使うものなので、G = Go として覚えましょう。

H 画面の一番上へカーソルを飛ばす
M 画面の真ん中へカーソルを飛ばす
L 画面の一番下へカーソルを飛ばす

大まかに飛んで微調整する、と言うのが高速編集のコツなので、これもしょっちゅう使います。

H high
M middle
L low

で覚えると良いです。

微調整に使う移動として

数字j 数字行分下へ
数字k 数字行分上へ

がオーソドックスに使えます。数字の 4 までが押しやすいので、2~4 を適当に押して大雑把に移動します。4j -> 4j -> kk、こんな感じで。

飛び過ぎて戻る事を気にせずバシバシ行きましょう。トータルでキータイプが減れば良いんですよ。

関数の間を空行無しでコーディングしておくと関数毎に飛べて便利だったりします。私のコードはそのおかげで空行が殆ど無かったりします。

{ 上の空行へ
} 下の空行へ

カーソルを固定して上下に移動

カーソルはその場にそっとしておいて、画面からはみ出た部分をちょっと見たい、とかありますよね。そういう時に使います。

ctrl + y カーソルを固定して上へスクロール
ctrl + e カーソルを固定して下へスクロール

私はこれをかなり使います。高速移動での微調整に使うと最初にカーソル飛ばしを行わなくて良いのでとても楽できます。

ctrl + f で飛びすぎた。ctrl + u でちょいと戻す。戻りすぎたので ctrl + e でちょびちょび下げる。狙ったところが真ん中に来たあたりで M。

こんな感じで使います。

これとは別に、カーソルを固定したまま画面を上下と真ん中にスクロールさせる方法があります。

zEnter または zt カーソルがある行を画面最上部に
zz カーソルがある行を画面中央に
z- または zb カーソルがある行を画面最下部に

自分は z -> Enter と z -> - を使いますが、zt(z 位置を topに)、zb(z 位置を bottom に)の方が覚えやすいかもしれません。

カーソルを左右に飛ばす

上下に動かすだけで色々ありすぎだろ!と思いました?残念、左右はもっとありますから(白目)。

行頭、行末へ

0 行の一番左側へ
^ インデントを意識しつつ行の一番左側へ
$ 行の一番右側へ

0 はとにかく行の一番左側へカーソルを移動させます。

^ は、タブやスペースを使ってコードをインデントをしている場合、そのインデントを超えること無く行の一番最初の文字にカーソルが飛んでくれます。

^ と $ は正規表現と似ているので覚えやすそうですが、若干違うので注意が必要です。(正規表現の ^ は空白文字も含んで文字列の先頭)

単語ジャンプ

次は非常によく使う単語のジャンプです。

w 次の単語の頭
b 単語の頭
e 次の単語のケツ

これで単語をバシバシ飛びます。この単語ジャンプは空白と記号で引っかかります。日本語だと漢字でひっかかります。

記号を無視して空白のみで飛びたい場合は全てを大文字にしてください。

W 記号を無視して次の単語の頭
B 記号を無視して単語の頭
E 記号を無視して次の単語のケツ

h や l を気長に押しておけるほど人生は長くはないので、この大文字での単語ジャンプを殆どの場合利用することになります。

w word
b back
e end

で覚えると良いと思います。

単語ジャンプでひっかかる文字はコマンドモードの :set isk (または iskeyword) で設定出来ますがお勧めしません。

次で説明する文字に対するジャンプを使えば特に気にならなくなります。

文字へのジャンプ

任意の文字へのジャンプが出来ます。検索とは違うの?と思うでしょうが、違います。

入力する場所を狙い撃つのは当然なんですが、これコピーや削除と組み合わせると強力になっていきます。とにかくめちゃくちゃ使うものなので絶対覚えましょう。

f任意の文字 任意の文字へカーソルを移動
t任意の文字 任意の文字の1つ手前へカーソルを移動

なんのこっちゃかですかね。ここはものすごく大切で、これを使いこなせるかどうかで vim ライフが随分変わってくるので、しつこいぐらい詳しく説明します。

例えば、下のような文字列の先頭にカーソルがいたとするじゃないですか。

f の後に ( を押す、つまり f( とすると ( のところまでカーソルが飛びます。

function hoge(i, str) {
------------->
      f(

これの何が嬉しいの?って話ですが、例えば、関数の第一引数に別のものを足したい場合、一瞬で足したいポイントに到達していることになります。

そこに移動して、a を押すとそのまま別の引数を定義できる、と言うわけです。

f( -> a -> hoge, -> スペース の結果

function hoge(hoge, i, str) {

こうなります。狙い撃つ文字は ( じゃなくて i でもいけますが、その行に1つしか存在しない目立つものの方が一瞬の判断で飛べます。

一番最後に足したい場合は、

function hoge(i, str) {
-------------------->
         f)

f) で飛んで、i -> , hoge でこうなります。

function hoge(i, str, hoge) {

f と t の使い分けですが、単に文字の挿入であれば、f で事足りますが t は切り取りやコピーで非常に大事になってくるので覚えておきましょう。

覚え方としては

f focus or find
t 手前

です(適当)。

この f と t ですが、大文字にするとひっくり返ります。

F文字 文字のところへカーソルを移動(右から)
T文字 文字の1つ手前へカーソルを移動(右から)

vim の癖発動です。

さっきの例とは逆に行末にカーソルがいたとすると

function hoge(i, str) {
             <---------
                 F(

こんな感じです。どこに今カーソルがいるかで使い分けましょう。

もう一つ、良く使うものの、ちょっと覚えづらいものがあります。それは、繰り返しです。

例えば下の文字列の行頭にカーソルがあったとして

hoge hoge hoge hoge hoge
----->---->---->---->
  fh   fh   fh   fh

こんな眠いことやってられません。

かと言って

hoge hoge hoge hoge hoge
-------------------->
        4fh

だと、数えるのが面倒くさい場合が多いです。そういう時は繰り返しを使います。

; 前へ繰り返し
, 後ろへ繰り返し

これらを使って繰り返すことができます。

hoge hoge hoge hoge hoge
----->---->---->---->
  fh   ;    ;    ;
     <----<----<-----
       ,    ,    ,

; で進んで、行き過ぎたら , で戻ってやれば良いんです。

これの覚え方は、; は2個あるから増やす方、, は1個なんで減らす方、みたいな感じでしょうか・・・。

対応した括弧に飛ぶ

()、{}、[]、それぞれの括弧の開始と終了に % を押すことで飛べます。

vim の場合対応する括弧の上にカーソルが乗るとハイライトされちゃってどう飛んでるかわかりづらいと思うので、コマンドモードで

:NoMatchParen

と打ってハイライトを切って試すとわかりやすいかと思います。(:No と打って tab を押すと補完してくれます)。

戻す時は

:DoMatchParen

です(:Do で補完出来ます)。

この対応括弧に飛ぶのはクソコードでインデントがおかしいやつとかでは多用しますね。

「どこがどうなってんだ?」-> % ポチポチ、みたいな。

普通のコードでも、if 文で条件追加したくなった時とか最初の条件で $ を使ってケツに飛んで % を押して、みたいな感じで使います。

      $
------------->
if (i == 10) {
	console.log(10);
} <-- % を押してココへ移動して、o を押して条件を足す

後もう1つ便利な使い方としては、同一行の括弧の中にカーソルがあった場合に % を押すと開始の括弧へ飛ぶので、F( や F[ を使う頭出しで2回キーを叩くのではなく % 1回で飛んだりします。

                %
           <--------
var list = [ 1, 2, 3, 4 ];

カッコへ飛ぶ方法はこの他にもあります。

[{ カーソルがある箇所を囲んでいる { へ飛ぶ
]} カーソルがある箇所を囲んでいる } へ飛ぶ
[( カーソルがある箇所を囲んでいる ( へ飛ぶ
]) カーソルがある箇所を囲んでいる ) へ飛ぶ

使う場面を選んでしまいますが

int main(void)
{
	return 0;
}

こんな書き方の場合は以下が役に立ちます(個人的にはこの書き方は嫌いです)。

]] カーソルより下にある一番左に張り付いている { に飛ぶ
][ カーソルより上にある一番左に張り付いている { に飛ぶ
][ カーソルより下にある一番左に張り付いている } に飛ぶ
[] カーソルより上にある一番左に張り付いている } に飛ぶ

まとめ

今回は vim の基本的な動かし方と、強力な移動法について書いてみました。

魅力がちょっとでも伝わりましたかね。

この移動に慣れると、のんびりカーソルキーを押していた時代がバカバカしく思えるようになりますし、他人がエディットしている様を見ていて「おっそ・・・」と思えるようになってくると思います。

最初にも言いましたがこのエディタは楽器と同じなので、何度も反復的に使って体に覚え込ませる必要があります。

キツイかもしれませんが、それを乗り越えた先には快適なノンストレスエディットライフが待っているので是非がんばってみてください。

その応援を微力ながらこれからもさせていただきます。

wolfbash.hateblo.jp