Skip to content

Commit d7cd559

Browse files
committed
fix: Windows path conversion fails for forward-slash paths
1 parent 104822f commit d7cd559

File tree

3 files changed

+49
-14
lines changed

3 files changed

+49
-14
lines changed

lua/oil/fs.lua

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,20 @@ M.is_subpath = function(root, candidate)
8484
return candidate_starts_with_sep or root_ends_with_sep
8585
end
8686

87+
---@param path string
88+
---@return string
89+
local function normalized_path_seperators(path)
90+
local leading_slashes, rem = path:match("^([\\/]*)(.*)$")
91+
local normalized_rem = rem:gsub("[\\/]+", M.sep)
92+
local normalized_leading = ""
93+
if #leading_slashes >= 2 then
94+
normalized_leading = M.sep .. M.sep
95+
elseif #leading_slashes == 1 then
96+
normalized_leading = M.sep
97+
end
98+
return string.format("%s%s", normalized_leading, normalized_rem)
99+
end
100+
87101
---@param path string
88102
---@return string
89103
M.posix_to_os_path = function(path)
@@ -105,11 +119,12 @@ end
105119
---@return string
106120
M.os_to_posix_path = function(path)
107121
if M.is_windows then
108-
if M.is_absolute(path) then
109-
local drive, rem = path:match("^([^:]+):\\(.*)$")
122+
local normalized_path = normalized_path_seperators(path)
123+
if M.is_absolute(normalized_path) then
124+
local drive, rem = normalized_path:match("^([^:]+):\\(.*)$")
110125
return string.format("/%s/%s", drive:upper(), rem:gsub("\\", "/"))
111126
else
112-
local newpath = path:gsub("\\", "/")
127+
local newpath = normalized_path:gsub("\\", "/")
113128
return newpath
114129
end
115130
else

tests/fs_spec.lua

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,16 @@ a.describe("File system", function()
3030
assert.equals("/C/a/b/c", fs.os_to_posix_path("C:\\a\\b\\c"))
3131
end)
3232

33+
a.it("converts Windows local path with extra backslash path seperators to posix", function()
34+
set_env_windows()
35+
assert.equals("/C/a/b/c", fs.os_to_posix_path("C:\\\\a\\b\\c"))
36+
end)
37+
38+
a.it("converts Windows local path with forward slashes to posix", function()
39+
set_env_windows()
40+
assert.equals("/C/a/b/c", fs.os_to_posix_path("C:/a/b/c"))
41+
end)
42+
3343
a.it("converts Windows UNC path to posix", function()
3444
set_env_windows()
3545
assert.equals("//a/b/c", fs.os_to_posix_path("\\\\a\\b\\c"))

tests/url_spec.lua

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,35 @@
11
local oil = require("oil")
22
local util = require("oil.util")
3+
4+
local uv = vim.uv or vim.loop
5+
36
describe("url", function()
47
it("get_url_for_path", function()
58
local cases = {
6-
{ "", "oil://" .. util.addslash(vim.fn.getcwd()) },
7-
{ "term://~/oil.nvim//52953:/bin/sh", "oil://" .. vim.loop.os_homedir() .. "/oil.nvim/" },
8-
{ "/foo/bar.txt", "oil:///foo/", "bar.txt" },
9+
{ "", "oil://" .. util.addslash(vim.fn.getcwd()), skip_on_windows = true },
10+
{
11+
"term://~/oil.nvim//52953:/bin/sh",
12+
"oil://" .. vim.loop.os_homedir() .. "/oil.nvim/",
13+
skip_on_windows = true,
14+
},
15+
{ "/foo/bar.txt", "oil:///foo/", "bar.txt", skip_on_windows = true },
916
{ "oil:///foo/bar.txt", "oil:///foo/", "bar.txt" },
1017
{ "oil:///", "oil:///" },
1118
{ "oil-ssh://user@hostname:8888//bar.txt", "oil-ssh://user@hostname:8888//", "bar.txt" },
1219
{ "oil-ssh://user@hostname:8888//", "oil-ssh://user@hostname:8888//" },
1320
}
1421
for _, case in ipairs(cases) do
15-
local input, expected, expected_basename = unpack(case)
16-
local output, basename = oil.get_buffer_parent_url(input, true)
17-
assert.equals(expected, output, string.format('Parent url for path "%s" failed', input))
18-
assert.equals(
19-
expected_basename,
20-
basename,
21-
string.format('Basename for path "%s" failed', input)
22-
)
22+
local is_skip = case.skip_on_windows and uv.os_uname().version:match("Windows")
23+
if not is_skip then
24+
local input, expected, expected_basename = unpack(case)
25+
local output, basename = oil.get_buffer_parent_url(input, true)
26+
assert.equals(expected, output, string.format('Parent url for path "%s" failed', input))
27+
assert.equals(
28+
expected_basename,
29+
basename,
30+
string.format('Basename for path "%s" failed', input)
31+
)
32+
end
2333
end
2434
end)
2535
end)

0 commit comments

Comments
 (0)