mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
fix(fs): allow backslash characters in unix paths
Backslashes are valid characters in unix style paths. Fix the conversion of backslashes to forward slashes in several `vim.fs` functions when not on Windows. On Windows, backslashes will still be converted to forward slashes.
This commit is contained in:
parent
36acb2a8ec
commit
38e38d1b40
@ -2954,13 +2954,14 @@ vim.fs.joinpath({...}) *vim.fs.joinpath()*
|
|||||||
|
|
||||||
vim.fs.normalize({path}, {opts}) *vim.fs.normalize()*
|
vim.fs.normalize({path}, {opts}) *vim.fs.normalize()*
|
||||||
Normalize a path to a standard format. A tilde (~) character at the
|
Normalize a path to a standard format. A tilde (~) character at the
|
||||||
beginning of the path is expanded to the user's home directory and any
|
beginning of the path is expanded to the user's home directory and
|
||||||
backslash (\) characters are converted to forward slashes (/). Environment
|
environment variables are also expanded.
|
||||||
variables are also expanded.
|
|
||||||
|
On Windows, backslash (\) characters are converted to forward slashes (/).
|
||||||
|
|
||||||
Examples: >lua
|
Examples: >lua
|
||||||
vim.fs.normalize('C:\\\\Users\\\\jdoe')
|
vim.fs.normalize('C:\\\\Users\\\\jdoe')
|
||||||
-- 'C:/Users/jdoe'
|
-- On Windows: 'C:/Users/jdoe'
|
||||||
|
|
||||||
vim.fs.normalize('~/src/neovim')
|
vim.fs.normalize('~/src/neovim')
|
||||||
-- '/home/jdoe/src/neovim'
|
-- '/home/jdoe/src/neovim'
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
local iswin = vim.uv.os_uname().sysname == 'Windows_NT'
|
local iswin = vim.uv.os_uname().sysname == 'Windows_NT'
|
||||||
|
local os_sep = iswin and '\\' or '/'
|
||||||
|
|
||||||
--- Iterate over all the parents of the given path.
|
--- Iterate over all the parents of the given path.
|
||||||
---
|
---
|
||||||
@ -47,19 +48,23 @@ function M.dirname(file)
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
vim.validate({ file = { file, 's' } })
|
vim.validate({ file = { file, 's' } })
|
||||||
if iswin and file:match('^%w:[\\/]?$') then
|
if iswin then
|
||||||
return (file:gsub('\\', '/'))
|
file = file:gsub(os_sep, '/') --[[@as string]]
|
||||||
elseif not file:match('[\\/]') then
|
if file:match('^%w:/?$') then
|
||||||
|
return file
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not file:match('/') then
|
||||||
return '.'
|
return '.'
|
||||||
elseif file == '/' or file:match('^/[^/]+$') then
|
elseif file == '/' or file:match('^/[^/]+$') then
|
||||||
return '/'
|
return '/'
|
||||||
end
|
end
|
||||||
---@type string
|
---@type string
|
||||||
local dir = file:match('[/\\]$') and file:sub(1, #file - 1) or file:match('^([/\\]?.+)[/\\]')
|
local dir = file:match('/$') and file:sub(1, #file - 1) or file:match('^(/?.+)/')
|
||||||
if iswin and dir:match('^%w:$') then
|
if iswin and dir:match('^%w:$') then
|
||||||
return dir .. '/'
|
return dir .. '/'
|
||||||
end
|
end
|
||||||
return (dir:gsub('\\', '/'))
|
return dir
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Return the basename of the given path
|
--- Return the basename of the given path
|
||||||
@ -72,10 +77,13 @@ function M.basename(file)
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
vim.validate({ file = { file, 's' } })
|
vim.validate({ file = { file, 's' } })
|
||||||
if iswin and file:match('^%w:[\\/]?$') then
|
if iswin then
|
||||||
return ''
|
file = file:gsub(os_sep, '/') --[[@as string]]
|
||||||
|
if file:match('^%w:/?$') then
|
||||||
|
return ''
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return file:match('[/\\]$') and '' or (file:match('[^\\/]*$'):gsub('\\', '/'))
|
return file:match('/$') and '' or (file:match('[^/]*$'))
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Concatenate directories and/or file paths into a single path with normalization
|
--- Concatenate directories and/or file paths into a single path with normalization
|
||||||
@ -334,15 +342,16 @@ end
|
|||||||
--- @field expand_env boolean
|
--- @field expand_env boolean
|
||||||
|
|
||||||
--- Normalize a path to a standard format. A tilde (~) character at the
|
--- Normalize a path to a standard format. A tilde (~) character at the
|
||||||
--- beginning of the path is expanded to the user's home directory and any
|
--- beginning of the path is expanded to the user's home directory and
|
||||||
--- backslash (\) characters are converted to forward slashes (/). Environment
|
--- environment variables are also expanded.
|
||||||
--- variables are also expanded.
|
---
|
||||||
|
--- On Windows, backslash (\) characters are converted to forward slashes (/).
|
||||||
---
|
---
|
||||||
--- Examples:
|
--- Examples:
|
||||||
---
|
---
|
||||||
--- ```lua
|
--- ```lua
|
||||||
--- vim.fs.normalize('C:\\\\Users\\\\jdoe')
|
--- vim.fs.normalize('C:\\\\Users\\\\jdoe')
|
||||||
--- -- 'C:/Users/jdoe'
|
--- -- On Windows: 'C:/Users/jdoe'
|
||||||
---
|
---
|
||||||
--- vim.fs.normalize('~/src/neovim')
|
--- vim.fs.normalize('~/src/neovim')
|
||||||
--- -- '/home/jdoe/src/neovim'
|
--- -- '/home/jdoe/src/neovim'
|
||||||
@ -364,7 +373,7 @@ function M.normalize(path, opts)
|
|||||||
|
|
||||||
if path:sub(1, 1) == '~' then
|
if path:sub(1, 1) == '~' then
|
||||||
local home = vim.uv.os_homedir() or '~'
|
local home = vim.uv.os_homedir() or '~'
|
||||||
if home:sub(-1) == '\\' or home:sub(-1) == '/' then
|
if home:sub(-1) == os_sep then
|
||||||
home = home:sub(1, -2)
|
home = home:sub(1, -2)
|
||||||
end
|
end
|
||||||
path = home .. path:sub(2)
|
path = home .. path:sub(2)
|
||||||
@ -374,7 +383,7 @@ function M.normalize(path, opts)
|
|||||||
path = path:gsub('%$([%w_]+)', vim.uv.os_getenv)
|
path = path:gsub('%$([%w_]+)', vim.uv.os_getenv)
|
||||||
end
|
end
|
||||||
|
|
||||||
path = path:gsub('\\', '/'):gsub('/+', '/')
|
path = path:gsub(os_sep, '/'):gsub('/+', '/')
|
||||||
if iswin and path:match('^%w:/$') then
|
if iswin and path:match('^%w:/$') then
|
||||||
return path
|
return path
|
||||||
end
|
end
|
||||||
|
@ -36,6 +36,7 @@ local test_basename_dirname_eq = {
|
|||||||
'c:/users/foo',
|
'c:/users/foo',
|
||||||
'c:/users/foo/bar.lua',
|
'c:/users/foo/bar.lua',
|
||||||
'c:/users/foo/bar/../',
|
'c:/users/foo/bar/../',
|
||||||
|
'~/foo/bar\\baz',
|
||||||
}
|
}
|
||||||
|
|
||||||
local tests_windows_paths = {
|
local tests_windows_paths = {
|
||||||
@ -70,26 +71,26 @@ describe('vim.fs', function()
|
|||||||
it('works', function()
|
it('works', function()
|
||||||
eq(test_build_dir, vim.fs.dirname(nvim_dir))
|
eq(test_build_dir, vim.fs.dirname(nvim_dir))
|
||||||
|
|
||||||
--- @param paths string[]
|
---@param paths string[]
|
||||||
local function test_paths(paths)
|
---@param is_win? boolean
|
||||||
|
local function test_paths(paths, is_win)
|
||||||
|
local gsub = is_win and [[:gsub('\\', '/')]] or ''
|
||||||
|
local code = string.format(
|
||||||
|
[[
|
||||||
|
local path = ...
|
||||||
|
return vim.fn.fnamemodify(path,':h')%s
|
||||||
|
]],
|
||||||
|
gsub
|
||||||
|
)
|
||||||
|
|
||||||
for _, path in ipairs(paths) do
|
for _, path in ipairs(paths) do
|
||||||
eq(
|
eq(exec_lua(code, path), vim.fs.dirname(path), path)
|
||||||
exec_lua(
|
|
||||||
[[
|
|
||||||
local path = ...
|
|
||||||
return vim.fn.fnamemodify(path,':h'):gsub('\\', '/')
|
|
||||||
]],
|
|
||||||
path
|
|
||||||
),
|
|
||||||
vim.fs.dirname(path),
|
|
||||||
path
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test_paths(test_basename_dirname_eq)
|
test_paths(test_basename_dirname_eq)
|
||||||
if is_os('win') then
|
if is_os('win') then
|
||||||
test_paths(tests_windows_paths)
|
test_paths(tests_windows_paths, true)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
@ -98,26 +99,26 @@ describe('vim.fs', function()
|
|||||||
it('works', function()
|
it('works', function()
|
||||||
eq(nvim_prog_basename, vim.fs.basename(nvim_prog))
|
eq(nvim_prog_basename, vim.fs.basename(nvim_prog))
|
||||||
|
|
||||||
--- @param paths string[]
|
---@param paths string[]
|
||||||
local function test_paths(paths)
|
---@param is_win? boolean
|
||||||
|
local function test_paths(paths, is_win)
|
||||||
|
local gsub = is_win and [[:gsub('\\', '/')]] or ''
|
||||||
|
local code = string.format(
|
||||||
|
[[
|
||||||
|
local path = ...
|
||||||
|
return vim.fn.fnamemodify(path,':t')%s
|
||||||
|
]],
|
||||||
|
gsub
|
||||||
|
)
|
||||||
|
|
||||||
for _, path in ipairs(paths) do
|
for _, path in ipairs(paths) do
|
||||||
eq(
|
eq(exec_lua(code, path), vim.fs.basename(path), path)
|
||||||
exec_lua(
|
|
||||||
[[
|
|
||||||
local path = ...
|
|
||||||
return vim.fn.fnamemodify(path,':t'):gsub('\\', '/')
|
|
||||||
]],
|
|
||||||
path
|
|
||||||
),
|
|
||||||
vim.fs.basename(path),
|
|
||||||
path
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test_paths(test_basename_dirname_eq)
|
test_paths(test_basename_dirname_eq)
|
||||||
if is_os('win') then
|
if is_os('win') then
|
||||||
test_paths(tests_windows_paths)
|
test_paths(tests_windows_paths, true)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
@ -284,9 +285,6 @@ describe('vim.fs', function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
describe('normalize()', function()
|
describe('normalize()', function()
|
||||||
it('works with backward slashes', function()
|
|
||||||
eq('C:/Users/jdoe', vim.fs.normalize('C:\\Users\\jdoe'))
|
|
||||||
end)
|
|
||||||
it('removes trailing /', function()
|
it('removes trailing /', function()
|
||||||
eq('/home/user', vim.fs.normalize('/home/user/'))
|
eq('/home/user', vim.fs.normalize('/home/user/'))
|
||||||
end)
|
end)
|
||||||
@ -309,10 +307,18 @@ describe('vim.fs', function()
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
if is_os('win') then
|
if is_os('win') then
|
||||||
it('Last slash is not truncated from root drive', function()
|
it('Last slash is not truncated from root drive', function()
|
||||||
eq('C:/', vim.fs.normalize('C:/'))
|
eq('C:/', vim.fs.normalize('C:/'))
|
||||||
end)
|
end)
|
||||||
|
it('converts backward slashes', function()
|
||||||
|
eq('C:/Users/jdoe', vim.fs.normalize('C:\\Users\\jdoe'))
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
it('allows backslashes on unix-based os', function()
|
||||||
|
eq('/home/user/hello\\world', vim.fs.normalize('/home/user/hello\\world'))
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user