This commit is contained in:
Mike 2024-12-18 21:41:58 +01:00 committed by GitHub
commit 527b8fb243
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 74 additions and 9 deletions

View File

@ -2972,6 +2972,7 @@ vim.fs.dir({path}, {opts}) *vim.fs.dir()*
• skip: (fun(dir_name: string): boolean)|nil Predicate to
control traversal. Return false to stop searching the
current directory. Only useful when depth > 1
• follow: boolean|nil Follow symbolic links. (default: true)
Return: ~
(`Iterator`) over items in {path}. Each iteration yields two values:
@ -3013,7 +3014,7 @@ vim.fs.find({names}, {opts}) *vim.fs.find()*
-- get all files ending with .cpp or .hpp inside lib/
local cpp_hpp = vim.fs.find(function(name, path)
return name:match('.*%.[ch]pp$') and path:match('[/\\\\]lib$')
return name:match('.*%.[ch]pp$') and path:match('[/\\]lib$')
end, {limit = math.huge, type = 'file'})
<
@ -3027,8 +3028,10 @@ vim.fs.find({names}, {opts}) *vim.fs.find()*
If {names} is a function, it is called for each traversed
item with args:
• name: base name of the current item
• path: full path of the current item The function should
return `true` if the given item is considered a match.
• path: full path of the current item
The function should return `true` if the given item is
considered a match.
• {opts} (`table`) Optional keyword arguments:
• {path}? (`string`) Path to begin searching from. If
omitted, the |current-directory| is used.
@ -3042,6 +3045,8 @@ vim.fs.find({names}, {opts}) *vim.fs.find()*
• {limit}? (`number`, default: `1`) Stop the search after
finding this many matches. Use `math.huge` to place no
limit on the number of matches.
• {follow}? (`boolean`, default: `true`) Follow symbolic
links.
Return: ~
(`string[]`) Normalized paths |vim.fs.normalize()| of all matching

View File

@ -127,6 +127,7 @@ end
--- - skip: (fun(dir_name: string): boolean)|nil Predicate
--- to control traversal. Return false to stop searching the current directory.
--- Only useful when depth > 1
--- - follow: boolean|nil Follow symbolic links. (default: true)
---
---@return Iterator over items in {path}. Each iteration yields two values: "name" and "type".
--- "name" is the basename of the item relative to {path}.
@ -138,6 +139,7 @@ function M.dir(path, opts)
vim.validate('path', path, 'string')
vim.validate('depth', opts.depth, 'number', true)
vim.validate('skip', opts.skip, 'function', true)
vim.validate('follow', opts.follow, 'boolean', true)
path = M.normalize(path)
if not opts.depth or opts.depth == 1 then
@ -168,7 +170,9 @@ function M.dir(path, opts)
if
opts.depth
and level < opts.depth
and t == 'directory'
and (t == 'directory' or (t == 'link' and opts.follow ~= false and (vim.uv.fs_stat(
M.joinpath(path, f)
) or {}).type == 'directory'))
and (not opts.skip or opts.skip(f) ~= false)
then
dirs[#dirs + 1] = { f, level + 1 }
@ -202,6 +206,10 @@ end
--- Use `math.huge` to place no limit on the number of matches.
--- (default: `1`)
--- @field limit? number
---
--- Follow symbolic links.
--- (default: `true`)
--- @field follow? boolean
--- Find files or directories (or other items as specified by `opts.type`) in the given path.
---
@ -225,7 +233,7 @@ end
---
--- -- get all files ending with .cpp or .hpp inside lib/
--- local cpp_hpp = vim.fs.find(function(name, path)
--- return name:match('.*%.[ch]pp$') and path:match('[/\\\\]lib$')
--- return name:match('.*%.[ch]pp$') and path:match('[/\\]lib$')
--- end, {limit = math.huge, type = 'file'})
--- ```
---
@ -235,6 +243,7 @@ end
--- If {names} is a function, it is called for each traversed item with args:
--- - name: base name of the current item
--- - path: full path of the current item
---
--- The function should return `true` if the given item is considered a match.
---
---@param opts vim.fs.find.Opts Optional keyword arguments:
@ -247,6 +256,7 @@ function M.find(names, opts)
vim.validate('stop', opts.stop, 'string', true)
vim.validate('type', opts.type, 'string', true)
vim.validate('limit', opts.limit, 'number', true)
vim.validate('follow', opts.follow, 'boolean', true)
if type(names) == 'string' then
names = { names }
@ -336,7 +346,14 @@ function M.find(names, opts)
end
end
if type_ == 'directory' then
if
type_ == 'directory'
or (
type_ == 'link'
and opts.follow ~= false
and (vim.uv.fs_stat(f) or {}).type == 'directory'
)
then
dirs[#dirs + 1] = f
end
end

View File

@ -152,7 +152,7 @@ describe('vim.fs', function()
)
end)
it('works with opts.depth and opts.skip', function()
it('works with opts.depth, opts.skip and opts.follow', function()
io.open('testd/a1', 'w'):close()
io.open('testd/b1', 'w'):close()
io.open('testd/c1', 'w'):close()
@ -166,7 +166,7 @@ describe('vim.fs', function()
io.open('testd/a/b/c/b4', 'w'):close()
io.open('testd/a/b/c/c4', 'w'):close()
local function run(dir, depth, skip)
local function run(dir, depth, skip, follow)
return exec_lua(function()
local r = {}
local skip_f
@ -177,7 +177,7 @@ describe('vim.fs', function()
end
end
end
for name, type_ in vim.fs.dir(dir, { depth = depth, skip = skip_f }) do
for name, type_ in vim.fs.dir(dir, { depth = depth, skip = skip_f, follow = follow }) do
r[name] = type_
end
return r
@ -197,6 +197,7 @@ describe('vim.fs', function()
exp['a/b2'] = 'file'
exp['a/c2'] = 'file'
exp['a/b'] = 'directory'
local lexp = vim.deepcopy(exp)
eq(exp, run('testd', 2))
@ -213,10 +214,32 @@ describe('vim.fs', function()
exp['a/b/c/c4'] = 'file'
eq(exp, run('testd', 999))
vim.uv.fs_symlink('a', 'testd/l', { junction = true, dir = true })
lexp['l'] = 'link'
eq(lexp, run('testd', 2, nil, false))
lexp['l/a2'] = 'file'
lexp['l/b2'] = 'file'
lexp['l/c2'] = 'file'
lexp['l/b'] = 'directory'
eq(lexp, run('testd', 2, nil, true))
end)
end)
describe('find()', function()
before_each(function()
vim.uv.fs_symlink(
test_source_path .. '/build',
test_source_path .. '/build_link',
{ junction = true, dir = true }
)
end)
after_each(function()
vim.uv.fs_unlink(test_source_path .. '/build_link')
end)
it('works', function()
eq(
{ test_build_dir .. '/build' },
@ -224,6 +247,26 @@ describe('vim.fs', function()
)
eq({ nvim_prog }, vim.fs.find(nvim_prog_basename, { path = test_build_dir, type = 'file' }))
eq(
{ nvim_prog, test_source_path .. '/build_link/bin/' .. nvim_prog_basename },
vim.fs.find(nvim_prog_basename, {
path = test_source_path,
type = 'file',
limit = 2,
follow = true,
})
)
eq(
{ nvim_prog },
vim.fs.find(nvim_prog_basename, {
path = test_source_path,
type = 'file',
limit = 2,
follow = false,
})
)
local parent, name = nvim_dir:match('^(.*/)([^/]+)$')
eq({ nvim_dir }, vim.fs.find(name, { path = parent, upward = true, type = 'directory' }))
end)