feat: add follow opt to vim.fs.find

This commit is contained in:
Mike 2024-12-04 20:21:04 +01:00
parent 3bb2d02759
commit 7c5a461b59
No known key found for this signature in database
GPG Key ID: B27ADEA45243EBEE
3 changed files with 54 additions and 5 deletions

View File

@ -3013,7 +3013,7 @@ vim.fs.find({names}, {opts}) *vim.fs.find()*
-- get all files ending with .cpp or .hpp inside lib/ -- get all files ending with .cpp or .hpp inside lib/
local cpp_hpp = vim.fs.find(function(name, path) 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'}) end, {limit = math.huge, type = 'file'})
< <
@ -3027,8 +3027,10 @@ vim.fs.find({names}, {opts}) *vim.fs.find()*
If {names} is a function, it is called for each traversed If {names} is a function, it is called for each traversed
item with args: item with args:
• name: base name of the current item • name: base name of the current item
• path: full path of the current item The function should • path: full path of the current item
return `true` if the given item is considered a match.
The function should return `true` if the given item is
considered a match.
• {opts} (`table`) Optional keyword arguments: • {opts} (`table`) Optional keyword arguments:
• {path}? (`string`) Path to begin searching from. If • {path}? (`string`) Path to begin searching from. If
omitted, the |current-directory| is used. omitted, the |current-directory| is used.
@ -3042,6 +3044,8 @@ vim.fs.find({names}, {opts}) *vim.fs.find()*
• {limit}? (`number`, default: `1`) Stop the search after • {limit}? (`number`, default: `1`) Stop the search after
finding this many matches. Use `math.huge` to place no finding this many matches. Use `math.huge` to place no
limit on the number of matches. limit on the number of matches.
• {follow}? (`boolean`, default: `true`) Follow symbolic
links.
Return: ~ Return: ~
(`string[]`) Normalized paths |vim.fs.normalize()| of all matching (`string[]`) Normalized paths |vim.fs.normalize()| of all matching

View File

@ -202,6 +202,10 @@ end
--- Use `math.huge` to place no limit on the number of matches. --- Use `math.huge` to place no limit on the number of matches.
--- (default: `1`) --- (default: `1`)
--- @field limit? number --- @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. --- Find files or directories (or other items as specified by `opts.type`) in the given path.
--- ---
@ -225,7 +229,7 @@ end
--- ---
--- -- get all files ending with .cpp or .hpp inside lib/ --- -- get all files ending with .cpp or .hpp inside lib/
--- local cpp_hpp = vim.fs.find(function(name, path) --- 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'}) --- end, {limit = math.huge, type = 'file'})
--- ``` --- ```
--- ---
@ -235,6 +239,7 @@ end
--- If {names} is a function, it is called for each traversed item with args: --- If {names} is a function, it is called for each traversed item with args:
--- - name: base name of the current item --- - name: base name of the current item
--- - path: full path of the current item --- - path: full path of the current item
---
--- The function should return `true` if the given item is considered a match. --- The function should return `true` if the given item is considered a match.
--- ---
---@param opts vim.fs.find.Opts Optional keyword arguments: ---@param opts vim.fs.find.Opts Optional keyword arguments:
@ -247,6 +252,7 @@ function M.find(names, opts)
vim.validate('stop', opts.stop, 'string', true) vim.validate('stop', opts.stop, 'string', true)
vim.validate('type', opts.type, 'string', true) vim.validate('type', opts.type, 'string', true)
vim.validate('limit', opts.limit, 'number', true) vim.validate('limit', opts.limit, 'number', true)
vim.validate('follow', opts.follow, 'boolean', true)
if type(names) == 'string' then if type(names) == 'string' then
names = { names } names = { names }
@ -336,7 +342,14 @@ function M.find(names, opts)
end end
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 dirs[#dirs + 1] = f
end end
end end

View File

@ -217,6 +217,18 @@ describe('vim.fs', function()
end) end)
describe('find()', function() 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() it('works', function()
eq( eq(
{ test_build_dir .. '/build' }, { test_build_dir .. '/build' },
@ -224,6 +236,26 @@ describe('vim.fs', function()
) )
eq({ nvim_prog }, vim.fs.find(nvim_prog_basename, { path = test_build_dir, type = 'file' })) 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('^(.*/)([^/]+)$') local parent, name = nvim_dir:match('^(.*/)([^/]+)$')
eq({ nvim_dir }, vim.fs.find(name, { path = parent, upward = true, type = 'directory' })) eq({ nvim_dir }, vim.fs.find(name, { path = parent, upward = true, type = 'directory' }))
end) end)