🦹

Vim/Neovimのプラグインマネージャーを悪用してCLIの管理ツールとして使う

2023/10/16に公開
3

TL;DR

  • CLI ツールを管理する方法として、Vim/Neovimのプラグインマネージャーを使うと意外と便利

はじめに

皆さんはCLI ツールをどのように管理していますか?

私はmacOSで使うツールの管理に以下のパッケージマネージャーたちを使っています。

  • 汎用的なパッケージマネージャー
    • aqua - YAMLでDeclarativeにツールを管理できる。極力これで管理したい
    • Homebrew - 有名なパッケージマネージャー。macOSのデファクトスタンダード。Aquaで管理できないツールを管理する
  • 言語ごとのパッケージマネージャー
    • volta - Node.jsのバージョン管理ツール。Node.jsのバージョンを切り替えるのに使う
    • rye - Pythonのバージョン管理ツール。Pythonのバージョン/仮想環境/ツールを管理するのに使う
    • rustup - Rustの管理ツール。Rustのバージョン/ツールを管理するのに使う
    • zigup - Zigのバージョン管理ツール。Zigのバージョンを切り替えるのに使う
  • ツールごとのパッケージマネージャー
    • fisher - fishのプラグインマネージャー。fishのプラグインを管理するのに使う
    • lazy.nvim - Neovimのプラグインマネージャー。Neovimのプラグインを管理するのに使う

結構多いですね。
ツールは多岐にわたるので、それぞれのツールに合ったパッケージマネージャーを使っています。

理想のパッケージマネージャー

私は複数マシンを使っているので、マシン間の設定をdotfilesとして管理しています。

https://github.com/ryoppippi/dotfiles

自分がdotfilesで使用するパッケージマネージャーに求める条件は以下の通りです。

  • パッケージマネージャーのインストール、アンインストールが簡単
  • パッケージマネージャーの設定をDeclarativeに記述できる
  • パッケージマネージャがー管理するツールの設定やバージョンをDeclarativeに記述できる
  • Lockfileでバージョン、差分を管理できる
  • パッケージマネージャーが管理するツールのバージョンを切り替えることができる/簡単に戻すことができる
  • 設定量は多過ぎず少な過ぎず
  • 暗黙の動作が少ない

これらを満たしていると、Github上で差分も簡単に確認でき、またマシン間でもgit pullして簡単なコマンドを打つだけで環境を再現できるので、とても便利です。

Aqua

これらを条件を考えた時に、汎用のパッケージマネージャーにおいては、Aquaが一番条件を満たしていると思います。

https://aquaproj.github.io/

AquaはYAMLでDeclarativeにツールを管理でき、またRenovateを併用すれば最新版の確認、更新も簡単にできます。
また、設定もプリセットのものが多く、もし欲しいツールがなかった場合も本家のRegistryにPull Requestを送ることで追加できます。
そのため、自分の使用するCLI ツールは極力Aquaで管理したいと思っています。

しかし、AquaはGo言語以外のビルドをサポートしていないので、Go言語以外で書かれていて尚且つバイナリが提供されていないツールを管理することができません。
また、特定の場所にインストールが必要なもの(gh extension)も管理できません。

追記:
CargoによるInstallにも対応しているようです!

afx

自分は使用していないのですが、afxというパッケージマネージャーもあります。

https://github.com/babarot/afx

このパッケージマネージャーはAquaと同じくYAMLでDeclarativeにツールを管理できます。
AquaのようなRegistryは存在しないので、自分でビルドスクリプトを書く必要がありますが、その分ビルドスクリプトを定義したり、gh extensionを管理したりと、より柔軟な管理ができます。
とても魅力的なパッケージマネージャーですが、以下の理由で自分は使用していません。

  • 更新時、Releaseにあるものは最新版をチェックして落とすことができるが、例えばmain ブランチのHEADを落としてきてビルドするようなことはできない
  • Lockfileを採用していないので、ツールのバージョン一覧を1箇所で確認することができない
  • (これはAquaも同じであるが) YAMLで設定を記述するので、設定量が多いとYAMLの記述が煩雑になる
  • (これはafxは何も悪くないのですが)これ以上パッケージマネージャーを増やしたくない

とても良いパッケージマネージャーではあるので、ぜひ皆さんチェックしてみてください。

解: lazy.nvimを悪用する

というわけで、自分が求める条件を満たすパッケージマネージャーがなかなか見つかりません。

これは自分で作るしかないのかなと思いつつ、なかなか手がつけられない中数ヶ月が経ちました。

そんな中、先日の駅伝でslinさんがvim/neovimのパッケージマネージャーであるdeinを悪用して、IMEの辞書を管理する方法を紹介していました。

https://github.com/Shougo/dein.vim

https://zenn.dev/slin/articles/2023-10-02-skktips#辞書をdeinで管理する

またこれについて楽園で盛り上がっていたところ、CLI ツールを管理するのにも使えるんじゃないかという話になりました。

これについて考えてみると、vim/neovimのパッケージマネージャー、特に自分の使っているlazy.nvimは以下のような特徴があります。

  • パッケージマネージャーのインストール、アンインストールが簡単 → vimの設定の一部なのですでにある
  • パッケージマネージャーの設定をDeclarativeに記述できる → lua で記述できる
  • パッケージマネージャーが管理するツールの設定やバージョンをDeclarativeに記述できる → lua で記述できる
  • Lockfileでバージョン、差分を管理できる → lazy-lock.jsonが生成されるので、差分が取れる
  • 設定量は多過ぎず少な過ぎず → お作法に乗っ取れば、設定量は少ない。独自のビルドの設定も記述できる

https://github.com/folke/lazy.nvim

というわけで、1からパッケージマネージャーを作るよりも、vim/neovimのパッケージマネージャーを悪用する方が簡単そうだなと思い、実際に設定を書いてみました。

以下に自分がAqua/Homebrew管理外だったツールをいかにして管理したかを書いていきます(da-ja-re)。

gh extensionの管理

gh extensionは、ghコマンドの拡張機能です。
自分もいくつか愛用しているものがあります。

https://github.com/ryoppippi/gh-cr
https://github.com/yusukebe/gh-markdown-preview
https://github.com/actions/gh-actions-cache
https://github.com/seachicken/gh-poi

これらのコマンドはghコマンドと一緒に使うことで、githubにまつわる便利な機能を提供してくれます。
しかし、これらのツールを管理するツールは(現時点ではafxをのぞいて)存在しません。

これをlazy.nvimで管理してみましょう。

https://github.com/ryoppippi/dotfiles/blob/9c94e60236511be2f9cdd87d90cd2cbb21fffdbc/nvim/lua/cli/gh.lua

この設定ファイルの中でやっていることは以下の通りです。

  • 指定したレポジトリの最新版を落としてくる
  • go build する
  • ビルドされたバイナリをgh extensionのディレクトリ(macOSでは~/.local/share/gh/extensions/)に配置する

これで、gh extensionをlazy.nvimで管理することができました。

新しいgh extensionを追加したい場合は、この設定ファイルに追記するだけで、lazy.nvimのアップデートをすると、自動的に最新版が落とされます。
別のマシンを使う時にも、dotfilesをpullしてNeovimを起動するだけで、最新版のgh extensionが自動的にインストールされます。

lazy-lock.jsonにバージョンが記述されるので、差分も確認できて嬉しいですね。

https://github.com/ryoppippi/dotfiles/blob/9c94e60236511be2f9cdd87d90cd2cbb21fffdbc/nvim/lazy-lock.json#L51-L56

追記:
gh extension install .でローカルのレポジトリをインストールできることを知り、設定を簡素化しました。
https://github.com/ryoppippi/dotfiles/blob/b0a7e71f797259847106786a1fce7eefef4b18b3/nvim/lua/cli/gh.lua

zlsの管理

zlsはzigのLanguage Serverです。
https://github.com/zigtools/zls

自分はzigのHEADを使っているので、zlsを使用するにはmasterをcloneして最新版のzigでビルドする必要があります。

今までは毎日手動でzlsからgit pull、ビルドしていましたが、これもlazy.nvimで管理することにしました。

https://github.com/ryoppippi/dotfiles/blob/9c94e60236511be2f9cdd87d90cd2cbb21fffdbc/nvim/lua/cli/zls.lua

これもやっていることは簡単で、lazy.nvimでアップデートをすると、zlsのレポジトリをgit pullして勝手にビルドしてくれます。
あとはビルドされたバイナリをnvim-lspconfigで指定するだけで、zlsを使うことができます。

https://github.com/ryoppippi/dotfiles/blob/9c94e60236511be2f9cdd87d90cd2cbb21fffdbc/nvim/lua/plugin/nvim-lspconfig/init.lua#L359-L364

これで、zlsをlazy.nvimで管理することができました。

https://github.com/ryoppippi/dotfiles/blob/9c94e60236511be2f9cdd87d90cd2cbb21fffdbc/nvim/lazy-lock.json#L214

まとめ

この記事では、vim/neovimのプラグインマネージャーを悪用してCLI ツールを管理する方法、そしてlazy.nvimを使用した具体的な設定を紹介しました。
推奨されている方法ではないので、自己責任でお願いします。

これまで、Vimはエディタとして、単なる便利なCLI ツールの一つでしかありませんでした。
しかし、他のCLI ツールの管理をしたり、またGitを拡張するツールとしてVim使ったりしていると、VimがTerminalの環境を全て飲み込んでいくような、そんな感覚になります。

https://zenn.dev/vim_jp/articles/3b5125f9e06bf9

これからもVim/Neovimと仲良くしていきたいですね。

Discussion

kyoh86kyoh86

go build してlinkの流れ、出力されてほしいディレクトリを環境変数 GOBIN に放り込んだコンテキストで go install するのも悪くないかもしれないですね。私も使わせてもらいますこの手法

Shunsuke SuzukiShunsuke Suzuki

aqua をご紹介いただきありがとうございます!

しかし、AquaはGo言語以外のビルドをサポートしていないので、Go言語以外で書かれていて尚且つバイナリが提供されていないツールを管理することができません。

正確に言うと、 https://crates.io/ で公開されている Rust 製のツールのビルドにも対応しています。
cargo install でビルドします。

https://aquaproj.github.io/docs/reference/registry-config/cargo-package

もっとも、 standard registry で対応しているツールの数はとても少ないですが(意外と需要がないのか知られてないのか、 Pull Request が来ません)。

https://github.com/aquaproj/aqua-registry/tree/main/pkgs/crates.io

ryoppippiryoppippi

ありがとうございます。
いつもお世話になっています。

以前記事でGo Buildに対応したことは存じていましたが、Cargoにもいつのまに対応されていたのですね!
今度PRします