mirror of
https://github.com/neovim/neovim
synced 2025-07-16 09:11:51 +00:00
fix(fs): make vim.fs.root work for relative paths and unnamed buffers (#28964)
If a buffer does not have a backing file then fall back to the current working directory.
This commit is contained in:
@ -3012,7 +3012,10 @@ vim.fs.parents({start}) *vim.fs.parents()*
|
|||||||
|
|
||||||
vim.fs.root({source}, {marker}) *vim.fs.root()*
|
vim.fs.root({source}, {marker}) *vim.fs.root()*
|
||||||
Find the first parent directory containing a specific "marker", relative
|
Find the first parent directory containing a specific "marker", relative
|
||||||
to a buffer's directory.
|
to a file path or buffer.
|
||||||
|
|
||||||
|
If the buffer is unnamed (has no backing file) or has a non-empty
|
||||||
|
'buftype' then the search begins from Nvim's |current-directory|.
|
||||||
|
|
||||||
Example: >lua
|
Example: >lua
|
||||||
-- Find the root of a Python project, starting from file 'main.py'
|
-- Find the root of a Python project, starting from file 'main.py'
|
||||||
@ -3029,7 +3032,8 @@ vim.fs.root({source}, {marker}) *vim.fs.root()*
|
|||||||
|
|
||||||
Parameters: ~
|
Parameters: ~
|
||||||
• {source} (`integer|string`) Buffer number (0 for current buffer) or
|
• {source} (`integer|string`) Buffer number (0 for current buffer) or
|
||||||
file path to begin the search from.
|
file path (absolute or relative to the |current-directory|)
|
||||||
|
to begin the search from.
|
||||||
• {marker} (`string|string[]|fun(name: string, path: string): boolean`)
|
• {marker} (`string|string[]|fun(name: string, path: string): boolean`)
|
||||||
A marker, or list of markers, to search for. If a function,
|
A marker, or list of markers, to search for. If a function,
|
||||||
the function is called for each evaluated item and should
|
the function is called for each evaluated item and should
|
||||||
|
@ -328,8 +328,11 @@ function M.find(names, opts)
|
|||||||
return matches
|
return matches
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Find the first parent directory containing a specific "marker", relative to a buffer's
|
--- Find the first parent directory containing a specific "marker", relative to a file path or
|
||||||
--- directory.
|
--- buffer.
|
||||||
|
---
|
||||||
|
--- If the buffer is unnamed (has no backing file) or has a non-empty 'buftype' then the search
|
||||||
|
--- begins from Nvim's |current-directory|.
|
||||||
---
|
---
|
||||||
--- Example:
|
--- Example:
|
||||||
---
|
---
|
||||||
@ -346,13 +349,13 @@ end
|
|||||||
--- end)
|
--- end)
|
||||||
--- ```
|
--- ```
|
||||||
---
|
---
|
||||||
--- @param source integer|string Buffer number (0 for current buffer) or file path to begin the
|
--- @param source integer|string Buffer number (0 for current buffer) or file path (absolute or
|
||||||
--- search from.
|
--- relative to the |current-directory|) to begin the search from.
|
||||||
--- @param marker (string|string[]|fun(name: string, path: string): boolean) A marker, or list
|
--- @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
|
--- 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.
|
--- 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
|
--- @return string? # Directory path containing one of the given markers, or nil if no directory was
|
||||||
--- found.
|
--- found.
|
||||||
function M.root(source, marker)
|
function M.root(source, marker)
|
||||||
assert(source, 'missing required argument: source')
|
assert(source, 'missing required argument: source')
|
||||||
assert(marker, 'missing required argument: marker')
|
assert(marker, 'missing required argument: marker')
|
||||||
@ -361,14 +364,18 @@ function M.root(source, marker)
|
|||||||
if type(source) == 'string' then
|
if type(source) == 'string' then
|
||||||
path = source
|
path = source
|
||||||
elseif type(source) == 'number' then
|
elseif type(source) == 'number' then
|
||||||
path = vim.api.nvim_buf_get_name(source)
|
if vim.bo[source].buftype ~= '' then
|
||||||
|
path = assert(vim.uv.cwd())
|
||||||
|
else
|
||||||
|
path = vim.api.nvim_buf_get_name(source)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
error('invalid type for argument "source": expected string or buffer number')
|
error('invalid type for argument "source": expected string or buffer number')
|
||||||
end
|
end
|
||||||
|
|
||||||
local paths = M.find(marker, {
|
local paths = M.find(marker, {
|
||||||
upward = true,
|
upward = true,
|
||||||
path = path,
|
path = vim.fn.fnamemodify(path, ':p:h'),
|
||||||
})
|
})
|
||||||
|
|
||||||
if #paths == 0 then
|
if #paths == 0 then
|
||||||
|
@ -310,6 +310,25 @@ describe('vim.fs', function()
|
|||||||
it('works with a filename argument', function()
|
it('works with a filename argument', function()
|
||||||
eq(test_source_path, exec_lua([[return vim.fs.root(..., '.git')]], nvim_prog))
|
eq(test_source_path, exec_lua([[return vim.fs.root(..., '.git')]], nvim_prog))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('works with a relative path', function()
|
||||||
|
eq(
|
||||||
|
test_source_path,
|
||||||
|
exec_lua([[return vim.fs.root(..., '.git')]], vim.fs.basename(nvim_prog))
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('uses cwd for unnamed buffers', function()
|
||||||
|
command('new')
|
||||||
|
eq(test_source_path, exec_lua([[return vim.fs.root(0, '.git')]]))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("uses cwd for buffers with non-empty 'buftype'", function()
|
||||||
|
command('new')
|
||||||
|
command('set buftype=nofile')
|
||||||
|
command('file lua://')
|
||||||
|
eq(test_source_path, exec_lua([[return vim.fs.root(0, '.git')]]))
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('joinpath()', function()
|
describe('joinpath()', function()
|
||||||
|
Reference in New Issue
Block a user