新宿もくもく会(仮)をやった

1 年ぶりくらいのブログ更新。まだ書く気あったんですねー。

新宿もくもく会(仮)開催までの流れ

きっかけは 12/26 に日付が変わった直後頃のこと。 Slack での何気ない発言に私が反応したことでした。

Slack での発言

結果的に元発言の「イベント」はリアルイベントを想定したものではなかったんですが、きっかけなんてなんでもいいのです。

呼応する Vimmer

呼応する Vimmer

鉄は熱いうちに打て。即座に調整さんを立てます。

調整さんによる参加者の募集

集結する Vimmer

入力された調整さん

同日 19 時過ぎ。新宿にあるレンタルスペースを予約。開催決定です。

予約完了

当日の様子

途中参加や、都合により早抜けする人もいましたが、計 8 名の Vimmer が集結。

私自身、Vim 関係のリアルイベントは 2020 年 3 月以降で初めてです。 非常に和気あいあいとした雰囲気で、もくもく会と言いつつ常に誰かが誰かと相談したり雑談したりしていて、全員が作業に没頭して静まり返っている時間はまったくなかったように思います。

途中、会場の様子を Discord のボイスチャンネル経由で中継したりもしました。会場の様子がどの程度伝わっていたのかはちょっとわからないですが…。

個人的な成果

進捗

action-setup-vim が一部環境で動かなくなっていたのをなんとかしました。

GitHub Actions の GitHub Hosted Runner の ubuntu-latest のバージョンが 22.04 になり、環境の条件が変わった影響で AppImage が動かなくなっていました。 これに対する対応を以前 k-takata さんが vimdoc-ja-working リポジトリにて行っていたので、このやり方を取り入れる形で対応しました。

この方法は apt-get で新しいパッケージが入ってしまったり、ちょっと危険な環境変数が設定されてしまったりと副作用も大きいのですが、動かないよりかはマシだろう、と言うことで一旦入れました。問題があったら誰かが報告してくれるだろう…。

ガジェットの譲渡

個人的に不要になって持ち腐れ状態になっていたモバイルディスプレイ 2 枚と、格安の HDMI キャプチャを他の参加者の方に譲ることに成功しました(※有償)。

ずっと使われていなくてもったいなかったので、活用してくれる人の手に渡ったのはよいですね。

感想など

突発的な集まりにも関わらず参加してくださった皆さん、ありがとうございました! やはり実際に集まってわいわいするのは楽しいですね。

このくらい緩い会ならまた開催することは可能だと思うので、希望者の声などを聞きつつ折を見てまた開催するのもいいかもしれません(※開催を保証するものではありません)。

qfhl.vim を作った

quickfix は便利ですが、それがバッファ内のどの位置を指しているのか、視覚的には分かりづらいです。

これを解決するための vim-hier というプラグインがあります。このプラグインは、quickfix の位置をハイライトで視覚的に表示してくれます。 実用には十分ではあるのですが、長らくメンテされておらず、またプラグインの構造やハイライトの仕組みが古いことが気になっていました。

一方、現在の Vim には text property という仕組みがあります。これを使えば、いい感じのものが作れそうな気がしました。

というわけで作ってみました。

github.com

(作ってみましたと軽く言ってますが、放置期間も含めると数年越しのリリースです…。)

qfhl.vim は、quickfix および location list の場所をバッファ上でハイライトします。

ハイライトには text property を使用しています。text property はバッファの一部に埋め込まれ、バッファ編集に合わせて位置が移動します。 これにより、ハイライト後にバッファを編集して行がずれたりした場合でも、ハイライトの位置も適切に移動します。

quickfix には行と桁と言う位置情報があり、それを元にハイライトを行っていますが、これだけだとどこまでハイライトをすればいいのかが判断できません。

これは不便なので、Vim 本体に PR を出しました。

github.com

quickfix が持つ位置情報に、オプショナルな終了位置の行と桁の情報を持たせられるようにする変更です。この PR は無事 v8.2.3019 で取り込まれました。

と言うわけで、もし quickfix が終了位置を持っていた場合は qfhl.vim も適切な範囲をハイライトします。 とは言うものの、quickfix を設定する多くの grep 系のコマンドやプラグインは、まだ終了位置を設定してくれないでしょう。終了位置がない場合は、仕方ないので行末までハイライトをします。

現時点で手軽に試すには :vimgrep コマンドが使えます。:vimgrep は組み込みコマンドだったので、上記の PR で終了位置を設定するように対応しています。

f:id:thinca:20210731135546p:plain
qfhl でハイライトを行った様子

最後に注意点ですが、Vim script の新しめの機能を使って書いているため、恐らく Neovim では動きません…。

以上、もし需要が合う方はお試しください。

dein.vim でのプラグインの更新チェックを爆速にする

先日、Vimプラグインマネージャである dein.vim に、プラグインの更新チェックを劇的に高速にする変更が取り込まれた。使うには設定が必要なので、その方法を紹介する。

dein.vim を最新版にする

言うまでもないが、まずは dein.vim を最新版にする。

:call dein#update('dein.vim')

GitHub の Personal Access Token を生成する

この機能を使うには、GitHub の Personal Access Token を用意する必要がある。

https://github.com/settings/tokens

GitHub にログインして上記のページにアクセスし、Generate new token を押す。token の用途がわかりやすいように名前を付け、Generate token を押す。追加の権限は必要ない。生成された token をなくさないようにメモし(ページ遷移すると二度と見れないので注意。メモし忘れた場合は再生成する)、vimrc に以下のように設定する。

let g:dein#install_github_api_token = 'your token'

your token のところに生成した token を書く。言うまでもないが、この token は人に知られてはまずいものなので、vimrc を公開しているのであれば別のファイルに分離するなどの工夫が必要だ。

更新方法を変更する

通常、プラグインの更新には dein#update() を使っていたと思うが、新しい方法では dein#check_update() の第1引数に TRUE な値を渡すことで行う。

call dein#check_update(v:true)

特定のプラグインだけ更新したい場合はプラグインの一覧を第2引数に渡す。

call dein#check_update(v:true, ['dein.vim'])

プラグインを100個単位で入れていたとしても、あっという間に更新のチェックが終わる。

仕組み

ここからはオマケで、高速化の仕組みについて。

Vimプラグインはそのほとんどが GitHub 上で公開されている。今までは、プラグインの新しいバージョンが公開されているかどうかを、リポジトリ 1 つずつチェックしていた。当然 1 件ずつ通信を行うため、プラグインを100個も200個も入れていると、とても時間がかかる。

新しい方法では、GitHub の GraphQL API を使い、リポジトリを 100 件単位で更新があるかどうかをチェックする。このために Personal Access Token が必要になる。

GitHubREST API では 1 度のリクエストでアクセスできるリポジトリは 1 つだけになってしまうが、GraphQL API であれば 1 度の API リクエストで 100 件のプラグインのチェックができるため、更新されたプラグインがなければ非常に高速にチェックが終了する、というわけだ。

この手法については私が雑談レベルで提案していたものだが、今回 Shougo さんがものすごい速さで実装してくれた。ありがとうございます!

更にオマケ: 別の高速化の話

プラグインマネージャは更新処理の際、「今ローカルにインストールされているプラグインのバージョン(Git のコミット)はいくつか」を知る必要があるが、Windows では Linux などに比べると外部プロセスの起動が非常に遅く、リポジトリ毎に git コマンドを実行するだけでも数が多いとかなり時間がかかっていた。

別のプラグインマネージャである minpac ではこの問題を改善するために、「Git のコミットを得るために git コマンドを実行せずに直接 .git/ ディレクトリ内のファイルを読む」という手法を採用していたが、このたびこの方法が dein.vim にも取り込まれた

よって特に Windows ユーザーは以前に比べて更に高速になっている。

なお、こちらの変更は特に設定をしなくても恩恵を受けられる。

Vim で q を prefix キーにする

前置き

Vimプラグインをたくさんいれていると、それらを呼び出すためにキーマッピングを用意したくなることはよくある。

Vim はキーシーケンスに対してマッピングを割り当てられるので、何かのキーを prefix キーとして、そのキーに続けて何かしら機能を割り当てると言うテクニックがよく用いられる。

" スペースキーを prefix にする例

" スペースキー単体では何も起きないようにする
" これをしておかないと、うっかり <Space> + 割り当ててないキーを
" 押すと <Space> の元の機能が発動する
nnoremap <Space> <Nop>

" <Space>q でウィンドウを閉じる
nnoremap <silent> <Space>q :<C-u>quit<CR>

" ... 以下、<Space> + 何かにキーを割り当てられる

しかしこの方法をもってしても、割り当てたい機能はどんどん増えていくものである。prefix キーとして利用しやすいキーはいくつかあるが、それらが枯渇するほど機能を割り当てている人も世の中にはいるようだ。

q を prefix にすることで起きる問題

q は、マクロの記録を開始するコマンドである。q + レジスタのアルファベット1文字で、そのレジスタに対してマクロの記録を開始する。

しかし、26個もあるマクロを全て器用に使いこなしている人はおそらくまずいないと思う。私なんてだいたい1つしか使わない。どこに何が記録されているか、覚えられないからだ。

となると、残りの q + アルファベットは空いていることになる。q を prefix にすればこれらが使える。何ならアルファベット以外の文字も使えることになる。

nnoremap q <Nop>
nnoremap qa :<C-u>echo 'Awesome feature!'<CR>

こうすることで、qa は無事便利機能に割り当てることができる…が、こうしてしまうと、q<Nop> にすることで、マクロの開始が一切できなくなってしまう。

これはさすがにまずい。しかしこれは単に q<Nop> を割り当てなければ解決する。

nnoremap qa :<C-u>echo 'Awesome feature!'<CR>

マクロの記録も開始できる。これで何も問題はない…?

更に潜む問題

Vim のマクロの記録は q 単体で終了する。ところが、q で始まるキーマッピングがあると、押された q がマクロの終了であるのか、はたまたキーマッピングの呼び出しなのかを判断するため、Vim はしばらくの間キーマッピングの待受をする。

待受時間を待ってやり過ごすか、q で始まるキーマッピングではない何か別のキーのコマンドを実行すれば済むのだが、いかんせんやきもきしてしまう。やはり prefix 以外のキーマッピング待ちは発生させたくない。

解決策

今回、この問題を解決するために以下のように設定してみた。

nnoremap <script> <expr> q reg_recording() is# '' ? '<SID>(q)' : 'q'

nnoremap <silent> <SID>(q) q
nnoremap <silent> <SID>(q)a :<C-u>echo 'Awesome feature!'<CR>
nnoremap <silent> <SID>(q)<Space> :<C-u>quit<CR>

q を押した際に、マクロの記録中であれば即座に q を起動してマクロの記録を終了させ、そうでなければ prefix としての q を呼び出す。prefix の設定がない場合はそのまま q として機能させることで、マクロの記録開始も行えるようにする。

こうすることで、q を prefix として機能させつつマクロの記録開始/終了に影響を与えないようにすることができる。私は <Space>q をよく q<Space>誤爆することがあったので、同じ機能を割り当ててみた。

今回はなんとなく <SID> を使ってみたが、q prefix のキーマッピングを複数のスクリプトで定義したい場合は <Plug> を使っても問題ないだろう。

nmap <expr> q reg_recording() is# '' ? '<Plug>(q)' : 'q'

nnoremap <silent> <Plug>(q) q
nnoremap <silent> <Plug>(q)a :<C-u>echo 'Awesome feature!'<CR>
nnoremap <silent> <Plug>(q)<Space> :<C-u>quit<CR>

この場合は q のキーマッピングnnoremap ではなく nmap を使うことに注意する必要がある。

残る問題

ここまでやっても一応まだ問題は残ってる。ここで定義した q で始まるキーマッピングは、マクロの記録中に呼び出すことはできない。 しかしこれはある意味当然であり、マクロ記録中に呼び出したい機能を q に割り当てないようにする他はない。

VimConf 2019 が開催されて1週間が過ぎました

今年も無事 VimConf を終えることができました。私は今年もスタッフの一人として参加しました。参加してくれた皆さん、発表してくれた皆さん、スタッフ、そのほか関係者の皆さん、ありがとうございました。おつかれさまでした。

1週間経ったこともあり、感想記事が続々上がってきています。また、(遅くなりましたが)参加した皆さんにアンケートのお願いも送信し、続々と回答が集まっています。

VimConf の運営スタッフは全てボランティアです。スタッフには金銭的な報酬は一切ありません。まあこれは別に珍しいことではなく、大抵のコミュニティドリブンのカンファレンスはどこもそうだと思います。

それでいてやることは山のようになります。みんなプライベートの時間を切り崩してなんとか対応しています。みんなできる範囲でやっているので、負担が偏ったりもします。たぶん私は他のメンバーに比べると負担は軽かった方。みんなありがとう。

話が逸れた。こういった状況の中で、多くの感想記事やアンケートでの意見を拝見していると、大変だったけどやってよかった、と思えます。今のところ発見できた感想記事は全て目を通しています。ありがとうございます。

イベントの盛り上がりと継続と言う意味で、フィードバックは非常に重要です。「もうみんな書いてるし…」「イベントから時間が経ってしまったから…」そんなことはありません。今からでも遅くないです。あなたの記事を見た誰かが、次回は参加したいと思うかもしれません。

…感想を書こうと思ったら感想にすらなっていないポエムになってしまった。 ともあれ、カンファレンスは、参加してくれる皆さんがいてくれてこそ成立しています。そして参加してくれた皆さんがまた参加したいと思ってくれたのであれば、運営スタッフの一人としてこれほど嬉しいことはありません。

ライブコーディングで作ったプラグインを整理して公開した

先日、ゴリラ.vim #9 に参加してライブコーディングをしてきた。

gorillavim.connpass.com

その際に作ったプラグインを整理して最低限の形した。整理する過程で色々変わったのでその話など。

公開したプラグインは以下。

github.com

どんなプラグインなのか

これは日本語における、ひらがな⇔カタカナの変換や全角⇔半角の変換をするプラグイン

極稀に欲しくなる操作で、サクラエディタなどには標準で付いている。Vim でもやりたかったので作ってみることにした。ネタとしても小さめでライブコーディングでもなんとかなるかなという目論見。

試験的なプラグインということもあって、無駄に最新バージョンの Vim を要求する。scriptversion 4 が通らない Vim では動かない。

プラグイン

変換するという想定でライブコーディング時には convja.vim という名前で作り始めた。

しかしあとであれこれ考えて、文字種の判定や抽出もできると便利かも(やるとは言っていない)と思い、汎用的な処理ができるように jautil.vim という名前にしてみた。無駄に汎用化してしまうのは私の悪い癖である。わかってはいる…。

インターフェース

ライブコーディング時では、以下のようなインターフェースを想定していた。

echo convja#convert('123アイウ', {'target': 'hankaku', 'type': 'kana'})
# => '123アイウ'

しかし作っているうちに紆余曲折があり、もっとシンプルに指定できるようにしたいなぁという気持ちになったので以下のような形式に落ち着いた。

echo jautil#convert('123アイウ', 'hankaku:kana')
# => '123アイウ'

簡易とはいえ特殊な文法を知る必要があるが、まあ辞書の形式を知るのと大差ないだろう。

拡張

第2引数の target に配列を渡せるようにした。これにより、まず半角カナを全角カナにし、その後全角カナをひらがなにすることで全角/半角両方のカナをひらがなに直す、ということが1度の呼び出しでできる。

echo jautil#convert('アイウエオカきくけこ', ['hankaku:kana', 'katakana'])
# => 'あいうえおかきくけこ'

また、第1引数に配列を渡すことで第1引数と第2引数を入れ替えられるようにした。これにより、partial を使って特定の変換をする関数を用意することができるようになる。

let H2Z = function('jautil#convert', [['hankaku']])
echo H2Z('abc')
" => 'abc'

今後の展望

あれこれこうできたらいいなと思っていることはあるが、優先度は激低なのでやるかは不明。ライブラリだし vital module 化したいよなー。

もっとちゃんと使いたいぜって人がいたら Issue を立てたりしてください。やるかどうかはわからないですが…。

ゴリラ.vim #1 に行ってきた

ゴリラ.vim #1 に行ってきた。

この規模の Vim イベントで定員オーバーは初めて見たかもしれない。しかもまだ実績のない第1回でこれなのだから、ゴリラさんの求心力の高さが伺える。

会場は渋谷ヒカリエにある株式会社ディー・エヌ・エーさん。セキュリティゲートの受付で思わず「うほうほ」と挨拶しそうになったけど、なんとか堪えました。危なかった。

発表は初心者向けから上級者向けまでいい感じにバラけており、後になるほど高度になっていく感じで発表順序も完璧だった。満足度が高い。

dice_zu さんが私の作った showtime.vim を使ってくれてて嬉しかった。もうちょっとちゃんとメンテしないと…。

懇親会では寿司とカツサンドをつまみながらおしゃべり。学生さんが多かった印象。ちょいちょい移動しつつ話してたけども、更にもうちょっとあちこち移動して話をすれば良かったと少し後悔。

この感じのイベントを今後は毎月のペースでやる予定とのことで、今後が楽しみです。

帰り際のゴリラさんとの会話

ゴリラさん「thinca さん、次回は発表してください!」

マンボウ「そうですね。検討してみます」

ゴリラさん「検討じゃなくて、してください!」

マンボウ「あ、は、ハイ…」

ということで次回は何か発表することになった。進撃のゴリラには敵わなかったよ…。何を話そうかなぁ。