Neovimでディレクトリを開いた時に任意のファイラープラグインを起動する設定を楽にするプラグインを作った

この記事は、Vim駅伝の2023/07/14の記事です。

Vim/Neovimには、2020秋 Vim のファイラー系プラグイン比較で紹介されているように様々な特徴を持ったファイラープラグインが開発されてきました。 しかし、好みのファイラープラグインを単純にインストールしただけでは、 nvim dir_path のようにディレクトリを指定してNeovimを起動した時には自分でインストールしたファイラーではなくnetrwが使われます。 つまり、ただインストールするだけでは不十分です。

そこで、ディレクトリをNeovimで開いた時に好みのファイラープラグインを起動する設定を簡単に行うためのプラグインを作成しました。

github.com

やっていることは単純でバッファに入った時にディレクトリかどうかを判定して、ディレクトリであれば初期化時に設定したコールバック関数を実行します。 コールバック関数は、開くディレクトリへのパスを引数として受け取ります。

お使いのプラグインマネージャで好みのファイラープラグインと hijack-open-directory.nvim をインストールし、次のような設定をinit.lua相当の場所に追記してください。 下記は、私の使っている設定です。

-- Disable the default filer plugin netrw
vim.api.nvim_set_var('loaded_netrwPlugin', 1)

-- Exapmle for vfiler.vim
-- Start VFiler when open directory
require('hijack_open_directory').setup({
    filer = function(path)
        -- callback function when open directory
        require('vfiler').start(path, {noremap = true, silent = true })
    end
})

プラグインのファイル構造は次のようになります。 僕は最低限のドキュメントは必要だと信じてるので、docディレクトリも含めてこれが最小構成のプラグインだと思っています。

% tree hijack-open-directory
hijack-open-directory
├── README.md
├── doc
│   └── hijack-open-directory.txt
└── lua
    └── hijack_open_directory.lua

3 directories, 3 files

lua/hijack_open_directory.luaが実装で、doc/hijack-open-directory.txt は、:help hijack-open-direcotry として表示されるヘルプファイルです。ちなみに、ヘルプファイルの書き方は、:help helpとすると説明があります。再帰味があっていいですね。 Luaプラグインの場合、luaディレクトリの下にあるファイル名がモジュール名になります。

lua/hijack_open_directory.luaの中身はこれだけです。

-- hijack_open_directory.lua
local M = {}

local function create_callback(filer)
        -- 現在のバッファのパス(`path`)がディレクトリならfiler(path)を実行する関数を返す
    return function()
        local path = vim.fn.expand('%:p')
        if not (vim.fn.isdirectory(path) == 1) then return end
        filer(path)
    end
end

M.setup = function(opts)
    local callback = create_callback(opts.filer)
        -- バッファに入った時に発生するイベントを定義する
    vim.api.nvim_create_autocmd({ "BufEnter" }, {
        callback = callback,
    })
end

return M

1行目の local = M = {}で定義し、最終行でオブジェクトMを返却してます。 このオブジェクトMLuaのモジュールでありプラグインの実装部分です。 一般的なプラグインでは、慣習的にsetup() を呼ぶことでプラグインの初期化を行うことが多いです。 本プラグインでもそれに倣ってsetup()で初期化をします。 setup()C言語におけるmain()関数のように特殊なメソッドとして定められたものではなく、あくまでLuaモジュールのメソッドの1つです。「lua "setup function"」で検索してもNeovimのことしか出てこないので、おそらくVimプラグイン実装特有の流儀だと思います。

また、本プラグインでは省略してしまっていますが下記のようなinit_opts() 関数を定義して、setup()関数の冒頭でopts = init_opts(opts) のように呼ぶことでユーザが明示的に設定しなかったオプションにM.default_opts で定義したデフォルト値を設定できます。 vim.tbl_deep_extend() についての詳細は、:help vim.tbl_deep_extend() をNeovimから実行するとヘルプを開けるので読んでみてください。

local M.default_opts = {
    callback = function(path) print("No callback function defined.") end
}

local init_opts = function(user_opts)
    return vim.tbl_deep_extend("force", M.defalt_opts, user_opts or {})
end

ランキングが懐かしくなったので、なんとなくVimのランキングに参加してみました。