Slackでスニペットを共有するためのVimプラグインつくってみた

この記事は [Yahoo! JAPAN 2018年新卒有志2 Advent Calendar 2018](https://adventar.org/calendars/3419) の14日目の記事です。
前回は@teakunさんの[Scratchで始める大人のための子ども向けプログラミング入門](https://qiita.com/teakun/items/243394d5936ae1601e92)でした。

# はじめに
皆さん、Vimは使っていますか？
僕は業務でのコーディングには使わなくなったものの[^1]、yamlファイル修正したり、シェルスクリプト書いたり、簡単なメモをとったりするときにバリバリ使っています。

Vimはデフォルトでも十分に使えるのですが、プラグインを使うとさらに便利に拡張できます。
補完機能を充実させたり、ファイラーを拡張したり、git連携を容易にしたりなどなど、うまく組み合わせて使えば、自分だけの最強のテキストエディタを作り上げることができます。

たくさんのVimプラグインにお世話になってるVimmerとしては、やはり一度はプラグイン作ってみなきゃと思うわけです。
ちょうど思いついた案もあったので、プラグイン開発に初挑戦してみました。

# つくるもの
Vimで開いてるファイルの一部をSlackにメモしたり、上司とその部分をシェアする、といったことがよくあります。
その時どういう操作を行っているかというと、

1. Visual modeで選択してコピー
2. Slackに切り替える
3. +ボタン→「コードまたはテキストのスニペット」をクリック
4. コード貼り付け、必要ならファイルタイプ、タイトル、メッセージなども設定
5. Command+Enterで送信

…地味にめんどくさくないですか？

これをもっと素早く、手軽にpostできたらなーと思い、プラグインで実現させることにしました。

# できたもの
作成したものをGitHubにて公開しました。
[snipslack.vim](https://github.com/abekoh/snipslack.vim)

動作はこのような感じです。
![snipslack_low.gif](https://qiita-image-store.s3.amazonaws.com/0/184083/c18756f5-a8fb-675f-7a2d-0482eb5cd046.gif)

使用方法としては、
1. postしたい行をVisual modeで選択 (全体をpostしたい場合は選択不要)
2. `:SnipSlack`と入力してEnter

たった2ステップでpostできます。とっても簡単！
気になったところをチャンネルなどに溜めておいて、それを後で別チャンネルにシェアってこともできるので便利です。

# 特徴

snipslack.vimの特徴として3点あげます。

#### オプションなし一発で、設定しておいたチャンネル/DMに送信
できるだけ手軽にスニペットを保存したいため、チャンネルはその都度入力ではなく、一発で決まったチャンネル、またはDMとして送信するようにしました。

#### ファイル名、切り取った行番号、ファイルタイプも自動的に設定
どのファイルのどの部分か、という情報も同時に付与されます。
またファイルタイプについても、Slack側が対応していればシンタックスハイライトが反映されます。

#### 対象ファイルのGitHubリモートURLが存在する場合は付与 (※Gitで管理されている、かつリモートがGitHubである場合)
GitHub上の該当コミットのファイルのURLも付与するようにしました。
切り取った部分の前後などについても、後から確認することができます。

# 使うための準備
次の環境が必要となります。

- Vim(8.0+) or Neovim(0.2.0+)
- curlコマンド
- gitコマンド (Github URLを付与したい場合)

Vimプラグインは[dein.nvim](https://github.com/Shougo/dein.vim)や[vim-plug](https://github.com/junegunn/vim-plug)といったプラグインマネージャを使って管理するのが主流です。
詳しくは割愛しますが、他のプラグインと同様に設定を行います。

```vimscript
" for dein.nvim
call dein#add('abekoh/snipslack.vim')
" for vim-plug
Plug 'abekoh/snipslack.vim'
```

また、Slackにポストするためのtokenを用意する必要があります。
こちらの記事などを参考に、"Upload and modify files as user (files:write:user)"の権限を付与したAppを設定しましょう。
[Slack API 推奨Tokenについて - Qiita](https://qiita.com/ykhirao/items/3b19ee6a1458cfb4ba21)

取得したTokenと、ポスト先のチャンネルの設定を、vimrcなどに次のように設定します。

```vimscript
let g:snipslack_token = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
let g:snipslack_default_channel = '@abekoh'
```

※tokenをGitHubなどで公開しないよう注意しましょう。

これで設定完了です！
なお、他にもいくつかオプションを備えています。
詳細は[README](https://github.com/abekoh/snipslack.vim/blob/master/README.md)、または`:help snipslack`をご覧ください。

# 実装について

少しだけ実装の話について書きます。

SlackAPIを叩く処理は非同期で行うようにしています。
Vim8/NeovimではJobという機能で非同期に外部コマンドを実行することができます。

しかし、JobはVimとNeovimとで呼び出し方、仕様などが異なります。
例えば下記のように、スタートさせる関数名からして微妙に違います。

```vimscript
" Vim8
call job_start(args, options)
" Neovim
call jobstart(args, options)
```

両方に対応させるため、今回はAlisueさん作の[vital-Whisky](https://github.com/lambdalisue/vital-Whisky)の`System.Job`というラッパーを利用しました。
vital-Whiskyは[vital.vim](https://github.com/vim-jp/vital.vim)というVimプラグイン向けライブラリの外部モジュールです。
vital.vim系のライブラリはプラグインを作るときに便利なものが詰まっているので、一度目を通してみると良いと思います。

また、GitHubのURLの生成は力技です。
gitのリモートURLは`git@github.com:abekoh/snipslack.vim.git`だったり`https://github.com/abekoh/snipslack.vim.git`だったり`ssh://git@github.com/abekoh/snipslack.git`だったりするので、これを正規表現で一定のURLにするようにしています。

他にブランチ名、コミットハッシュ値を取得するために`git symbolic-ref`や`git rev-parse`など、あまり使わないコマンドをもりもり使っています。
もっといい取得方法などあれば教えていただきたいです…！

# まとめ
自分がほしいと感じるドンピシャのプラグインを開発して、日常的に使うのはやはり満足感が違いますね。
またいい案が思いついたら開発してみようと思いました。

あと、今回はVimScriptで開発しましたが、最近ではNeovim+Pythonといった慣れ親しんだ言語で書くということもできるようです。
痒いところに手が届く、オリジナルのVimプラグインをあなたも開発してみませんか…？

[^1]: 本当は使いたいんですがVimでJavaはいろいろ辛いので…