Reputation: 19
I have two absolute file path (A
and B
). I want to convert A
in relative path of B
. How can i do it using Lua script?
Upvotes: 1
Views: 3900
Reputation: 8914
It's not for general Lua users, but for neovim users, there is a useful plenary.nvim utility for this:
local Path = require "plenary.path"
local abspath = "/a/b/c"
local cwd = "/a/"
local relpath = Path:new(abspath):make_relative(cwd)
relpath -- "b/c"
Upvotes: 2
Reputation: 39950
An algorithm to do this would be:
A="/a/b/c/d.txt" B="/a/b/e/f.txt"
to A="c/d.txt" B="e/f.txt"
)A={"c", "d.txt"} B={"e", "f.txt"}
B
points to a regular file, remove the last element of B
. If it points to a directory, leave it as is. (For our example, you'd get B={"e"}
)..
at the beginning of A
. (Resulting with A={"..", "c", "d.txt"}
)A
using the path separator to get the final result: "../c/d.txt"
Here is a very rough implementation that works with no libraries. It doesn't handle any edge cases like from
and to
being the same, or one being a prefix of the other. (By this I mean the function will certainly break in those cases because mismatch
will be equal to 0
.) This is mainly because I'm lazy; also because the code is already getting a little long and this would harm readability even more.
-- to and from have to be in a canonical absolute form at
-- this point
to = "/a/b/c/d.txt"
from = "/a/b/e/f.txt"
min_len = math.min(to:len(), from:len())
mismatch = 0
print(min_len)
for i = 1, min_len do
if to:sub(i, i) ~= from:sub(i, i) then
mismatch = i
break
end
end
-- handle edge cases here
-- the parts of `a` and `b` that differ
to_diff = to:sub(mismatch)
from_diff = from:sub(mismatch)
from_file = io.open(from)
from_is_dir = false
if (from_file) then
-- check if `from` is a directory
result, err_msg, err_no = from_file:read(0)
if (err_no == 21) then -- EISDIR - `from` is a directory
end
result = ""
for slash in from_diff:gmatch("/") do
result = result .. "../"
end
if from_is_dir then
result = result .. "../"
end
result = result .. to_diff
print(result) --> ../c/d.txt
Upvotes: 5