diff options
author | Steven Arcangeli <506791+stevearc@users.noreply.github.com> | 2023-12-06 22:20:29 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-06 22:20:29 -0800 |
commit | 659838ff4244ef6af095395ce68aaaf99fa8e696 (patch) | |
tree | b92754f2de1a225187769ed2c30e01a3ea703b3c /lua/conform/util.lua | |
parent | 8d0421a11b2944c6c059e0936a95182972921c30 (diff) |
refactor!: formatter config functions take self as first argument (#233)
This is a breaking API change, but there is a shim in place that will keep existing functions working, just with a warning notification. Most people should not encounter this at all. For anyone overriding a formatter config value with a function that takes `(ctx)` as the parameter, it will need to be updated to take `(self, ctx)`.
Diffstat (limited to 'lua/conform/util.lua')
-rw-r--r-- | lua/conform/util.lua | 62 |
1 files changed, 52 insertions, 10 deletions
diff --git a/lua/conform/util.lua b/lua/conform/util.lua index bbb711a..0ff54de 100644 --- a/lua/conform/util.lua +++ b/lua/conform/util.lua @@ -10,11 +10,11 @@ end ---Search parent directories for a relative path to a command ---@param paths string[] ---@param default string ----@return fun(ctx: conform.Context): string +---@return fun(self: conform.FormatterConfig, ctx: conform.Context): string ---@example --- local cmd = require("conform.util").find_executable({ "node_modules/.bin/prettier" }, "prettier") M.find_executable = function(paths, default) - return function(ctx) + return function(self, ctx) for _, path in ipairs(paths) do local normpath = vim.fs.normalize(path) local is_absolute = vim.startswith(normpath, "/") @@ -46,9 +46,9 @@ M.find_executable = function(paths, default) end ---@param files string|string[] ----@return fun(ctx: conform.Context): nil|string +---@return fun(self: conform.FormatterConfig, ctx: conform.Context): nil|string M.root_file = function(files) - return function(ctx) + return function(self, ctx) local found = vim.fs.find(files, { upward = true, path = ctx.dirname })[1] if found then return vim.fs.dirname(found) @@ -101,8 +101,8 @@ M.wrap_callback = function(cb, wrapper) end ---Helper function to add to the default args of a formatter. ----@param args string|string[]|fun(ctx: conform.Context): string|string[] ----@param extra_args string|string[]|fun(ctx: conform.Context): string|string[] +---@param args string|string[]|fun(self: conform.FormatterConfig, ctx: conform.Context): string|string[] +---@param extra_args string|string[]|fun(self: conform.FormatterConfig, ctx: conform.Context): string|string[] ---@param opts? { append?: boolean } ---@example --- local util = require("conform.util") @@ -113,12 +113,12 @@ end --- }) M.extend_args = function(args, extra_args, opts) opts = opts or {} - return function(ctx) + return function(self, ctx) if type(args) == "function" then - args = args(ctx) + args = M.compat_call_with_self("unknown", self, args, ctx) end if type(extra_args) == "function" then - extra_args = extra_args(ctx) + extra_args = M.compat_call_with_self("unknown", self, extra_args, ctx) end if type(args) == "string" then if type(extra_args) ~= "string" then @@ -143,7 +143,7 @@ M.extend_args = function(args, extra_args, opts) end ---@param formatter conform.FormatterConfig ----@param extra_args string|string[]|fun(ctx: conform.Context): string|string[] +---@param extra_args string|string[]|fun(self: conform.FormatterConfig, ctx: conform.Context): string|string[] ---@param opts? { append?: boolean } ---@example --- local util = require("conform.util") @@ -183,4 +183,46 @@ M.buf_get_changedtick = function(bufnr) end end +---Returns true if the function takes no args or has self as the first arg +---@param name string +---@param fn function(...: any): T +---@return boolean +local function has_self_arg(name, fn) + local first_arg_name = nil + debug.sethook(function() + local info = debug.getinfo(3) + if info.name ~= "pcall" then + return + end + first_arg_name = debug.getlocal(2, 1) + error() + end, "c") + pcall(fn) + debug.sethook() + + return first_arg_name == "self" or first_arg_name == nil +end + +---@generic T +---@param formatter_name string +---@param self any +---@param fn fun(...: any): T +---@param ... any +---@return T +M.compat_call_with_self = function(formatter_name, self, fn, ...) + local has_self = has_self_arg(formatter_name, fn) + if has_self then + return fn(self, ...) + else + vim.notify_once( + string.format( + "[conform] formatter %s should take 'self' as the first argument for args, range_args, cwd, condition, and env functions (see :help conform-self-args)\nCompatibility will be dropped on 2024-03-01", + formatter_name + ), + vim.log.levels.WARN + ) + return fn(...) + end +end + return M |