@@ -59,6 +59,17 @@ function M.path_basename(path)
5959 return path :sub (i + 1 , # path )
6060end
6161
62+ --- Check if there are parentheses before brackets, it causes problems for windows.
63+ --- Refer to issue #2862 and #2961 for more details.
64+ local function has_parentheses_and_brackets (path )
65+ local _ , i_parentheses = path :find (" (" , 1 , true )
66+ local _ , i_brackets = path :find (" [" , 1 , true )
67+ if i_parentheses and i_brackets then
68+ return true
69+ end
70+ return false
71+ end
72+
6273--- Get a path relative to another path.
6374--- @param path string
6475--- @param relative_to string | nil
@@ -68,13 +79,18 @@ function M.path_relative(path, relative_to)
6879 return path
6980 end
7081
71- local _ , r = path :find (M .path_add_trailing (relative_to ), 1 , true )
72- local p = path
82+ local norm_path = path
83+ if M .is_windows and has_parentheses_and_brackets (path ) then
84+ norm_path = path :gsub (" /" , " \\ " )
85+ end
86+
87+ local _ , r = norm_path :find (M .path_add_trailing (relative_to ), 1 , true )
88+ local p = norm_path
7389 if r then
7490 -- take the relative path starting after '/'
7591 -- if somehow given a completely matching path,
7692 -- returns ""
77- p = path :sub (r + 1 )
93+ p = norm_path :sub (r + 1 )
7894 end
7995 return p
8096end
@@ -272,14 +288,22 @@ function M.canonical_path(path)
272288 return path
273289end
274290
291+ --- Escapes special characters in string for windows, refer to issue #2862 and #2961 for more details.
292+ local function escape_special_char_for_windows (path )
293+ if has_parentheses_and_brackets (path ) then
294+ return path :gsub (" \\ " , " /" ):gsub (" / " , " \\ " )
295+ end
296+ return path :gsub (" %(" , " \\ (" ):gsub (" %)" , " \\ )" )
297+ end
298+
275299--- Escapes special characters in string if windows else returns unmodified string.
276300--- @param path string
277301--- @return string | nil
278302function M .escape_special_chars (path )
279303 if path == nil then
280304 return path
281305 end
282- return M .is_windows and path : gsub ( " \\ " , " / " ) or path
306+ return M .is_windows and escape_special_char_for_windows ( path ) or path
283307end
284308
285309--- Create empty sub-tables if not present
0 commit comments