haya14busa

haya14busa’s memo

Vimでmigemoを使って日本語でもローマ字のまま検索がしたい

この記事は Vim Advent Calendar 2013 75日目の記事になります。

Migemoとは

「Migemoとはローマ字のまま日本語を検索できるものです」みたいな紹介をしようと思ったら思ったよりも『インクリメンタル』が重要なファクターっぽいですね。今回はインクリメンタル基本的にしない/できないmigemoの紹介です。

vimでもmigemo使いたいですよね。

+kaoriyaのVimならデフォルトでmigemoが使えるけど

+kaoriya以外のVimでmigemo使うのは(昔は)結構面倒くさかったように思えます。

-kaoriyaでmigemoを使う方法としては

  1. C/Migemoを端末にインストール
  2. cmigemoと連携する Vim プラグインをインストール

なのですが、1は

apt-get install cmigemo
brew install cmigemo

などなどで割と簡単だったのですが、koron/cmigemoのVimプラグインの部分がかなり昔から書かれていたこともありその後の2でパス通すのがつらい、プラグインのみで配布されていないのでプラグインマネージャで簡単にインストールできないなどなどちょっとつらい仕様だったので、Vimプラグイン読書会がはじまった初期の右も左もわからない時にPull Requestしてkaoriyaさんにレビューしてもらったり、プラグイン部分を独立してGitHubに上げる権限をもらったりしました。

haya14busa/vim-migemo

ということで、昔の他の人の記事とかを見るとちょっと面倒くさいようにみえるcmigemoのVimへの導入も、

NeoBundle 'haya14busa/vim-migemo'

このように割と簡単にできるようになりました。あとvimprocが使えたら使うなどちょっとした改善もしたような記憶があります。

使い方は以前と同じで :Migemo コマンドまたはデフォルトで <Leader>mi にマッピングされています。(<Plug>の提供とかプロンプトの文字列の変更とかの追加はそういえばやっていないけれどしたほうがよいかな…)

別のプラグインでちょっと便利に(?)つかう

基本的にどのプラグインも+kaoriyaでmigemoがデフォルトで使えればそれを、cmigemoがインストールされていればcmigemoを、どれも無理なら使えないという仕様になっていたはずです。

rhysd/migemo-search.vim

つい先日、vim日本語検索をちょっと便利にするmigemo検索 | TechRachoで紹介されていましたがLindanさん ware のrhysd/migemo-search.vimというプラグインがあります。

NeoBundle 'rhysd/migemo-search.vim'
if executable('cmigemo')
    cnoremap <expr><CR> migemosearch#replace_search_word()."\<CR>"
endif

これは<CR>にマッピングすることで、Vimデフォルトの検索をするときに、検索文字列がローマ字っぽかったらmigemoをよしなに呼んでくれるというものです。こちらの仕様のほうが好きな人はオススメです。個人的にはちょっと試した程度でほぼ使っていないので実は使用感はお伝え出来ません。

Uniteのmatcherにmigemoを使う

Shougo/unite.vim

:h unite-filter-matcher_migemo

NeoBundle 'Shougo/unite.vim'
nnoremap <silent> g/ :<C-u>Unite -buffer-name=search line -start-insert<CR>
call unite#custom#source('line', 'matchers', 'matcher_migemo')

実はUniteのmatcherの1つにmigemo機能があります。なので、Vimデフォルトの検索とは 操作法が異なりますが、lineソースにmigemoのmatchersを充ててmigemo検索をUniteですることができます。

EasyMotionのmigemo機能

Lokaltog/vim-easymotion

2012年のVAC記事(Vim-Easymotionを拡張してカーソルを縦横無尽に楽々移動する « haya14busa)でEasyMotionで1文字migemoを使えるようにしたと紹介したのですが、最近 n-key motionとして任意の数のキーでEasyMotionできるVimデフォルトの検索の拡張を実装したので、cmigemoがインストールかつ、migemoオプションがオンなら同様にEasyMotionでもmigemo検索できるようになりました。

NeoBundle 'Lokaltog/vim-easymotion'
map g/ <Plug>(easymotion-sn)
omap g/ <Plug>(easymotion-tn) " opeartor-pending時にVimデフォルトの検索の仕様に合わせる
let g:EasyMotion_use_migemo = 1 " Migemo機能ON

このあたりは全く別の記事でまた紹介したいのですが、このEasyMotionの検索機能の拡張とも言うべき機能は、インクリメンタルにハイライトしたり、普通のEasyMotionの機能と違って画面外まで飛んだり、<Tab>キーでスクロールできたり、勿論検索履歴やテキストオブジェクトgnとも連携させたりしているので、完璧とは言わないまでもデフォルトの検索をこれに置き換えてもよいかなぁというレベルになっています。

仕様

もともとEasyMotionがスクリーン内の移動を拡張するというコンセプトなので、仕様としてはmigemo機能がONになっていてもスクリーン上にマルチバイト文字が無ければmigemoを使わないようになっています。なので、普段コードを書くときにmigemoによって遅くならないようになっているともいえるし、画面外に日本語があるとはわかっているんだけど画面内に日本語が無ければ発動しないという残念仕様でもあるとは言えますね…

またインクリメンタルハイライトにmigemoを対応させていないので、実はMigemoに関してはインクリメンタルハイライトの一貫性がなくなってしまっている状態(インクリメンタルにハイライトはされていなくても<CR>で実行するとマッチする)なのでmigemo機能として使うには実はあんまりオススメはできません()。現状での仕様をわかった上で使ってくれたらいいかなぁと思います。

というのも、システムのcmigemoを呼ぶという性質上、毎回のinputでインクリメンタルにcmigemoを呼ぶと、とてもじゃないけど耐えらたものじゃない速度になってしまい、実装してみましたが敢え無く断念しました。このためにProcessManagerも使ってみたんですがやっぱりダメでした…無念。

そのうち要望 or 気が向いたら、インクリメンタル検索中のキーマッピングとしてmigemo使って一時的にハイライトさせるみたいな機能を実装するかもしれません。(それでも不便感は拭えないですが…)

まとめ

migemoで日本語の検索も出来てよいです。ただ+kaoriyaコンパイル以外でのインクリメンタル検索は基本つらいのでまだ改善の余地はあるかもしれないですね。

それでは Vim Advent Calendar 2013 75日目の記事でした。

Vimの検索ハイライト,hlsearch,:nohlsearch,v:hlsearchがややこしい

この記事は Vim Advent Calendar 2013 73日目の記事になります。

普段何気なくvimrcに書いているset hlsearch:nohlsearch。実はこれ、結構ややこしいです。

まずはhelp!

そして他に注意すべきものとして

  • set nohlsearch <- set hlsearchの逆。:nohlsearchとは違う
  • &hlsearch <- オプションhlsearchの値の変数。set hlsearchなら1,set nohlsearchなら0

ややこしいですね。

v:hlsearchを解説しながら全体的に説明するよ

最近縁があったのでv:hlsearchの日本語訳を書かせて頂きましたが、ぶっちゃけ元の英語の説明もわかりづらいのでここで解説します。

                    v:hlsearch hlsearch-variable
v:hlsearch  検索による強調表示がオンになっているかどうかを決定する変数。
        |+extra_search| 機能が必要である ‘hlsearch’ が有効になっている
        時のみ意味をなす。この変数を0に設定することは、 |:nohlsearch|
        コマンドを実行することと同様に働き、1に設定することは以下と同様に働く >
            let &hlsearch = &hlsearch

まず仕様ですが、この変数は実際に現在検索によるハイライトが行われているかどうかを判定、決定できます。

判定

echo v:hlsearch

  • ハイライトが行われている -> 1
  • ハイライトが行われていない -> 0

決定(ハイライトをON or OFFにする)

この変数を0に設定することは、 |:nohlsearch| コマンドを実行することと同様に働き、 1に設定することは以下と同様に働く let &hlsearch = &hlsearch

わかりずらい!!!

let v:hlsearch = 0

これは、helpによると:nohlsearchコマンドを実行することと同様に働きます。

|:nohlsearch| コマンドを使うと、一時的に強調表示をやめさせることができます。

一時的に というのがミソです。この:nohlsearchコマンドはhlsearchオプションの変数である、&hlsearchを変更しないのです。つまりset hlsearchしている場合&hlsearch変数の値は1ですが、:nohlsearchを実行しても&hlsearchの値は1のままでハイライトを一時的にオフにします。

let v:hlsearch = 1

helpによると1に設定することは

let &hlsearch = &hlsearch

をすることと同様に働くようです。ここがかなりわかりずらい。

前提として、

  1. 基本的にv:hlsearchは実際にハイライトを行っているかどうかを決定するのですがset nohlsearchが設定されていた場合はset nohlsearchが優先されます。
  2. コマンド:nohlsearchによって一時的にハイライトをオフにした場合、再び検索するなどしたときにハイライトが有効になるのですが、set hlsearch,つまりはlet &hlsearch = 1を設定した場合も同様にトリガーとなってハイライトが有効になります(実装は見ていないので予測含む。動作確認はしています)

よって、もしset nohlsearchが設定されていれば&hlsearchの値は0なのでlet &hlsearch = 0と同様の動作となり何も起こりません。

反対に、set hlsearchが設定されていれば&hlsearchの値は1で、let &hlsearch = 1と同様になり、前提の2からこの動作がトリガーとなって再びハイライトがONになります。

はぁ、ややこしかった。わからなかった方は直接@haya14busaまで質問とかしてください。また間違ってたらご指摘よろしくおねがいします。

ここからv:hlsearchから得られたTipsを2つ紹介します

Reloadableなvimrcの設定

一般的には下記のような設定をしている方が多いと思います

set hlsearch
nnoremap <silent><Esc><Esc> :<C-u>nohlsearch<CR>

が、リローダブルなvimrcを目指している方はこの問題に少なからず気づいているかもしれません。

つまり、set hlsearchを記述しているとリロード時に問答無用でハイライトされてしまうのです。(ウザイ

これを改善しましょう

1. 簡単かつv:hlsearchがなくてもOK

“ hlsearchは使うがvimrcを読み込んだ時にハイライトしないようにする
set hlsearch | nohlsearch

上記のようにすると&hlsearchの値は1で検索のハイライトは有効になっていますが、:nohlsearchコマンドによりそれを一時的にOFFにします。

欠点: ハイライトしている状態でリロードするとハイライトが消えてしまう。

2. v:hlsearchを使って1の欠点をなくす

if exists(‘v:hlsearch’)
  let v_hl_save = v:hlsearch
endif
set hlsearch
execute exists(‘v:hlsearch’) ? ‘let v:hlsearch = v_hl_save’ : ‘nohlsearch’

欠点: 書き方が悪いということを除いてもわざわざそこまでしたくない…

スクリプトから扱う

ハイライトを確認する

v:hlsearchが登場する以前では&hlsearchの値を見ることしかできず、ハイライトの設定がされているかどうかは分かるけれども、実際にハイライトされているかどうかがわかりませんでした。(:nohlsearchで一時的にハイライトしていなくてもset hlsearchしていれば一貫して&hlsearchの値は1です)

v:hlsearchの登場によって改善されたのはほぼこの一点といってもいいでしょう。

実際に関数からハイライトさせる

上記の記事の問題はv:hlsearchでも同じなようで、関数内でlet v:hlsearch = 1にしても実行が終わると勝手に元の値に戻されてしまいます。これを回避するには記事にあるように:h feedkeys()を使うしかないようです。残念…

ちょっと改善

上記の記事の関数だとset nohlsearchのオプションを無視してしまうので下記のように:let &hlsearch=&hlsearch\<CR>を使うとよりお行儀よくハイライトさせることができます。

function! HLsearch()
    call feedkeys(“:let &hlsearch=&hlsearch&lt;CR>”, “n”)
    “ または
    ” call feedkeys(“:let v:hlsearch=1&lt;CR>”, “n”)
endfunction

最後に

最新への追従 #84: https://github.com/vim-jp/vimdoc-ja/issues/84

Vimの日本語訳がオリジナルのヘルプに追従しきれていないようです。実際v:hlsearchを訳して、レビューしてもらったりしましたが、結構新鮮で面白かったしこれからも暇があれば、僕も日本語訳に参加して貢献できればいいなと思います。人手は足りていないようなので、気になった方は簡単な/分かるところからでもいいから訳して、vim-jpに投げてみるといいのではないでしょうか。きっとみんな優しくしてくれると思います。

第3回 Vim Plugin読書会が開催されます!!!

投稿時点で30分前です!!!怠慢!

ぜひわいわい参加しましょう。

unite sourceの作り方

:h unite-create-source

読むプラグインの紹介

unite-mcdonalds-vim

unite-sourceの作り方とweb-api.vimの使い方を両方同時に学べて,お腹もいい感じにすく一石三鳥なプラグインです。

mattn/unite-gyukaku-vimもあるのでこちらもオススメです

unite-fold

製作者のおしょーさん曰く、魔改造されていて自分でも難しいとのこと[要出典]なので、気合を入れて読む必要があるかもしれません。Vim script力の高まりを感じましょう。

Vimのhelpを快適に引こう

この記事はVim Advent Calendar 2013 : ATNDの58日目の記事です。 57日目は@deris0126さんによるVimのタブで開いているバッファのdiffを簡単に表示するpluginを書いたでした。

Vimのhelpを自由自在に引けることは、真のvimmerになるための第一歩。

:helpを使いこなす = Vimを極めるための一歩

Vimの極め方

ということで、数多くのVimmerがVimのhelpの使い方を解説したり、おすすめのhelpを紹介したりしています。しかし、helpを読むための設定、カスタマイズ方法を紹介するものがあまりないように思えたので、今回は既存のhelpに関する記事のまとめと、設定/カスタマイズ方法を中心に書いていきます。

help記事のまとめ

Helpの使い方全般

まずは上記の記事や:h helphelp.txtで使い方を覚えましょう。さらっと流し見するだけでも未だに使いこなせてないものがたくさん見つかったりなどすることがあり、今一度読んでみるのもいいのではないでしょうか。

詳しい使い方については上記の記事でほぼ解説されているのでここでは割愛します。

おすすめのhelp

覚えておくor読むと良さげなhelpがたくさん紹介されています。

ここに載ってるものを除いて独断でおすすめすると

このあたりですね。

motion.txtはhjklからtext-objects,inclusive/exclusiveのような普段あまり意識しない概念など、詳しくmotionについて書かれているので時間があるときに読むと面白いです。

cmdwinについてはちょっとした思い入れがあるという個人的な紹介です。

Vimの設定/操作法を大きく変更するときは、何かとVACの記事などでおすすめされているものをみて設定するということが多いのですが、通常のcommandlineからcommandline-windowに乗り換えたきっかけは僕の場合helpを読んでいて便利そう!と感じたからでした。

よりよい設定方法を模索するためにその後コマンドラインウィンドウに関する記事を読んだりはしましたが、「記事を読む->便利かも?」という流れより「help読んで便利そう-> もっといい設定法ないか探す」という流れのほうが愛着が沸くのでオススメです。

ここから設定Tips

Kでカーソル下の単語のhelpを引く

set keywordprg=:help " Open Vim internal help by K command

デフォルトでKはmanを引く設定になっていますが、上記の設定でvimのhelpを引けるようになります。visualモードで選択した範囲を引くこともできます。引きたいものが関数だと括弧を含めるかどうかで結果が変わるので(を含めて選択して引くといったことができるのでいい感じです。K押しやすい。

helpがちょっと読みにくい

nnoremap <Space>t :<C-u>tab help<Space>
nnoremap <Space>v :<C-u>vertical belowright help<Space>
" MoveToNewTab
nnoremap <silent> tm :<C-u>call <SID>MoveToNewTab()<CR>
function! s:MoveToNewTab()
    tab split
    tabprevious

    if winnr('$') > 1
        close
    elseif bufnr('$') > 1
        buffer #
    endif

    tabnext
endfunction

参考: あにゃログ – vim でタブを使う

直接helpとは関係ありませんが、使い始めの頃helpのウィンドウが読みづらくて仕方なかった覚えがあります。特に開いた後ちまちまwindowのサイズを大きくするのは面倒くさい。

ということで、最初からtab/vsplitで開く設定や、カレントウィンドウを別のタブに開き直すキーマップを使うといいと思います。MoveToNewTabの設定によって「気軽にKで開く->本格的に読みたいからタブページで開き直す」という流れなどがスムーズになっておすすめです。

カレントウィンドウを別のタブに開き直すMoveToNewTabの設定は最初の頃設定してライフチェンジングした覚えがあり、今でもかなり使ってます。help以外でも使えますね。

help用の設定をする

augroup MyVimrc
  autocmd!
augroup END

" qでhelpを閉じる
autocmd MyVimrc help nnoremap <buffer> q <C-w>c

" 一気に複数設定する場合
function! s:init_help()
  nnoremap <buffer> q <C-w>c
  nnoremap <buffer> <Space><Space> <C-]>
  " etc ...
endfunction
autocmd MyVimrc help call s:init_help()

個人的にはqで閉じるくらいしか設定していませんが、もっと便利な設定とかきっとあるので自分好みにしていきたい。

日本語でも読みたい

  • vim-jp/vimdoc-ja

    set helplang& helplang=en,ja “ If true Vim master, use English help file. NeoBundle ‘vim-jp/vimdoc-ja’

僕の場合最初は英語だけを設定しており、なんとか頑張ってhelpを読むといった状態でした。

それはそれでいいことだとも言えるのですが、なんだかんだ日本語だとよりわかりやすかったり、英語でわからなかったら日本語で読めばいいという安心感からhelpを読む抵抗が減るので、英語環境でvimを使っていてまだ使っていない方はインストールしておくと良いと思います。

上記の設定だとkeywordの後に@jaをつけることで日本語helpが読め、デフォルトでは英語になります。

自動でhelpを折りたたんでほしい

これは、前々から思っていて、無ければ自分で作ってみようかと思っていた時期が僕にもありました。

が、調べてみるとthincaさんがすでに作ってた。試してみたところfoldtextも含めいい感じに折りたたんでくれます。

折りたたみ好きはぜひ

Uniteでhelpを引く

  • tsukkee/unite-help
  • Shougo/unite-help

    “ NeoBundleLazy ‘tsukkee/unite-help’ NeoBundleLazy ‘Shougo/unite-help’, { \ ‘unite_sources’ : ‘help’ \ }

    “ Execute help. nnoremap :Unite -start-insert help ” Execute help by cursor keyword. nnoremap g :UniteWithCursorWord help

書いている時に気づいたのですがShougoさんのfork版が存在してメンテナンスされてるっぽいです。中身の差分みてないので何が改善されてるかは知らない(怠慢)

追記: 主にキャッシュ周りが改善されているようです

Uniteでインクリメンタルに検索できてhelpが格段にひきやすくなるので良さげです。

ブラウザでもhelpを引く

Vim記事を呼んでいるとき、LingrのVim部屋で気になるものがあったけど、botに検索してもらうほどでもないかな..というとき、手元のタブレットでvimのヘルプが読みたいときなどなど、ブラウザでvimのhelpを読めると便利な場面がきっとあるとおもいます。

そんな時は上記の日本語版ヘルプ or Sourceforgeの本家のヘルプを読むといいんですが、日本語版は検索がGoogleカスタム検索で少し不便、英語版は検索機能は高いけどレイアウトが見づらい…両方わざわざアクセスするの面倒くさい…

そういった不満を改善する(かもしれない)ブックマークレット、作りました。

GitHub: haya14busa/vimdoc-marklet

ブックマークバーにドラッグ&ドロップで登録できます。

上から日本語版ヘルプを検索、英語版ヘルプを検索、どちらかを開いているときにもう片方の言語で開くブックマークレットです。(en-to-jaとかネーミングおかしいのは目を瞑りましょう)

vimdoc@ja,@enは事前に選択しておくとそのワードで検索します。これでVim記事読む時もhelpが手軽に読めて便利。

日本語版ヘルプの検索機能は、Googleカスタム検索ではなく、おしょーさんにつけてもらったLingrのbotが使っている方法のリダイレクトバージョンを使っているので、ほとんどvimの検索ワードと同じように使えるはずです。おしょーさんありがとうございます。

まとめ

ここまで個人的に有用だと思うhelpに関する設定やプラグインを紹介しましたが、もっと便利な設定や知見がきっとたくさんあります。それを上級Vimmerに教えてもらう…のもいいですが、それだけでなく自分でhelpを読み込んで使いこなせるようになりましょう!(自戒)

Let’s :help!

Don’t panic!

Vimプラグイン読書会第2回が1/11(土)21:00から開催されます!

第2回 Vimプラグイン読書会 案内

このページでVimプラグイン読書会の情報をまとめています。-> Vimプラグイン読書会

clever-fの紹介

clever-fはその名の通りf{char} による移動を強力にするプラグインです。

fで移動したあと;,の代わりにf , Fでそれそれ順方向、逆方向に移動できるのでキーマップを節約できたり、オプションを設定すれば、行をまたいで移動、smartcase機能、migemo機能などを使うことができます。

使ったことない人は、少しだけ試してから読書会にくると、より見るべき部分がわかって面白いと思うので使ってみるとよさそうです。

;,はあまり頻繁に使用しないせいで何かしらのprefixキーとして潰されてたり、そうでなくてもこれから使えると便利な位置にあるので、オプション設定無しで単にf or Fでリピートさせるという使い方だけでも地味に助かるプラグインだと思います。

個人的には簡単なマクロ使うときにとても重宝しています。(そういう意味では行を跨ぐ機能はOFFにしたほうがいいかなーと最近思ってる。オプションでちゃんと設定できます)

見どころ(個人的に)

前回のjunkfile.vimやvisualstar.vimよりも少し大きくなってちょっと実践度があがるのかなと思います。(helperスクリプトようにファイルを分けたりも前回はしていなかった気もするし)

カーソルキーの位置、状態によってキーの挙動をかえてる

どうやって実装してるのか、こういうところはkana/vim-submodeと似たようなところがあるのかな?ないのかな?とか他にも応用できないかとか、いろいろ考えられそう。(これはvim-submode読まないとわからないけど。あとたぶん違う実装方な気がする)

他にも行跨ぐ機能とか気になるところを重点的によんだりすると良さげ

.によるオペレーションのリピート対応

カーソル移動系プラグインではこれがあるのとないのとではランクがひとつ、ふたつ違うってほど重要事項だとおもうのでこのへんのノウハウはぜひ読みたい。

ちなみにeasymotionでは対応できていないし、同じくfを拡張して2キー対応しているvim-sneakは2キーの場合はリピートできるけど1キーだとできないという現状だったりします。(あとtpope/vim-repeat依存だったり)

migemo対応時のマルチバイト対応など

clever-fとかあんまり使わないというひとでもこういう細かいところは他の場面でも使えるので、汎用的な部分があれば積極的にみていくと良さげ感あります。clever-fに限った話じゃないですが。

Vim scriptでもテストを書きたい

テストの書き方とか参考にしたいなとか個人的に思ってるけど、clever-fの場合はvim-vspecだけでなく、rhysd/vim-vspec-matchersを使っててさらに拡張していたりするので、そのへん見たり見なかったりするのもよさげ。

2キー対応拡張したい

justinmk/vim-sneakのように2キー(or 複数キー)対応ができれば更に便利になるので余裕があれば複数キーに対応するにはどうやって実装すればいいかなーとか考えると面白いと思います。

最後に

ぜひ参加してわいわい読みましょう。

今回参加できなくてもまだゆるゆると続くと思うので、Vimプラグイン読書会に更新情報を載せたりしますので時間あるときに参加しましょう。日時もなんとなく土曜21:00となっているけど、他の時間帯がいいという人が多ければ変えれると思うので意見していくときっといいです。