aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/fs.lua
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/lua/vim/fs.lua')
-rw-r--r--runtime/lua/vim/fs.lua57
1 files changed, 50 insertions, 7 deletions
diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua
index 65ad58c720..766dc09691 100644
--- a/runtime/lua/vim/fs.lua
+++ b/runtime/lua/vim/fs.lua
@@ -197,13 +197,6 @@ end
--- Examples:
---
--- ```lua
---- -- location of Cargo.toml from the current buffer's path
---- local cargo = vim.fs.find('Cargo.toml', {
---- upward = true,
---- stop = vim.uv.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'},
@@ -334,6 +327,56 @@ function M.find(names, opts)
return matches
end
+--- Find the first parent directory containing a specific "marker", relative to a buffer's
+--- directory.
+---
+--- Example:
+---
+--- ```lua
+--- -- Find the root of a Python project, starting from file 'main.py'
+--- vim.fs.root(vim.fs.joinpath(vim.env.PWD, 'main.py'), {'pyproject.toml', 'setup.py' })
+---
+--- -- Find the root of a git repository
+--- vim.fs.root(0, '.git')
+---
+--- -- Find the parent directory containing any file with a .csproj extension
+--- vim.fs.root(0, function(name, path)
+--- return name:match('%.csproj$') ~= nil
+--- end)
+--- ```
+---
+--- @param source integer|string Buffer number (0 for current buffer) or file path to begin the
+--- search from.
+--- @param marker (string|string[]|fun(name: string, path: string): boolean) A marker, or list
+--- of markers, to search for. If a function, the function is called for each
+--- evaluated item and should return true if {name} and {path} are a match.
+--- @return string? # Directory path containing one of the given markers, or nil if no directory was
+--- found.
+function M.root(source, marker)
+ assert(source, 'missing required argument: source')
+ assert(marker, 'missing required argument: marker')
+
+ local path ---@type string
+ if type(source) == 'string' then
+ path = source
+ elseif type(source) == 'number' then
+ path = vim.api.nvim_buf_get_name(source)
+ else
+ error('invalid type for argument "source": expected string or buffer number')
+ end
+
+ local paths = M.find(marker, {
+ upward = true,
+ path = path,
+ })
+
+ if #paths == 0 then
+ return nil
+ end
+
+ return vim.fs.dirname(paths[1])
+end
+
--- Split a Windows path into a prefix and a body, such that the body can be processed like a POSIX
--- path. The path must use forward slashes as path separator.
---