Mac(High Sierra)上のvimでtermdebugする

先日のVimConf 2018でujihisaさんがお話されていたtermdebug、早速試してみたところ、主にMacgdbでハマったので自分用にメモ。

まずは、ありがたくujihisaさんのスライドを見ましょう。
Modes / VimConf 2018 - Speaker Deck

最新のHomeBrewでgdbを入れると、今だと8.2がインストールされ、Mac(High Sierra)だと動かないらしいので、以下の記事を参考に、8.0を入れる。(Mojaveだとまた違うかもしれない)
macOS High Sierra 10.13 では gdb 8.1 は動かない - Qiita

gdbを動かすために、コード署名が必要なので、以下の記事を参考に署名する。
mac OS 10.13(High Sierra) で gdb を使う - Qiita

ujihisaさんのスライドを参考に

  1. git clone https://github.com/vim/vim
  2. cd ./vim
  3. ./src/Makefile を手動編集 (ujihisaさんスライド参照)
  4. make
  5. ./src/vim ができる。
  6. ./src/vim を実行 (.vimrcなど読まれたくなければ適宜-u NONE -Nなどをつける)
  7. :set packpath+=./runtime (termdebugをpackaddで追加するため)
  8. :packadd termdebug
  9. :Termdebug ./src/vim
  10. terminal上でgdb表示される。
  11. run -u NONE -N

:Termdebug めっちゃ便利

P.S.
6. 以降は別にビルドしたvim使わなくてもMacVimなどでも良かった。
ただし、:Termdebug ./src/vimにはビルドしたvimを指定すること

VimConf2018が最高に最高だった話

この記事は、2018/11/24(土)に秋葉原富士ソフトアキバプラザで開催されたVimConf2018の参加レポートです。

はじめに

まず始めにお伝えしたいのは、運営の方への感謝の言葉です。

今年は運営として参加することができませんでしたが、 昨年のVimConf2017の運営に参加させていただき、運営側の大変さは身にしみて感じているだけに、 Bramさん、Akinさん など海外勢を招待するためにかけた労力、翻訳周りの調整など、 同会場で昨年開催した実績があるとはいえ、新たに準備が必要になったことも増えていて (多分私が把握していないことも多々あるでしょう)、 それをあの人数でまわすのは相当な労力がかかったかと思います。
運営の皆さん本当にお疲れ様でした!そしてありがとうございました!

また、発表された方もお疲れ様でした。
準備にかけた時間、当日の緊張感(おそらくご自分の発表までは気が気でなかったと思います)は相当なものだったと思います。
今年も例年通り、質の高い発表ばかりで本当に楽しい1日を過ごさせていただきました。
発表された皆さん本当にお疲れ様でした!そしてありがとうございました!

また、参加者の方もお疲れ様でした。
お話できた方、お話できなかった方含め、皆さんの参加、熱量で成り立っているカンファレンスです。
皆さんと同じ時を共有できてとても有意義な時間を過ごすことができました。
皆さんありがとうございました。

今年も大成功のカンファレンスでした!

Vim人生最良の日

一晩明けてだいぶ落ち着いてきましたが、昨日(11/24)は私の(いや、多分VimConf2018に参加した全員にとっての)Vim人生においての本当に記念すべき日で、 私は1日中興奮しっぱなしで夢のような1日でした。
一晩明けた今も若干夢見心地な気分です。

だって考えてみてください。Apple好きにとってのSteve JobsMicrosoft好きにとってのBill Gates、そしてそう、VimmerにとってのBram Moolenaarです。
(この記事を読むだろうVimmerにとっては言うまでもないかもしれませんが、BramさんはVimを作った人です)

歴史上の偉人が目の前に顕現したかのような、不思議な光景。その偉人ご本人による素晴らしいキーノート。
(後日動画が公開されると思いますので是非見てみてください。Vim作者御本人から語られる Vimに今後追加されるかもしれないnext featureの話は必見です)
カンファレンスの間は始終アドレナリンが出っぱなしでした。
(そのおかげか、帰ってからの疲労感が半端なかったです。心地よい疲労感でしたが)

Bramさんはとても気さくな方で、休憩時間中の参加者からの質問にはとても丁寧にお答えしていて、 また握手、サイン、写真撮影のお願いにも 快く応じてくれていました。

私は、幸運にもBramさんの近くに席を陣取ったものの、英語力のなさとVim作者が眼の前にいることの畏怖感、 話しかけたいけど話しかけられない緊張状態が午前中ずっと続いていました。
お昼に振る舞われた美味しいお弁当(今半のお弁当ですよ!)も味わって食べることもできず、 運営のKaoriyaさん(昨年運営でご一緒したので普通に話せる仲になりましたが、 この方も日本人Vimmerにとっては偉人です)に「ご飯食べるの早いね」と言われる始末でした。

また、休憩時間中に友人に会っては、「Bramさんに話しかけました?」と声をかけたり、 Bramさんと話している参加者を遠目で眺めては羨ましく思っていました。

そんなこんなで始終グダグダしていましたが、おそらく一生に1度しかないチャンスです。
千載一遇、一期一会、勇気を出して声をかけました。友人の後ろからついていく形で…(tsukkeeさんありがとう!)
正直話したと言っても、眼の前に行って、握手して、横で話をフンフン頷いて聞いているだけでしたが、 本当に夢のようなひとときでした。

そしてなんと!記念にBramさんと一緒に写真も撮ってしまいました!
これは一生の宝ものです。
写真をお願いしたときもとても快く応じてくださいました。
Bramさん本当にありがとうございました!

VimConf本編

何かBramさんの話ばかりになってしまいましたが、VimConf本編も豪華な発表者、非常に濃い内容で本当に素晴らしいものでした。

発表に関する詳細は後日公開される動画や、他の方の参加レポートを参照いただくとして、 個人的に気になったポイントだけお話すると

  • mattnさんのVimのnext featureの話(Bramさんの目の前でnext featureについて提案する発表は本当に興奮しました)
  • Bramさん自身によるVimのnext featureの話(こんな話を聞ける機会はVimConfでしかありえないでしょう。本当に興奮しました。Vim scriptコンパイル来るか!?)
  • daisuzuさんのpluginからVimの標準に置き換える話(目が冷めました。もっとVim道を精進します)、
  • ujihisaさんのVimのモードについての話(タイトルからVimソースが出てくるとは想像できなかったw termdebug超便利)、
  • OKURAさんの日々の開発におけるVimの使い方について(デモ中は会場全体が一体になって応援してました)
  • USAMIさんのPHPを開発する上でのEmacsの話(The PHPerという感じでHacker感が強く良かったです)
  • Alisueさんの効率的なモダンVim scriptの話(最初の厨ニ感満載のスライドからどうなるかと思いましたが、非常に丁寧なVim scriptの解説良かったです)
  • rhysdさんのWebAssenblyを使ってブウザでVimを動かす話(流石の犬クオリティ。レベルが高くて、相変わらず頭おかしい。いや、いい意味で。あと軽い話ではなかったですよ)
  • どのLTも面白かったです。ドラ役のaomoriringoさんもグッジョブでした

皆さん本当にとても素晴らしい発表でした。ありがとうございました。

懇親会

久しぶりな色々な方とお話させていただきとても楽しい時間を過ごすことができました。
お話していただいた皆さんありがとうございました。

特に印象的(というかびっくりした)だったのは、h_eastさんがいらっしゃっていたことです。
k-takataさんとお話されているところを、たまたま気づくことができ、少しですがお話させていただきました。
SNSでは交流があったのですが、初対面で直接お話できて嬉しかったです。ありがとうございました。
(ちなみにご存じない方にお話しておくと、h_eastさんはVimにめっちゃパッチを送っている日本Vim界の重鎮です。 関東在住ではなく勉強会もあまり参加されないので直接お会いできるのは相当貴重でした)

ちなみに余談ですが、mattnさん、kaoriyaさん、h_eastさん、k-takataさんがちょうどカメラの画角に収まる範囲に 揃っていたのでめっちゃ写真撮りたかったですw
(VimConfはプライバシーに配慮していて、不特定多数が映る写真撮影NGなので無理でしたが)

おわりに

最近、Vim活できていなかったのですが、VimConfに参加して一気にVim熱が上がりました。
特に感じたのは英語ができない不甲斐なさだったので、心機一転英語頑張っていきます。

最後になりますが、VimConf2018運営にかかわられた皆さん、発表された皆さん、参加者の皆さん、本当にありがとうございました!
最高の1日を過ごすことができました!
またどこかでお会いしましょう!
Happy Vimming!
f:id:deris:20181125162705j:plain

VimConf2016の延長線で出来たネタ

本記事はVim Advent Calandar 2016の13日目の記事です。

前置き

まずはこの動画を見てください(※私の動画ではないです)。

この動画は先日行われたVimConf2016でt9mdさんが発表されたときの動画です。


vim-mode-plus for Atom editor

私はVimConf2016に参加して、リアルタイムに発表を拝見していたのですが、 発表中「すげー」という単語しか出てこないくらいすごかったです。

言葉でうまく表現するのが難しいですが、すごかったところをざっくり言うと、

  • Vimの、特にtextobjects、operator周りの考察が深い。
  • AtomVim風に操作できるvim-modeというpackage(Vimでいうplugin)をforkしてvim-mode-plusで、Vimの機能を移植するのみならず、様々な独自機能を追加され、完全に独自進化を遂げている。
  • そして、そのvim-mode-plusで独自追加された機能が、Vimについて深く考えていないと作れないようなもので、どれも面白く便利そう。

vim-mode-plusの機能について説明するのが本記事の目的ではないので 詳しく知りたい方は、上の動画およびt9mdさんの発表slideを是非見てみてください。

この発表を見てVimを初めた当初の様々な新しい機能を覚えていくときや、新しいVim pluginを思いついたときと似たような、 最近忘れていたVimへの気持ちの高まりというか、なんというか不思議な感覚を覚えました。

そして、VimConf2016が終わっても熱は冷めやらず Twitter上で何人かのVimmervim-mode-plusについての議論になりました。

そして議論の延長で、

と、kaoriyaさんがマルチ選択のVimのissueを立てられたり、

と、haya14busaさんが爆速でvim-mode-plusのoccurence機能と似たような機能を持つ(ちょっと違うけど便利) Vim pluginを実装したり

vim-mode-plusに触発されて色々な話がでてきて盛り上がりました。

で、やっと本題になるんですが、以下のhaya14busaさんのツイート

を、ここ1ヶ月ほど放置していたのを、ちょうど先週Vim Advent Calendarネタに困っていたときに 思い出したので、これをネタにしようという運びとなりました。(ヒドイ)

haya14busaさん、そしてt9mdさんありがとうございました。

以下今回のネタですが、vim-mode-plusの機能である、Keep cursor position by operator (operatorでの操作時カーソル位置を移動しない機能 & operatorの操作対象を一瞬ハイライトする機能) 相当の機能をVim pluginでできるようにしましたという話です。

Keep cursor position by operator

Vimで例えばoperatorのヤンクを使用すると、 カーソル位置がヤンク対象の textobject の先頭に移動します。 この動作はVimの設定で変えられるものではなく、 状況によっては使いづらいケースがあります。

例えば、大きめの段落をテキストオブジェクトでヤンクした際や、 textobj-entireでファイル全体をヤンクした際など、 「あれ?さっきいたところどこだっけ?」となることがあります。

本記事では上記ケースを解決するために「ヤンクした時にカーソル移動しない」機能を 実現するためにoperator-userを forkして実験的にフック機能をつけてみました。

なお、実験的なのでexperiment/hookというブランチを切ってそちらで実装しています。 時間がなくI/Fが練られていなかったり、テストがなかったり、ドキュメントが雑だったりの状態なので、使用は自己責任でお願いします。

(インストール方法も、使用方法もあまり詳しく載せていないのは決して時間がなかったからではない。はず。。。)

整理してそのうち本家にPRを送りたいですが、いつになるかは不明です。。。

(どなたか代わりにやりたいという方がいたらお願いしたいです)

operator-userのfork版 実験ブランチのフック機能

以下のようなフックを追加する関数を用意しています。 (なお実験ブランチなのでI/Fは変更される可能性があります。ご了承ください。)

" フックを登録する。
" {hook}で登録した関数を、{when}で指定したタイミングで呼び出すことができる。
"
" {hook}は文字列stringまたは関数参照Funcrefで指定。
" 文字列で指定する場合、定義された関数名である必要がある。
" フック関数が取る引数は{when}の指定によって異なる。
"   'before'  Hook(operator_name)
"   'after'   Hook(operator_name, motionwise)
" operator_nameは、operator#user#define()または
" operator#user#define_ex_command()の第1引数
" motionwiseはoperatorで選択された範囲が行単位か、文字単位か、ブロック単位か
" を表す。
"   'line'  行単位
"   'char'  文字単位
"   'block' ブロック単位
"
" {when}には、どのタイミングでフックするかを指定。
" 'before'と'after'を指定可能。それぞれ意味は
"   'before'  operatorが実行される前
"   'after'   operatorが実行された後
"
" 戻り値はフックのID。後述するフック削除関数で該当フックを削除できる。
call operator#user#add_hook({hook}, {when})

" 登録されているフックを削除する。
" {id}で削除対象のフックを指定。
" {id}はoperator#user#add_hook()関数の戻り値を指定。
call operator#user#delete_hook({id})

" 登録されているすべてのフックを削除する。
" {when}は省略可能。
" {when}が省略された場合、登録されているすべてのフックを削除する。
" {when}に'before'が指定された場合、登録時に'before'で登録したすべてのフックを削除する。
" {when}に'after'が指定された場合、登録時に'after'で登録したすべてのフックを削除する。
call operator#user#delete_hook([{when}])

上記フック関数で、前述の「ヤンクした時にカーソル移動しない」および、「ヤンク対象をハイライト」 を実現してみたいと思います。

フック関数はoperator-userの実験ブランチで実装しているので、 ヤンク時にフック関数を呼び出すために、operator-userを使用して、オペレータでヤンクするoperator-yankを作りました。 (当たり前ですが、operator-userのフック機能は、operator-userをベースとしたoperatorでしか使えません。Vim標準のoperatorでは残念ながらフックは使えません。)

operator-yankと、上記フック関数を利用してまずは「ヤンクした時にカーソル移動しない」機能の 設定を書いてみます。

" operator操作前のカーソル位置を保存
function! MySavePosition(opename)
  let s:save_cursor = getcurpos()
endfunction

" operator-yank操作後に、操作前のカーソル位置に移動
function! MyRestorePosition(opename, motionwise)
  " a:openameをチェックして、operator-yankの操作時のみ移動するようにしている
  if a:opename ==# 'yank'
    call setpos('.', s:save_cursor)
  endif
endfunction

call operator#user#add_hook('MySavePosition', 'before')
call operator#user#add_hook('MyRestorePosition', 'after')

operator操作前にカーソル位置を保存するというフック関数と operator操作後に保存したカーソル位置に移動するというフック関数を用意し、 これら関数をそれぞれフックとして登録しています。

1点だけ特徴的なのが、フック関数の第1引数は、operatorの名前が渡されるため、 これを判定して、特定のoperator(ここではoperator-yank)のみ動作させるフックを記述しています。 上記例では、operator-yankの名前は'yank'で登録しているため、 'yank'で判定することで、operator-yankでの操作時にのみ operator操作後のカーソル位置移動を行っています。

次に、「ヤンク対象をハイライト」機能の設定を書いてみます。

" ハイライト時間
let s:highlight_time = 500
" ハイライトグループ(デモで見やすいようにErrorMsgに)
let s:highlight_group = 'ErrorMsg'

" ハイライトパターンのIDs
let s:matched_ids = []

" ハイライトパターンを削除する
function! MyHighlightDelete(timer)
  for mm in s:matched_ids
    call matchdelete(mm)
  endfor
  let s:matched_ids = []
endfunction

" operator対象を規定時間ハイライトする
function! MyHighlightOperatorTarget(opename, motionwise)
  " operator-yankでの操作時のみハイライト
  if a:opename !=# 'yank'
    return
  endif
  let start = getpos("'[")
  let end = getpos("']")
  if a:motionwise == 'line'
    if start[1] == end[1]
      call add(s:matched_ids, matchadd(s:highlight_group, '\%'.start[1].'l'.'.*'))
    else
      call add(s:matched_ids, matchadd(s:highlight_group, '\%'.start[1].'l'.'\_.*\%'.end[1].'l'))
    endif
  elseif a:motionwise == 'char'
    if start[1] == end[1]  " マッチ行が1行内
      call add(s:matched_ids, matchadd(s:highlight_group, '\%'.start[1].'l'.'\%'.start[2].'c'.'.*\%'.(end[2]+1).'c'))
    elseif start[1] < end[1]  " マッチ行が2行以上
      " マッチした先頭行をハイライト
      let lastscol = col([start[1], '$'])
      call add(s:matched_ids, matchadd(s:highlight_group, '\%'.start[1].'l'.'\%'.start[2].'c'.'.*\%'.lastscol.'c'))
      " マッチした最終行をハイライト
      call add(s:matched_ids, matchadd(s:highlight_group, '\%'.end[1].'l'.'^.*\%'.end[2].'c'))

      if end[1] - start[1] == 2 " マッチ行が3行
        call add(s:matched_ids, matchadd(s:highlight_group, '\%'.(start[1]+1).'l'.'.*'))
      else " マッチ行が4行以上
        call add(s:matched_ids, matchadd(s:highlight_group, '\%'.(start[1]+1).'l'.'\_.*\%'.(end[1]-1).'l'))
      endif
    endif
  endif
  call timer_start(s:highlight_time, 'MyHighlightDelete', {'repeat': 1})
endfunction

" バッファ移動時、ハイライトパターンをすべて削除
augroup MyHighlightDeleteGroup
  autocmd!
  autocmd BufLeave * call MyHighlightDelete(0)
augroup END

call operator#user#add_hook('MyHighlightOperatorTarget', 'after')

ヤンク対象を正規表現で記述しているのと、motionwiseごとの処理 行数によりパターンの切り分けをしており若干読みづらいですが、 気持ちで感じてください。 matchaddにより、ハイライトしています。

規定時間たったらハイライトを消すために、地味にVim8.0のtimer機能を使っていたりします。

BufLeaveイベント時にハイライトを消しているのは、 こうしておかないとハイライト中に別バッファに切り替えたとき timerのコールバックでmatchdelete()によりハイライトが削除しようとしますが matchadd()はウィンドウ単位であり、別ウィンドウでハイライトを削除しようとしてエラーになります。

上記によって、行単位および文字単位での操作対象をハイライトできるようになっています。 なお、ブロック単位でのハイライトはめんどうなので実装していません。

最後に実際に試したデモを載せておきます。

f:id:deris:20161213001117g:plain

ヤンクしてもカーソル位置が移動していないのがわかると思います。 また、ヤンク対象が赤背景で一瞬ハイライトされるのもわかると思います。

類似Vim plugin

vim-operator-flashy

ヤンクした際に規定時間、ヤンク対象をハイライトできるVim pluginです。

今回私が作った、operator-userのfork版の実験ブランチを使わなくても、 operator-userを入れていれば、今すぐ気軽に試せるので便利です。

ちなみに私は先週このpluginに気づいたのですが、これを見たときに「えっ、haya14busaさん既にflash on operate作ってるやん」としばらく呆然としてました。

ただ、こちらはヤンクのみが対象なので、ネタがボツにならなくてすみました。(ホッ

まとめ

以上が、VimConf2016の延長線でできたネタでした。

それではVim Advent Calendar 2016の13日目の記事を終わります。

Happy Vim Life!

VimConf2016に参加しました

2016/11/5(土)に株式会社ミクシィで開催されたVimConf2016に参加してきたので感想レポートを書きました。

ラーメン

今年は、午前中の集まりもあったみたいだけど、前日の終電帰りの疲労により不参加。 今年は運営側でも、発表者でもなく、一参加者として参加したので、かなり気楽に出発し、12:00くらいに会場下についた。 会場についた直後に、thincaさんとryunixさんと一緒に、で すごい煮干ラーメンを食した。

名前の通り煮干がきいてて、こってり系で美味しかった。 thincaさんは、「おにぎり食べちゃったんだよねぇ」と言いつつ、 つけ麺大盛りを頼み、その上スープまで完飲していたので、 ラーメンに対する熱意がすごかった。

一部のVimmerにはVimConfに来たら凪を食べるというのが定番になっているらしい?ので チャンスがあれば食べてみることをおすすめします。

念願の?

会場に着くとVim界の大御所 kaoriyaさん自らが受付で対応されていて、 前々回?くらいのVimConfから面識があったので、少し挨拶をさせていただき 参加者ストラップを頂いたらそこには伝説のアレが…

当時の午前中にTwitterで何人かの方がVimリストバンドの写真を あげられていたので、余っていれば購入しようと考えていたんですが、 まさかの、参加者全員プレゼントなんて!

テンションがあがりすぎてロクなコメントもお礼もできませんでしたが、 ありがとうございました! > kaoriyaさん

家宝にします。

セッション

通常発表からLTに至るまで、Vim界で著名な錚々たるメンツなのは 例年のことなのですが、今年はGoに関連する発表が多く、 特にGo界隈で著名なtenntennさんが発表されに来ていたのが印象的だった。 tenntennさんが講師をされているハンズオンにも一度参加したことがあったので 個人的に楽しみだった。

Vim界隈の人は若干固定化されてきている感じがするので こういう交流が増えていくのは良いなぁと思った。

各界隈でVimをゴリゴリ使っている方はいるはずなので Vimに直接的に関係なくても、少しでも関連があれば 是非発表していただきたいと思った。

各セッションの詳細は既に他の方が書いているので、 気になったところをいくつかピックアップしました。

  • Vim8.0の興味深い機能のいくつかは、vim-jpからの働きによって 入った機能(channel, lambda, etc)であり、改めて、vim-jpすごいなぁと感じた。
  • golang関係の発表が3つもあってgolangの勢いを感じた。
  • golangVimの親和性良い。
  • vim-mode-plus の考察の深さがすごく、感動した。発表中はただただすごいとつぶやいていた。
  • golang速い。nodeもなかなか速い。
  • Vimのhelp翻訳人が足りない問題。参加するとVimの有名人とたくさん知り合いになれて便利そう。

懇親会

懇親会の様子です。

ピザ

寿司

ピザと寿司

ピザと寿司が大量にあり、お酒も出て これで参加費2,000円とはお得以外のなにものでもなかった。

寿司うまいうまい。

懇親会では割と色々な人(といっても知り合いばかりだったのが反省点)と話せてとても満足でした。

以下、酔っていてあまり覚えていないけど、私の懇親会の様子です。

  • haya14busaさんと一緒に、vim-mode-plusのネタを聞きにt9mdさんに突撃するなどした。
  • tsukkeeさんとVim8のjob周りの話、golangVimの相性の話、Vim8以降のVim pluginの話(jobとgolang組み合わせて楽ちんVim programming)などをした。
  • daisuzuさんとdaisuzuさんの職場の方、kaoriyaさん、k-takataさんと職場でのVimの話などをした。
  • aomoriringoさん、ryunixさんとともに寿司行脚をした。
  • aomoriringoさん、ujihisaさん、色々な方とVRの未来について語った。
  • VRはいいぞ

2次会?

会が終わり、何人の方が徹夜カラオケに行くという話になり、開始までに時間が空いたので、 2次会?として、参加者の何人かと渋谷でビックカメラ⇒本屋とブラブラしていました。

と言っても、私は徹夜カラオケ参加は厳しかったのでここで撤収。 徹夜カラオケも盛り上がったようです。 私も行きたかったなぁ…

以下2次会?の様子の写真で締めとします。

終わりに

最近、Vim熱が大分おさまっていてあまり活動できていなかったのですが、 熱い発表ばかりでかなりVim熱が高まったので非常によかったです。

まとめ役のb4b4r07さん、ryunixさん、VimConf2016運営にかかわられた皆さん、 発表された皆さん、参加者の皆さん、会場を貸していただいた 株式会社ミクシィさん、本当にありがとうございました。

またどこかのVim関係の勉強会でお会いしましょう!

Happy Vim Life!

jとkでの移動を矯正するためのVim pluginを作った

本記事はVim Advent Calandar 2015の13日目です。

本来書こうと思っていたネタがあったんですが、若干ネタが大きかったため期間的に厳しく そのネタの内容を検討している時に思いついて作ったVim pluginについてご紹介します。

背景

みなさんはカーソル位置からスクリーン上に見える範囲の特定の行への移動はどのように操作されていますでしょうか?

Vimmerは十人十色なので、様々なやり方があると思います。

例えば

  • 気合でjjjjj・・・kkkkk・・・を使う
  • 5j5kなどを繰り返し実行して距離を詰めた後に最後微調整する
  • (relativenumberオプションを有効にするなどで) 目視で極力一発で目的の行に移動する
  • 様々な縦方向の移動コマンドの中から状況にあった移動コマンドを選択する (/, }, { などなど)
  • (vim-easymotionなどの) 移動系のVim pluginを使う
  • マウスが大好きでマウスを使う

他にも色々あるかと思います。

私は、上記の中で以下を組み合わせてやりたい派です。

  • 様々な縦方向の移動コマンドの中から、状況にあった移動コマンドを選択する
  • 5j5kなどを繰り返し実行して距離を詰めた後に最後微調整する

基本的には、j, k以外のその場に適したコマンドで移動できるところは移動して、 j, k以外の移動コマンドだと手詰まりだったり、面倒だったりした場合には、5j, 5k、 また、j, kで調整するというスタイルです。

効率化という意味ではベストではないかもしれませんが、素Vimでの操作も考えると別に悪くはなさそうです。 ただ、個人的に1点課題に感じているところがありました。

それが以下の部分です。

  • 5j5kなどcount指定で距離を詰めて移動する方

これ、やりたいと思っていますが、実は現状できていません。

じゃあ現状どうやっているかというとこれです。

  • 気合でjjjjj・・・kkkkk・・・を使う

私はOSのキーリピート速度を高速化して、速度的には不都合がないとはいえ、 個人的にはキーリピート速度の高速化は邪道だと思っていますし、 「素Vimでもそれなりのパフォーマンスで操作できる」をモットーで やっている身として、count指定を使えるところは、count指定する べきだし、したほうが効率的だと思うのです。

でも、長年の手癖は早々直せないもの。ということで、これを矯正するために vim-gothrough-jkというVim pluginを作ってみました。

vim-gothrough-jk

vim-gothrough-jkの機能は以下です。

  • j, kを連続で3回以上タイプするとgothroughモードに移行する
  • gothroughモードではj, kをタイプした時の移動幅が5になる。
  • gothroughモードでは 4秒待つか、count指定でj, k移動するか、j, k以外の移動(h, lなど)で通常のj, kに戻る

なお、以下の部分はカスタマイズ可能です(I/Fは変更の可能性があるためここには書きません)

  • どれくらいの間隔(ミリ秒)で連続でタイプしたらgothroughモードに移行するか(現状デフォルトは150ミリ秒)
  • 何回以上タイプしたらgothroughモードに移行するか(現状デフォルトは3回以上)
  • gothroughモード時にj, kで移動する移動幅の変更(現状デフォルトは5)
  • gothroughモードに移行した後、最後にj, kをタイプしてからどれくらいの間隔(ミリ秒)が空いたら通常のj, kに戻るか(現状デフォルトは4000)

以下に動作のスクリーンショットを載せます。

f:id:deris:20151213180358g:plain

3回下に移動した後に、移動幅が5になり、3回上に移動した後に移動幅が5になっていることがわかるかと思います。

わかりやすいように、どれくらいの間隔で連続でタイプしたらgothroughモードに移行するかの値を 大きめにしてやっていますが、実際はj, kを押しっぱなしでないと発動しないくらいでいいかと思います(デフォルトは150ミリ秒)。 環境によってカスタマイズすることを推奨します。

で、このVim pluginの機能でどうやって矯正されることを期待しているのかというと

  • j, kを連続で3回以上タイプするとgothroughモードになるので、count指定のj, kを使わないと近い距離に移動する際に移動しづらくなる。 (例えば、カーソル行から4行下に移動したい場合、jの連続タイプだと途中で移動幅が5に置き換わるので、最初から4jで移動することを意識せざるを得なくなる)
  • 途中から5j, 5kに移行するので、20行下程度でもそれなりに高速で調整できるため、素Vimに戻った時に違和感を感じて、5j, 5kを使いたくなる…(かも)

なお、一般向けに今のデフォルト値にしていますが、移動幅を20くらいにすると、ハードモードになり 矯正もかなり進むのではないかと思っているので、私はしばらくそれで運用してみるつもりです。

類似Vim plugin

vim-hardtime

名前を失念してしまいリンクを貼れず申し訳ないのですが、(Lingr上でryunixさんに教えていただきました。 ありがとうございました。) vim-hardtimeは、j, kを連続で一定回数以上タイプすると、 しばらく(1秒とか)sleepするため、j, kを連続タイプしないよう矯正できます。

Vim pluginの着想は、ここから来た部分が大きいです。

ただ、流石にsleepはやり過ぎだなぁと思って、もう少し有用に使えて、 でも矯正にもなるような機能は無いかなぁと考え、現状の仕様にしました。

vim-accelerated-jk

vim-accelerated-jkj, kでの移動を加速度的に 速くできるVim pluginです。(実際は加速度を計算しているわけではなく、タイプ数に応じて移動幅を増やしています)

最初は似ていると気づかなかったのですが、j, kで、移動幅を変更するという点でかなり似ています。

気づいた時点で、新規にVim pluginを書き起こすか、vim-accelerated-jkの Pull Requestですますか悩んだのですが、用途もやりたいことも(多分)微妙に違うので、新規に書き起こすことにしました。

(もし、気になる機能があったらこれを見た作者のLindanさんが vim-accelerated-jkに輸入してくれるはず…)

まとめ

以上が、j, kでの移動を矯正するためのVim plugin、vim-gothrough-jkの紹介でした。

本題とはそれますが、Vimレベルが上がるのでvimrc読書会に参加することをおすすめします。 私は最近あまり顔を出せていませんが、毎週土曜日23時からやってます。

それではVim Advent Calendar 2015の13日目の記事を終わります。

Happy Vim Life!