aboutsummaryrefslogtreecommitdiffstats
path: root/lua/conform/fs.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/conform/fs.lua
parent393210360b9e807862e5329763526509f52b5218 (diff)
feat: formatters can use $RELATIVE_FILEPATH in args (#349)
Diffstat (limited to 'lua/conform/fs.lua')
-rw-r--r--lua/conform/fs.lua68
1 files changed, 68 insertions, 0 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