aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/lua.txt6
-rw-r--r--runtime/lua/vim/fs.lua56
-rw-r--r--test/functional/lua/fs_spec.lua17
3 files changed, 61 insertions, 18 deletions
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index 35badb13b1..e5bfd9e4c6 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -2323,8 +2323,10 @@ find({names}, {opts}) *vim.fs.find()*
specifying {type} to be "file" or "directory", respectively.
Parameters: ~
- {names} (string|table) Names of the files and directories to find.
- Must be base names, paths and globs are not supported.
+ {names} (string|table|fun(name: string): boolean) Names of the files
+ and directories to find. Must be base names, paths and globs
+ are not supported. If a function it is called per file and
+ dir within the traversed directories to test if they match.
{opts} (table) Optional keyword arguments:
• path (string): Path to begin searching from. If omitted,
the current working directory is used.
diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua
index ce845eda15..7bd635d8b6 100644
--- a/runtime/lua/vim/fs.lua
+++ b/runtime/lua/vim/fs.lua
@@ -76,8 +76,11 @@ end
--- The search can be narrowed to find only files or or only directories by
--- specifying {type} to be "file" or "directory", respectively.
---
----@param names (string|table) Names of the files and directories to find. Must
---- be base names, paths and globs are not supported.
+---@param names (string|table|fun(name: string): boolean) Names of the files
+--- and directories to find.
+--- Must be base names, paths and globs are not supported.
+--- If a function it is called per file and dir within the
+--- traversed directories to test if they match.
---@param opts (table) Optional keyword arguments:
--- - path (string): Path to begin searching from. If
--- omitted, the current working directory is used.
@@ -98,7 +101,7 @@ end
function M.find(names, opts)
opts = opts or {}
vim.validate({
- names = { names, { 's', 't' } },
+ names = { names, { 's', 't', 'f' } },
path = { opts.path, 's', true },
upward = { opts.upward, 'b', true },
stop = { opts.stop, 's', true },
@@ -123,18 +126,31 @@ function M.find(names, opts)
end
if opts.upward then
- ---@private
- local function test(p)
- local t = {}
- for _, name in ipairs(names) do
- local f = p .. '/' .. name
- local stat = vim.loop.fs_stat(f)
- if stat and (not opts.type or opts.type == stat.type) then
- t[#t + 1] = f
+ local test
+
+ if type(names) == 'function' then
+ test = function(p)
+ local t = {}
+ for name, type in M.dir(p) do
+ if names(name) and (not opts.type or opts.type == type) then
+ table.insert(t, p .. '/' .. name)
+ end
end
+ return t
end
+ else
+ test = function(p)
+ local t = {}
+ for _, name in ipairs(names) do
+ local f = p .. '/' .. name
+ local stat = vim.loop.fs_stat(f)
+ if stat and (not opts.type or opts.type == stat.type) then
+ t[#t + 1] = f
+ end
+ end
- return t
+ return t
+ end
end
for _, match in ipairs(test(path)) do
@@ -162,17 +178,25 @@ function M.find(names, opts)
break
end
- for other, type in M.dir(dir) do
+ for other, type_ in M.dir(dir) do
local f = dir .. '/' .. other
- for _, name in ipairs(names) do
- if name == other and (not opts.type or opts.type == type) then
+ if type(names) == 'function' then
+ if names(other) and (not opts.type or opts.type == type_) then
if add(f) then
return matches
end
end
+ else
+ for _, name in ipairs(names) do
+ if name == other and (not opts.type or opts.type == type_) then
+ if add(f) then
+ return matches
+ end
+ end
+ end
end
- if type == 'directory' then
+ if type_ == 'directory' then
dirs[#dirs + 1] = f
end
end
diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua
index 2bcc84db0f..3123ec324c 100644
--- a/test/functional/lua/fs_spec.lua
+++ b/test/functional/lua/fs_spec.lua
@@ -78,6 +78,23 @@ describe('vim.fs', function()
return vim.fs.find(nvim, { path = dir, type = 'file' })
]], test_build_dir, nvim_prog_basename))
end)
+
+ it('accepts predicate as names', function()
+ eq({test_build_dir}, exec_lua([[
+ local dir = ...
+ local opts = { path = dir, upward = true, type = 'directory' }
+ return vim.fs.find(function(x) return x == 'build' end, opts)
+ ]], nvim_dir))
+ eq({nvim_prog}, exec_lua([[
+ local dir, nvim = ...
+ return vim.fs.find(function(x) return x == nvim end, { path = dir, type = 'file' })
+ ]], test_build_dir, nvim_prog_basename))
+ eq({}, exec_lua([[
+ local dir = ...
+ local opts = { path = dir, upward = true, type = 'directory' }
+ return vim.fs.find(function(x) return x == 'no-match' end, opts)
+ ]], nvim_dir))
+ end)
end)
describe('normalize()', function()