mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
feat(fs): extend fs.find to accept predicate (#20193)
Makes it possible to use `vim.fs.find` to find files where only a substring is known. This is useful for `vim.lsp.start` to get the `root_dir` for languages where the project-file is only known by its extension, not by the full name. For example in .NET projects there is usually a `<projectname>.csproj` file in the project root. Example: vim.fs.find(function(x) return vim.endswith(x, '.csproj') end, { upward = true })
This commit is contained in:
parent
1970d2ac43
commit
a8c9e721d9
@ -2323,8 +2323,10 @@ find({names}, {opts}) *vim.fs.find()*
|
|||||||
specifying {type} to be "file" or "directory", respectively.
|
specifying {type} to be "file" or "directory", respectively.
|
||||||
|
|
||||||
Parameters: ~
|
Parameters: ~
|
||||||
{names} (string|table) Names of the files and directories to find.
|
{names} (string|table|fun(name: string): boolean) Names of the files
|
||||||
Must be base names, paths and globs are not supported.
|
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:
|
{opts} (table) Optional keyword arguments:
|
||||||
• path (string): Path to begin searching from. If omitted,
|
• path (string): Path to begin searching from. If omitted,
|
||||||
the current working directory is used.
|
the current working directory is used.
|
||||||
|
@ -76,8 +76,11 @@ end
|
|||||||
--- The search can be narrowed to find only files or or only directories by
|
--- The search can be narrowed to find only files or or only directories by
|
||||||
--- specifying {type} to be "file" or "directory", respectively.
|
--- specifying {type} to be "file" or "directory", respectively.
|
||||||
---
|
---
|
||||||
---@param names (string|table) Names of the files and directories to find. Must
|
---@param names (string|table|fun(name: string): boolean) Names of the files
|
||||||
--- be base names, paths and globs are not supported.
|
--- 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:
|
---@param opts (table) Optional keyword arguments:
|
||||||
--- - path (string): Path to begin searching from. If
|
--- - path (string): Path to begin searching from. If
|
||||||
--- omitted, the current working directory is used.
|
--- omitted, the current working directory is used.
|
||||||
@ -98,7 +101,7 @@ end
|
|||||||
function M.find(names, opts)
|
function M.find(names, opts)
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
vim.validate({
|
vim.validate({
|
||||||
names = { names, { 's', 't' } },
|
names = { names, { 's', 't', 'f' } },
|
||||||
path = { opts.path, 's', true },
|
path = { opts.path, 's', true },
|
||||||
upward = { opts.upward, 'b', true },
|
upward = { opts.upward, 'b', true },
|
||||||
stop = { opts.stop, 's', true },
|
stop = { opts.stop, 's', true },
|
||||||
@ -123,18 +126,31 @@ function M.find(names, opts)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if opts.upward then
|
if opts.upward then
|
||||||
---@private
|
local test
|
||||||
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
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return t
|
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
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, match in ipairs(test(path)) do
|
for _, match in ipairs(test(path)) do
|
||||||
@ -162,17 +178,25 @@ function M.find(names, opts)
|
|||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
|
||||||
for other, type in M.dir(dir) do
|
for other, type_ in M.dir(dir) do
|
||||||
local f = dir .. '/' .. other
|
local f = dir .. '/' .. other
|
||||||
for _, name in ipairs(names) do
|
if type(names) == 'function' then
|
||||||
if name == other and (not opts.type or opts.type == type) then
|
if names(other) and (not opts.type or opts.type == type_) then
|
||||||
if add(f) then
|
if add(f) then
|
||||||
return matches
|
return matches
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
||||||
if type == 'directory' then
|
if type_ == 'directory' then
|
||||||
dirs[#dirs + 1] = f
|
dirs[#dirs + 1] = f
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -78,6 +78,23 @@ describe('vim.fs', function()
|
|||||||
return vim.fs.find(nvim, { path = dir, type = 'file' })
|
return vim.fs.find(nvim, { path = dir, type = 'file' })
|
||||||
]], test_build_dir, nvim_prog_basename))
|
]], test_build_dir, nvim_prog_basename))
|
||||||
end)
|
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)
|
end)
|
||||||
|
|
||||||
describe('normalize()', function()
|
describe('normalize()', function()
|
||||||
|
Loading…
Reference in New Issue
Block a user