Leverage Copy

メモの公開場所

競技プログラマーにアピールしたいVim/VSCodeVim

この記事の目的

エディタに興味の薄い競技プログラマー(あるいは誰でも)に、「Vimちょっと調べてみようかな、遊んでみようかな」と少しでも思ってもらうことです。

導入

私は昨年の4月に働き始めてからVimを使い始めて、1年半ほど経った今ではVimキーバインドは手放せないものとなりました。

職場で周囲のほとんどの人がVimを使っていたことから、「きっと素晴らしいものなんだろう」と思いはじめました。 当時は研修中で比較的時間に余裕があったため、帰宅してからVimについて調べたり練習したりしていました。

また一方で、昨年9月頃から始めた競技プログラミングでは、素早く問題を解くことが重要で、ひいては高速なコーディングがプレイする上で有利になります。 最近ではVSCodeを使っている競技プレイヤーも多いようですが、幸いVSCodeにはVSCodeVimという優れたVim拡張があります。 多少の初期投資によって今後一生活かせる、快適で高速で、そしてなにより楽しいコーディング体験をしてみませんか。

Vimって難しいんじゃないの?

しばしば、Vimの習得難易度は高いと聞きます。 自分もVimを使い始めるまではそう思っていましたし、実際にそのとおりな部分もあると思います。 しかしながら、標準のキーバインドや初歩的なコマンドを常用して快適にコーディング・文書作成する分には、それほど難しいものではないと思っています *1

自分の場合、よく使うコマンドを整理した上で数週間Vim縛りでコーディング、テキスト編集をしていたら、自然と定着していました。

Vimを覚えるためのモチベーション

「これは便利そう」と思えるような「かんたんな」操作を実際に観てみる のが一番いい気がします。

よく「とりあえずvimtutorをやってみよう」とか「実践Vimという本を読むといいよ」と呼びかけているのを見かけます。 しかしながら、これらを両方完遂できる人はすでに決意が硬い人であって、殆どの「やってみようかな」レベルの人は途中で折れるか飽きてしまうような気がします *2

いずれはこれらについても一度さらっておいたほうがいいのは間違いないのですが、 まずは強い動機づけをすることで、意欲を保ったまま効率的に学習できると考えています。 そのために、黒魔術のようなとても覚えられそうにないものではなく、すぐにでも便利に使えそうな操作を「下見してみる」のが良いかと思います。

私が1年半ほど使ってみて、今でも変わらずに便利だと思っておりかつかんたんな操作は、以下のようなものです。

テキストオブジェクトの操作

私がVimを学び始めて一番「おおっ」となったのはこれで、今でも他人に勧めたい操作No.1です。

かんたんに紹介すると、例えば ciw は "correct in word" の略で、現在カーソルが置かれている単語を削除しインサートモードに移行するコマンドです( ※嘘でした )。 削除後にインサートモードに移行してくれるおかげで、単語を即座に修正することができます。

f:id:maguroguma:20191009201214g:plain
カーソル位置の単語の修正

あるいは、 da" とすると "delete all "" の略で、現在カーソルが置かれておりダブルクォートで囲まれている部分を、 ダブルクォート含めてすべて削除するコマンドです。

f:id:maguroguma:20191009201306g:plain
カーソル位置の二重引用符部分の削除

これらのコマンドを XYZ と表すなら、 X = {c(correct), d(delete), y(yank, copy), v(visual)}, Y = {i(in), a(all)}, Z = {(, ), [, ], ", ', w, ...} というようなバリエーションが有り、それぞれの要素数の掛け算の数だけ異なった操作ができることになります。

※2020-07-16追記 : うっでぃさんよりコメントでご指摘いただきましたが、 in/allは嘘でした。正しくはinner/a or an objectというのが正式 のようです( :h v_a 参照)。 2年以上頭の中でin/allで考えてしまったのでなかなか脳内修正が難しいですが、上述はあくまで「私の頭の中の動き」とお考えください(ていうかよくよく英語的に動詞・目的語で考えたらin/allじゃ文法が壊れてますね)。

同様な操作を普通のエディタでやるならば、マウスカーソルで正確にドラッグする手間が必要だと思います。 あるいは、カーソルを消したい文字の一番右に移動させてからback space長押し、とかでしょうか。

一方、Vimであれば「雑に」目標位置にカーソルを移動させたあと、上記の3つのキーを押下するだけで、所望の結果が達成できます。

ノーマルモードにおける o コマンド

めちゃくちゃ地味なんですが、これを知ったときかなり嬉しかったのを覚えています。

このコマンドは、現在のカーソル位置に関わらず、1つ下に改行してインサートモードに移行します。 行の途中にカーソルがあるけど、すぐ下に改行したい、というケースは結構あるのではないでしょうか。

f:id:maguroguma:20191009201347g:plain
行末以外で改行

これも普通のエディタだと、「カーソルを行末に移動させてEnter」という手間が必要だと思いますが、Vimならばキー入力一回のみです *3

dd による1行削除、 yy による一行コピー

これもとても地味ですが、1行単位で削除したりコピーしたりというのは、頻繁に行う操作の1つかと思います。 Vimでは、これらはそれぞれ dd および yy で実現できます。 p で後ろにペーストできます。

f:id:maguroguma:20191009201427g:plain
カーソル位置の行削除とカーソル後へのペースト

普通のエディタを使っていた頃は、複数回左クリックし行を選択してからback spaceもしくはctrl+cとかやっていました (行全体を選択するのに2回でいいときと3回やらないとダメなときとかがあって、ちょっといらっとするときがあります)。

surround.vimによる「なにかを囲むもの」に対する操作

Vimネイティブなものではなく、プラギンの範疇なのですが、おそらくは導入することになるので紹介しています。

ちょっと操作がややこしくなりますが、例えば以下のように、ビジュアルモードで選択した範囲について Sb もしくは S( と打つと、 選択範囲を丸括弧で囲んでくれます。

f:id:maguroguma:20191009201519g:plain
選択範囲を丸括弧で囲む

また、ビジュアルモードを介さなくても、先述のテキストオブジェクトの要領で ysiw" と打つと、 現在カーソル位置にある単語に対してダブルクォートで囲むことができます。

f:id:maguroguma:20191009201608g:plain
カーソル位置の単語を二重引用符で囲む

あるいは、既存の「囲んでいるもの」を別のものに置換することもできます。 例えば、 cs'" と打つと、現在のカーソル位置を囲んでいる最近傍のシングルクォートを、ダブルクォートで置換します。

f:id:maguroguma:20191009201739g:plain
単引用符を二重引用符に置換

もう予想がつくかもしれませんが、 dsb とすると、カーソル位置を囲む最近傍の丸括弧を削除します。

f:id:maguroguma:20191009201840g:plain
既存の丸括弧を削除

紹介した操作の中ではちょっとだけ複雑ですが、何回も使っていると忘れないぐらいには頭に染み込んできます。 直前に別のプログラミング言語を使っていて、「この言語では丸括弧が必要なのに丸括弧なしで書いちゃった」というときなどはよく使っています。


ごく一部ですが、私が特に便利だと感じている操作を紹介しました。 殆どの操作において、普通のエディタならばマウスや矢印キーを慎重に使うことが要求されるのに対し、Vimでは雑かつ楽に実行できます。

VSCodeVim: VSCodeVim拡張

VSCodeにおけるVim拡張がVSCodeVimなんですが、話を聞いたところ他のIDEVimプラグインに比べて出来がいいようです*4

個人的に優れていると思うのは、以下の点です。

  1. オリジナルのキーマッピング設定が(それなりに)可能、初心者によっては.vimrcよりも書きやすいかも
  2. 有名なVimプラギンがデフォルトで有効になっている
  3. VSCodeオリジナルの機能とのバッティングがない(自分が知らないだけかも)

1については、例えば ESCjjマッピングしたりだとか、 ctrl + h,l について、ノーマルモード時はビューグループ間の左右移動でインサートモード時はカーソルの1文字左右移動にしたりとか、 モードごとに動作を変えたりもできます。 なので、込み入ったものでなければ.vimrcに記述しているようなカスタムマッピングは、たいていVSCodeVimでも再現できます。

2については、surround.vim, easymotion, commentary.vimなどが該当します*5

雑に紹介しておくと、easymotionはカーソル移動に関するプラギンで、例えば <space><space>j と打つと*6、下方向へのジャンプのアシスト文字が表示され、 対応する文字を入力すると、文字が付与されている部分にカーソルがジャンプします。

f:id:maguroguma:20191009201913g:plain
easymotionのデモ

また、commentary.vimはコメント補助のプラギンで、 gcc とだけ打つとカーソル位置の行をコメントアウトしてくれます。 また、行ビジュアルモードで複数行選択している状態で gc と打つと、その行範囲をすべてコメントアウトしてくれます。

f:id:maguroguma:20191009201945g:plain
カーソル位置の行をコメントアウト
f:id:maguroguma:20191009202017g:plain
選択した複数行をコメントアウト

3については、そもそもVSCode本来の機能で便利なものが多いため、VSCodeの強みとVimの強みの両方を享受できます。 VSCodeの話になりますが、ファジーファインダーになっているquickOpenが特にお気に入りです。

インストール方法はVSCodeの他の拡張機能と同じで、簡単に導入・破棄できます。 「ちょっとだけVim試してみよう」と思ったら是非気軽にインストールしてみてください。

おまけ: Vimを学ぶことによる副次的なメリット

ある程度Vimに習熟してから気づいたことですが、以下のようなメリットがあったことに気づきました。

  • いくつかのVimキーバインドとシェルのショートカットが同じであるため、シェルの操作も効率的に行えるようになる
  • 置換コマンドを覚えると同時に、かんたんなsedコマンドの使い方も覚えられる
  • 置換コマンドを覚えると同時に、正規表現も覚えられる
  • CUIに抵抗がなくなる、CUIが好きになる

1年目はフロントエンドの業務がほとんどであり、シェルを操作する機会が少なかったため、 このあたりの抵抗が早めになくせたのは、個人的には結構大きいと思っています。

これらをVimを学習する主たる動機にするのは難しいと思いますが、一応触れておこうと思いました。

おわりに

Vimの解説記事などは出尽くしており、今更自分が書くほどでもないと思ったので、 「自分はVimのここが好きで、そんなに導入コストは高くないと思うから試してみて!」という部分に特化した内容をまとめてみました。

自分自身、これまでVimのいいところに触れる機会がなく、もっと早く知っていればなぁと思ったりしたので、 若い人などで「Vimってなんなの?」と思っている人が少しでも興味を持ってくれたりするととても嬉しいです。

ちなみに、私は業務ではVSCodeを、競技プログラミングではneovimを使っています*7

*1:Vim scriptや周辺技術をちゃんと理解してプラギンを管理したり、あるいはプラギンを自作するとなると、とても難しくなってくるという認識です。

*2:どちらも優れた教材なのは疑いようがなく、実際に私も両方やりました。

*3:これは流石に自分のエディタ操作スキルが低いだけで、それぞれのエディタでショートカットがあるものなのかもしれません。

*4:聞いたところによると、Vimの基本的な機能もエミュレートできていないものもしばしばあるとか。

*5:最近はREADMEを読めていないので、もう少し増えているかもしれません。

*6:厳密には、Leaderをspaceキーにマッピングする設定が必要です。

*7:GoとVimの相性が良いのと、neosnippetがとても使いやすい。