aboutsummaryrefslogtreecommitdiffstats
path: root/lua
diff options
context:
space:
mode:
authorSteven Arcangeli <stevearc@stevearc.com>2024-05-07 16:25:03 -0700
committerSteven Arcangeli <stevearc@stevearc.com>2024-05-07 16:25:15 -0700
commit6dc1603ea408f476a57937bbeaf7f86520a21a98 (patch)
tree095014f597d256cd3c3a4bfc40df8552a7c65470 /lua
parent393210360b9e807862e5329763526509f52b5218 (diff)
feat: formatters can use $RELATIVE_FILEPATH in args (#349)
Diffstat (limited to 'lua')
-rw-r--r--lua/conform/fs.lua68
-rw-r--r--lua/conform/runner.lua13
2 files changed, 80 insertions, 1 deletions
diff --git a/lua/conform/fs.lua b/lua/conform/fs.lua
index d303dbd..6f92e18 100644
--- a/lua/conform/fs.lua
+++ b/lua/conform/fs.lua
@@ -15,4 +15,72 @@ M.join = function(...)
return table.concat({ ... }, M.sep)
end
+M.is_absolute = function(path)
+ if M.is_windows then
+ return path:lower():match("^%a:")
+ else
+ return vim.startswith(path, "/")
+ end
+end
+
+M.abspath = function(path)
+ if not M.is_absolute(path) then
+ path = vim.fn.fnamemodify(path, ":p")
+ end
+ return path
+end
+
+--- Returns true if candidate is a subpath of root, or if they are the same path.
+---@param root string
+---@param candidate string
+---@return boolean
+M.is_subpath = function(root, candidate)
+ if candidate == "" then
+ return false
+ end
+ root = vim.fs.normalize(M.abspath(root))
+ -- Trim trailing "/" from the root
+ if root:find("/", -1) then
+ root = root:sub(1, -2)
+ end
+ candidate = vim.fs.normalize(M.abspath(candidate))
+ if M.is_windows then
+ root = root:lower()
+ candidate = candidate:lower()
+ end
+ if root == candidate then
+ return true
+ end
+ local prefix = candidate:sub(1, root:len())
+ if prefix ~= root then
+ return false
+ end
+
+ local candidate_starts_with_sep = candidate:find("/", root:len() + 1, true) == root:len() + 1
+ local root_ends_with_sep = root:find("/", root:len(), true) == root:len()
+
+ return candidate_starts_with_sep or root_ends_with_sep
+end
+
+---Create a relative path from the source to the target
+---@param source string
+---@param target string
+---@return string
+M.relative_path = function(source, target)
+ source = M.abspath(source)
+ target = M.abspath(target)
+ local path = {}
+ while not M.is_subpath(source, target) do
+ table.insert(path, "..")
+ local new_source = vim.fs.dirname(source)
+ assert(source ~= new_source)
+ source = new_source
+ end
+
+ local offset = vim.endswith(source, M.sep) and 1 or 2
+ local rel_target = target:sub(source:len() + offset)
+ table.insert(path, rel_target)
+ return M.join(unpack(path))
+end
+
return M
diff --git a/lua/conform/runner.lua b/lua/conform/runner.lua
index 0f31e64..b3a1e61 100644
--- a/lua/conform/runner.lua
+++ b/lua/conform/runner.lua
@@ -33,8 +33,17 @@ M.build_cmd = function(formatter_name, ctx, config)
end
end
+ local cwd
+ if config.cwd then
+ cwd = config.cwd(config, ctx)
+ end
+ local relative_filename = fs.relative_path(cwd or vim.fn.getcwd(), ctx.filename)
+
if type(args) == "string" then
- local interpolated = args:gsub("$FILENAME", ctx.filename):gsub("$DIRNAME", ctx.dirname)
+ local interpolated = args
+ :gsub("$FILENAME", ctx.filename)
+ :gsub("$DIRNAME", ctx.dirname)
+ :gsub("$RELATIVE_FILEPATH", relative_filename)
return command .. " " .. interpolated
else
local cmd = { command }
@@ -44,6 +53,8 @@ M.build_cmd = function(formatter_name, ctx, config)
v = ctx.filename
elseif v == "$DIRNAME" then
v = ctx.dirname
+ elseif v == "$RELATIVE_FILEPATH" then
+ v = relative_filename
end
table.insert(cmd, v)
end