🐼

Neovimにおいてluaのfunctionに対するbindは地味だけど便利

2023/12/02に公開

便利

Neovimの設定やらプラグインやらをLuaで書いていると、頻出する即時関数たち。

vim.api.nvim_create_user_command("Hoge", function()
    vim.fn["hoge"]()
end, {})

function() ~ end はFormatterで改行されがちです。Formatterは無設定こそ至上と主張する者としては、これは致し方無しと飲むしかありません。

しかしかといって、即時関数で包むことを止めて

vim.api.nvim_create_user_command("Hoge", vim.fn["hoge"], {})

などと書くと、意図しない引数を受け取って痛い目を見がちです。(詳細は割愛します)

…だったら、JavaScriptのbindのように、引数を固定してしまえば良いのでは?

作った

func.lua
local M = {}

--- 指定の関数のすべての引数を束縛した関数を返す
--- @param f function
--- @param ... any
--- @return function
function M.bind_all(f, ...)
  local args = { ... }
  return function()
    return f(unpack(args))
  end
end

--- 指定の関数の先頭のいくつかの引数を束縛した関数を返す
--- @param f function 関数
--- @param ... any 束縛する引数
--- @return function
function M.bind(f, ...)
  local bound = { ... }
  return function(...)
    local args = { ... }
    local merged = {}
    for v in ipairs(bound) do
      table.insert(merged, v)
    end
    for v in ipairs(args) do
      table.insert(merged, v)
    end
    return f(unpack(merged))
  end
end

return M

冒頭のユースケースを考えると、ほとんどのシーンはbind_allで充分ですが、一応bindも用意してみました。
充分にテストされていないので、後者の利用については十分ご注意ください。

local func = require("func")

vim.api.nvim_create_user_command("Hoge", func.bind_all(vim.fn["hoge"]), {})

便利ですね。

Bindをそんなくだらない目的に使うな、とお叱りを受けそうですが。

蛇足: 記事を書くということ

この記事は、ふとNeovimの設定をしていて思いついた便利関数を、Copilotに生成してもらい、それを元に20分ほどで書いた記事です。

正味本当にしょうもない内容だと思います。Neovimの標準機能のどこかにすでにある気もします。
ですが詳しく調べたりはしていません。思いつきをそのまま垂れ流すことにしました。

「記事を書く」というと、なんだか特別なもので、重厚で社会的意義のある文章を提供しなくてはならない、というプレッシャーがあります。
特にアドベントカレンダーとなると、そのプレッシャーは特に大きく感じられると思います。

しかし、そんなプレッシャーは実在しません。
ちょっとした思いつき、ちょっとしたハックをどんどん公開していきましょう。

時には批判を受けることもあるでしょう。時には過ちを含むこともあるでしょう。
しかし天賦の才でもない限り、記事を書かねば記事を書けるようにはなりません。
記事を書かねば、批判を受けることもできません。

他人の目にさらさねば、過ちに気づけないことすらあるでしょう。
他人の目に触れることで、あるいは意外な発想を誰かに与えることもあります。

いかに雑に記事を書くか。

今年はこれを1つのテーマとして、Vim駅伝にも参加してきました。
みなさんも、恐れず、雑なアウトプットを世の中に晒してほしいと常々思っています。
アドベントカレンダーは1つの良いきっかけになることでしょう。是非。

Discussion