強まっていこう

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

さっさと帰りたい怠け者エンジニアは vim をマスターしましょう その2 - 編集

さっさと帰りたい怠け者エンジニアは vim をマスターしましょう その2 - 編集

いざ編集ですよ。これまた狂った便利機能が豊富にあります。

第1回と今回の操作方法をマスターするだけで、他人のエディットが超鈍足に見えるようになるでしょう。

自分の頭の中ではとっくに終わっている編集がちっとも終わらない様にびっくりしますよ。

さ、今回も長いですが、張り切っていきましょう。かのアニマル浜口もこう言っています。

長州ー!気合だ気合だー!!(名言)

Undo、Redo

編集をする上でまずこれがわからないと困るので最初にサラッと書いておきます。

u Undo
ctrl + r Redo

ビジュアルモード

vim にはビジュアルモードと言う、範囲選択機能があります。むちゃくちゃ使うので必ず覚えましょう。

v 範囲選択
V 行選択
ctrl + v 矩形選択

v は範囲選択を開始します。v を押した後上下左右に動いて範囲を選択します。

選択範囲は全てハイライトされます。

Visual の v なので覚えやすいですよね。

V は一発で1行を丸ごと選択します。その後上下にカーソルを動かすと複数行の選択ができます。

ctrl + v は矩形で選択になります。v と V と比べてあまり使用頻度は高くないです。

選択の取り消しは ctrl + c です。とにかく何もかも取り消したい場合は ctrl + c を押しておけば OK です。

ただ、vi では使えないので、vi を使った時にイラッとする一番の要因になります。

ビジュアルモードで選択中に o を押すと、選択状態を維持したままカーソルが選択開始位置に飛びます。開始位置をずらしたい場合に使うと良いです。

もう一度押すと選択終了位置に戻ります。

大文字 O も同じなんですが矩形選択時には最終選択行の開始位置にカーソルが飛びます。正直使いません。

コピー・ペースト・削除

y コピー
d 削除
x カーソル位置の1文字を削除
X カーソルの手前の1文字を削除
p カーソルの右側へペースト
P カーソル位置へペースト

これらが基本になります。ただ vim の性質上 y や d だけ押したところで何も起こりません。

まずは先程のビジュアルモードの行選択や矩形選択で範囲を選択します。その後 y や d を押すとコピーと削除がそれぞれ行われます。

範囲選択後にコピーや削除をし p や P でペーストをして動作を確認してみましょう。

一つ注意点があるのですが vim の削除は文字を消すコピーだと思ってください。そのため削除した文字もペーストすることができます。

別の言い方をすると、何かを削除してしまうと、先にコピーしていたものがクリップボード(コピーバッファ)から消えることになります。

このバッファをコントロールする方法は後から説明します。

x は範囲選択時は d と同じ挙動をしますが、単体で使った場合はカーソル上の文字を1文字だけ削除します。

ここで、ちょっとした tips があります。

例えば custom と打つつもりが cusotm とタイポしてしまったとします。

そんな時は o のところへカーソルを持っていって xp と打てば文字がひっくり返ります。

cusotm あ、間違った、と思ったらカーソルはそのままで、文字へのジャンプを使いつつ Foxp です。

X は一つ手前を消します。Backspace と同じ動きになります。

その他よく使う便利なものが以下になります。

Y 行コピー
Vd 行削除
D カーソルの位置から行末まで削除
dd 行削除(vim では使わない方が良い)

dd で削除ができるのですが、同じキーを連打すると遅いので使いません。vi の時はしょうがないので使うので一応覚えておきましょう。

Vd でやると、パパンッと小気味よく押せるので vim の場合はこちらを使いましょう。
行は Vx でも消せるんですが、押しづらいのでやめた方が良いです。

行コピーをした際のペーストは改行を含んでいるため以下のような挙動になります。

p カーソルの下の行にペースト
P カーソルの上の行にペースト

D は以下のような要らないコメントを消す時に使ったり、行頭にカーソルがある場合に行削除として使ったりします。

var hoge = 10; // hogehoge

上記の行の ; 以前にカーソルがある場合 f;lD でコメントが消せます。

これら一連のコマンドの覚え方は

y vim ではコピーのことを yank(強く引っ張る) と呼ぶ
d delete
x バツ or ペケ
p paste

と言うイメージで覚えてください。

(本当は vim の世界では paste ではなく put と呼ぶんですが気にしなくていいです)

カット・上書き

先程 vim の削除は文字を消すコピーだ、と書きましたが「それって切り取り、カットじゃん?」と思った方いませんか?

その通りなんですが vim にはきちんとしたカットがあります。削除と何が違うの?と言うと、文字を消した後、入力モードに移るかどうか、です。

たったそれだけなんですが、vim はキータイプを1つでも減らしたい怠け者専用狂気エディタなので、削除して a 、なんてのんびりしたことできないんですね。

何かを消して入力し直す場合は1タイプずつ減るので必ずこれらを使うようにしましょう。

c カット
C カーソルの位置から行末をカット
s 一文字カット
S 行カット
r 1文字書き換える
R カーソルの位置から上書き

範囲選択からの c は削除と同じで、違いは入力モードになるだけです。

C はカーソル位置から行末までをカットします。

S は行削除して入力を開始します。

s は1文字削除してそのまま入力モードになります。

r は1文字だけを書き換えます。文字を書き換えた後はノーマルモードに戻ります。

例えば、pront と言うタイポを発見したら、o にカーソルを合わせて ri とすると print に書き換えられます。

R は上書きモードになって文字をバンバン上書いて行きます。Windows の普通のエディタにもある Ins ボタン押した後のアレです。正直使いません。

覚え方は

c cut
r replace
s そこをカット(無理やり過ぎてごめんなさい)

いろんなコピー・カット・削除(YCD: Yank Cut Delete)

さぁここからが本題ですよ。敷居は高いですが、覚えるとエディット効率が跳ね上がるので絶対にマスターしましょう。

これから先は、コピー・カット・削除をまとめて YCD(Yank Cut Delete) と表記します。

ちょっぱや範囲指定で YCD

まずは簡単なものから行きましょう。文字ジャンプと組み合わせる方法です(文字ジャンプに関しては第1回の講座を参照してください)。

カーソル位置からある文字までを YCD、カーソル位置からある文字を含んで YCD ができます。

[ycd][fFtT]任意文字 カーソル位置から任意文字までを YCD

[]でくるんだ文字はその中に入っている文字のうちどれか、と言う意味になります。正規表現と同じです。

[ycd] はコピー、削除、カットのどれかを指定すると言う意味です。

[fFtT] は文字ジャンプと同じです。

具体的にどう使うかというと、例えば

function hoge(args1, args2, args3) {

と言う文字列があったとしてカッコの中の「最初の引数だけにしたいから ", args2, args3" を消したい」となったとします。

コピペで持ってきたものを書き換えたり、リファクタする際によくあるシチュエーションですよね。

カーソルが先頭にあるとして f, -> d -> t) でそれが可能になります。

         f,
------------------->
                         dt)
                   <------------>
function hoge(args1, args2, args3) {

文字ジャンプ f, で最初の , にカーソルを飛ばします。その後、d で削除である事を指示して、t) で ) の1つ手前を指定します。

なんかプログラムっぽいでしょ。わかりづらいですって?ちょっと効率は落ちますがビジュアルモードでやるとわかりやすいかもしれません。

         f,
------------------->
                       v -> t)
                   ------------->
                         d
                   <------------>
function hoge(args1, args2, args3) {

ですが、タイプが1回増えちゃうので、最初の方法に慣れた方が良いです。

「消すぞ!」と言う意思を示した後「ココまで!」と指定する、こんなイメージでやればすんなり身につくと思います。

もし t) ではなくて f) とした場合

                         df)
                   -------------->
function hoge(args1, args2, args3) {

", args2, args3)" が削れて構文が壊れます。f と t は適宜使い分けましょう。

そしてこれらは大文字にすると逆方向に行くんでしたね。今度は、一番最後の引数だけ残すために "args1, args2, " を消してみましょう。

                 $
------------------------------------>
                                B
                            <-------
                    dT(
              <-------------
function hoge(args1, args2, args3) {

どうでしょうか。なんとなくイメージつかめましたかね。

単語単位で YCD

cw カーソル位置から単語のケツまでカット
[ycd]iw カーソル位置の単語を YCD
[ycd]b カーソル位置から単語の頭まで YCD
[ycd]e カーソル位置から単語のケツまで YCD
[yd]w カーソル位置から単語(空白を含む)のケツまでコピー・削除
[ycd]aw カーソル位置の単語(空白を含む)を YCD

なんか cw だけ挙動が違うのですが、これは結構使います。

例えば hoge_fuga と言う変数があったとして、hoge_hoge にしたい、なんて時です。

   ff
--------->
        cw -> hoge
var hoge_fuga = "HOGE";

空白を含まないので使いやすいんです。ce でも良いんですが、cw の方が押しやすいので多用しています。

一方 dw は空白を含んでしまいます。hoge_fuga の _fuga を消したい場合に

   f_
-------->
        dw
var hoge_fuga = "HOGE";

とやると

var hoge= "HOGE";

こなります。英文を書いている際にはこの挙動が便利なのですが、コーディング時には不便だったりします。

なので _fuga を消したい場合は de にすれば良いです。

   f_
-------->
        de
var hoge_fuga = "HOGE";

そうすると

var hoge = "HOGE";

きちんと空白が残ります。

iw は単語のどこかにカーソルが乗っていればその単語を全て YCD します。

   f_
-------->
       yiw
var hoge_fuga = "HOGE";

これで hoge_fuga がコピーされます。

[ycd]aw、[ycd]iw の覚え方は

i inner word(単語の中身)
a a word(1つの単語)

なんですが、これ英文をエディットする際の事を考えてみるとすんなり覚えることが出来ます。

These commands move slowly the cursor position.

slowly を消したい、となった場合、diw を使ってしまうと単語の中身だけを消すので

These commands move the cursor position.

スペースが1つ余分に入ったままになってしまいます。daw を使うと綺麗に単語が丸ごと消えたことになります。

These commands move the cursor position.

なんとなくイメージが掴めたでしょうか。

いろんなものの間を消す

コーディング時にむっちゃくちゃ便利な代物です。

カッコとクォートで囲われた文字列を YCD したり、囲んだカッコとクォート含んで YCD したりします。

カッコとクォートを BQ(Bracket and Quote) と表記します。

[BQ]は、[]{}()<>"'` のどれかの文字です。

[ycd]i[BQ] BQ で囲まれた文字列を YCD
[ycd]a[BQ] BQ で囲まれた文字列を BQ含んで YCD

一体どう言うことかを具体的に説明すると例えば以下のような関数があったとして、() の中身を全て消したい、となったとします。

その際は () の適当な位置で di( または di) とすることで中身を消すことができます。

カーソルは () の上でも良いです。

             di( または di)
             <------------>
function hoge(args1, args2) {

これで

function hoge() {

こうなります。

カッコごと消したい場合は da( または da) です。

大抵の使い方としては f で飛んで使うことになります。行頭にカーソルがあるとして

     f(
------------->
            di(
function hoge(args1, args2) {

こんな感じですね。

シングルクォートで囲まれた文字列の中身をコピーしたいなぁとなったら

             yi'
           <---->
var hoge = 'HOGE';


HOGE がコピーできます。

ただ、クォートの場合 a の挙動が微妙なんです。空白を含んでしまうので。カッコは大丈夫なんですけどね。

             da'
           <---->
var hoge = 'HOGE';

これをやると

var hoge =;

こうなっちゃって " 'HOGE'" が消されたことになります。前後に空白があるとさらに良くわからない消え方をしてしまうのでイマイチ使い物になりません。

こうやった方が良いと思います。

            F'
           <--
           df'
var hoge = 'HOGE';

これだと空白を残してきれいに消えるので。

HTML で便利に使えるものもあります。

[ycd]it タグで囲まれた文字列を YCD
[ycd]at タグで囲まれた文字列をタグごと YCD

こちらの a はカッコと同じで前後の空白を含まないので使い勝手が良いです。

後、よく使うものなので、di( などには別のものが割り当ててあります。

[ycd][ia]b [ycd][ia](、 [ycd][ia]) と同じ
[ycd][ia]B [ycd][ia]{、 [ycd][ia]} と同じ

キーが近い分、覚えることが出来るならこちらを使った方が良いです。

繰り返し

vim は繰り返しを . で行うことができます。

例えば hoge と入力した後、ノーマルモードで . を連打すると hoge が大量に書き込まれます。

別の例として、下の文字列の頭にカーソルがあったとして、dw を使って hoge を消したとします。

その後 . を連打すると fuga、foo が消えていきます。

hoge fuga foo bar

dw を押すと

fuga foo bar

. を押すと

foo bar

さらに . を押すと

bar

同じことを繰り返す際は積極的に使っていきましょう。

インデント

入力モードからタブキーでタブ挿入とは別にノーマルモードからタブを入れる事ができます。

>> 右にインデント
<< 左にインデント

複数行選択しても行けるので、コードを整形する際によく使います。

複数インデントする場合は >> と1回打った後、. で繰り返した方が楽です。

矩形選択を使うと、一行コメントのインデントを複数行でずらしたりできて便利です。

        f/
------------------->
              ctrl + v -> j -> >>..
var hoge = 'HOGE'; // 何かのコメント
var fuga = 'FUGA'; // 素敵なコメント

こうなります。

var hoge = 'HOGE';             // 何かのコメント
var fuga = 'FUGA';             // 素敵なコメント

改行を潰す

J 行末の改行を削除

行末の改行を削除してくれる便利なやつです。この行無駄だと思ったら J でバンバン潰していけます。

複数行選択して J を押すと一気に改行を消して1行に出来ます。途中にある行頭の空白文字も全て消えます。

こんな

    改行と行頭空白文字混じりの

        文章があったとしても一発で1行にできます

上の文章を全て選択して J を押すと

こんな改行と行頭空白文字混じりの文章があったとしても一発で1行にできます

こうなります。

コードを整形する際にはこんな感じで使います。

if (i = 10) {
    alert(i);
}

上のようなコードがあったとして、if のところにカーソルがあったとします。

$ -> V -> % -> J

if (i = 10) { alert(i); }

こうなります。良い感じにタブも消してくれるので便利です。

無駄な空行を潰す時にも使います。Vd やるより速いですからね。

検索

/任意の文字 任意の文字で検索
* カーソル位置の文字で検索

/ を押した後文字を打つとその文字で検索できます。

:set hls (または hlsearch)

とすると検索された文字がハイライトされます。
ハイライトがウザくなったら

:noh (または nohlsearch)

でハイライトが消えます。

:set is (または incsearch)

とするとインクリメントサーチになります。

この2つは ~/.vimrc に書いておくことをオススメします。

複数検索でヒットした場合は以下を使って飛びます。

n カーソルより後にあるマッチした文字列に飛ぶ
N カーソルより前にあるマッチした文字列に飛ぶ

後、ものすごく便利なのが * です。単語にカーソルをのせて * を押すだけで検索できるので。

コードを書いている時、その変数がある別の場所に飛ぶ、なんて使い方をしてジャンプの一環として使ったりもしますし

既に出てきている文字列をタイポしていないかどうかを咄嗟に確かめる時にも使ったりします。ハイライトされて飛べば OK ってことですから。

一応、/ と * がひっくり返った ? と # ってのがあるんですが、使いません。n を押すか N を押すかの違いでしか無いので。

補完

コードを書く時に多用します。今開いているものの中に書かれた文字列であればガンガン補完ができます。

ctrl + n 補完の候補を下に
ctrl + p 補完の候補を上に

候補の並びは、ファイルに存在する文字列で先頭マッチしてヒットした順になっているので、ファイルで上と下どっちにいるかで使い分けると良いかもしれませんが、まぁ通常は ctrl + n だけ使っていれば問題は無いです。

補完対象が1つしかない、または全く無い場合は候補は出てこず ctrl + n も ctrl + p も動作は同じに見えます。

プラグイン入れるともっと強力に補完できるんですが補完速度がどんどん遅くなるのであまりオススメしません。やり過ぎはやはり良くないです。

コピーバッファをコントロールする方法

削除などをするとコピーしていたものがバッファから消えます。が、実は微妙に残っています。

:di

または

:reg

とコマンド(それぞれ display、registers の省略形)を打ってもらうと、ズラッと何やら出てきます。これはレジスターと呼ばれるものです。

"" にあるものが、コピーや削除したもので、ペーストされる文字列です。

"0 はコピーされた時に入り、"1 以降は行削除した際に入り、逐次 "9 まで送られて行きます。

"7p とやると "7 に入ったものがペーストできます。

が、これは非常に使いにくくて実際使い物にはならないので、忘れて良いです。

実際に使うのは

"a ~ "z

です。これは自分で a から z までのアルファベットを指定してレジスターに突っ込むことができます。

V で行選択して、"ay とやると "a に登録されます。

"ap とやればそいつを呼び出してペーストできるわけです。

これらは vim を閉じても残っているので大事なものはレジスターに入れておくと随分と捗ります。

"A ~ "Z

と大文字でやると、そのレジスターに追記されるんですが、使いにくさ抜群です。小文字だけ使っておかないと不幸せになる、と覚えておくと良いでしょう。

まとめ

さて、一通り編集に関するノウハウをお伝えしてみました。膨大すぎて心折れそうになるかもしれませんが、マスターすると全くの別世界がそこに広がるので焦らずちょっとずつ身に付けていってください。

やればやる程周りと差がついて行くのが面白くなってくるはずです。

仕事も早くなってさっさと帰っていろんなことができるようになりますしね。竿をちょっと担いでシーバス狙いに行ったりできますよ。