haya14busa

haya14busa’s memo

ブログを書くまでが #yapcasia なのでブログでLT発表して感想かく ― Vim駆動学習

YAPC::Asia 2015 に1日目・2日目と参加してきました.

ブログを書くまでがYAPCで,LTしてみたかったならやぷしー終了するまでにブログで発表すればいいじゃない

YAPC 2015 初めての参加でしたが一言で言うと最高でした!!! 刺激になるトーク多すぎました.

ただひとつ悔やまれるのは1日目の前日くらいに勢いでLT応募したけど,そのまま勢いで落ちたのでチョット発表してみたかった…倍率高すぎる〜

(本当に悔やまれるのはトラック被って見れなかった裏トラックを見れてないということで,資料とかまとめとかYouTube見ていくゾ!!!)

…ところで,YAPCはブログを書くまで終わらないんだからブログでLTしたかった内容発表すれば, それはもうYAPCでLTしたことになるのでは…!?!?!?(混乱)

と考えたのでブログで発表したかった資料をあげる最高にカッコワルイことを今からします. その後参加記みたいな何かを書いています.

いろいろと,読む前でも読んだ上でも思うことはあると思いますが自分でも思うことはあるので 察してそっとしておいてください!! いろいろと反省はしている.

Vim 駆動学習

※ 1箇所gifが表現できないのでクリックして見てと言っているけどSpeaker Deckだとクリックできないのでスルーしてください(PDFをダウンロードすれば一応クリックできるけど)

LT説明や資料の反省とか.あと参考記事

エモイ話だ…

基本的にはこれまでにどこかでアウトプットした内容で,なるべくそうならないように意識はしてたのだけど, 説明文とか内容とか何か聴衆に有益情報話すというより,単なる自分語り感が強すぎるのがウーンっていう感じだと思っています.

まぁ技術的な説明とかは他の人のほうが断然できるはずだし, 僕ができるのは僕の経験を話すこと.それが一番僕にしかできない発表で, そこで何か聴衆に響かせることができたらいいなって考えたのでこういった内容になってます.

内容がだいたいどこかで以前アウトプットしたものになった原因は,これまで基本的には記事書くようにしていたからっていうことや, 聴衆がどうよりも経験としてYAPCみたいな舞台で発表したいというエゴによって自分のなかでGoサインが勢いで出てしまった感じになってます.

資料できてここまで書いて思ったけどたぶん落ちてよかったんじゃないかなぁみたいな思いもある. 普通に5minオーバーすると思うし.

これからまた頑張っていくゾイ!!!

参考記事

だいたい僕のブログ読んでたらLT資料読まなくてもだいたいわかる感じになっている. もし興味出たっていう優しいかたは気になった記事を読んでいただけると少し詳しく書かれています.

自分の LT のくだり終了.

YAPC::Asia 2015 Day1 感想

聴いたTalkと感想

1日目は朝5時半くらいから起きて東京に向かったのでなかなか大変でしたが,早起きチャレンジ成功してよかった.

1) メリークリスマス! - YAPC::Asia Tokyo 2015

perl を書いたことは無かったけど歌って踊るラリーウォールみれてよかった. perl6 面白そうなようなので(又聞き),クリスマス期待.

2) 世界展開する大規模ウェブサービスのデプロイを支える技術 - YAPC::Asia Tokyo 2015

Miiverse のデプロイを支える技術の話だった.海を超えたgit pullとかその不可を抑えるためのランダムスリープみたいな つらい話からはじまって,それを解決していった話が聞けました. 大規模ウェブサービスのデプロイ,やったこと一切なくてあまり個人の実感がわかないのでムズカシイけどこういう話も勉強していきたい.

3) TBD - YAPC::Asia Tokyo 2015

Rubyのパパ Matz が Rubyの話しを封印したと思ったら10分で封印を解いたり, Ruby のディスと見せかけて間接的にperlディスってたりしておもしろかった. 内容も面白くて,主流のアーキテクチャが変わると言語デザインも変わってきて,それに対応してデザインされているのが streem ならしい.

4) Perlの上にも三年 〜 ずっとイケてるサービスを作り続ける技術 〜 - YAPC::Asia Tokyo 2015

おもしろトークだった上にめっちゃ開発の参考になる話が多かった.紹介されていた本読みたい -> YAPCの発表で紹介した本 - hitode909の日記. DDDとかユビキタス言語の導入の話とかがとてもいい話で,僕もやっていきたい. 最近自分でもプログラムやドキュメントに書いてる単語がブレていたりするのを感じていて, ユビキタス言語.md (ファイル名違う気がする) とかをリポジトリに置いて管理するのとかもよさそうと思った.

事前条件/事後条件とかあってそこで 責任外のことをチェックせずお互いを信頼するとスッキリするという話もなんとなくスッキリして面白かった.

5) うっかりをなくす技術 - YAPC::Asia Tokyo 2015

うっかりすることよくあるので,うっかりをなくす技術を聞きに行った. assertion ライブラリ的なものを最近作っていたのでassertionの話とかもっと聞きたかった.契約プログラミングとか???(わかってない) defer/guard object とかスゴイよさそうだった.golang に defer とかあるようだし,goやっていきたい.

追記: あとせっかくうっかりをなくす技術聴いたのに2日目に会場に荷物忘れるうっかりをやらかした. そしてこの文をブログに書くのを忘れるといううっかりもして,うっかりしないようにするのはムズカシイ…

6) Lightning Talks Day 1 - YAPC::Asia Tokyo 2015

Slack + Hubot でお前の一番好きな二次元嫁キャラと一緒に仕事をする 話とかが思考がぶっ飛んでいて面白かった. PHPでregister_globalsの話をしてた方が最初にgongo/emacs-ikkuとか作っていて 「Vimでやらなきゃ…負けてられない…」とか考えていたけどまだできていない.

YAPC::Asia 2015 Day2 感想

聴いたTalkと感想

Mackerel開発におけるScalaとGo、そしてPerl - YAPC::Asia Tokyo 2015

  • 複数の言語,技術を用途によって適切に使い分けてるのがすごい.
  • Scalaのimplicit conversion の解決遅すぎ問題のつらさわかる〜みたいな気持ちになったりした.
  • ちょっと最初の10minくらい遅れていってしまってツライ…ちゃんと見直したい.

我々はどのように冗長化を失敗したのか - YAPC::Asia Tokyo 2015

  • 式年遷宮面白かった.
  • 発表前から資料がアップロードされていてよさ.
  • 冗長化ムズカシイ.

MySQLで2億件のシリアルデータと格闘したチューニングの話 - YAPC::Asia Tokyo 2015

  • 自分にとっては難しかったのとあまり集中して聞けてなかったのであまり記憶がない…(LT採択どうかな〜みたいな気持ちで気が気じゃなかったのもある)
  • あとから資料見てみたい.

Adventures in Refactoring - YAPC::Asia Tokyo 2015

  • GitHubの中の人のリファクタリングの話でめっちゃよかった!!! リファクタリングしたい気持ちが高まりまくった.
  • リファクタリングは挙動を変えては行けなくて,それはバグも同じで一緒に修正したら問題の切り分けができなくてダメだよという話は, わかるという思いと共に,そうは言ってもムズカシイので意識してデキルようにしていきたい.
  • リファクタリングをナゼするのかとか,成果を計測しなくてはならないというのは全然意識したことがなかった.資料とか見直しながらやっていきたい.
  • (変数・)メソッド名のアンダースコアはリファクタリングチャンス.なるほどという感じだった.
  • とにかくリファクタリングやっていくゾ!!!

Posture for Engineers - YAPC::Asia Tokyo 2015

  • 肩こりがひどいので姿勢の話を聞きに行った.
  • いくつかヨガのポーズみたいなものを教えてもらったので実践できればいいのだけどデキルだろうか…
  • バランスボールのって開発してたら逆に肩こりと首こりがヤバくなった経験があってすぐにやめちゃったのでいい座り方・使い方がしりたい.(質問しそこねた)

Run containerized workloads with Lattice - YAPC::Asia Tokyo 2015

  • 正直わからんかったマン(ムズカシイ…)

Profiling & Optimizing in Go - YAPC::Asia Tokyo 2015

  • とにかくライブコーディングがカッコヨサで Go の標準で提供されている tool すごい強いし,コンパイル速くて書きやすそうだし, まだ Go はかけてないけど,Go 書いていくゾ!という気持ちになった. Go 書き始めたらまた参照して学んで行きたい.

Lightning Talks Day 2 - YAPC::Asia Tokyo 2015

  • どのLT もこれぞLTってカンジで良かった…あんなLTできるようになりたい.
  • @orga_chem さんの Vim script 静的解析の闇がトリで Vim script の闇を暴露していていい話だった. Vim script はああいった感じでカワイイのでぜひ興味を持った皆さんには vint のチカラを借りながら Vim script を書いてみて欲しい. 基本静的解析のときツライという話で,v:count, 関数と変数のネームスペース, map() の引数とかが文字列って以外は普通に書いてるときの 闇としては避けられそう.(十分多い…???)

個人的な悔やまれることとか

  • 最近Vim版power-assert作って補足して頂いたりしたので @t_wada さんに会ってご挨拶くらいしておきたかった. Vim版 power-assert もっと便利にしておきたい.
  • 世界の @miyagawa さんを見かけて Rebuild.fm 大好きでめっちゃ聴いてますって言ってみたかったけど,誰かと話されていて, Rebuild.fm 聴いてますとか耳たこかもしれないし,その後何か話せるか考えたけど訳分からんくておそらく Rebuild.fm で Vim とかエディタの話をしてほしいとかは言わないまでも,Vimmerのゲスト増やしてくださいみたいな困らせるようなことを喋りそうで そうこう言ってるうちに機会が過ぎてしまった…フベン…
  • Twitter のタイムラインを見る限り,オープンインターネッツ上で見たことあるひとがたくさんいたけど,現実の顔と一致しなくて結局 会わずじまいな人が多かったのでまた何かの機会にお会いしたい.会えたひとも何人かいてそれはよかった.
  • 発表しようと思うならもっと早めに用意しないと,僕のレベルだと時間をいっぱいかけてやっと聴くに耐えるものになるかどうかギリギリみたいな 感じだと思うし,ちゃんと準備したい.

全体的に

YAPC::Asia 2015,YAPC初めての参加でしたが本当に最高でした!!! 同時通訳の方の同時通訳がすごくて圧巻されたり,会場のWifiはあの人数だったのに個人的にはほとんど繋がっていて CONBU さん凄かった. 無限に湧き出てくるコーヒーも美味しかったし,懇親会も豪華だしスポンサーの皆様ありがとうございました.

そして発表者の皆様,@lestrratさんをはじめとした運営の皆様,他の参加者の方々, (漏れていたとしたらその方々!), 最高のYAPC本当にありがとうございました.楽しかったです!!!

絶対来年も参加したい!!!!

Vim Script版 Power-assert! テスト書いてないとかお前それ Vim Script の前でも同じこと言えんの?

Vim script で最高の assertion 体験,vital-power-assert を作りました

Gyazo

haya14busa/vital-power-assert

テスト書いてないとかお前それ Vim script の前でも同じこと言えんの?

ということで Vim script 版 power-assert, vital-power-assert を作りました.

Vim script でも power-assert できてテストをバリバリ書けるんだから Vim で書いてる他の言語でテスト書いてないとか Vim が泣いちゃいますね…(煽り,そしてブーメラン)

使い方とか 力こそパワー!! 百聞よりパワー!!

使っている様子です

1
2
3
4
" in your vimrc
NeoBundle 'vim-jp/vital.vim'
NeoBundle 'haya14busa/vital-vimlcompiler'
NeoBundle 'haya14busa/vital-power-assert'
1
2
3
4
5
6
7
8
9
10
11
12
13
let s:V = vital#of('vital')
let s:PowerAssert = s:V.import('Vim.PowerAssert')
let s:assert = s:PowerAssert.assert
execute s:PowerAssert.define('PowerAssert')
function! s:power_assert() abort
  let x = { 'ary': [1, 2, 3], 'power': 'assert' }
  let l:zero = 0
  let s:two = 2
  PowerAssert index(x.ary, l:zero) is# s:two
  " or
  execute s:assert('index(x.ary, l:zero) is# s:two')
endfunction
call s:power_assert()

上記コードを実行するとこうなります.

1
2
3
4
5
6
7
8
9
vital: PowerAssert:
index(x.ary, l:zero) is# s:two
     |||     |       |   |
     |||     |       |   2
     |||     |       0
     |||     0
     ||[1, 2, 3]
     |{'ary': [1, 2, 3], 'power': 'assert'}
     -1

インストールや詳しい使い方は GitHub/help を参照してください.

-> haya14busa/vital-power-assert

基本的に関数とコマンドのassert方法を用意しているのですが,プラグインのコードに残しておいたりするものは 関数の .assert(), Vimのテスティングフレームワークで使う際などはコマンドでやることを推奨してます.

1
2
3
4
" 関数で assert. 引数は文字列として渡す必要がある
execute s:assert('index(x.ary, l:zero) is# s:two')
" コマンドで assert. 文字列で囲う必要がないのでシンタックスハイライトも効く
PowerAssert index(x.ary, l:zero) is# s:two

両者ともデバッグ用変数をONにしないとassertは実行されないので,プラグインに埋め込んでおいても プラグインのユーザが使ってる時は発動しないし,評価なにもされないのでコードに残しておいても 問題ないようになっています.(コマンドの方はユーザのVimにコマンドが新たに定義されてしまうので推奨しません)

power-assert 最高! 一番好きな assertion ライブラリです!

vital-power-assert はもちろん JavaScript の assertion ライブラリである https://github.com/power-assert-js/power-assert にインスパイアされて作っています.

何がベンリなのかとかは @t_wadaさんが本家のpower-assertの紹介とかで 各所で説明なされているので説明は不要だとおもいますが,

個人的にはやはり

  1. assert 失敗時の式がどうなってるか一目瞭然のグラフィカルな見た目
  2. たくさんの matcher を一つ一つ憶えたりドキュメントを見なくても assert 一つだけ知ってれば使える優しさ

あたりのよさが使ってみて,開発してみて本当によいなと思います.

マッチャーは自然言語的な書き方ができたり, テストのコード自体が間違えにくいみたいなところがよいとチラッと聞いたことがありますが 僕は断然power-assertのほうが好きという思いが強まりました (間違ってたり他にもある場合は教えてください)

Vim script 版 vital-power-assert のよさ

(このあたりは特に Vim script 書いてる人/興味あるひと向けです)

power-assert としてのよさはもちろんのところ, Vim script の assertion ライブラリとしての vital-power-assert のいいところがあります.

それはassertionを実行する際のスコープが assert する行と 同じなので, スクリプトローカル変数やローカル関数など何でもassert する 式の中で使えるということです!!! (わかりづらい)

1
2
3
4
5
6
7
8
9
:let s:x = 2
:PowerAssert s:x == 1
" or
:execute s:assert('s:x == 1')
" => ちゃんとs:xも使える
"   s:x == 1
"   |   |
"   |   0
"   2

例えば Vimのテスティングフレームワークの一つの thinca/vim-themis の assert コマンドではスクリプトローカル変数が使えなくて不便…ということがあったりするのですが vital-power-assert を使えばそのあたりを気にせず使うことができます.ベンリ.

どうやって実装しているか

Vim script のパース & コンパイル

power-assert のようにassert が失敗したときに式中のそれぞれの変数や関数, 演算子の評価結果を得るためにはまず与えられた式をパースする必要があります. そこでは Vim script で Vim script をパースできる ynkdir/vim-vimlparser を使用させていただいています. 使っていて改めて ynkdir さんすごすぎる…

vitalのライブラリとして使うためにhaya14busa/vital-vimlcompilerにバンドルしちゃっています.(ライセンス的に問題なさそうだったのでynkdirさんに相談するまえに衝動的にVim版power-assertを作ってしまいました…スイマセン)

とにかく,vimlparser のおかげでVim scriptをパースしてASTを得ることができたので, あとはASTをトラバースして評価したいノードを集めることができました.

そして再コンパイル

あとは集めたASTのノードの式中の位置を記録, そしてASTをVim scriptに戻してスコープに気を付けながら評価すれば必要なものが揃います.

vimlparser に付属している Compiler オブジェクトはS式的なものにコンパイルするものだったので, Vim scriptにコンパイルする haya14busa/vital-vimlcompiler というライブラリを作って使用しています.

注意点としてまだexprのコンパイルしか実装してないので関数とかはコンパイルできないです. ドキュメントもないし今のところ完全に vital-power-assert 用になっていますが,何かできたら面白そう.

Vim script スコープハック

Vim のコマンドの引数はStringとして渡されてその場で評価しているわけではないので 普通にやるとスクリプトローカル変数が無いと怒られます. もちろん文字列で受け取って eval() してもスコープは変わってるので対応できません.

これを完全に解消するためにはassertする行と同じ位置で評価する必要がありますが, そこで execute を使うことによって実現しています.

どういうことかというと,{rhs} である s:assert('...') が評価され返り値が帰ってくるのですが, その返り値に実行したいコマンドを文字列として返すと :executeによってそのコマンドが同じスコープで 実行できて… という感じで実装しております.

1
2
3
4
5
6
7
8
9
10
11
:execute s:assert('x == 1')
" ->
:execute 'execute' "s:assert2(x == 1, 'x == 1')"
" -> {expr} と 文字列の '{expr}' を別の関数に渡し直す
:execute s:assert2(x == 1, 'x == 1')
" -> 評価したいノードリストを引数にとる関数を返す
:execute 'execute' "s:assert3('x == 1', [{pos: `xの位置`, value: x}])"
" -> { "value": x } で xが評価される
:execute s:assert3('x == 1', [{"pos": `xの位置`, "value": x}])
" -> 実はこのあとここで `:throw` コマンドを返してthrowすることによってエラー位置をこの行にしたり...
:throw ...

コマンドも基本は同じでコマンドの{rhs}executeになってるのですが, どうしてもスクリプトローカル変数だけはコマンドを定義したファイルの方で評価されてしまうので ファイルごとにコマンドは定義する必要があるのはこれが理由です.

つまりスクリプトローカル変数諦めるなら一回定義すればあとは同じように使えますが そもそもコマンドは雑な開発用スクリプトとかテスティングフレームワークで使うことを想定しているので そんな感じで察してください.

グラフィカルな描画

ところで見た目とユーザの驚き的には power-assert のあのグラフィカルな表示を作るところが華と見ることもできそうですが, 今のところとりあえず線が被らない最低限のアルゴリズムで作っているのでもっと改善した表示ができると思います.

もしいい感じのグラフ描画のアルゴリズムわかる人は僕に教えてくださると大変ウレシイです

最後に

勢いでワーッと作っていてまだまだ改善点はあるのですが,一通り開発してテストしてる限りではめっちゃよい感じに動くので Vim script 書いてる方や興味あるかたは是非使って見ていただけると嬉しいです.

あと themis との連携を書いてますが,別に themis の作者である thinca さんに使い方とか確認をとったわけでもないので もしかしたらもうちょっと良く出来たりするかもしれません.

フィードバックとか使い方の質問とか github: https://github.com/haya14busa/vital-power-assert , twitter: https://twitter.com/haya14busa , Lingr: http://lingr.com/room/vim あたりにいただけると嬉しさあります.

Vim script でも power-assert して最高の assertion 書いていくゾ!!!

Vimの検索はもっともっと便利になる! incsearch.vim v2.0 をリリースしました

haya14busa/incsearch.vim

incsearch.vim について知らないかたはこちらの記事を参照してください. 簡単に言えばVimのインクリメンタル検索をカイゼンするプラグインです. -> incsearch.vimでVimの検索体験をリッチにする - haya14busa

incsearch.vim v2.0 をリリースした!

v0.9, v1.0, v1.1, v1.2, … とこれまで incsearch.vim をインクリメンタルにカイゼンにカイゼンを重ねてきました… そして本日, incsearch.vim は晴れて一段階進化し, バージョン2.0 となりました!

この進化を一言で言えば,incsearch.vim はもっともっと Vim の検索を便利にすべく 進化・拡張可能 になりました.

2.0で何ができるようになったか?

百聞は一見に如かず.以下のgifとともに拡張プラグイン達をご覧ください!

曖昧検索 | fuzzy search

incsearch-fuzzy.gif

1
2
3
4
5
6
7
NeoBundle 'haya14busa/incsearch-fuzzy.vim'
" マッピング例
map z/ <Plug>(incsearch-fuzzy-/)
map z? <Plug>(incsearch-fuzzy-?)
map zg/ <Plug>(incsearch-fuzzy-stay)
" サクッとためす
" :call incsearch#call(incsearch#config#fuzzy#make())

曖昧スペル検索 | fuzzy spell search

incsearch-fuzzyspell.gif

1
2
3
4
5
6
7
NeoBundle 'haya14busa/incsearch-fuzzy.vim'
" マッピング例
map z/ <Plug>(incsearch-fuzzyspell-/)
map z? <Plug>(incsearch-fuzzyspell-?)
map zg/ <Plug>(incsearch-fuzzyspell-stay)
" サクッとためす
" :call incsearch#call(incsearch#config#fuzzyspell#make())

高速でインクリメンタルなmigemo検索 | migemo search

incsearch-migemo.gif

1
2
3
4
5
6
7
NeoBundle 'haya14busa/incsearch-migemo.vim'
" マッピング例
map m/ <Plug>(incsearch-migemo-/)
map m? <Plug>(incsearch-migemo-?)
map mg/ <Plug>(incsearch-migemo-stay)
" サクッとためす
" :call incsearch#call(incsearch#config#migemo#make())

EasyMotion との連携 | integration with vim-easymotion

incsearch-easymotion.gif

1
2
3
4
5
6
7
NeoBundle 'haya14busa/incsearch-easymotion.vim'
" マッピング例
map z/ <Plug>(incsearch-easymotion-/)
map z? <Plug>(incsearch-easymotion-?)
map zg/ <Plug>(incsearch-easymotion-stay)
" サクッとためす
" :call incsearch#call(incsearch#config#easymotion#make())

拡張はcomposable!

incsearch-fuzzy-easymotion.gif incsearch.vim x fuzzy x easymotion

1
2
3
4
5
6
7
8
9
10
11
12
13
" incsearch.vim x fuzzy x vim-easymotion

function! s:config_easyfuzzymotion(...) abort
  return extend(copy({
  \   'converters': [incsearch#config#fuzzy#converter()],
  \   'modules': [incsearch#config#easymotion#module()],
  \   'keymap': {"\<CR>": '<Over>(easymotion)'},
  \   'is_expr': 0,
  \   'is_stay': 1
  \ }), get(a:, 1, {}))
endfunction

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

仕組み

converter 機能

  • :h incsearch-config-converters

バージョン2.0でのメイン追加機能,パターンコンバート機能です. 入力したパターンを変換して正規表現を返すコンバーター(複数可)を指定することによって, 入力した正規表現だけでなく,変換された正規表現も追加で検索してくれます.

fuzzy, fuzzyspell, migemo の拡張はどれもこの新たに入った仕組み,converter機能を使っています.

他にも スネークケースとキャメルケースを相互変換してどちらも検索できるようにするとか, {a,b}\(a\|b\)に変換するようなオレオレ簡易正規表現シンタックス(?)シュガーを作るとか, inputを受け取って正規表現を返すというシンプルな機能ながら,活用可能性はたくさんあります! (※ これらはそのうち実装していくと思います)

module 機能

vital-over という incsearch.vim が使用しているライブラリにおけるモジュールを追加できる機能です. これがどんなことができて,どうやって作ればいいかといったことはそれだけで別の一つの記事どころか数十記事書ける内容なので割愛しますが, かなりいろんなことができるようになるはずです.(が,その分何でもできすぎるので注意は必要そうですが).

haya14busa/incsearch-easymotion.vim がこの機能を使って検索後に easymotion/vim-easymotion の機能を呼び出しています.

自分で拡張を作ることも可能!※ ただしAPIが固まってるとは言ってない

もちろんもっと便利な拡張を自分で作っていくことも可能です. ここでは例としてちょっとした converter を作ってみましょう

参照

  • :h incsearch#go()
  • :h incsearch-config()

仕様

  • 正規表現をエスケープして単なる文字列として返し,検索する.
  • つまりは\Vの機能.ただし,普通の正規表現に加えて検索できるところが違う.

実装

pattern を受け取って正規表現を返す関数 (s:noregexp()) を実装して, incsearch#go()に渡すconfigのconvertersとして渡してあげるだけ. ※ converterオブジェクトを作って渡してあげる方法もありますが,現時点では関数を渡してできること大差ない.

1
2
3
4
5
6
7
8
9
10
function! s:noregexp(pattern) abort
  return '\V' . escape(a:pattern, '\')
endfunction

function! s:config() abort
  return {'converters': [function('s:noregexp')]}
endfunction

noremap <silent><expr> z/ incsearch#go(<SID>config())
" 例: /\vpattern と検索したら \vpattern がマッチする.普通の検索なら pattern だけ

めっちゃ簡単!!!

Special Thanks

おしょーさん(github@osyo-manga)のライブラリには 毎度お世話になっており,incsearch.vim v2.0 はコマンドラインライブラリである osyo-manga/vital-over の拡張性があってこそ リリースできたことだったり,cmigemoコマンドでも高速に migemo 検索できるのはそのまま osyo-manga/vital-migemo のおかげだったりします.

また Lingrのvim部屋 でもincsearch.vimの開発に関わる質問をしたりして参考にしたりフィードバックをもらったりしました. 皆さんありがとうございますっ!

終わりに.そして次のカイゼンへ…

incsearch.vim はシンプルかつVimデフォルトの検索と同じように快適に使用できるオススメプラグインです. それがバージョン2.0 になり,望めばもっともっと便利に,拡張可能なものになりました. 気になった方は是非つかってみてください.

そして incsearch.vim にはまだまだ改善点があるかと思います(ジッサイあります). なにか見つけた方や「おまえーっ…APIがなーっ…ふわふわでなぁーっ…使いにくくてなーっ…ゆるさーん(バシーン)」 という方は Issuestwitter:@haya14busa, はたまた Lingrのvim部屋 あたりなどでフィードバックいただければカイゼンしていきたいと思うのでよろしくお願いしますっ

haya14busa/incsearch.vim

2014年の振り返り. またはプログラミング2年目をVimに捧げるとこうなるという話

この記事について

この記事は Vim Advent Calendar 2014 の30日目かもしれません(または来年, Vim記事集約系のイベントやりたいという気持ちの1つです).

今年の2月に 1年間『Vim駆動学習』してきて最高に楽しかったのでオススメしたい - haya14busa というVim歴換算で1年を振り返ったエントリーを書いたのですが, 今回は2014年を振り返ってみたら, やっぱりVim活たのしかったなぁという日記的エントリーです.

また思い返してみると僕がプログラミング始めたのは2年と少し前だったので, 2014年はプログラミング2年目の年でもありました. この文脈でみると「プログラミング2年目をVimに捧げるとどうなるか?」 というエントリーとも言えそうです. (※1年目からかなりの割合をVimに捧げていました)

2014年, 今年のVim活を振り返る

※Vim活が9割です

カーソル移動系人気プラグインの vim-easymotion の開発を乗っ取った!

20141230_easymotion_contribution_graph easymotion_on_speed_ex

これは2013年の後半からforkして活動していて, 今年の2月くらいに起こった出来事なのですでに下記の記事に少し感想を書いています.

-> 1年間『Vim駆動学習』してきて最高に楽しかったのでオススメしたい - haya14busa

記事執筆現在, GitHub のStar数 1556 で, 開発を引き継いだ時点での Star数は 1000 にちょっと届かない程度でした. もともとほっといた場合の伸び具合がどれくらいかはわからないですが, 自分が引き継いだ時点で Star数 約1000 のリポジトリが, さらに500強増えたという事実は本当に嬉しいです. GitHub Star 500+ めでたい.

これだけ 「たくさんのスター数がついている≒たくさんの人に使っていただけている」 プロジェクトを開発 & メンテするというのはなかなかに学ぶことがおおくてとても楽しかったです. 今後はリファクタリング含めもっと便利にしたいなぁと思っているんですが, そう思ってから半年くらい経過しております(すでに十分に便利&安定してきているのでモチベが低い).

最高の検索体験を提供したい! incsearch.vim つくった

incremental_regex_building

今年の前半がvim-easymotionだとしたら, 後半はほとんど incsearch.vim でした. 実はこのプラグインは最初はサクッと気晴らしにつくったぜーというレベルのものだったのですが, なんだかんだちゃんとしたものにしようという流れになり目一杯頑張りました.

また使用しているライブラリの osyo-manga/vital-over にもコントリビューションという名のリクエスト丸投げや, 設計についてコメント, ダメダメな Pull Request を交えながらいろいろ関わらせていただきました. おしょーさんありがとうございます, 迷惑いっぱいかけてスイマセンッ, これからもよろしくお願いします..!

便利さの9割は vital-over のおかげなのですが, 自分が1から開発してるリポジトリーでスター数3桁を達成してこれもまた非常に嬉しいです. これもめでたい.

GitHubの VimL trending で Repositories & Developers の両方で1位も獲得できました…! 嬉しさ.

github-trending-viml-today-incsearch github-developer-today-vimL-2014-10-22 22:51:58

VimConf 2014 で発表した

VimConf2014 という感極まるVimのカンファレンスが今年も開催されたのですが, そこでLT枠で発表させていただきました. Vimの便利な検索機能と上述した incsearch.vim の紹介をしました. 発表グダったりもしましたが, よかったという反応をいただけたり, スライドを英語で書いたので英語圏の人にも見てもらって便利さを伝えられたのは良かったです. 英語というより gif をふんだんに活用したので伝わったという説もある. (usevim, reddit )

ちなみに動画はテンパッて間違ったことも多々言ってるので鵜呑みにしないでください… この辺慣れるには場数を踏む必要がありそう

最高の検索体験を提供したい + α!. vim-asterisk 勢いでつくった

asterisk_z_star

Vim の * ってとても便利なのですが, 自分のユースケースとしては次のマッチにジャンプして欲しくないという不満があったので, そこを解消するために作りました. * からの gn テキストオブジェクト活用でスムーズに編集できるようになってとても気に入っています.

結構小さいプラグインではあるのですが, 今まで得たVim scriptの知識や経験をたくさん使っていたり, ビジュアルモードにおける * 機能は thinca/vim-visualstar の部分をお借りしたり, マルチバイトの扱いをプルリク貰って直したりとなかなかよさ気なものになりました.

実は似たような機能を提供してるプラグインはいくつかあるのですが, どれも不満がまだありました(Vimの検索機能周りの拡張は結構落とし穴が多い). incsearch.vim の経験などが活きて落とし穴はうまく回避できました. 気になった方は是非使ってみてください.

vimrc 読書会にいっぱい参加 & 管理のデータ化・自動化 & 統計ページ をつくった

確か管理者権限貰ったのは恐らく今年(すこしあやしい…厳密には去年だったかも…)で, 参加するだけでなくちょっとずつ運営面でも関わらせていただきました. Jekyll を覚えて 読書会のデータを yaml でデータ化したり, そのデータを使って Angularとd3.jsで 読書会の統計ページをつくったり, データ化によって扱いやすくなったので python や ruby で簡単なスクリプトを作成して更新作業を自動化したりしました. 読書会は毎週やるので更新が一瞬でできるようになって非常に便利になりました. 統計ページのJS, よくない部分多々あるのでそのうち書き直したい.

毎週土曜日23:00からやっているので皆さん参加しましょう! -> http://lingr.com/signup?letmein=vim

Vim プラグイン読書会やってた

こちらも1ヶ月周期でやっていました. Vim プラグイン開発, 興味ある. という方にオススメです! 一緒に読みましょう. またvimrc読書会とVim プラグイン読書会での経験が, Vim以外の普段の開発のレビューにも活かされたような気も…しま…す(自信なし).

執筆時現在次の日付が更新されてないという少々のグダりを見せていますが, 落ち着いたら必ず更新します!

Osaka.vim やで

connpass上では運営になっていますが一切の運営をしていません…!

関西のVim勉強会, 近年ではほとんどなかったので便利. 関西の皆さん参加しましょう.

Vimで緊急地震速報が見れるの便利では…? eew.vim つくった

EmacsやSublimeに移植されたりとちょっとだけ話題になった(すこし).

その他ちっちゃい Vim plugin 達

  • haya14busa/unite-ghq
    • uniteでghqできるの便利では…?と思ってつくって公開したら, そのわずか数時間前に sorah さんが sorah/unite-ghq を公開しており, しかもこちらのほうが基本的によくできていて「アアアッ…」とリアルで声がでた少し苦い思い出のあるプラグイン. 自分のバージョン使ってるの自分だけだとおもう. でも便利. 既存プラグインの検索は直前まで入念にやりましょうという教訓を得ました. (数日前にやった時点ではなかったので大丈夫だと思ってた)
  • haya14busa/unite-reading-vimrc
    • vimrc読書会のログやvimrcのリンクをuniteで絞り込んで開ける. たまに vimrc読書会 の管理とか過去の記録を見るときに便利.
  • haya14busa/endtagcomment.vim
    • よくvimrcで見かけるhtmlタグにコメントをつけるスクリプトをforkしてプラグイン化しただけ. もともと便利
  • haya14busa/unite-action-vimfiler_lcd
    • vimfilerでlcdしてから開くというuniteアクションが欲しかった. 結局つかってないのであまり便利じゃない.
  • haya14busa/vim-textobj-number
    • 数字のテキストオブジェクト. たまに便利. テキストオブジェクト学ぶかぁーという意図も含まれてた気がするけど結局それ以降テキストオブジェクト系プラグインは作成してない. なにかアイデア湧いたら作りたい.

Vim活以外の進捗(残りの1割)

  • プログラミングのバイトを4月からはじめました(たぶんVim活アピール補正はかかりました. ある意味 Vim script もペイする言語…?).
  • それに伴って Scala をやりはじめたんですが視野が広がってとてもよかったし, もっと学んでいきたいです.
  • JavaScript もそこそこ書いて, Angular.js に触れたりなどしました. underscore.js も便利.
  • しかし Scala その他 Vim 以外のOSS活動の進捗ダメです
  • heroku にPythonで小さいウェッブアプリをつくったのですが, 乗っかってるサービスが終了したので一緒にお亡くなりになってつらい.

勉強会にちょっとずつ参加するようになった

Vim 以外の勉強会にも今年はちょっとずつ参加するようになりました(Vimも基本的には今年からですが). しかしこれは進捗でゎなぃな…

その他

GitHub current streak 365 日達成した

dotfile 1行変更といったものがたくさんあるので全く大したことはしてないのですが, 日によってはそのついでにちゃんとプログラミングするぞっ! というきっかけになるので自分には合ってる継続的進捗管理術でした. 1年継続めでたい.

2014年 GitHub の Pull Requests / Issues 一覧

追記:

PullRequest 8 opens / 83 closed, Issues 53 open / 95 closed ※99% Vimである

Podcast 聴くようになった

聴いてるPodcastは

という感じです. 例に漏れず(?), Rebuild.fm から聴き始めてめっちゃおもしろいっ! となり, そこから バイリンガルニュース や The Changelog を聴くようになりました. 最近はずっと気になってはいたけど聞いていなかった mozaic.fm を聴くようになって, こちらも Rebuild とは別のベクトルのよさがあって全部聴きました. 技術系(?)英語 podcast の binpress podcast というポッドキャストは, 全部無料でスクリプトがついているというエイゴ・ゼンゼン・キキトレナイ勢としては歓喜のサービスがついていてお気に入りです. おもしろさは回によって違う感じですが, 英語もついでに学ぶかーという方にはオススメです.

リスニング能力高めてもっと英語のポッドキャストを楽しめるようになりたい…

英語の記事をコンスタントに読む & 検索するようになった

1年目も別に避けたりはしてなかったのですが, 最近は能動的に英語の情報に触れようとする確率が高くなったかなと思います. 検索や話題になっている記事を除けば, 見ているのはだいたい上記のリンクです. ただ単に読んでるだけではなかなか得るものも少ないので, 自分から英語で発信する能力をつけたいなーというのが最近の悩みです. 現状 GitHub の issue のやりとりやプラグインのドキュメントは基本英語を使ってるのですが, もっともっと使っていかないとなかなか身につかないですねー.

来年の抱負とか

  • Vim もっと頑張る.
  • Vim のソースコード側も C言語ちょっとぐらい読み書きできるようになって簡単なバグくらいなら報告だけでなく修正案まで出せるようにしたい.
  • Vim 以外も頑張る. なにか小さなウェッブサービスとか適当につくったりしたい.
  • Scala力をより深めるのに加えて C, Go, Haskell あたりの言語を触って学んでいきたいという思いがある.
  • データベース周りとか, 今触ってるレイヤーと別の部分も触っていきたい. 最低限基礎力が欲しい.
  • 英語力をつけていきたい. Vim について英語で適当に英語用Twitterアカウントつくってつぶやくとかなら継続してできるのでは…?という考えがある. 欲を言えば Lingr の Vim 部屋のノリで英語でチャットとかできれば一番いいんじゃないかという思いがある. IRC に #vim チャンネルあるらしいけど, IRCよくわからない…ログ読みたい…
  • 人生は厳しいので人生についてちゃんと考える必要がある. 人生キビシイ.

「プログラミング2年目をVimに捧げるとどうなるか?」

少々Vim以外の進捗が少なすぎる気がするのは反省ですが, Vim活によってVimというコンテキストに留まらず, たくさんの貴重な経験ができました. git や GitHub, テスト, CI, オブジェクト指向やらクロージャ, 変数や関数の名前の付け方, 英語での技術系コミュニケーションなどなど, たくさんのことを Vim駆動で理解したり, 理解を深めた1年間だったと思います.

Vim駆動学習, よさがあるのでオススメです. ※ただし用法用量を守って正しく Vim 活しないと Vim 以外の進捗が遅れます. 反省…

また Vim だといろいろな言語を使ってる人がいて, しかも雲の上のような存在の人もたくさんいたり, オンラインでもオフラインの勉強会でも活動が活発なのでVim以外にもいろんなことが知れるし, プログラミング初学者でも最初から Vim をガンガン使ってプログラミングしていくのはおもしろいかなぁと思います.

振り返ってみるとたくさんのVimmerにお世話になったなぁと思います. ※もちろんVimmerでないひとにもお世話になりました.

みなさん今年はお世話になりました. 来年の2015年もぜひ仲良くしてください. よろしくお願いします.

以上, @haya14busa の 2年目のプログラミング Vim活記録でした.

incsearch.vimでVimの検索体験をリッチにする

この記事はVim Advent Calendar 2014の14日目の記事です。 13日目は deris さんによるスマートフォンでVimを操作するためにやっておいたほうがいいこと - derisの日記 でした。

1. incsearch.vim つくった

Vimの検索体験をリッチにする, incsearch.vim を作りました

haya14busa/incsearch.vim

incremental_regex_building


あなたとincsearch.vim 今すぐインストール

1
2
3
4
5
6
NeoBundle 'haya14busa/incsearch.vim'
Plugin 'haya14busa/incsearch.vim'
Plug 'haya14busa/incsearch.vim'
map /  <Plug>(incsearch-forward)
map ?  <Plug>(incsearch-backward)
map g/ <Plug>(incsearch-stay)

TL;DR

  1. Vim デフォルトの検索だとインクリメンタルハイライトは1つのマッチしかみてくれない
  2. incsearch.vim はマッチしたものすべてをインクリメンタルにハイライトする
  3. デフォルトのコマンドラインと高い互換性を持っているのでインストールしてデフォルトの/を置き換えてもスムーズかつ手軽に使える
  4. 本日バージョン1.0としてリリースしました
  5. ぜひ使ってみてください…!

※ ホントにToo long になった感があるので記事は長くて嫌いになってもincsearch.vimはシンプルに使えるので嫌いにならないでくださいっ…!

2. Introduction

Vimの検索を便利にする. incsearch.vim を バージョン 1.0 としてリリースしました!

「百聞は一見に如かず」ということで, 冒頭のgifなどを見ていただくだけで大事なことはすべて伝えつくしてしまった感があります. 「もう便利さはわかった!」 という方は記事なんてすっ飛ばして是非ブラウザバックして使ってみてください!

しかし今まで日本語でまともに解説したことがなかったこともあるので, ちょっとした便利機能やカスタマイズの仕方, 開発についてなど話していきたいと思います. もうすでに使っていたり, 聞いたりしたことあるよーという方も, 本日バージョン1.0としてリリースし, 以前から比べてインクリメンタルに改善してきたので少しは新しい情報もあるかなーと思います

3. incsearch.vim の機能を解説していくっ!

3.1 シンプルにすべてをハイライトするっ

  1. デフォルトの :h ‘incsearch’ とは違い, マッチしたパターンのすべてをハイライトする
  2. 別ウィンドウのハイライトも対応できる(オプションで変更可, version 1.0 で追加されました)

一番シンプルかつメインの機能としてマッチしたパターンをすべてハイライトします. 便利さ, 自明っぽいので説明を省きます!

incsearch_window

3.2 正規表現をインテラクティブに作って確認する

  1. デフォルトの検索だとエンターを押して:set hlsearch 状態になるまで, 現在入力している正規表現がどこにマッチしているかわからない
  2. incsearch.vim はもちろん正規表現に対応しており, スムーズに正規表現を作っていける
  3. <Plug>(incsearch-stay) というマッピングを提供しており, これはカーソルが動かないので途中でウィンドウ外に飛ぶといったこともない

マップ例:

1
map g/ <Plug>(incsearch-stay)

incremental_regex_building

(冒頭のgifと同じ)

これは vimrc によく書かれているプラグインマネージャが提供してるインストールコマンドから, インストールされているプラグインの部分とマッチする正規表現を作ってます(簡易版ですが). 普段の検索時にも勿論便利なのですが, 正規表現作る際の便利さは1つしかマッチを確認できないデフォルトの挙動と比べると段違いに捗ります. もしも incsearch.vim でデフォルトの検索を置き換えるまでもないかなーという人でも, 正規表現による検索の際のためにg/など好みのマッピングに定義しておくとこういうケースでは便利に使えると思われます.

3.3 検索中のインクリメンタルカーソル移動とスクロールで快適ファイル内検索

  1. Emacsは検索中にカーソルを前後に動かせるけどVimにはない…
    • ※ Vim には n/N があるので別になくてもよい
  2. incsearch.vim はデフォルトでは <Tab>/<S-Tab>で前後のマッチに移動できる
  3. Emacsや他のエディタでは見ない機能としてスクロール機能を提供しており, 画面内に目的地がないと判断すれば一気にスキップして画面外の次のマッチに飛べる(デフォルトでは<C-j>/<C-k>)

incremental_move_and_scroll

なにが便利か?

a) オペレータ待機モード時のモーションとドットリピート

ノーマルモードでは問題でもないですが, d/{pattern} といった オペレータ待機モード で使う場合, 決定したあとに n/N を使うことはできません. しかし, 最初に目測でマッチを確認してからカウントをつけて 3d/{pattern} とするのはとてもしんどい上に間違う可能性もあり, 生産的ではありません…

また1回だけの場合は ビジュアルモード を使えば上記の問題は回避できますが, これだとドットリピート が効きません.

そこで, incsearch.vim の <Tab>/<S-Tab> (:h <Over>(incsearch-next)) を使って 検索中にカーソルを移動させれば一目で目的地まであとどれくらいかもわかるし, オペレータと組み合わせるモーションとしての使用も, その後のドットリピートの問題も解消できます.

b) :h jumplist の更新が1回で済む

ノーマルモードでは問題でもないといったな? あれは嘘だ!

Vimには :h jump-motions というモーションの種類があり, これに属するモーションを 行うとジャンプ前のカーソル位置が記憶され, <C-o>/<C-i> でそれらのカーソル位置を 行ったり来たりできる超便利機能が存在します. 検索系のモーション(/,?,n,N, etc..) はこの jump-motions に属しており incsearch.vim でも勿論対応しているのでその機能を バリバリ使うことができます.

ここで問題なのは nN も jump-motions ということです. 検索後に n/Nで移動したあとやっぱり検索した元の位置に戻りたいな〜という時に n/N を押した回数分<C-o>を押す(またはカウントを前置する)必要があって地味に不便です.

incsearch.vim で検索中に<Tab>を押して移動してから検索を決定すれば勿論 jumplist の更新は1回で済むのでjumplistを汚すことなく十二分にそのジャンプ機能の便利さを享受することができます. 地味なよさがありますね.

c) スクロール機能で n 連打せずファイル内をサクっと検索

a), b) は1つ1つ前後に移動する機能の紹介でしたが, incsearch.vim は スクロール(デフォルトでは <C-j>がスクロールダウン, <C-k>がスクロールアップ)という機能を搭載しており, これは人に よってはライフチェンジングになりうるなかなかオススメ機能の1つです.

先ほどのgifを見てもらうとわかりやすいかと思うのですが,

デフォルトの場合

  1. 「あーファイル内の{pattern}って部分に用があるな〜」
  2. 「よーし/{pattern}<CR>で検索してn, n, n, …」
  3. 「まだ見つからない…(ファイル内に{pattern}がたくさんあって辿り着かない)」
  4. => 不便…

incsearch.vimのスクロール機能を使った場合

  1. 「あーファイル内の{pattern}って部分に用があるな〜」
  2. 「よーし/{pattern}で incsearch.vim を起動しよう」
  3. 「あー画面内にいっぱい{pattern}がある…よし<C-j> で次の画面へ」
  4. <C-j>を数回押して目的地発見. 任意で<Tab>/<S-Tab>で前後に移動してから<CR>!」
  5. => 幸せ便利

勿論, そもそもファイル内にたくさん存在しないようなキーワードを使って検索したり, タグが存在するなら ctagsなどを使用してタグジャンプしたほうが断然よいですが, いつでもユニークなキーワードが思い浮かんだり, タグが存在するわけではないので万能ではありません. 検索だとかなり汎用性が高いので個人的にはとても多用してる機能の1つになってます.

また他にもファイルの横断検索を補助するような機能を提供しているVimの機能や プラグインなどなどはあるとは思いますが, 以下のようなメリットがあります

  1. “検索” として使える
    • gn:substituteと連携したりなど”検索”は他のVimの機能と一緒に使うことによって, 相乗効果でより手に馴染む快適なキーストロークでエディットすることができます.
  2. 周囲のコンテキスト, 前後の行がみやすい
    • :vimgrepunite-line といった機能はだいたい前後の行が見れなかったりして ユースケースによっては困ることもあります. ただしgrep などは複数のファイルを扱える大きなメリットがあるので使い分けれるようになるのが一番よさそうです.

3.4 オート:nohlsearch

  1. :set hlsearchって便利でもあるけどだいたいウザイ
    • nnoremap <Esc><Esc> :<C-u>nohlsearch<CR> と言ったマッピングで検索後に消す人が多いと思います.
  2. incsearch.vim の オート:nohlsearch 機能を使えば検索後カーソル移動したらハイライトが消えるようになります.
  3. 地味に便利

incsearch_auto_nohlsearch

設定

1
2
3
4
5
6
7
8
set hlsearch
let g:incsearch#auto_nohlsearch = 1
map n  <Plug>(incsearch-nohl-n)
map N  <Plug>(incsearch-nohl-N)
map *  <Plug>(incsearch-nohl-*)
map #  <Plug>(incsearch-nohl-#)
map g* <Plug>(incsearch-nohl-g*)
map g# <Plug>(incsearch-nohl-g#)

<Plug>(incsearch-nohl-n) などは単なる <Plug>(incsearch-nohl)n のエイリアス なので独自の n*の機能を提供しているわけではありません

3.5 他のプラグインと組み合わせて使う

(3.4のつづき)

incsearch.vim/ とそれにまつわる検索の便利機能を提供するようにシンプルにしようとデザインしてるつもりです(そこっ!検索にまつわる〜とか言ってる時点でシンプルではないとか言わない!). なので n* を拡張したい場合に備え別の拡張プラグインと同時に扱える用に設計しています.

普通に一緒に使う分には何も考えなくとも併用できますが, incsearch.vim の オート :nohlsearch 機能 を使いたい場合はマッピングをちょっといじる必要があるので自分が使ってる例を出してみます

n 拡張プラグイン vim-auzu と一緒に使う

1
2
3
4
map   n <Plug>(incsearch-nohl-n)
map   N <Plug>(incsearch-nohl-N)
nmap  n <Plug>(incsearch-nohl)<Plug>(anzu-n-with-echo)
nmap  N <Plug>(incsearch-nohl)<Plug>(anzu-N-with-echo)

vim-anzu は n/N を押すとファイル内の 現在位置までの数/全マッチ数 を表示してくれる拡張機能です.

* 拡張プラグイン vim-asterisk と一緒に使う

1
2
3
4
map *  <Plug>(incsearch-nohl)<Plug>(asterisk-*)
map g* <Plug>(incsearch-nohl)<Plug>(asterisk-g*)
map #  <Plug>(incsearch-nohl)<Plug>(asterisk-#)
map g# <Plug>(incsearch-nohl)<Plug>(asterisk-g#)

または vim-asterisk のz*機能(カーソルが動かない*) をメインに使う場合

1
2
3
4
map *  <Plug>(incsearch-nohl0)<Plug>(asterisk-z*)
map g* <Plug>(incsearch-nohl0)<Plug>(asterisk-gz*)
map #  <Plug>(incsearch-nohl0)<Plug>(asterisk-z#)
map g# <Plug>(incsearch-nohl0)<Plug>(asterisk-gz#)

vim-asterisk は僕が最近作った * をカイゼンするプラグインです. 機能としては

  1. カーソルを動かさない * 機能の提供(マッピングにzのprefixがついてる)
    • 動かさずに *g* でカーソル位置の単語を検索レジスタ(@/)に入れたあとに gn などを組み合わせて編集したいというケースでは次のマッチに飛ぶ必要がないので カーソル動かないバージョンの * が欲しかった. どうせ n/N ですぐ動かせる
    • noremap * *N という解決法はダサいしウィンドウが一時的に動くので不便
  2. ビジュアルモードで選択したテキストを検索するvisual-star 機能
    • サクッと勢いで作ったので thinca/vim-visualstar のマルチバイトや keyword の扱いの部分のコードをお借りしています. ありがとうございます
    • visual-star は CursorMoved イベントが2回発生してしまうという問題があり, incsearch.vim の オート:nohlsearch 機能と併用できなかった. なので visual-star機能と同時に使いたい場合はvim-asteriskのvim-asterisk機能を使うと便利
  3. ignorecase だけでなく smartcase の値も一緒にみてくれる
    • デフォルトはなぜか ignorecase の値しかみてくれず, smartcase を設定していてもignorecase状態で検索される
    • 非直感的すぎるので vim-asterisk は :set ignorecaseの値も:set smartcaseをみるようになっています

3.6 Vim のデフォルトからちょっとカイゼン

a) magic オプションカイゼン

Vimには 'magic' という正規表現のエスケープする文字を変えるオプションがありますが \m, \M しか設定できません(:h /magic). またこれは/だけでなくすべての正規表現の挙動を変えてしまい設定すると, 対応できていないプラグインが動かなくなったりする問題があります (:h 'magic')

incsearch.vim ではこれをカイゼンして \v, \V, \m, \M の, どの magic でも設定できる. また勿論他のプラグインには一切影響しません.

1
let g:incsearch#magic = '\v'

b) カーソル下単語補完やCtrl-Wによる単語削除のカイゼン

Vimはset incsearch状態で検索中に<C-r><C-w>を押すとコマンドラインのカーソル前の単語とのマッチをみて, バッファのカーソル下の単語を補完してくれる機能を持っています. この機能自体はとてもべんりなのですが, コマンドラインが /\vwo の状態, カーソル下の単語が word の時に <C-r><C-w> を押しても補完が発動せず単にカーソル下の単語が挿入され /\vwowordになってしまいます.

これはvery magicオプションを設定する\vv部分とwoとの区別がなくvwor がコマンドラインのカーソル前の単語と認識されているのが原因なので, カーソル前の単語 の範囲をかしこく決めてくれる機能を提供しています(オプションでoffにすることは可能です. :h g:incsearch#smart_backward_word)

<C-w> によるカーソル前の単語の削除も同様の問題がありこれもカイゼンして, /\vword状態で<C-w>を押すとデフォルトだと/\となるところを\vとなるようにしています

incsearch_smart_backward_word

見た目はとっても地味で聞いてもピンとこないかもしれないですが, 挙動が直感的になるとても気に入ってる機能のひとつです. ジッサイベンリ

3.6 マッピングについて

  1. :cnoremap:cmap に設定されているマッピングは自動で適用される
  2. incsearch.vim が提供する機能へのマッピングや, :cnoremap の設定の上書き, incsearch.vim でのみマッピングしたいという場合は :h IncSearchNoreMap コマンド を使います

設定例

1
2
3
4
5
6
7
8
9
10
augroup incsearch-keymap
    autocmd!
    autocmd VimEnter * call s:incsearch_keymap()
augroup END
function! s:incsearch_keymap()
    IncSearchNoreMap <Right> <Over>(incsearch-next)
    IncSearchNoreMap <Left>  <Over>(incsearch-prev)
    IncSearchNoreMap <Down>  <Over>(incsearch-scroll-f)
    IncSearchNoreMap <Up>    <Over>(incsearch-scroll-b)
endfunction

3.7 autocmd で拡張できる

参照: :h incsearch-autocmd

incsearch.vim は Vim デフォルトのコマンドラインのと違い独自の autocmd イベントを発行しているので, それをつかってincsearch.vimを拡張することができます. 以下は inside/vim-search-pulse というプラグインの機能を簡単に組み込んでみた例です. 個人的には要らないけどなんかカッコイイ…!?

incsearch_autocmd_flash

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function! s:flash()
  for _ in range(1, 3)
    set cursorline!
    redraw
    sleep 50m
  endfor
  set cursorline!
endfunction

augroup incsearch-pulse
    autocmd!
    autocmd User IncSearchExecute call s:flash()
augroup END

noremap <silent> <Plug>(my-flash) :<C-u>call <SID>flash()<CR>
map n <Plug>(incsearch-nohl-n)<Plug>(my-flash)
map N <Plug>(incsearch-nohl-N)<Plug>(my-flash)
" デフォルトの場合
" map n n<Plug>(my-flash)
" map N N<Plug>(my-flash)

4. Development

開発の話とか.

4.1 Design

ここまでいろいろと紹介しておいてどうかという話なのですが, incsearch.vim は シンプルに機能を提供し , デフォルトのコマンドラインと高い互換性を保ちつつ, それでいて拡張性の高いものにしようというコンセプトでつくっています(実際そうなっているとは言ってない)

特に一番苦心したのはデフォルトのコマンドラインとの互換性を保つように開発するところでした. 現在はVimのデフォルトの/でできるほとんどのことはできますが,

ビジュアルモードでのハイライトだったり, vim-repeat といった別のプラグインに依存せず ドットリピートを可能にしたり, 逆にそれを可能にした <expr> マッピングによる textlock という Vimの制限を解消するために, 必要でない部分は<expr> マッピングを使わないようにするといった回り道を しながら, 現在はほぼデフォルトと互換性のある状態にできたと思います.

<expr> についてちょっと解説したりする

  1. :h :map-<expr>
  2. ドットリピート対応できる
  3. :h function-search-undo とかの制限をかいくぐれる
  4. いろいろいじった上で最終的にデフォルトのマッピングを返して実行! ということができるのでデフォルトのモーションを拡張する際にとても便利
  5. しかし問題点もある

<expr> とは expression mapping の略で, {rhs}(right-hand-side) を評価した値を返してくれます.

1
noremap <expr> g/ printf("/%s\<CR>", input('>'))

上記のマッピング例では, {rhs}input('>') が評価され, そこで入力した値を{pattern}とすると それがprintf()によって最終的には /{pattern}<CR> になります.

何がいいのかというと, 実際に dg/pattern などと使った際に, {rhs} が評価されて d/pattern になります. これはそもそも最初から d/pattern と打った時と同様の挙動になるので, あたかもデフォルトの/を使ったような挙動を簡単に実装できるのです! これによって ドットリピート や :function-search-undo に対応することが可能となります.

とは行ってもイマイチわかりにくいと思うので <expr> を使わないマッピングを見てみましょう.

1
2
3
4
function! s:non_expr_search()
    execute 'normal!' printf("/%s\<CR>", input('>'))
endfunction
noremap z/ :<C-u>call <SID>non_expr_search()<CR>

単に検索という意味では動いているように見えるのですが, function-search-undoの制限により ハイライトされず, また dz/patternd:<C-u>call <SID>non_expr_search()<CR> となるので, ドットリピート時にも s:non_expr_search 関数が呼ばれてしまします. これによってその中の input()がドットリピートでも呼ばれてしまい入力待ちになってしまいます. これでは以前に入力した値をつかって検索してくれるデフォルトのドットリピートの挙動が再現出来ていません…不便…

普通のマッピングだとこういう問題があるのでそれを解消ができる <expr> はデフォルトのモーションの拡張にとてもあっているのですが, <expr><expr>で上述した副作用として :normal が使えないといった問題もあるので これから<expr>を使ってプラグイン作りたいっという方は注意して使ってみてください.

incsearch.vim や先ほど紹介した vim-asterisk も<expr>を活用して便利にしたりしています. 他にも rhysd/clever-f.vimderis/vim-shot-f といった f を拡張するプラグインでも <expr> が使用されており, もともとこの<expr>でドットリピートに対応するという方法は 僕は clever-f で初めてみました. スゴイ.

4.2 vital-over, または incsearch.vim のカスタムコマンドラインインターフェースについて

incsearch.vim は vital-over というカスタムコマンドラインインターフェースを提供するライブラリを使わせていただいてます. incsearch.vim のデザインとしてVimデフォルトとの互換性を目指していると先ほど書いたのですが, 実はincsearch.vimがやっている部分は検索だけで, コマンドラインインターフェースがVimのデフォルトと同じように使えるのはこの vital-over というライブラリのおかげです. 本当にアツイプラグインなので興味あるVim プラグイン開発者は是非使ってみてください!

モジュール性が高いのでガッツリとしたコマンドラインとしてではなく, ちょっと便利な input()getchar() として使えるかなーと思います. そのうち何かまた作ってみたい…!

4.3 テストとかLintとか

  1. themis.vim でテスト書いた
  2. vim-lint / vint (期待)
  3. テストって便利って改めて気づいた…!
  4. themis のテスト書き方自体は vim-jp/vital.vim など他のものを参考にするとよいと思う

incsearch_dot_reporter_test.png incsearch_badges.png

今回incsearch.vim は(現在が開発&メンテしてるvim-easymotionでもちょっとずつやってはいましたが)割と初めてスクラッチでテストやlintをしながら 書いたものだったのですが Vim script の開発周りの環境はかなり便利です. 特に Vim を使えるところが開発しやすくてよいです.

CI も travis で 最新に近い Vim と travis.org の Vim のバージョンの両方でテスト (Test on the latest Vim by crazymaster · Pull Request #241 · vim-jp/vital.vim) したり, Vim プラグインを Windows 環境でテストする - 永遠に未完成 を参考に Windows 環境 でもテストがしてみたりしてなかなかよかったです. (Windows環境だけで違う挙動になるのヤメローッ!)

Lint に関しては Kuniwak/vint という python 製ツールも気になっているので期待ですね.

4.4 Vim script 楽しいっ

テストやLintツールもあるし, vim-jp/vital.vimosyo-manga/vital-over といったライブラリ, Vim から引ける膨大な:help, 困ったら vim-jp – LingrIssues · vim-jp/issues に相談, バグ報告できる環境, Vim を使って開発できる Vim script を書くのは楽しいです…!


……..

….ほんとうですよっ!? (言語仕様は寛容な心でカバー)

ぜひぜひみなさんVim プラグイン開発やっていって開発効率を上げたり快適でリッチなエディタ環境を作ってみましょう…!

(※ 用法, 用量を守ってただしくVimしましょう)

5. 最後に

話が逸れてる感をひしひしと感じますが, あくまで incsearch.vim を紹介・解説する記事だったはずなので話を戻しましょう.

incsearch.vim, 今でもとても便利だと思っているのですが, まだまだ開発していく余地があります. (後方互換性を壊すことはしないと思います)

autocmd の拡張例を上述しましたが, まだコマンドラインの中身をいじれるようなインターフェースは実は提供できていません. どこまでオープンにしていけばいいのか, オープンにしたら本当に便利になるのか, などなど僕にとっては難しくゆっくり考えながら決めて行きたいです. 意見頂けたりとかコントリビューションお待ちしています…!

Vim Advent Calendar でテンションあがってちょっと長くなってしまいました. ここまで読んでくださった方ありがとうございます.

incsearch.vim 是非1度使ってみてください. 気に入って頂けるとそれはとっても嬉しいです!

それではVim Advent Calendar 2014の14日目の記事でした.

Happy Vimming!