aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike <Mike325@users.noreply.github.com>2023-03-01 10:51:22 -0600
committerGitHub <noreply@github.com>2023-03-01 08:51:22 -0800
commitbc15b075d14c85098d674a2466d2386e08b0005f (patch)
tree22eb1817988f98c7c55d5fc39e09d2287215c847
parent014981c9006f9b96b8045e609dc27f4a84da5263 (diff)
downloadrneovim-bc15b075d14c85098d674a2466d2386e08b0005f.tar.gz
rneovim-bc15b075d14c85098d674a2466d2386e08b0005f.tar.bz2
rneovim-bc15b075d14c85098d674a2466d2386e08b0005f.zip
feat(vim.fs): pass path to find() predicate, lazy evaluate #22378
Problem: No easy way to find files under certain directories (ex: grab all files under `test/`) or exclude the content of certain paths (ex. `build/`, `.git/`) Solution: Pass the full `path` as an arg to the predicate.
-rw-r--r--runtime/doc/lua.txt35
-rw-r--r--runtime/lua/vim/fs.lua35
-rw-r--r--test/functional/lua/fs_spec.lua11
3 files changed, 70 insertions, 11 deletions
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index 8ae1c6dc40..e3e0665025 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -2359,12 +2359,37 @@ find({names}, {opts}) *vim.fs.find()*
The search can be narrowed to find only files or only directories by
specifying {type} to be "file" or "directory", respectively.
+ Examples: >lua
+
+ -- location of Cargo.toml from the current buffer's path
+ local cargo = vim.fs.find('Cargo.toml', {
+ upward = true,
+ stop = vim.loop.os_homedir(),
+ path = vim.fs.dirname(vim.api.nvim_buf_get_name(0)),
+ })
+
+ -- list all test directories under the runtime directory
+ local test_dirs = vim.fs.find(
+ {'test', 'tst', 'testdir'},
+ {limit = math.huge, type = 'directory', path = './runtime/'}
+ )
+
+ -- 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$')
+ end, {limit = math.huge, type = 'file'})
+<
+
Parameters: ~
- • {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. The function is called per file and
- directory within the traversed directories to test if they
- match {names}.
+ • {names} (string|table|fun(name: string, path: string): boolean) Names
+ of the files and directories to find. Must be base names,
+ paths and globs are not supported when {names} is a string or
+ a table. If {names} is a function, it is called for each
+ traversed file and directory with args:
+ • name: base name of the current item
+ • path: full path of the current item The function should
+ return `true` if the given file or directory is considered
+ a match.
• {opts} (table) Optional keyword arguments:
• path (string): Path to begin searching from. If omitted,
the |current-directory| is used.
diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua
index a0d2c4c339..2c3fc64d57 100644
--- a/runtime/lua/vim/fs.lua
+++ b/runtime/lua/vim/fs.lua
@@ -144,11 +144,34 @@ end
--- The search can be narrowed to find only files or only directories by
--- specifying {type} to be "file" or "directory", respectively.
---
----@param names (string|table|fun(name: string): boolean) Names of the files
+--- Examples:
+--- <pre>lua
+--- -- location of Cargo.toml from the current buffer's path
+--- local cargo = vim.fs.find('Cargo.toml', {
+--- upward = true,
+--- stop = vim.loop.os_homedir(),
+--- path = vim.fs.dirname(vim.api.nvim_buf_get_name(0)),
+--- })
+---
+--- -- list all test directories under the runtime directory
+--- local test_dirs = vim.fs.find(
+--- {'test', 'tst', 'testdir'},
+--- {limit = math.huge, type = 'directory', path = './runtime/'}
+--- )
+---
+--- -- 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$')
+--- end, {limit = math.huge, type = 'file'})
+--- </pre>
+---
+---@param names (string|table|fun(name: string, path: string): boolean) Names of the files
--- and directories to find.
---- Must be base names, paths and globs are not supported.
---- The function is called per file and directory within the
---- traversed directories to test if they match {names}.
+--- Must be base names, paths and globs are not supported when {names} is a string or a table.
+--- If {names} is a function, it is called for each traversed file and directory with args:
+--- - name: base name of the current item
+--- - path: full path of the current item
+--- The function should return `true` if the given file or directory is considered a match.
---
---@param opts (table) Optional keyword arguments:
--- - path (string): Path to begin searching from. If
@@ -201,7 +224,7 @@ function M.find(names, opts)
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
+ if (not opts.type or opts.type == type) and names(name, p) then
table.insert(t, join_paths(p, name))
end
end
@@ -250,7 +273,7 @@ function M.find(names, opts)
for other, type_ in M.dir(dir) do
local f = join_paths(dir, other)
if type(names) == 'function' then
- if names(other) and (not opts.type or opts.type == type_) then
+ if (not opts.type or opts.type == type_) and names(other, dir) then
if add(f) then
return matches
end
diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua
index 642d36f63a..03de16c079 100644
--- a/test/functional/lua/fs_spec.lua
+++ b/test/functional/lua/fs_spec.lua
@@ -8,6 +8,7 @@ local mkdir_p = helpers.mkdir_p
local rmdir = helpers.rmdir
local nvim_dir = helpers.nvim_dir
local test_build_dir = helpers.test_build_dir
+local test_source_path = helpers.test_source_path
local nvim_prog = helpers.nvim_prog
local is_os = helpers.is_os
@@ -252,6 +253,16 @@ describe('vim.fs', function()
local opts = { path = dir, upward = true, type = 'directory' }
return vim.fs.find(function(x) return x == 'no-match' end, opts)
]], nvim_dir))
+ eq(
+ exec_lua([[
+ local dir = ...
+ return vim.tbl_map(vim.fs.basename, vim.fn.glob(dir..'/contrib/*', false, true))
+ ]], test_source_path),
+ exec_lua([[
+ local dir = ...
+ local opts = { path = dir, limit = math.huge }
+ return vim.tbl_map(vim.fs.basename, vim.fs.find(function(_, d) return d:match('[\\/]contrib$') end, opts))
+ ]], test_source_path))
end)
end)