mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	backport: feat(vim.fs): vim.fs.root() can control priority #34413
feat(vim.fs): vim.fs.root() can control priority
Adds the capability of controlling the priority of searched markers in
vim.fs.root() by nesting lists.
(cherry picked from commit 0f0b96dd0f)
			
			
This commit is contained in:
		| @@ -3165,6 +3165,10 @@ vim.fs.root({source}, {marker})                                *vim.fs.root()* | ||||
|         vim.fs.root(0, function(name, path) | ||||
|           return name:match('%.csproj$') ~= nil | ||||
|         end) | ||||
|  | ||||
|         -- Find the first ancestor directory containing EITHER "stylua.toml" or ".luarc.json"; if | ||||
|         -- not found, find the first ancestor containing ".git": | ||||
|         vim.fs.root(0, { { 'stylua.toml', '.luarc.json' }, '.git' }) | ||||
| < | ||||
|  | ||||
|     Attributes: ~ | ||||
| @@ -3174,10 +3178,22 @@ vim.fs.root({source}, {marker})                                *vim.fs.root()* | ||||
|       • {source}  (`integer|string`) Buffer number (0 for current buffer) or | ||||
|                   file path (absolute or relative to the |current-directory|) | ||||
|                   to begin the search from. | ||||
|       • {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. | ||||
|       • {marker}  (`(string|string[]|fun(name: string, path: string): boolean)[]|string|fun(name: string, path: string): boolean`) | ||||
|                   A marker or a list of markers. A marker has one of three | ||||
|                   types: string, a list of strings or a function. The | ||||
|                   parameter also accepts a list of markers, each of which is | ||||
|                   any of those three types. If a marker is a function, it is | ||||
|                   called for each evaluated item and should return true if | ||||
|                   {name} and {path} are a match. If a list of markers is | ||||
|                   passed, each marker in the list is evaluated in order and | ||||
|                   the first marker which is matched returns the parent | ||||
|                   directory that it found. This allows listing markers with | ||||
|                   priority. E.g. - in the following list, a parent directory | ||||
|                   containing either 'a' or 'b' is searched for. If neither is | ||||
|                   found, then 'c' is searched for. So, 'c' has lower priority | ||||
|                   than 'a' and 'b' which have equal priority. >lua | ||||
|                           marker = { { 'a', 'b' }, 'c' } | ||||
| < | ||||
|  | ||||
|     Return: ~ | ||||
|         (`string?`) Directory path containing one of the given markers, or nil | ||||
|   | ||||
| @@ -305,6 +305,7 @@ LUA | ||||
| • |vim.hl.range()| now has a optional `timeout` field which allows for multiple | ||||
|   timed highlights. | ||||
| • |vim.text.indent()| indents/dedents text. | ||||
| • |vim.fs.root()| can define "equal priority" via nested lists. | ||||
|  | ||||
| OPTIONS | ||||
|  | ||||
|   | ||||
| @@ -388,14 +388,29 @@ end | ||||
| --- vim.fs.root(0, function(name, path) | ||||
| ---   return name:match('%.csproj$') ~= nil | ||||
| --- end) | ||||
| --- | ||||
| --- -- Find the first ancestor directory containing EITHER "stylua.toml" or ".luarc.json"; if | ||||
| --- -- not found, find the first ancestor containing ".git": | ||||
| --- vim.fs.root(0, { { 'stylua.toml', '.luarc.json' }, '.git' }) | ||||
| --- ``` | ||||
| --- | ||||
| --- @since 12 | ||||
| --- @param source integer|string Buffer number (0 for current buffer) or file path (absolute or | ||||
| ---               relative to the |current-directory|) 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. | ||||
| --- @param marker (string|string[]|fun(name: string, path: string): boolean)[]|string|fun(name: string, path: string): boolean A marker or a list of markers. | ||||
| ---               A marker has one of three types: string, a list of strings or a function. The | ||||
| ---               parameter also accepts a list of markers, each of which is any of those three | ||||
| ---               types. If a marker is a function, it is called for each evaluated item and | ||||
| ---               should return true if {name} and {path} are a match. If a list of markers is | ||||
| ---               passed, each marker in the list is evaluated in order and the first marker | ||||
| ---               which is matched returns the parent directory that it found. This allows | ||||
| ---               listing markers with priority. E.g. - in the following list, a parent directory | ||||
| ---               containing either 'a' or 'b' is searched for. If neither is found, then 'c' is | ||||
| ---               searched for. So, 'c' has lower priority than 'a' and 'b' which have equal | ||||
| ---               priority. | ||||
| ---               ```lua | ||||
| ---                   marker = { { 'a', 'b' }, 'c' } | ||||
| ---               ``` | ||||
| --- @return string? # Directory path containing one of the given markers, or nil if no directory was | ||||
| ---                   found. | ||||
| function M.root(source, marker) | ||||
| @@ -415,16 +430,19 @@ function M.root(source, marker) | ||||
|     error('invalid type for argument "source": expected string or buffer number') | ||||
|   end | ||||
|  | ||||
|   local paths = M.find(marker, { | ||||
|   local markers = type(marker) == 'table' and marker or { marker } | ||||
|   for _, mark in ipairs(markers) do | ||||
|     local paths = M.find(mark, { | ||||
|       upward = true, | ||||
|       path = vim.fn.fnamemodify(path, ':p:h'), | ||||
|     }) | ||||
|  | ||||
|   if #paths == 0 then | ||||
|     return nil | ||||
|     if #paths ~= 0 then | ||||
|       return vim.fs.dirname(paths[1]) | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   return vim.fs.dirname(paths[1]) | ||||
|   return nil | ||||
| end | ||||
|  | ||||
| --- Split a Windows path into a prefix and a body, such that the body can be processed like a POSIX | ||||
|   | ||||
| @@ -708,13 +708,7 @@ function lsp.start(config, opts) | ||||
|     validate('root_markers', opts._root_markers, 'table') | ||||
|     config = vim.deepcopy(config) | ||||
|  | ||||
|     for _, marker in ipairs(opts._root_markers) do | ||||
|       local root = vim.fs.root(bufnr, marker) | ||||
|       if root ~= nil then | ||||
|         config.root_dir = root | ||||
|         break | ||||
|       end | ||||
|     end | ||||
|     config.root_dir = vim.fs.root(bufnr, opts._root_markers) | ||||
|   end | ||||
|  | ||||
|   if | ||||
|   | ||||
| @@ -357,6 +357,36 @@ describe('vim.fs', function() | ||||
|       ) | ||||
|     end) | ||||
|  | ||||
|     it('nested markers have equal priority', function() | ||||
|       local bufnr = api.nvim_get_current_buf() | ||||
|       eq( | ||||
|         vim.fs.joinpath(test_source_path, 'test/functional'), | ||||
|         exec_lua( | ||||
|           [[return vim.fs.root(..., { 'example_spec.lua', {'CMakeLists.txt', 'CMakePresets.json'}, '.luarc.json'})]], | ||||
|           bufnr | ||||
|         ) | ||||
|       ) | ||||
|       eq( | ||||
|         vim.fs.joinpath(test_source_path, 'test/functional/fixtures'), | ||||
|         exec_lua( | ||||
|           [[return vim.fs.root(..., { {'CMakeLists.txt', 'CMakePresets.json'}, 'example_spec.lua', '.luarc.json'})]], | ||||
|           bufnr | ||||
|         ) | ||||
|       ) | ||||
|       eq( | ||||
|         vim.fs.joinpath(test_source_path, 'test/functional/fixtures'), | ||||
|         exec_lua( | ||||
|           [[return vim.fs.root(..., { | ||||
|             function(name, _) | ||||
|               return name:match('%.txt$') | ||||
|             end, | ||||
|             'example_spec.lua', | ||||
|             '.luarc.json' })]], | ||||
|           bufnr | ||||
|         ) | ||||
|       ) | ||||
|     end) | ||||
|  | ||||
|     it('works with a function', function() | ||||
|       ---@type string | ||||
|       local result = exec_lua(function() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Siddhant Agarwal
					Siddhant Agarwal