refactor(fs): replace vim.fn/vim.env in vim.fs (#20379)

Avoid using vim.env and vim.fn in vim.fs functions so that
they can be used in "fast" contexts.
This commit is contained in:
Mike 2022-12-01 09:15:05 -06:00 committed by GitHub
parent adda751407
commit 61e99217e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 105 additions and 3 deletions

View File

@ -1,5 +1,7 @@
local M = {} local M = {}
local iswin = vim.loop.os_uname().sysname == 'Windows_NT'
--- Iterate over all the parents of the given file or directory. --- Iterate over all the parents of the given file or directory.
--- ---
--- Example: --- Example:
@ -40,7 +42,19 @@ function M.dirname(file)
if file == nil then if file == nil then
return nil return nil
end end
return vim.fn.fnamemodify(file, ':h') vim.validate({ file = { file, 's' } })
if iswin and file:match('^%w:[\\/]?$') then
return (file:gsub('\\', '/'))
elseif not file:match('[\\/]') then
return '.'
elseif file == '/' or file:match('^/[^/]+$') then
return '/'
end
local dir = file:match('[/\\]$') and file:sub(1, #file - 1) or file:match('^([/\\]?.+)[/\\]')
if iswin and dir:match('^%w:$') then
return dir .. '/'
end
return (dir:gsub('\\', '/'))
end end
--- Return the basename of the given file or directory --- Return the basename of the given file or directory
@ -48,7 +62,14 @@ end
---@param file (string) File or directory ---@param file (string) File or directory
---@return (string) Basename of {file} ---@return (string) Basename of {file}
function M.basename(file) function M.basename(file)
return vim.fn.fnamemodify(file, ':t') if file == nil then
return nil
end
vim.validate({ file = { file, 's' } })
if iswin and file:match('^%w:[\\/]?$') then
return ''
end
return file:match('[/\\]$') and '' or (file:match('[^\\/]*$'):gsub('\\', '/'))
end end
--- Return an iterator over the files and directories located in {path} --- Return an iterator over the files and directories located in {path}
@ -229,7 +250,12 @@ end
---@return (string) Normalized path ---@return (string) Normalized path
function M.normalize(path) function M.normalize(path)
vim.validate({ path = { path, 's' } }) vim.validate({ path = { path, 's' } })
return (path:gsub('^~/', vim.env.HOME .. '/'):gsub('%$([%w_]+)', vim.env):gsub('\\', '/')) return (
path
:gsub('^~/', vim.loop.os_homedir() .. '/')
:gsub('%$([%w_]+)', vim.loop.os_getenv)
:gsub('\\', '/')
)
end end
return M return M

View File

@ -12,6 +12,39 @@ local is_os = helpers.is_os
local nvim_prog_basename = is_os('win') and 'nvim.exe' or 'nvim' local nvim_prog_basename = is_os('win') and 'nvim.exe' or 'nvim'
local test_basename_dirname_eq = {
'~/foo/',
'~/foo',
'~/foo/bar.lua',
'foo.lua',
' ',
'',
'.',
'..',
'../',
'~',
'/usr/bin',
'/usr/bin/gcc',
'/',
'/usr/',
'/usr',
'c:/usr',
'c:/',
'c:',
'c:/users/foo',
'c:/users/foo/bar.lua',
'c:/users/foo/bar/../',
}
local tests_windows_paths = {
'c:\\usr',
'c:\\',
'c:',
'c:\\users\\foo',
'c:\\users\\foo\\bar.lua',
'c:\\users\\foo\\bar\\..\\',
}
before_each(clear) before_each(clear)
describe('vim.fs', function() describe('vim.fs', function()
@ -41,15 +74,58 @@ describe('vim.fs', function()
local nvim_dir = ... local nvim_dir = ...
return vim.fs.dirname(nvim_dir) return vim.fs.dirname(nvim_dir)
]], nvim_dir)) ]], nvim_dir))
local function test_paths(paths)
for _, path in ipairs(paths) do
eq(
exec_lua([[
local path = ...
return vim.fn.fnamemodify(path,':h'):gsub('\\', '/')
]], path),
exec_lua([[
local path = ...
return vim.fs.dirname(path)
]], path),
path
)
end
end
test_paths(test_basename_dirname_eq)
if is_os('win') then
test_paths(tests_windows_paths)
end
end) end)
end) end)
describe('basename()', function() describe('basename()', function()
it('works', function() it('works', function()
eq(nvim_prog_basename, exec_lua([[ eq(nvim_prog_basename, exec_lua([[
local nvim_prog = ... local nvim_prog = ...
return vim.fs.basename(nvim_prog) return vim.fs.basename(nvim_prog)
]], nvim_prog)) ]], nvim_prog))
local function test_paths(paths)
for _, path in ipairs(paths) do
eq(
exec_lua([[
local path = ...
return vim.fn.fnamemodify(path,':t'):gsub('\\', '/')
]], path),
exec_lua([[
local path = ...
return vim.fs.basename(path)
]], path),
path
)
end
end
test_paths(test_basename_dirname_eq)
if is_os('win') then
test_paths(tests_windows_paths)
end
end) end)
end) end)