neo-tree.nvim
neo-tree.nvim copied to clipboard
fix: handle more edge cases for Windows path escaping
This PR fixes #1448, among other edge cases that weren't previously handled.
Relevant notes were captured in the discussion for #1448, but the gist is that certain punctuation ([
, ]
, backticks, $
, etc.) causes Neovim to drop an escaped path separator on Windows. This requires us to use an additional \
(e.g. X:\[foo]\\\(bar)\baz.txt
).
For anyone who wants to verify/test the logic, the following script was ran in Neovim with :luafile %
:
local dpunc = {
"()",
"[]",
-- "{}",
"^",
"&",
";",
"`",
-- these are left out because this causes exponentially longer runtime.
-- they should have similar behavior to the above
-- "!", "#", "$", "%", "+", ",", "-", "=", "@", "_", "~"
}
local fpunc = [[!#$%&'()+,-;=@[]^_`{}~ ]]
-- testing implementation for this function
local function escape_path_for_cmd(path)
local escaped_path = vim.fn.fnameescape(path)
if true then -- assume is windows
local need_extra_esc = path:find("[%[%]`%$~]")
local esc = need_extra_esc and "\\\\" or "\\"
escaped_path = escaped_path:gsub("\\[%(%)%^&;]", esc .. "%1")
if need_extra_esc then
escaped_path = escaped_path:gsub("\\\\['` ]", "\\%1")
end
end
return escaped_path
end
-- makes a value like `[foo]` from part='foo' and p='[]'
local function make_part(part, p)
local open = p:sub(1, 1)
local close = p:sub(2, 2)
if close == "" then
close = open
end
return (open .. part .. close)
end
-- create nested directories with leading/trailing punctuation
local dirs = {}
for _, p1 in ipairs(dpunc) do
for _, p2 in ipairs(dpunc) do
local part1 = make_part("foo", p1)
local part2 = make_part("bar", p2)
local path = string.format(".\\tests\\%s\\%s", part1, part2)
vim.fn.mkdir(path, "p")
table.insert(dirs, path)
end
end
local files = { "baz.txt" }
for c in string.gmatch(fpunc, ".") do
table.insert(files, c .. "baz.txt")
end
-- try to write files with weird path
for _, d in ipairs(dirs) do
for _, f in ipairs(files) do
local p = escape_path_for_cmd(d .. "\\" .. f)
local ok, err = pcall(vim.cmd, "silent w " .. p)
if not ok then
print("fail:", p, "->", err)
end
end
end
Thank you so much for working in this @bwpge !!
Passing this to @cseickel .
@pysan3 wanted to ping you on this one.
I'm sure things are a bit hectic with the changeover in responsibilities so no rush, just a bump to keep on the radar :)
Thanks mate, I totally forgot this one my bad.
Merging! Thanks for your amazing work.
Happy to help, have a good weekend!
Don't know why but still not working for me.
@SuperSheykh It's not released as a version yet. Are you sure you are on the latest master branch?
My bad it actually works fine. Thanks so much guys!