Neovim の Runtime ファイルを GitHub で開く

:::note info

この記事は [Vim 駅伝](https://vim-jp.org/ekiden/)の 2025/5/16 の記事です。前回は kawarimidoll さんによる「[mini.nvimの新モジュールmini.keymapで決めろマルチステップコンボ](https://zenn.dev/vim_jp/articles/9a89ecb5ff14a9)」でした。

:::

## 作ったもの

まずはこの動画を貼っておきます。表題を見て機能が想像できた人はこれ見りゃ十分でしょう。今すぐレポジトリーのページへ飛んでください。

* [delphinus/rtbrowse.nvim: Browse Neovim runtime files on GitHub directly from your editor.](https://github.com/delphinus/rtbrowse.nvim)

Runtime ファイルを開いているならそれを開きますし、それ以外のファイルなら設定している関数にフォールバックします。デフォルト値は [Snacks.gitbrowse()](https://github.com/folke/snacks.nvim/blob/main/docs/gitbrowse.md) です。

https://x.com/delphinus35/status/1923039075314938266

## Neovim の Runtime ファイルを読む

分かる人にはこれだけで十分なのですが、なぜこんなものが必要なのか、以下で説明しています。

Neovim には多くの機能がありますが、最近の機能は C では無く Lua で書かれることも多くなっています。Neovim ユーザーは設定のために Lua を必ず読めますから、機能の詳細を確認したいと思ったらまずソースを読むはずです（よね？）。

このようなソースは「Runtime ファイル」と呼ばれ、インストールされている場所は [`$VIMRUNTIME`](https://neovim.io/doc/user/starting.html#%24VIMRUNTIME) という環境変数にセットされています。Neovim の中なら `:echo $VIMRUNTIME` で見れますし、シェルから確認するならこのようになります。

```bash
~ ❯❯❯ nvim --clean --headless +'echo $VIMRUNTIME' +q
/opt/homebrew/Cellar/neovim/HEAD-40b64e9/share/nvim/runtime
```

あるいは、`nvim -V1 --version` でも表示されます。

```bash
~ ❯❯❯ nvim -V1 --version
NVIM v0.12.0-dev-5607+g40b64e9100-Homebrew
Build type: Release
LuaJIT 2.1.1744318430

   system vimrc file: "$VIM/sysinit.vim"
  fall-back for $VIM: "/opt/homebrew/Cellar/neovim/HEAD-40b64e9/share/nvim"

Run :checkhealth for more info
```

実際にこの配下のファイルを表示するとなると `$VIMRUNTIME` の値がシェルでも欲しくなります。ですが、これを手に入れるのには上記のような操作を行わないと難しいです。もし単にその配下のファイルを開きたいだけなら、[`+{command}`](https://neovim.io/doc/user/starting.html#-%2Bc) を使うといいでしょう。

```bash
# LSP 機能のソースを開く
nvim +'e $VIMRUNTIME/lua/vim/lsp.lua'
```

あるいは、[nvim-telescope/telescope.nvim](https://github.com/nvim-telescope/telescope.nvim) などのファジーファインダーを使う手もありますね。例えば `:Telescope find_files cwd=$VIMRUNTIME` すると以下のように表示されます。

![スクリーンショット 2025-05-15 11.45.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8880/4261067a-e3a8-4468-9397-df227dbd70f4.png)

## 読んでいる所を GitHub で開きたい

一人で読むだけならこれでいいのです。しかし、例えば勉強会などで「この部分のソースが～」と説明しながら参加者に披露しようとすると困ってしまいます。「`$VIMRUNTIME/lua/vim/lsp.lua` の 543 行目を見てください」と口頭で案内するのは無理がありますし、そもそも使っている Neovim のバージョンによってファイル名や行数が変わってしまいます。

ここで GitHub を使います。例えば、↓以下のような URL を使うと、「特定のコミット、特定のパス、特定の行」を指定してソースを開くことができます。

```
https://github.com/neovim/neovim/blob/40b64e91007e364fd7c7eaab64ce7c8cf0150aec/runtime/lua/vim/lsp.lua#L543-L543
```

このようなリンクを作成するために、[Snacks.gitbrowse()](https://github.com/folke/snacks.nvim/blob/main/docs/gitbrowse.md) のようなプラグインを使うことができます。これを使うと、特定のキーを押すだけで上記のようなリンクがブラウザで開きます。はい。これでオシマイ！

……なんですが、これが使えるのは「Git レポジトリーの中のファイルのみ」なんです。Neovim の Runtime ファイルを開こうとしたら簡単な方法が無いんですね[^1]。

[^1]: 実際にやるとしたら、[neovim/neovim](https://github.com/neovim/neovim) レポジトリーをローカルにクローンし、開きたいコミットをチェックアウトし、該当のファイルを開いて `Snacks.gitbrowse()` を呼ぶ、という手順になります。

## で、プラグインを作りました

そこで作りましたのが、再掲になりますが↓これです。

* [delphinus/rtbrowse.nvim: Browse Neovim runtime files on GitHub directly from your editor.](https://github.com/delphinus/rtbrowse.nvim)

以下のようなフローで動作します。

1. `:lua require("rtbrowse").browse()` する。
2. 現在開いているのが Runtime ファイルでなければ、`fallback` オプションの関数（デフォルトでは [Snacks.gitbrowse()](https://github.com/folke/snacks.nvim/blob/main/docs/gitbrowse.md)）で開いて完了。
3. Neovim のバージョン、あるいはコンパイルしたコミットを調べる。
4. ビジュアルモードで選択中ならその行を、そうでなければ現在行をブラウザで開く。

キーマップを自前でやりたい人は、

```lua
-- 以下、lazy.nvim を使っているものとして書きます。
{ "delphinus/rtbrowse.nvim" }
```

だけでいいですし、lazy.nvim で一緒に設定するなら

```lua
{
  "delphinus/rtbrowse.nvim",
  keys = {
    {
      "<Leader>gB",
      function require("rtbrowse.nvim").browse() end,
      mode = { "n", "x", "o" },
    },
  },
}
```

で良いでしょう[^2]。これ以上書くことは特に無い（後は `:h rtbrowse.txt` してください）のですが、一点実装に苦労した部分があったので載せておきます。

[^2]: この場合は `keys` オプションによりプラグイン自体が遅延読み込みされますからオススメです。また、このプラグインを設定する際に `opts = {}` は不要です。

## 現在使っている Neovim のリビジョンを知る

実装するに当たり、結構困ったのがこれです。いや、リリース版をインストールしているなら簡単なんですよね。

### `vim.version()` を見る

```vim
lua print(vim.version())
" 0.11.1 などと表示される
```

これで終わりなんですが、Neovim を自前でコンパイルすると表示がこのように変わります。

```vim
lua print(vim.version())
" 0.12.0-dev+Homebrew
```

これは Homebrew でインストールした場合ですが、手ずから make した場合も同様でしょう。このようなバージョン文字列では GitHub の狙ったコミットを表示させることができません。

### `:version` を見る

[`:version`](https://neovim.io/doc/user/various.html#%3Aversion) を使うのはどうでしょう。

```vim
NVIM v0.12.0-dev-5607+g40b64e9100-Homebrew
Build type: Release
LuaJIT 2.1.1744318430
Run ":verbose version" for more info
```

`g40b64e9100` という所にコミットハッシュのようなものがありますね。これを使えば良さそうなのですが、明らかに桁数が足りません。もうひと手間必要です。

### 完全なコミットハッシュを知る

このためにも、再び GitHub の機能を使います。この用途には GitHub API の [“Get a commit”](https://docs.github.com/ja/rest/commits/commits?apiVersion=2022-11-28#get-a-commit) を使います。

```bash
~ ❯❯❯ curl -H 'Accept: application/vnd.github.sha' https://api.github.com/repos/neovim/neovim/commits/40b64e9100
40b64e91007e364fd7c7eaab64ce7c8cf0150aec
```

このように、`https://api.github.com/repos/neovim/neovim/commits/` の後に短いハッシュを付けると、完全な形のハッシュを返してくれるようです。これを使って GitHub の URL を作ることができます。

なお、今回の実装では GitHub API のアクセストークンを指定していません。そのため、Rate Limit に達してしまい `curl` コマンドが失敗してしまう人も居ると思います。その場合は [`gh` コマンド](https://docs.github.com/ja/github-cli/github-cli/about-github-cli) を利用するオプションも提供していますのでそちらを使ってください（`:h rtbrowse-configuration-get_commit`）。

## まとめ

Neovim の Runtime ファイルを開いた状態から、そのファイルを GitHub で開くプラグインを作った話を書きました。勉強会なんかでやるソースリーディングのお供に是非お使いください。