aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lua/mason-core/path.lua33
-rw-r--r--tests/mason-core/path_spec.lua51
2 files changed, 83 insertions, 1 deletions
diff --git a/lua/mason-core/path.lua b/lua/mason-core/path.lua
index 9eeed3ba..66f0f964 100644
--- a/lua/mason-core/path.lua
+++ b/lua/mason-core/path.lua
@@ -24,7 +24,38 @@ end
---@path root_path string
---@path path string
function M.is_subdirectory(root_path, path)
- return root_path == path or path:sub(1, #root_path + 1) == root_path .. sep
+ local root_path_normalized = vim.fs.normalize(root_path)
+ local path_normalized = vim.fs.normalize(path)
+ if path_normalized == root_path_normalized then
+ return true
+ end
+ for dir in vim.fs.parents(path_normalized) do
+ if root_path_normalized == dir then
+ return true
+ end
+ end
+ return false
+end
+
+local function find_closest_common_parent(from, to)
+ local distance = 0
+ for parent in vim.fs.parents(from) do
+ if to:find(parent, 1, true) then
+ return parent, distance
+ else
+ distance = distance + 1
+ end
+ end
+ return "/", distance
+end
+
+function M.relative(from, to)
+ local from_normalized = vim.fs.normalize(from)
+ local to_normalized = vim.fs.normalize(to)
+
+ local common_parent, distance = find_closest_common_parent(from_normalized, to_normalized)
+ local relative_path_component = distance == 0 and "." or (".."):rep(distance, "/")
+ return vim.fs.joinpath(relative_path_component, to_normalized:sub(#common_parent + 1))
end
return M
diff --git a/tests/mason-core/path_spec.lua b/tests/mason-core/path_spec.lua
index 3d0c2e25..4aeb48f1 100644
--- a/tests/mason-core/path_spec.lua
+++ b/tests/mason-core/path_spec.lua
@@ -22,4 +22,55 @@ describe("path", function()
assert.is_false(path.is_subdirectory("/foo/bar", "/foo/bas/baz"))
assert.is_false(path.is_subdirectory("/foo/bar", "/foo/bars/baz"))
end)
+
+ describe("relative ::", function()
+ local matrix = {
+ {
+ from = "/home/user/dir1/fileA",
+ to = "/home/user/dir1/fileB",
+ expected = "./fileB",
+ },
+ {
+ from = "/home/user/dir1/fileA",
+ to = "/home/user/dir2/fileC",
+ expected = "../dir2/fileC",
+ },
+ {
+ from = "/home/user/dir1/subdir/fileD",
+ to = "/home/user/dir1/fileE",
+ expected = "../fileE",
+ },
+ {
+ from = "/home/user/dir1/subdir/fileD",
+ to = "/home/user/dir1/subdir/fileF",
+ expected = "./fileF",
+ },
+ {
+ from = "/home/user/dir1/fileG",
+ to = "/home/user/dir2/subdir/fileH",
+ expected = "../dir2/subdir/fileH",
+ },
+ {
+ from = "/home/user/dir1/subdir1/subdir2/fileI",
+ to = "/home/user/dir1/fileJ",
+ expected = "../../fileJ",
+ },
+ {
+ from = "/fileK",
+ to = "/home/fileL",
+ expected = "./home/fileL",
+ },
+ {
+ from = "/home/user/fileM",
+ to = "/home/user/dir1/dir2/fileL",
+ expected = "./dir1/dir2/fileL",
+ },
+ }
+
+ for _, test_case in ipairs(matrix) do
+ it(("should resolve from %s to %s: %s"):format(test_case.from, test_case.to, test_case.expected), function()
+ assert.equals(test_case.expected, path.relative(test_case.from, test_case.to))
+ end)
+ end
+ end)
end)