haya14busa

haya14busa’s memo

revital.vim で vital.vim を爆速にしてお前らの Vim Plugin を速くする

haya14busa/revital.vim

この度, revital.vim というプラグインを作って vital.vim のモジュールのローディングを爆速にしてお前らが使ってる Vim plugin を速くしました.

めでたい.

あと気づいたんですが今日は僕の誕生日のですね.これもまためでたい.

そして本当のところは vital.vim を使ってるプラグイン開発者が, revital.vim を使って初めて速くなるので実はまだ速くなってないものが多いです. 待ちきれない方はこの記事を読んで revital.vim の使い方を覚えてプルリクしていきましょう. また爆速にはなったと思うんですが,体感には個人差・環境差があり,もともとほとんど速度が気にならない人も多いかと思うのでご注意ください. Windows だか symlink だか virtualbox だか neovim だか何かはまだよくわかってませんが,特定の 環境が原因なのか vital.vim をヘビーに使用しているプラグインにまれによく「遅いぞ?」という issue が飛んできたりしていて, そういった方には顕著に効果があると思います.(たぶん)

参考: 遅いと言ってる人たち (放置気味でスイマセン…いや workaround な修正なら前からできたんだけど手元でも再現しないものをその場対処はあんまりやりたくなくてやる気が…)

vital.vim とは?

https://github.com/vim-jp/vital.vim

Vim script の最高のライブラリです.vital.vimのいいところとダメなところを個人的に上げるとこんな感じです.

vital.vim のいいところ

  1. 組み込み式なので依存ライブラリがアップデートされても安心
  2. プラグインのユーザはvital.vimを別途インストールする必要がない
  3. めっちゃ気軽に外部ライブラリを作って使える
  4. けっこういろんなものがそろっていて種類が豊富
  5. 日本人の凄腕 Vimmer 達が開発・メンテしているので品質も高い

とにかくベンリ

vital.vim のダメなところ

  1. (ロードが) 遅い (ケースがある)(基本的に気にならないけど)
  2. ドキュメントがたぶん足りないので敷居が高い(ように見えるだけで使い方は簡単なんだけど…)
  3. インストールやアップデートでハマることが多い印象

他のところで,ファイルをコピーするのが無駄だとかキッチンシンクじゃない?みたいな 話を聞いたことがありますが,前者は全然気にする時代じゃないはずだし,後者は単なる勘違いで vital.vim は使うライブラリのみ組み込めるので問題ないはずです.

Githubのリポジトリでは

This is like a plugin which has both aspects of Bundler and jQuery at the same time.

と(たぶん昔から)書いてあって,Bundler はともかく jQuery はちょっとあんまり良い印象ではないのかなぁと思う. どちらかというと lodash とか Bundler に合わせるなら npm と言ってもいい気がする.

で,話が少々それていますが,今回 1つ目のモジュールの読み込みが遅いという部分を revital.vim で解決してみました. 2と3はドキュメントを拡充したり,:Vitalizerというコマンドをもうちょっとユーザフレンドリーにしてあげるといいのかなぁと個人的に思うのでなんとかしたいと思います. (去年くらい前から思っているのでつらい)

とにかく vital.vim 最高なので revital.vim と一緒に使っていきましょう.

速くなったというならまずはベンチマークじゃん?(雑)

スクリプト

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
command! -bar TimerStart let start_time = reltime()
command! -bar TimerEnd echo reltimestr(reltime(start_time)) | unlet start_time

function! s:_vital_of() abort
  let V = vital#of('incsearch')
  call V.load('Data.List')
  call V.unload()
endfunction

function! s:_vital_incsearch_of() abort
  let V = vital#incsearch#of()
  call V.load('Data.List')
  call V.unload()
endfunction

let s:times = 100

TimerStart
for _ in range(s:times)
  call s:_vital_of()
endfor
TimerEnd
" => 1.565324

TimerStart
for _ in range(s:times)
  call s:_vital_incsearch_of()
endfor
TimerEnd
" => 0.028437

結果: vital#of() と V.import(‘Data.List’) 相当を100回回したベンチマーク

vital.vim (x 100) revital.vim (x 100)
1.565324 sec 0.028437 sec

ref: https://github.com/haya14busa/incsearch.vim/pull/112#issue-142680963

速くなってますね!!!

(まぁ僕の環境ではもともと1回分にすると0.01秒くらいで全然遅いと感じたことなかったのですが)

上記のベンチマークは https://github.com/haya14busa/incsearch.vim のコードで回しましたが,https://github.com/easymotion/vim-easymotion や 手元でテスト用に作った全部のvital モジュールをインストールしたプラグインでも同じような結果になりました.

revital.vim の使い方

さぁこれだけ速くなってるならvital.vimを既に使ってる人なんかは特に revital.vim を使ってみたくなりましたよね? 使い方は簡単です.

わかってる人向けの簡単説明

  1. vital.vim で :Vitalize しておく
  2. revital.vim の :Revitalize コマンドを実行
  3. vital#of('{plugin-name}') の変わりに vital#{plugin-name}#of()を使う.

これだけです.インターフェースは vital.vim をそのまま使う場合とほとんど変わりません.

ちょっと丁寧な説明

a) モジュールをインストール

{pluginname} をあなたかが開発しているプラグインの名前に置き換えましょう.

  1. :cd /path/to/your/plugin プラグインのディレクトリに移動.もちろん shell で移動してから Vim を起動するとかコマンドで指定してもOK.
  2. :Vitalize --name={pluginname} . +Data.List Data.List モジュールを組み込んでみる
  3. --nameには.-が使えないので適宜vim-とか.vimとかいらない部分は削る.
  4. :Revitalize . Revitalize 実行!

b) モジュールの使い方

1
2
3
4
let s:V = vital#{pluginname}#of()
let s:List = s:V.import('Data.List')
echo s:List.uniq([1, 1, 2, 3, 1, 2])
" => [1, 2, 3]

簡単で vital.vim のみで使うケースとほとんど変わりません.

c) モジュールのアップデート

:Vitalizeでアップデートしたあとにもう一度 :Revitalize する必要があります.

  1. :cd /path/to/your/plugin プラグインのディレクトリに移動.
  2. :Vitalize . アップデートするときはこれだけ.
  3. :Revitalize . Revitalize 実行

どうして revitalize.vim は速いのか?

vital.vim はモジュールをロードする際(s:V.import('Module.Name'))に

  1. モジュール名から目的のファイルを探す
  2. そのファイルからモジュール用のオブジェクトを作る

というざっくり2段階が必要です.このうち1などはsimlinkをたどるといった関数が遅 いせいで結構な時間が環境によってはかかっていますし,2はそこまで遅くはない気もし ますがいろいろ内部でやっています.(ちゃんとprofileはしてない.) vital.vim の組み込みライブラリであるという性質上,普通にやるなら上記の段階が必要です. また歴史的経緯も含まれているかもしれないですが上記の2段階の前にはライブラリを ロードするためのローダーを同じような手順で作成する必要があります(vital#of({plugin-name})).

速くする方法はないものかなぁと考えると1つ思い当たります.

モジュール名から目的のファイルを Vim script で素早く探すのにはなかなか骨が折れますが,Vim script には autoload function という機能があり,autoload 関数をいい感じに定義しいい感じに呼 べば(path#to#module#file),対応したファイルを勝手に内部で見つけてきて関数を呼 んでくれるという仕組みが存在します.Vim script で頑張るよりも組み込み機能を 使ったほうが速いはずです!! autoload 関数使いたい!!!

しかし,autoload 関数をいい感じに定義する際にはファイルのパス情報が必要になります. ここでvital.vim は別のプラグインに組み込まれることが前提のライブラリなのでパスが定まっていません. よって autoload はそのままでは使えませんでした…

うーん.困ったな…

でもでも,よくよく考えてみると最初からパスが定まっていなくても,モジュールをプラグインに組み込んだあとのパスは決定しています. つまり,:Vitalize でモジュールをプラグインに組み込んだあとにモジュールのファイルに適切な autoload 関数を追加してしまえばいいのです.

もうわかったでしょか?

revital.vim が提供する :Revitalize コマンドは組み込んだモジュールのファイルに 適切なautoload関数を追加し, s:V.import('Module.Name') の内部では追加した autoload 関数を呼ぶようになっているのです. また,autoload関数を追加する際にモジュールのオブジェクトの雛形となるようなオブジェクトをついでに生成してやっているので, そのオブジェクトの生成するプロセス分も速くなっています.

最後にファイルを探したりといろいろと大変な vital#of({plugin-name}) の代わりに 直接 vital のローダーオブジェクトを返す vital#{plugin-name}#of() を作って revital.vim の仕事は終了です.

モジュールのファイルに autoload 関数を追加するというちょっと刺激的なハックをすることによって vital.vim のロードを爆速化することができました. ただモジュールのファイルといっても組み込んだあとのモジュールのファイルを書き換 えるだけなのでオリジナルのファイルは書き換えないし,これくらいのハックは別に問題ないかなと思います. 一応vitalモジュールのファイルの途中で :finish されると使えなくなるという問題がありますが,まずそんなケースはないでしょう.

本家に入れたいような気もするけど要相談?

確実に速くなるし,本家ではテストされてないような部分もテストしているので,少々 ランニングして安定すれば本家にオプションかなにかで入れてもいいんじゃないかなぁと思います.

しかし,一応入り口のインターフェースが変わることと,ちょっと実装にハック感があ ること,ドラスティックな変更なのでいろいろ待つよりもまずは実装して見てみるということで revital.vim を作ってみました.

後方互換性は崩さないような仕組みになっているので時が来たらvital.vim 本家に同じ機能が実装されるとよさがありますね.

おわり

haya14busa/revital.vim で vital.vim が爆速になるので vital.vim を使っている Vim プラグイン開発者各位や これから vital.vim を使ってみたいという 各位は是非お試しください!

「爆ぜろリアル! 弾けろシナプス! Rev!talize Th!s World!」

Vimのカーソル移動はもっともっと爆速になる! Vim-EasyMotion v3.0 をリリースしました

Vim-EasyMotion でウィンドウをまたいだ移動ができるようになりました!!!

easymotion/vim-easymotion

過去の関連記事

そして今回の記事はvim-easymotionのリポジトリがorganization持ちになって久々に便利機能追加したという記事になります.

vim-easymotionとはVimのカーソル移動をブラウザでいうHit-A-Hint機能のように行うカーソル移動改善系プラグインです. よく知らないよ〜という方はREADME眺めたり, 過去記事 (Vim-EasyMotionでカーソル移動を爆速にして生産性をもっと向上させる - haya14busa ) をさらっと読むと分かるかと思います.過去記事はn-key Find Motionの節以外はだいたい現役で使えると思います.

vim-easymotion v3.0

Release EasyMotion now supports moving cursor over/across windows · easymotion/vim-easymotion

vim-easymotionではこれまでカーソルと同一ウィンドウ内にしか移動できなかったのですが,v3.0でとうとう他のウィンドウにも移動できるようになりました! めでたい. 実はv3.0 で追加するメイン機能はこれだけなんですが,個人的にかなり気に入ってしまい,「これはメジャーバージョンアップするしかない」と思い勢いだけでバージョンあげています. 他にはバグフィックスとか細かい修正で,とくに後方互換性は壊してないはずなので気軽にアップデートできると思います.

追加したマッピング

mapping description
<Plug>(easymotion-overwin-f){char} {char} にマッチする位置を対象として移動
<Plug>(easymotion-overwin-f2){char}{char} {char}{char} にマッチする位置を対象として移動
<Plug>(easymotion-overwin-line) 行を対象として移動
<Plug>(easymotion-overwin-w) 単語の先頭を対象として移動

マッピング例

ヴィジュアルモードやオペレータ待機モードで他のウィンドウに移動するというのは意味をなさないので, 他のウィンドウに移動する overwin モーションは Normal モードのマッピングのみ提供しています.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
" <Leader>f{char} to move to {char}
map  <Leader>f <Plug>(easymotion-bd-f)
nmap <Leader>f <Plug>(easymotion-overwin-f)

" s{char}{char} to move to {char}{char}
nmap s <Plug>(easymotion-overwin-f2)
vmap s <Plug>(easymotion-bd-f2)

" Move to line
map <Leader>L <Plug>(easymotion-bd-jk)
nmap <Leader>L <Plug>(easymotion-overwin-line)

" Move to word
map  <Leader>w <Plug>(easymotion-bd-w)
nmap <Leader>w <Plug>(easymotion-overwin-w)

EasyMotion触ったことなくてミニマムに始めたい場合は上記設定から気に入ったもの + 以下の設定でデフォルトマッピングをオフにするとよいかなと思います.

1
let g:EasyMotion_do_mapping = 0

もしひとつだけおすすめするならnmap s <Plug>(easymotion-overwin-f2)がオススメです. このマッピングだと画面上の見えているところへならどこへでも s{char}{char}{hint}の4 キーストロークで移動できます. <Plug>(easymotion-overwin-f)<Plug>(easymotion-overwin-w)だと候補が多すぎてヒントを2回以上打たないとダメなケースがよくあるのですが, {char}{char}と2文字打つと候補が劇的に減ってヒントは大抵のケースで1文字入力するだけですみます.

incsearch.vim との連携

vim-easymotionには<Plug>(easymotion-sn)という N 文字入力してマッチした位置 を対象として移動するモーション,言わばeasymotionの検索(/)版マッピングを提供していたのですが, 今回,それのウィンドウ間移動できるマッピングは提供していません.

というのも,<Plug>(easymotion-sn)はVimデフォルトの検索との互換性が甘いところがあり, Vimの検索はもっともっと便利になる! incsearch.vim v2.0 をリリースしました - haya14busa の記事で紹介した incsearch.vim と vim-easymotion を連携させたほうが基本的に便利になっていて, こちらを推奨したいなという訳です.

必要なもの

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
" You can use other keymappings like <C-l> instead of <CR> if you want to
" use these mappings as default search and somtimes want to move cursor with
" EasyMotion.
function! s:incsearch_config(...) abort
  return incsearch#util#deepextend(deepcopy({
  \   'modules': [incsearch#config#easymotion#module({'overwin': 1})],
  \   'keymap': {
  \     "\<CR>": '<Over>(easymotion)'
  \   },
  \   'is_expr': 0
  \ }), get(a:, 1, {}))
endfunction

noremap <silent><expr> /  incsearch#go(<SID>incsearch_config())
noremap <silent><expr> ?  incsearch#go(<SID>incsearch_config({'command': '?'}))
noremap <silent><expr> g/ incsearch#go(<SID>incsearch_config({'is_stay': 1}))

<CR><C-l>とかにすることで普段は普通の incsearch.vim, <C-l>押した時に easymotion発動といったことができたりします.僕はそういう設定にしていて,便利につかえてます.

おまけ

incsearch-migemo 連携

haya14busa/incsearch-migemo.vim

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function! s:config_migemo(...) abort
  return extend(copy({
  \   'converters': [
  \     incsearch#config#migemo#converter(),
  \   ],
  \   'modules': [incsearch#config#easymotion#module({'overwin': 1})],
  \   'keymap': {"\<C-l>": '<Over>(easymotion)'},
  \   'is_expr': 0,
  \ }), get(a:, 1, {}))
endfunction

noremap <silent><expr> m/ incsearch#go(<SID>config_migemo())
noremap <silent><expr> m? incsearch#go(<SID>config_migemo({'command': '?'}))
noremap <silent><expr> mg/ incsearch#go(<SID>config_migemo({'is_stay': 1}))

fuzzy search で easymotion

1
2
3
4
5
6
7
8
9
10
11
function! s:config_easyfuzzymotion(...) abort
  return extend(copy({
  \   'converters': [incsearch#config#fuzzyword#converter()],
  \   'modules': [incsearch#config#easymotion#module({'overwin': 1})],
  \   'keymap': {"\<CR>": '<Over>(easymotion)'},
  \   'is_expr': 0,
  \   'is_stay': 1
  \ }), get(a:, 1, {}))
endfunction

noremap <silent><expr> <Space>/ incsearch#go(<SID>config_easyfuzzymotion())

実装とか背景の話

実はこのウィンドウをまたいだ移動についてはvim-easymotionの開発を引き継いだころからずっと欲しいなぁ〜やりたいな〜と思っていた待望の機能でした. emacs版easymotionである winterTTr/ace-jump-mode や atomのsmalls (ATOM - smalls つくった - Qiita)ではラベルジャンプでウィンドウ移動ができています.

どの拡張も,もともとはEasyMotion にインスパイアされて作ったもので,他の機能はともかく少なくともウィンドウ間をまたげるという一点ではvim-easymotionを上回っていました. ではなぜ,vim-easymotionでもやりたいなぁと思っていたのに,これまで実装できていなかったかというと, これは「vim-easymotionのコードがちょっと闇でつらかった…」というわけではなく Vim の機能でやるのがきつかったことに起因します. Vimにはオーバーレイで文字を表示するといった機能がないのでvim-easymotionでは一旦バッファの文字を書き換えて戻すという実装になっていました. この実装だと同じバッファを別ウィンドウに表示している場合にラベルがバッティングしてしまいます.

では今回どうしたかというと Vim の conceal 機能, :h syn-cchar を使っています. この機能を使えば直接バッファを書き換えずにラベルを表示できるので,同じバッファが別ウィンドウにあっても違ったラベルを表示することが可能です.

Conceal の syn-cchar つらい問題

しかし,このconcealでラベルを表示するというアイデア自体は以前からあって justinmk/vim-sneak がこのスタイルで表示しています(カーソルと同一ウィンドウだけですが). 前からアイデアを知っていたのにやれなかったのは,決して「vim-easymotionのコードがちょっと闇でつらかった…」というわけではなく conceal機能はかなり制限があってやりたいことができなさそうだなぁと長らく思っていたからです. というも,syn-ccharでは1文字しか表示できないし,空白行といった無の部分に文字を表示することができません. この制限からラベルが2文字以上の時でも1文字しか表示できなかったり, Tab文字や文字幅が2以上のマルチバイトの文字をラベルに置き換えるとラベル表示時に表示にズレが生じてしまいます.

結局「vim-easymotionのコードがちょっと闇でつらかった…」

じゃあどうすればいいかというと,ここまでの話・実装を組み合わせると実は答えは出ています. ラベルを表示するさいに対象が空白行や行末,マルチバイト文字であれば一旦スペースを追加またはスペースに置き換えてしまう前処理をすればOKです. そうすれば空白行や行末を対象とできるし,2文字のラベルも表示できるし,ラベルを表示した際に表示のズレが生じません! やったぜこれで理論上実装可能じゃん!

なぜこれに気づくのに時間がかかったのかというと結局「vim-easymotionのコードがちょっと闇でつらかった…」 のでしばらくeasymotionにまともに向き合ってなかったからでした. vim-easymotionはforkする前のもともとコードがそんなに綺麗じゃなかった上に, プログラミング自体ほとんど初心者だった僕が以前に便利な機能を追加したりVimとの互換性を保ったりすることと引き換えに, コードは比較的カオス状態になっていました. 僕の実装力ではこれを互換性を保った状態でリファクタして他のウィンドウへ移動する抜本的な機能改善なんて無理や… と内心思っていましたし,実際無理感あります. こういった理由でウィンドウ間移動という待望の機能は2年間ほど待望の機能であり続けました.

1から作って互換性意識すればいいんじゃん?

互換性保ちながらリファクタしていくのがつらいなら1から作って,インターフェースを既存のeasymotionと合わせればいいんじゃないか? と気付き,今回の機能は実装されました.

「パンがなければお菓子を食べればいいじゃない」に通ずるものがあります(ない)

これに気づいてやってみると,一旦動くところまで実装する程度なら1日程度で待望の機能が実装できました. やってみるものですね.

しかし,vim-easymotionを活発に開発していた2年前の僕にはできなかったかなぁと感じていて, これまでに incsearch.vim といった他のプラグインを作った知見や,他の Vim プラグイン開発者から得た知見, そして2年間でちょっと基本的な開発力があがったおかげで開発できたなぁと思います. みなさまありがとうございました.そして自分,まだまだですがちょっと頑張ったなって思いました.

開発の実装や背景の話と2年前に熱を入れて取り組んでいたvim-easymotionに今の自分が取り組んでみたらちょっと感慨深かったなという話でした.

おわりに

vim-easymotion, また一段と便利になったので是非使ってみてください!

僕はもうこの機能なしでは生きていけなさそうです.

あぁ〜カーソルがぴょんぴょんするんじゃぁ〜

2015年夏,はてなインターンでMackerelをとにかく便利にして優勝してきた

インターン終わったときに書きたかったのですが,バタバタしていたのと,イカ (Splatoon)という麻薬に犯されたので2015 年の振り返りとして書いています. 乗り遅れた感しかないけど記録として残しておきま す! 2015年全体の振り返りはこちら -> はてな,Googleインターン行ってイカやりすぎたイカVimmerの2015年の振り返り - haya14busa

今年の夏はどこかインターン行きたいなぁ〜,最高の夏を過ごしたいなぁ〜と思っていました. そんな時に はてなサマーインターン2015 情報, 特に今年は Scala や swift が書けるコースもある という話を聞いてこれは行きたい! と応募しました. その結果幸運なことに選考に受かったので8月10日から9月4日まで最高の夏を過ごしにはてなインターンに行ってきました.

はてなインターン TL;DR

  • 噂の(?)今年のインターン生の Emacs 率が0だった
  • 僕は言語がScalaのMackerelコースで, id:tyage くんさんと一緒に Mackerel を便利にして優勝してきましたっ! めでたいっ 🎉🎉🎉
  • はてなインターンで優秀なはてなの社員さんや他のインターン生の仲間と開発できたのは最高の体験でした.もっかい体験したい.

参考情報

はてなインターン応募と参加

一昨年の2013年夏にインターン探していたときも,はてなインターン卒業生のブログな どを読んで, はてなインターンよさそうだなぁ〜と思ってました.その時は能力たりな さすぎて無理だろう…というのと perl かぁ〜 という思いで応募すら出来ていま せんでした.

今年は言語が Scala (!)のコースができていたこともあったこと,一昨年よりはアルバイトでScala 書いたりとある程度経験値積んでいて,Vim でよければいくつかアピールできるようなものもあったので えいやっと応募しました.はてなインターンの選考では基本的にポートフォリオを提出するのみ だったのですが,ポートフォリオは8割 Vim でした.評価されてよかった…

ところで実際にインターンに参加してから思ったことは,もし仮に書く言語が perl だったとしても来たほうが良かったなということでした. もし来年度以降のインターン に応募しようと思っているけど perl がちょっとネック… くらいで参加を迷ってるな ら勢いで参加申し込んでもよいと思います.

結局僕は perl 1行も書きませんでしたが.Scala最高!!!(コンパイル爆速になればより…)

事前課題がScalaを基礎から勉強するのに最高

さて,晴れてはてなインターンに行けることになったらインターンまでの学習としてちょっとした事前課題が課されます.

この事前課題では perl か scala, それに JavaScript でいくつか課題が与えられ,問題を解いてテストを通していく形式でした. 事前課題は全体,課題ごとに課題のねらいが書いてあり,言語の基本を学ぶのに最高だと思いました.

Scala の課 題 は 与えられたログ用に Labeled Tab-separated Values (LTSV) パーサを書くという課題だったのですが,言語の基本やテストの仕方,テストの追加の 仕方はもちろんのこと,問題の性質上 エラーハンドリングをどうするか,Option型を 使うか,Either型を使うか,パース失敗時に エラーの行を収集するために scalaz でいう Validation 型を使えばベンリ なんじゃないか…!といろいろやりがいがありました. もっと言うと指定されたログの モデル以外にも対応できるような汎用的なLTSVパーサにしたら便利そうと思ったんですが そこまでは時間と実力が足りなくてできませんでした.残念.

LTSV パーサ,Scalaの課題としてよかったなぁと思います.

またこの事前課題は単にテストを通して提出すると終了…というわけではなくインターンの初日あたりに 講評が行われるのが最高でした.自分のコードはどう書けばよりよかったのか,他のインターン生は どう書いていてどこがよかったのかといったことも知れて便利でした.この講評はインターンの前半課題 でも行われました.

前半の講義がウェブ開発を基礎から勉強するのに最高

スケジュール

  • 1日目 Perl/Scalaによるプログラミングの基礎
  • 2日目 Perl/Scalaによるデータベースプログラミング
  • 3日目 Perl/ScalaによるWebアプリケーション開発
  • 4日目 JavaScriptによるイベント・ドリブンプログラミング
  • 5日目 自由課題
  • 6日目 インフラ
  • 7日目 SwiftでのiOSアプリ開発

前半の講義パートは言語の基礎からWebアプリケーション,インフラ,それにSwift コースや希望者はSwiftのiOSアプリ開発までを1週間で学べるようになっていました. それぞれのコースのインターン生ごとにメンターさんがついてくれます.僕の場合は id:sixeight さん でした.

毎日課題が課されてそれをメンターさんに質問したり,レビューを受けたり,講評をも らったりとヒイヒイこなして行くことで後半に向けて基礎力を向上できる仕組みになってい ました.大変でしたが楽しかった…!

課題としては自由課題が最後で,その内容はそれまでに学んできた技術と課題で作って きたブログシステムを活かして好きなWeb アプリケーションを作るというものでした.

ここで作ったサービスは社内で投票で順位もつく前半の集大成という課題で厳しくも楽 しい,燃える課題となっていました.僕はあんまり独創的なアイデアのなくこれがあれ ばベンリやろ〜というノリでちょっとしたものしか作れなかったのですが,他のイン ターン生のアプリケーションのクオリティが高くて刺激になりました.

完全に言い訳になるのですが僕は自由課題の日の前の土日で開催されたオープンイン ターネッツに公開されてない,はてなで行われたもくもく回ハッカソンで途中まで 作ってた Vim script版 power-assert に夢中になってました. 他のインターン生のつくったサービスをみてもっと自由課題に力入れればよかった…と 思ったので来年度以降はてなインターンへの参加を考えている各位は前半最後の自由 課題はやりがいあってよいよ!と言っておきます.

後半の実践パートでサービスにコミットしていく実践経験が得られて最高

実践パート - はてなサマーインターン2015 レポートサイト

今年から前半/後半の比率が代わり前半が少し短く,その分後半の実践パートが長く なったようです.開発に時間がとれてベンリ.

後半は僕は id:tyage くんさんと一緒にMackerelコースに配属され, ちょっとしたバグ修正によるインターン生最速リリース(ちょっとズルイ)から始まり4つほ ど多方面からMackerelの機能改善や新機能のリリースを行い,最終成果発表で1位を獲得できました!

だいたい id:tyage くんやメンターの id:sixeightさんをはじめとするMackerelチーム の皆さんのおかげでした.

id:tyage くんさんはインターンまでScalaほとんど書いてなかったらしいのに, 後半過程では1年くらいScala経験あった僕と同じかそれ以上のレベルでScalaかけちゃうし, JavaScriptまわりでペアプロして相談しても的確に正しい方向に導いていってくれるし最強かよ〜という感じでした. id:tyage くんさんとのペアプロ,最高に便利体験でした.

id:sixeightさんやMackerelチームの方には 方針を一緒に考えてもらったり,ダメなところをダメと指摘してもらったり,実装・仕様の相談をさせてもらったりと, 最高の体験でした.

id:tyageくんや優秀なMackerelチームのメンバーと 少しの間とは言えチームとして働く経験ができて,しかも最後には優勝というおまけまでついてきて 最高の夏を過ごせました.ありがとうございました!

はてなインターン最高でした

上述したカリキュラム上の話だけじゃなく毎日おいしいはてなのまかないをはてなの社員さんと お話しながら食べたり,他の優秀なインターン生の話を聞いたり,実力を垣間見たり, インターン途中に参加したYAPCや社内TGIF,ごはん連れてってもらったりしたときにはてなの社員さんの 話を聞いたりなどなど,最高の夏を過ごせました.

逆に慣れなかったことといえばはてなの 「シュッと」 っという言葉だけは いやいや「サッと」とかのほうが馴染むじゃん…?とあんまり慣れな かったのですが, インターン終わってから「シュッと」,いいじゃん使いやすいじゃん…? となぜかインターン終わってから馴染むようになってしまいました.不思議だ…

他のインターン生の紹介

イカしたやつらを紹介するぜ! ってやつ.終始凄い人多すぎてびびってました… 僕も頑張りたい.

最高の夏〜

はてな,Googleインターン行ってイカやりすぎたイカVimmerの2015年の振り返り

今年は4月から大きく環境が変わったり,インターンに行ったりちょくちょくVim活したりイカ(Splatoon)したりと振り返ってみる と色んな事がありました.

最初にネタバレをすると最も進捗があったのは Splatoon で最高ウデマエS+90まで行ったことでした.

マンメンミ!

去年や一昨年の

今年はプログラミング初めてからだいたい3年目でした.もう初心者とか言ってられないようになって気がしますが,まだまだ勉強不足・力不足すぎるので精進したい.

はてなサマーインターン

長くなったので記事分けた -> 2015年夏,はてなインターンでMackerelをとにかく便利にして優勝してきた - haya14busa

最高の夏〜

Google Japan Software Engineer インターン

はてなインターンが終わった後,3ヶ月ほどGoogle Japanのインターンに行っていました. Googleは内側ではオープンで全然違う国の違うチームの情報を見れたりするオープンさなのですが, 外側にはオープンではないので基本的にブログに書いたらだめっぽい,というか線引きがわ からないので参加した内容に関する感想は書けません…残念…

Googleの優秀なエンジニアさんたちとGoogleという会社で開発できたのは学びもやりが いもたくさんあって最高の体験でした.

インターン対策とか競技プログラミング

はてなとGoogle以外にもいくつか応募して受かったり落ちたりしたのですが, そのうち1回ホワイトボードコーディング面接があり,超基本的なことを聞かれているの にぜんぜん答えられない…という苦い経験がありました.

頭のどこかで僕は情報学部じゃなかったし,プログラミングも独学で好きなことやってる段階だし 基礎的も知らなくてもまだ仕方ない…と思ってた節があったりしました. しかしこれは完全に言い訳です. 基礎は土台.最低限理解して説明できる程度にはなってないと面接とか関係なく マズいな…と思いデータ構造,アルゴリズムなど勉強しなおしました.

その一環として前から興味はあったんだけどなかなか手がでなかった競技プログラミングにも今年はちょくちょく手をだしはじめました. 最近ちょっとイカしすぎておろそかになってますがやっていきたいです.

面接対策でつかった本とか

世界で闘うプログラミング力を鍛える150問

The Joel on Software 採用面接ゲリラガイド

採用面接ゲリラガイド(version 3.0) - The Joel on Software Translation Project)

Vim 活

incsearch.vim v2.0

incsearch.vimをカイゼンしてv2.0にしてました.もっと昔にやってた気がするけど今年 の7月でした.リファクタリングしてコンポーザブルにしたりと拡張性をましてincsearch.vimをより便利にできました.

vital-power-assert と VimConf | Vim script 版 powerassert!

はてなインターン中に作ってその後もちょくちょくと触ってました.またVimConfで発表したりもしました.

去年も大概だったのですが今年は個人的にVimConfに向けての準備がゼンゼン足りてなくて来年こそはちゃんとするゾ!!という気持ちです.

underscore.vim

underscore.jsのVim scriptバージョンを作ってました.実装は去年からなんだかんだやっていましたがエイプリルフールにリリースしました. 実用性がないわけではないけど,ラムダが無いとかスコープの関係上凝ったことしようとすると微妙に使いづらいのが残念ですが開発してて面白かったです.

勢い Vim プラグイン系

niconicomment.vim

niconicomment2.gif (1366×747)

思い出したように実行すると面白い.

vim-undoreplay

undoreplay_fizzbuzz2.gif (1366×747)

思い出したように実行すると面白い2.

vital.vim にPullRequest

vim-jp/vital.vim というVim scriptのライブラリにいくつか欲しいモジュールをPRで送ったりした. Vim.ScriptLocal は Vim scriptのスクリプトローカル変数を外からハックするモジュールでVim scriptのテストフレームワークである thinca/vim-themis で使ってもらったりした. 他にはPythonあたりにある便利なデータ構造をVim scriptにポートする業などしていました.

Vim Advent Calendar

前から自分が欲しかった,まとめたかった記事を書きました.今までで最高ブクマ数を頂いてありがたい.

vim-operator-flashy

年末駆け込みプラグイン.VimConfでt9mdさんが開発してる t9md/atom-vim-mode-plus でヤンク対象を フラッシュしていてわかりやすいというのを見せて頂いたのがきっかけになってます. 地味にUX向上してよい.

参加・発表したミートアップ・勉強会系

YAPC

YAPCに初めて参加しました.学生無料便利すぎました.LT発表は応募したのですが残念ながら落ちて残念.

Yokohama.vim

Yokohama.vimではなぜか基調講演という名の戦犯をしてきました. 内容はYAPCでしようとしていたVim駆動学習の話の微調整という感じでした. ちゃんと基調講演と言えるような発表をできるようになってまたYokohama.vim参加したい.

VimConf 2015

上述した.

fpinscala読書会完走

大阪で定期的に開催されていたfpinscala読書会でFunctional Programming in Scalaを(一応)読了しました. が,まだまだ理解しきれてないところ,飛ばしたところなどたくさんあるので2週目に参加してしっかり 関数型プログラミング身につけたいなと思います.

GitHub 記録

あんまり大したことできてなかった

Splatoon

Splatoon S+ 90

インターン中に買ってインターン終了までにS+になるという目標は達成したのですが, 年内にカンストするという目標は残念ながらできませんでした. しかし,今年の後半は本当にイカしかやってないというベルでやっていてイカ進捗が一番でてました. イカちゃん楽しすぎる…

よかったらみなさん一緒にイカしましょう!

その他

ちょくちょくReact触ったり, 引き続きScala書いたり, golang はじめたりしましたが, OSSっぽいこと,ここに書くようなことはほとんどできませんでした.

最後に

今年は環境が変わっただとか,インターン長期間行ってたとか,Splatoonやってたとか で特に今年後半はあんまり見える活動できてなかったです.もっと頑張りたい.

去年も似たようなこと言ってたような気がしますが来年はVimはもちろんのことVim以外のこともやっていきたいなぁと思います. あともう少し大きいレベルで目標を定めてそれに向かってやれるとよさそう(まだふわふわだけど真剣に考えなきゃ…).

それと今年最も苦労して迷惑かけたのは英語ではないかという説があるので, 来年は英語でコミュニケーションとれるように頑張って勉強していきたいですね.

以上, @haya14busa の 2015年の振り返り記録でした.

来年もイカよろしく〜

Vim Mnemonic | Vim のコマンドの覚え方大全

この記事は Vim Advent Calendar 2015 の21日目の記事です.

もくてき

本記事では Vim のコマンドの”覚え方”を紹介します. 基本的にはトリッキーな”覚え方”ではなく由来の紹介となります. 例えば J で行連結は Join が元だとか, gfが”goto file”の略だといったことを 知っておくとなにかと憶えやすいと思います.

対象読者

主にこれから Vim を使ってみよう! でもなかなかコマンドを覚えられないっ! という Vim 初心者の方に由来を知ることで少しでも コマンドを憶えやすいようにすることが目的です. 初心者を想定しているのでコマンドの動作などもなるべく紹介していきます.

中・上級者の方には普段何気なく使ってたあのコマンドの由来を知って「フハハハハ」と ほくそ笑んでもらえるような記事になれば嬉しいです.

注意

注意点として公式のものから公式っぽいもの,独自の調査結果によるものなど信憑性はまちまちです. そしてVimのコマンドは無数にあるので覚え方大全と言っておきながらすべてを網羅できているわけではなくかなり偏っています. 抜けてるものとか間違ってるものとか俺はこう覚えてるぜ!というものがあったら教えてください!

出典は

  • ヘルプファイル
  • ソースコード
  • 出典不明だけどどこかで見聞きした話

などです.基本英語に直して理解する方針のものが多いです.

またこれからたくさんのコマンドを羅列していきますがすべてを覚える必要は一切ないこと, そして逆にここに載ってない便利な覚えるべきVimコマンドはきっとたくさんあるので覚えようと気負ったり, だいたいわかるからokと思ったりしないようにおねがいします.

そして何よりの注意点としては結局覚え方よりも実際にやってみることが大事だということです!!!

ただ単にやってみるだけでなく由来や覚え方も知ることでより憶えやすくなったらよいなというのが本記事の趣旨なので, 深く考えすぎずにそうなんだ〜へぇ〜と思いながら読むとよいと思います.

ではスタートっ

基本のカーソル移動 hjkl

vimtutor Lesson1

        ^
        k              Hint:  The h key is at the left and moves left.
  < h       l >               The l key is at the right and moves right.
        j                     The j key looks like a down arrow.
        v

出典: vimtutor

右手のホームポジションから1つ左にあるのでhは左方向に移動し, 右にあるlが右方向への移動です. jはどことなく(下矢印)に似ているので下方向に移動すると憶えましょう. kに関してはどことなく上にとんがってるので上方向に移動すると考えてもいいかも知れません.

もともとのhjklの由来

viの開発者であるビル・ジョイさんが 当時使っていたPCがADM-3A - Wikipedia, the free encyclopediaであり, そのキーボードには矢印キーはなくHJKLを使ってカーソルを移動していたのが由来とのこと.

931px-KB_Terminal_ADM3A.svg.png (931×301)

この由来は知っても憶えやすくならない単なる豆知識でした.

VIM の保存,終了と! (<bang>)

コマンド 説明と由来 help
:q :q[uit] カレントウィンドウを閉じる.quit から :h :q
:qa :qa[ll] quit all から. :h :qa
:q!, :qa! バッファに変更点があっても閉じる. quit + !
:w :w[rite] バッファ全体をカレントファイルに書き込む.writeから :h :w
:wq :wqall :w:qの組み合わせ :h :wq

コマンド末尾の!

:h :command-bang

Vim のコマンドは!修飾子を取ることができ,!の有無によって動作が変わる場合があります. 基本的には強制的に実行するという意味合いが多いので憶えておくと未知のコマンド + !に出会った時に びっくりしないですみますね.

挿入コマンド

コマンド 説明と由来 help
i カーソルの前にテキストを[count]回挿入する.insertから :h i
I 行の先頭の非空白文字の前にテキストを[count]回挿入する.insertの大文字バージョン.大文字は行指向になるパターンが多い印象 :h I
a カーソルの後ろにテキストを[count]回追加する.appendから :h a
A 行末にテキストを[count]回追加する. appendの大文字バージョン :h A
o カーソルのある行の下に新しい行を作り、そこにテキストを[count]回繰り返し挿入する.open line から. :h o
O カーソルのある行の上に新しい行を作り、そこにテキストを[count]回繰り返し挿入する.open line の大文字バージョン. :h O
gi 最後に入力がされた場所にテキストを入力. goto last insert position and start insert と思ってたがgは単なるprefixかも.後述するgvgiのヴィジュアル版っぽい :h gi

モーション,オペレータ, テキストオブジェクト, ヴィジュアルモードについて

個々のモーション(hjlk, w, etc…)やオペレータ(d,c, y…)について それぞれ説明する前に全体的な動作について理解しておくと覚えることが減って, しかもとても便利なのでぜひ理解しましょう.

モーション {motion}

  [count] {motion}

:h motion.txt

モーションとはカーソル移動コマンドです.[count]を前置すると[count] x {motion}分だけ移動します. すでに見たhjklももちろんモーションなので4hなどすると左に4文字移動するという意味になります.

オペレータ {operator} とモーション {motion}

:h operator

d2w.gif (661×157)

  {operator} {motion}

厳密にはカウントを{operator},{motion}のそれぞれに前置することができるので以下のようになります. ([count]を両者に前置させると掛け算になります. 2d3w -> 6つの単語を削除. 普通に6dwd6wとしたほうが基本的にわかりやすそうですね)

  [count] {operator} [count] {motion}

またオペレータによってはレジスタを前置できます.:h registers

  ["x] [count] {operator} [count] {motion}

Vimは変更する,削除するといった操作を表すオペレータ{operator}と, その操作の適用範囲であるモーション{motion}を組み合わせることでテキストを編集できます. 先ほどみた{motion}に操作を加えている形になっています.

オペレータ {operator} とテキストオブジェクト {text-objects}

:h text-objects

di'.gif (657×128)

  {operator} {text-objects}

また,移動コマンドとしては使えないけれど{operator}と組み合わせた時の操作範囲 となるテキストオブジェクトを先ほどの{motion}の代わりに使うことができます. 例えば文字列の中身を削除(オペレータの1つ)したい場合の”文字列の中身”は移動するような概念 ではないですが,オペレータの操作対象として妥当です.

ヴィジュアルモード とモーション,テキストオブジェクト

そして厳密にはオペレータではないですがヴィジュアルモードでもモーションやテキストオブジェクトと 組み合わせることができ,対象の範囲を選択できます.

vi'.gif (657×177)

  {visual-operation} {motion|text-objects}

ヴィジュアルモードを”選択する”という”操作”とみれば自然に理解できるかと思います.

オペレータの対象範囲としてのヴィジュアル選択範囲 {Visual}

そしてヴィジュアルモードで選択した範囲{Visual}{motion}{text-objects} と同様にオペレータの対象範囲として使えます.

  {Visual} {operator}

{operator}{operator} は行指向オペレーション!

gqq.gif (1131×312)

  [count] {operator} {operator}

そして上記の組み合わせの特殊なケースとしてオペレータ (2コマンド以上のオペレータの場合は最後の文字のみでも可), を繰り返して入力すると操作範囲が行指向になります.

例えばddyy といったオペレータを繰り返すと行を削除したりヤンクできるといった具合です.

僕が観測している範囲ではこの挙動はddyyといった基本的な編集オペレータだけでなく, 全てのオペレータに当てはまっているので憶えておくと便利です.(ソースコードは読んでないので確証がない.)

例えば2文字のオペレータであるgq(:h gq)は gqqgqgqと打つことでカーソル下の行を整形できたりします.

1つの変更単位としての {operator} {motion|text-objects}

Vim のおすすめコマンド10選!!! として “diw でカーソル下の単語を消す” といったここで述べた オペレータとテキストオブジェクトをいっしょにまとめたものを1つのコマンドとして 紹介するような記事がたくさんあったりしますが,これらは1つのコマンドでもなんでもないです. オペレータやモーション,テキストオブジェクトの概念を理解すれば無限大の組み合わせをそれぞれ 覚える必要はなく,便利なオペレータとモーションを別々に覚えてそれらを組み合わせればよいです.

これは覚え方とはまた別ですが上述したオペレータとモーション,テキストオブジェクトの組み合わせは 1つの”変更単位”となっておりドット.コマンドで同じ操作を繰り返すことも可能です (:h .).

説明が長くなりましたが,ここからそれぞれのオペレータやモーションの覚え方について見ていきましょう.

オペレータ {operator}

コマンド 説明と由来 help
c 変更する.changeから. :h c
d 削除する.deleteから. :h d
y コピーする.yankから. :h y
gU 大文字にする.おそらくprefixとしてg + Uppercaseから. 大文字にマッチする正規表現の \U :h gU
gu 小文字にする.おそらくgUの逆で小文字にするから.小文字にマッチする正規表現の \u :h gu
> 右にインデントをシフトする.見た目から?. :h <
< 左にインデントをシフトする.見た目から?. :h >
zf 折畳を作成する.zは後述するが”z” は紙片を折った様子を横からみた姿に見えるから.fは折りたたみを作成するのが一番基本コマンドと考えてfoldから? :h zf

他にも由来わからないけど便利なオペレータはあるので使って憶えましょう.個人的に憶えておくと便利そうなものをリストアップ.

コマンド 説明と由来 help
= フィルタ処理. インデント整形 :h =
gq 整形する.80文字で折り返すよう整形とかできる :h gq

先ほどオペレータを連続させると対象が行指向になると説明したように, ccなら行を変更,==gqqで行を整形できます.個別に覚える必要はないですね.

また ヴィジュアルモードでの<>を連続で操作するために下記のようなマッピング をしている人もいますが,他の選択範囲に対するオペレータによる操作となんら変わらないので 代わりにドットリピート.を使って繰り返すことができます.

1
2
vnoremap > >gv
vnoremap < <gv

ちょっと脱線してその他の変更コマンド系

c, d, y, gU…の他にもオペレータではない変更系コマンドがたくさんあります.:h change

コマンド 説明と由来 help
C 行末まで変更する.changeの大文字バージョン. :h C
D 行末まで削除する.deleteの大文字バージョン. :h D
Y 行をコピーする.yankの大文字バージョン.viの互換性から行末までではなく行. :h Y
p テキストをレジスタから貼付ける.put から.paste と憶えてもよさそう :h p
P カーソルの前にテキストを貼り付ける. pの逆 :h P
x カーソル下の文字を削除. バツマークに似てるから? :h x
X カーソルの前の文字を削除. xの逆 :h x
s カーソル下の文字を削除して挿入を始める. substituteから. :h s
S 行を削除して挿入を始める. sの大文字バージョン. :h S
r カーソル下の文字を置き換える. replaceから. :h r
R 置換モードに入る. replaceから. :h R
gr gR r, Rの仮想文字バージョン. g prefix :h gr :h gR
J, gJ 行を連結する. Join から :h J
:s/// 置換コマンド. 省略しないとsubstitute :h :substitute

由来ナゾ変更コマンド

コマンド 説明と由来 help
<C-a> カーソルの下または後の数またはアルファベットに [count] を加える. addから? :h CTRL-A
<C-x> カーソルの下または後の数またはアルファベットに [count] を減じる. 英語ではsubtractなので何故xかは不明.CTRL-Sが端末によっては使えない.XAに近いから? :h CTRL-A

モーション {motion}

:h motion.txt

左右の移動

コマンド 説明と由来 help
0 その行の最初の文字に移動. 0文字目??? :h 0
^ その行の最初の文字に移動. 正規表現の^ :h ^
$ その行の最後の文字に移動. 正規表現の$ :h $
g0 g^ g$ それぞれのスクリーン行バージョン(折り返し考慮)
gm スクリーンの幅の真ん中に移動. midleから.出典: ソースコード. middle of “g0” and “g$”. :h gm
f{char} 右に向かって [count] 番目に現れる {char} に移動.findから…と思いきやヘルプ/ソースコード的にはfindとは一切書いてない.確かにfindに移動するニュアンスはないか…? :h f
F{char} fの左に向かうバージョン. :h F
t{char} 右に向かって [count] 番目に現れる {char} まで移動.till(〜まで) から :h f
T{char} tの左バージョン :h f

由来ナゾ

コマンド 説明と由来 help
; [count] 回最後の f, t, F, T を繰り返す. 余った記号で;を順方向,,を逆方向にした? :h ;
, [count] 回最後の f, t, F, T を反対方向に繰り返す. :h ,

上下の移動

コマンド 説明と由来 help
G [count] 行目の最初の非空白文字に移動.カウントがなければ最後の行. Goto から :h G
gg [count] 行目の最初の非空白文字に移動.カウントがなければ最初の行. goto から :h gg
{count}% ファイルの {count} パーセントの位置に移動.そのままパーセントで直感的! :h %

単語単位の移動

コマンド 説明と由来 help
w [count] words前方に移動. word から :h w :h word
W [count] WORDS(非空白文字の連続)前方に移動. word から :h G :h WORD
e [count] word 前方の単語の終わりに移動. end of word から :h e
E [count] WORD 前方の単語の終わりに移動. End of WORD から :h E
b [count] words後方に移動. backward から :h b
B [count] WORDS後方に移動. backward から :h B
ge [count] word 後方の単語の終わりに移動. g prefix + end of word から :h ge
gE [count] WORD 後方の単語の終わりに移動. g prefix + End of WORD から :h gE

オブジェクト単位で移動

3つのオブジェクト, sentence(文), paragraph(段落), section(セクション) が存在し,それぞれ(), {}, []が対応する. セクションのみ少し例外で1桁目の’{‘ か ’}‘への移動を2コマンド目で表現する.

他に特に覚え方はわからないので表は省略.

:h object-motions

ジャンプ

コマンド 説明と由来 help
CTRL-O ジャンプリストの中の [count] だけ古いカーソル位置に移動({motion}ではない). Older cursor position から :h CTRL-O
CTRL-I ジャンプリストの中の [count] だけ新しいカーソル位置に移動({motion}ではない). キーボードでOの左にIがある :h CTRL-I
g; 変更リスト中の [count] 個前の位置に移動. ;が順方向への移動っぽい :h g;
g, 変更リスト中の [count] 個後の位置に移動. ,が逆方向への移動っぽい :h g,

様々な移動

コマンド 説明と由来 help
% 対応するアイテム([{}])にジャンプ. percent と parentheses(丸括弧) をかけている? %の文字が/を挟んで対応したがあると憶えてもよいかも :h %
H スクリーンの最上行から [count] 行目(デフォルト: スクリーンの最上行)に移動, Home(top) of window とhelpに書いてあるがhomeってそんなニュアンスあるんだろうか… High と覚えてもよいかもしれない. :h H
M スクリーンの中央に移動.Middle line of windowから :h M
L スクリーンの最下行から [count] 行目(デフォルト: スクリーンの最下行)に移動.Last line on the windowから.HHighと覚えた場合はLLowと覚えてもよいかも :h L

角括弧コマンド: [ + “?”, ] + “?” 系

:h [

ブロックやメソッド,コメントといった何かしら決められたものの始まり,終わりに移動する. “?”には({mM#*/などが入る.

コマンド 説明と由来
[{, [(, ]} or ]) マッチしない ‘{’, ‘(’, ‘}’ ‘)’ に移動
[#, ]# マッチしない #if..#endif の最初か最後に移動.
[/, [*, ]/, ]* Cスタイルコメントの最初か最後に移動.
[m or ]m Javaスタイルメソッドの最初に移動.
[M or ]M Javaスタイルメソッドの最後に移動.

テキストオブジェクト {text-objects}

基本的なテキストオブジェクトはi, aの2種類がそれぞれprefixとしてつくものが多い. iinner(内部)を表し,aa(1つの)まとまり(“a”n object)を表している. iinside, aのをオブジェクトのaround(まわり)まで含むと覚えてたりしてもよいと思いますが公式は”inner”と”a”です.

コマンド 説明と由来 help
aw, iw wordを選択. “a word”, “inner word”. aは周りのホワイトスペースを含む :h aw :h iw
aW, iW WORDを選択. “a WORD”, “inner WORD” :h aW :h iW
as, is “sentence”(文)を選択 :h as :h is
ap, ip “paragraph”(段落)を選択 :h ap :h ip
ab, a(, a), ib i(, i) (,)ブロック,またはその内部を選択. braces block から :h ab
aB, a{, a}, iB i{, i} {,}ブロック,またはその内部を選択. Brackets block から :h aB
a[, a], i[, i] [,]ブロック,またはその内部を選択 :h a[
a<, a>, i<, i> <,>ブロック,またはその内部を選択 :h at :h it
a", a', a`, i", i', i` 前の引用符から次の引用符まで, またはその内部を選択 :h aquote
gn 最後に使われた検索パターンを前方/後方検索してマッチを選択. g prefix + n, Nから :h gn :h gN

テキストオブジェクトの部分をハイライトした例 textobjects-example.gif (1366×721)

削除オペレータとの組み合わせ例

コマンド 動作
“dl” 1文字削除 (“x” と同じです)
“diw” inner word を削除
“daw” a word を削除
“diW” inner WORD を削除 (参照: |WORD|)
“daW” a WORD を削除 (参照: |WORD|)
“dgn” 次に検索パターンにマッチするものを削除
“dd” 1行削除
“dis” inner sentence を削除
“das” a sentence を削除
“dib” inner ‘(’ ‘)’ block を削除
“dab” a ‘(’ ‘)’ block を削除
“dip” inner paragraph を削除
“dap” a paragraph を削除
“diB” inner ‘{’ ‘}’ Block を削除
“daB” a ‘{’ ‘}’ Block を削除

検索コマンド

コマンド 説明と由来 help
/ 前方検索.由来はナゾ :h /
? 後方検索.SHIFT + //の逆から :h ?
n 最後の “/” か “?” を [count] 回繰り返す.next から :h n
N 最後の “/” か “?” を逆方向に [count] 回繰り返す.nの大文字でnの逆 :h N
* カーソルに最も近い単語で前方検索.USキーボードで4段目右手の中指 :h *
# カーソルに最も近い単語で後方検索.USキーボードで4段目左手の中指 :h #
g* g# *, # の”\<“ と ”>“(単語区切り)を加えないバージョン :h g*
gd カーソルからローカル宣言を検索.goto + declaration から. :h gd
gD カーソルからグローバル宣言を検索.gdの大文字バージョン :h gD

スクロールコマンド

上/下方スクロール

                                 +----------------+
                                 | some text      |
                                 | some text      |
                                 | some text      |
  +---------------+              | some text      |
  | some text     |  CTRL-U  --> |                |
  |               |              | 123456         |
  | 123456        |              +----------------+
  | 7890          |
  |               |              +----------------+
  | example       |  CTRL-D -->  | 7890           |
  +---------------+              |                |
                                 | example        |
                                 | example        |
                                 | example        |
                                 | example        |
                                 +----------------+
コマンド 説明と由来 help
CTRL-E 下へ[count]行ウィンドウをスクロール.Extra lines から(vimdocでは割増との訳注あり. 追加の行?) :h CTRL-E
CTRL-Y 上へ[count]行ウィンドウをスクロール.由来ナゾ… :h CTRL-Y
CTRL-D ウィンドウをバッファ内で下にスクリーンの半分スクロールする.Scroll Downwards から :h CTRL-D
CTRL-U ウィンドウをバッファ内で上にスクリーンの半分スクロールする.Scroll Upwards から :h CTRL-U
CTRL-F ページ前方(下方)にスクロール.Scroll Forwards から :h CTRL-F
CTRL-B ページ後方(上方)にスクロール.Scroll Backwards から :h CTRL-B

カーソル相関スクロール

  +------------------+            +------------------+
  | some text        |            | some text        |
  | some text        |            | some text        |
  | some text        |            | some text        |
  | some text        |  zz  -->   | line with cursor |
  | some text        |            | some text        |
  | some text        |            | some text        |
  | line with cursor |            | some text        |
  +------------------+            +------------------+
コマンド 説明と由来 help
zt [count]行(省略時はカーソルのある行)をウィンドウの最上行にして再描画. z prefix + top of window から :h zt
zz [count]行(省略時はカーソルのある行)をウィンドウの中央にして再描画. 由来はナゾ… :h zz
zb [count]行(省略時はカーソルのある行)をウィンドウの最下行にして再描画. z prefix + bottom of window から :h zz

折畳コマンド

全ての折畳コマンドは z で始まっている.z は紙片を折った様子を横からみた姿に見える.

コマンド 説明と由来 help
zf 折畳を作成する.(再掲) fは折りたたみを作成するのが一番基本コマンドと考えてfoldから? :h zf
zd 折畳を1つ削除する. delete から :h zd
zD 折畳を再帰的に削除する. 折りたたみコマンドにおける大文字は”再帰的”, “すべて”といった意味合いのものが多い :h zD
zE 折畳をすべて削除する. Eliminate から :h zE
zo 折畳を1つ開く. open から :h zo
zO 折畳を再帰的に開く. zoの大文字版 :h zO
zc 折畳を1つ閉じる. close から :h zc
zC 折畳を再帰的に閉じる. zcの大文字版 :h zC
za 折畳をトグル(開いていたら閉じ,閉じていたら開く). 由来はナゾ… :h za
zA 折畳を再帰的にトグル. zaの大文字版 :h za
zv カーソルのある行がちょうど表示されるレベルまで折畳を開く. View cursor から :h zv
zx, zX 折畳を更新する. 由来はナゾ…というかそもそもhelp読んでも動作がいまいちわからない… :h zx
zm 折畳をより閉じる(‘foldlevel’ を1減少させる) Fold More から :h zm
zM 全ての折畳を閉じる(‘foldlevel’ に0を設定する) zm の大文字版 :h zM
zr 折畳をより開く(‘foldlevel’ を1増加させる) Reduce folding から :h zr
zR 全ての折畳を開く(‘foldlevel’ に最大の折畳レベルを設定する) zr の大文字版 :h zR
zn 折畳しない(‘foldenable’ をリセットする。全ての折畳が開かれる) Fold none から :h zn
zN 折畳する(‘foldenable’ をセットする。全ての折畳が ‘foldenable’がリセットされる以前と同様になる) Fold normalから.しかしnが2つあって正直意味ない… :h zN
zi ‘foldenable’ を反転する. Invert から :h zi
[z, ]z 現在の開いている折畳の先頭/末尾へ移動する.角括弧コマンド(:h [)は似た動作をする :h z[
zj カーソルより下方の折畳へ移動. 折りたたみにおけるhjklj移動 :h zj
zk カーソルより上方の折畳へ移動. 折りたたみにおけるhjklk移動 :h zk

(zxとかzn,zNなどは覚えなくてもたいていの動作に支障ないのではという気がする...)

undo と redo のコマンド

コマンド 説明と由来 help
u [count] 個の変更を元に戻す.undo から :h u
CTRL-R undo された変更を [count] 個やり直す.redo から :h CTRL-R

ビジュアルモード

コマンド 説明と由来 help
v 文字単位のビジュアルモードを開始する.visualから :h v
V 行単位のビジュアルモードを開始する.vの大文字版 :h V
CTRL-V 矩形ビジュアルモードを開始する.vのctrl版 :h CTRL-V
gv 最後に使用したのと同じ範囲のビジュアルモードを開始する. gotoか単なるprefix. 最後に入力がされた場所にテキストを入力するgiのヴィジュアル版と言える :h gv
v_o 選択されたテキストのもう一方の端へ移動する.Go to other end of highlighted text から :h v_o
v_O 選択されたテキストのもう一方の端へ移動する.矩形選択では行内のもう一方のコーナーに移動する.Go to other end of highlighted text から :h v_O

その他

すべてのコマンドを体型的に網羅するとを諦めてその他で残りの言及すべきっぽいコマンドをいっしょくたにまとめる男の姿がそこにはあった…

コマンド 説明と由来 help
CTRL-W + “?” ウィンドウコマンド. Window commandsから. Windowの操作や”?“の結果を新規ウィンドウで開いたりする :h CTRL-W
i_CTRL-R c_CTRL-R レジスタの内容を挿入する. Registerから :h i_CTRL-R
gf カーソルの下か後ろの名前のファイルを編集する. goto file から :h gf
K カーソル位置のキーワードを調べるためのプログラムを実行.Keyword から :h K
q タイプした文字をレジスタ{0-9a-zA-Z”}にレコーディングする.特に覚え方は見つからなかったが,macro -> maqro みたいな覚え方もあり…? :h q

おわりに,そして覚えるのもよいけれど…

以上で本記事のコマンドの覚え方大全は終了です. ここまで読んだ方お疲れ様です.そして「アレ…?まだまだあるはずじゃない?」と思ったそこのあなた,正解です. 挿入モード,コマンドモードのコマンドはほとんどかけてないですし,単純に抜けてるものもあるかと思います. チカラ付きました… ただこう理解するとわかりやすいよ〜というコマンドはなるべく網羅したような気がします. もっとこれ追加しろとかあったらコメントかtwitterか何かで言っていただけると嬉しいです. そしてVimを始めたころの初々しい気持ちを忘れていて,いやもっとここ丁寧に書かなきゃわからんぜ!ってとこも遠慮無くおねがいします.

そして覚えるのも大事ですが,それと同じくらいわからないことをドキュメントから調べる力を つけるのも重要かなぁと思います.最初は覚えられなくても調べることができればかなり便利です. たとえば :helpだけでなく:helpgrepを使いこなしたり, :h help-context を読んで引きたい項目の指定ができるようになるとはかどります. (他にも(を末尾につけることで関数のヘルプを引くといった書いてないプチハックとかもあります)

種類 修飾子
ノーマルモードコマンド (無し) :help x
ビジュアルモードコマンド v_ :help v_u
挿入モードコマンド i_ :help i_<Esc>
コマンドラインコマンド : :help :quit
コマンドライン編集 c_ :help c_<Del>
Vim の起動引数 - :help -r
オプション ' :help 'textwidth'
正規表現 / :help /[

僕が思うhelp周辺の便利ツールとかは Vimのhelpを快適に引こう - haya14busa にまとめているのでよかった読んでみてください.

おわり.

Vim のコマンドを覚えて思考のスピードで編集しましょう!!!