mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	feat: add vim.fs.relpath
This is needed to replace the nvim-lspconfig function is_descendant that some lspconfg configurations still use.
This commit is contained in:
		| @@ -3148,6 +3148,23 @@ vim.fs.parents({start})                                     *vim.fs.parents()* | |||||||
|         (`nil`) |         (`nil`) | ||||||
|         (`string?`) |         (`string?`) | ||||||
|  |  | ||||||
|  | vim.fs.relpath({base}, {target}, {opts})                    *vim.fs.relpath()* | ||||||
|  |     Gets `target` path relative to `base`, or `nil` if `base` is not an | ||||||
|  |     ancestor. | ||||||
|  |  | ||||||
|  |     Example: >lua | ||||||
|  |         vim.fs.relpath('/var', '/var/lib') -- 'lib' | ||||||
|  |         vim.fs.relpath('/var', '/usr/bin') -- nil | ||||||
|  | < | ||||||
|  |  | ||||||
|  |     Parameters: ~ | ||||||
|  |       • {base}    (`string`) | ||||||
|  |       • {target}  (`string`) | ||||||
|  |       • {opts}    (`table?`) Reserved for future use | ||||||
|  |  | ||||||
|  |     Return: ~ | ||||||
|  |         (`string?`) | ||||||
|  |  | ||||||
| vim.fs.rm({path}, {opts})                                        *vim.fs.rm()* | vim.fs.rm({path}, {opts})                                        *vim.fs.rm()* | ||||||
|     WARNING: This feature is experimental/unstable. |     WARNING: This feature is experimental/unstable. | ||||||
|  |  | ||||||
|   | |||||||
| @@ -284,6 +284,7 @@ LUA | |||||||
|   supporting two new parameters, `encoding` and `strict_indexing`. |   supporting two new parameters, `encoding` and `strict_indexing`. | ||||||
| • |vim.json.encode()| has an option to enable forward slash escaping | • |vim.json.encode()| has an option to enable forward slash escaping | ||||||
| • |vim.fs.abspath()| converts paths to absolute paths. | • |vim.fs.abspath()| converts paths to absolute paths. | ||||||
|  | • |vim.fs.relpath()| gets relative path compared to base path. | ||||||
|  |  | ||||||
| OPTIONS | OPTIONS | ||||||
|  |  | ||||||
|   | |||||||
| @@ -741,4 +741,37 @@ function M.abspath(path) | |||||||
|   return M.joinpath(cwd, path) |   return M.joinpath(cwd, path) | ||||||
| end | end | ||||||
|  |  | ||||||
|  | --- Gets `target` path relative to `base`, or `nil` if `base` is not an ancestor. | ||||||
|  | --- | ||||||
|  | --- Example: | ||||||
|  | --- | ||||||
|  | --- ```lua | ||||||
|  | --- vim.fs.relpath('/var', '/var/lib') -- 'lib' | ||||||
|  | --- vim.fs.relpath('/var', '/usr/bin') -- nil | ||||||
|  | --- ``` | ||||||
|  | --- | ||||||
|  | --- @param base string | ||||||
|  | --- @param target string | ||||||
|  | --- @param opts table? Reserved for future use | ||||||
|  | --- @return string|nil | ||||||
|  | function M.relpath(base, target, opts) | ||||||
|  |   vim.validate('base', base, 'string') | ||||||
|  |   vim.validate('target', target, 'string') | ||||||
|  |   vim.validate('opts', opts, 'table', true) | ||||||
|  |  | ||||||
|  |   base = vim.fs.normalize(vim.fs.abspath(base)) | ||||||
|  |   target = vim.fs.normalize(vim.fs.abspath(target)) | ||||||
|  |   if base == target then | ||||||
|  |     return '.' | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   local prefix = '' | ||||||
|  |   if iswin then | ||||||
|  |     prefix, base = split_windows_path(base) | ||||||
|  |   end | ||||||
|  |   base = prefix .. base .. (base ~= '/' and '/' or '') | ||||||
|  |  | ||||||
|  |   return vim.startswith(target, base) and target:sub(#base + 1) or nil | ||||||
|  | end | ||||||
|  |  | ||||||
| return M | return M | ||||||
|   | |||||||
| @@ -168,8 +168,8 @@ describe('vim.fs', function() | |||||||
|  |  | ||||||
|       local function run(dir, depth, skip) |       local function run(dir, depth, skip) | ||||||
|         return exec_lua(function() |         return exec_lua(function() | ||||||
|           local r = {} |           local r = {} --- @type table<string, string> | ||||||
|           local skip_f |           local skip_f --- @type function | ||||||
|           if skip then |           if skip then | ||||||
|             skip_f = function(n0) |             skip_f = function(n0) | ||||||
|               if vim.tbl_contains(skip or {}, n0) then |               if vim.tbl_contains(skip or {}, n0) then | ||||||
| @@ -493,8 +493,8 @@ describe('vim.fs', function() | |||||||
|   end) |   end) | ||||||
|  |  | ||||||
|   describe('abspath()', function() |   describe('abspath()', function() | ||||||
|     local cwd = is_os('win') and vim.uv.cwd():gsub('\\', '/') or vim.uv.cwd() |     local cwd = assert(t.fix_slashes(assert(vim.uv.cwd()))) | ||||||
|     local home = is_os('win') and vim.uv.os_homedir():gsub('\\', '/') or vim.uv.os_homedir() |     local home = t.fix_slashes(assert(vim.uv.os_homedir())) | ||||||
|  |  | ||||||
|     it('works', function() |     it('works', function() | ||||||
|       eq(cwd .. '/foo', vim.fs.abspath('foo')) |       eq(cwd .. '/foo', vim.fs.abspath('foo')) | ||||||
| @@ -526,4 +526,57 @@ describe('vim.fs', function() | |||||||
|       end) |       end) | ||||||
|     end |     end | ||||||
|   end) |   end) | ||||||
|  |  | ||||||
|  |   describe('relpath()', function() | ||||||
|  |     it('works', function() | ||||||
|  |       local cwd = assert(t.fix_slashes(assert(vim.uv.cwd()))) | ||||||
|  |       local my_dir = vim.fs.joinpath(cwd, 'foo') | ||||||
|  |  | ||||||
|  |       eq(nil, vim.fs.relpath('/var/lib', '/var')) | ||||||
|  |       eq(nil, vim.fs.relpath('/var/lib', '/bin')) | ||||||
|  |       eq(nil, vim.fs.relpath(my_dir, 'bin')) | ||||||
|  |       eq(nil, vim.fs.relpath(my_dir, './bin')) | ||||||
|  |       eq(nil, vim.fs.relpath(my_dir, '././')) | ||||||
|  |       eq(nil, vim.fs.relpath(my_dir, '../')) | ||||||
|  |       eq(nil, vim.fs.relpath('/var/lib', '/')) | ||||||
|  |       eq(nil, vim.fs.relpath('/var/lib', '//')) | ||||||
|  |       eq(nil, vim.fs.relpath(' ', '/var')) | ||||||
|  |       eq(nil, vim.fs.relpath(' ', '/var')) | ||||||
|  |       eq('.', vim.fs.relpath('/var/lib', '/var/lib')) | ||||||
|  |       eq('lib', vim.fs.relpath('/var/', '/var/lib')) | ||||||
|  |       eq('var/lib', vim.fs.relpath('/', '/var/lib')) | ||||||
|  |       eq('bar/package.json', vim.fs.relpath('/foo/test', '/foo/test/bar/package.json')) | ||||||
|  |       eq('foo/bar', vim.fs.relpath(cwd, 'foo/bar')) | ||||||
|  |       eq('foo/bar', vim.fs.relpath('.', vim.fs.joinpath(cwd, 'foo/bar'))) | ||||||
|  |       eq('bar', vim.fs.relpath('foo', 'foo/bar')) | ||||||
|  |       eq(nil, vim.fs.relpath('/var/lib', '/var/library/foo')) | ||||||
|  |  | ||||||
|  |       if is_os('win') then | ||||||
|  |         eq(nil, vim.fs.relpath('/', ' ')) | ||||||
|  |         eq(nil, vim.fs.relpath('/', 'var')) | ||||||
|  |       else | ||||||
|  |         local cwd_rel_root = cwd:sub(2) | ||||||
|  |         eq(cwd_rel_root .. '/ ', vim.fs.relpath('/', ' ')) | ||||||
|  |         eq(cwd_rel_root .. '/var', vim.fs.relpath('/', 'var')) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       if is_os('win') then | ||||||
|  |         eq(nil, vim.fs.relpath('c:/aaaa/', '/aaaa/cccc')) | ||||||
|  |         eq(nil, vim.fs.relpath('c:/aaaa/', './aaaa/cccc')) | ||||||
|  |         eq(nil, vim.fs.relpath('c:/aaaa/', 'aaaa/cccc')) | ||||||
|  |         eq(nil, vim.fs.relpath('c:/blah\\blah', 'd:/games')) | ||||||
|  |         eq(nil, vim.fs.relpath('c:/games', 'd:/games')) | ||||||
|  |         eq(nil, vim.fs.relpath('c:/games', 'd:/games/foo')) | ||||||
|  |         eq(nil, vim.fs.relpath('c:/aaaa/bbbb', 'c:/aaaa')) | ||||||
|  |         eq('cccc', vim.fs.relpath('c:/aaaa/', 'c:/aaaa/cccc')) | ||||||
|  |         eq('aaaa/bbbb', vim.fs.relpath('C:/', 'c:\\aaaa\\bbbb')) | ||||||
|  |         eq('bar/package.json', vim.fs.relpath('C:\\foo\\test', 'C:\\foo\\test\\bar\\package.json')) | ||||||
|  |         eq('baz', vim.fs.relpath('\\\\foo\\bar', '\\\\foo\\bar\\baz')) | ||||||
|  |         eq(nil, vim.fs.relpath('a/b/c', 'a\\b')) | ||||||
|  |         eq('d', vim.fs.relpath('a/b/c', 'a\\b\\c\\d')) | ||||||
|  |         eq('.', vim.fs.relpath('\\\\foo\\bar\\baz', '\\\\foo\\bar\\baz')) | ||||||
|  |         eq(nil, vim.fs.relpath('C:\\foo\\test', 'C:\\foo\\Test\\bar\\package.json')) | ||||||
|  |       end | ||||||
|  |     end) | ||||||
|  |   end) | ||||||
| end) | end) | ||||||
|   | |||||||
| @@ -22,13 +22,6 @@ local M = { | |||||||
|   paths = Paths, |   paths = Paths, | ||||||
| } | } | ||||||
|  |  | ||||||
| --- @param p string |  | ||||||
| --- @return string |  | ||||||
| local function relpath(p) |  | ||||||
|   p = vim.fs.normalize(p) |  | ||||||
|   return (p:gsub('^' .. uv.cwd, '')) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| --- @param path string | --- @param path string | ||||||
| --- @return boolean | --- @return boolean | ||||||
| function M.isdir(path) | function M.isdir(path) | ||||||
| @@ -45,14 +38,15 @@ end | |||||||
| --- (Only on Windows) Replaces yucky "\\" slashes with delicious "/" slashes in a string, or all | --- (Only on Windows) Replaces yucky "\\" slashes with delicious "/" slashes in a string, or all | ||||||
| --- string values in a table (recursively). | --- string values in a table (recursively). | ||||||
| --- | --- | ||||||
| --- @param obj string|table | --- @generic T: string|table | ||||||
| --- @return any | --- @param obj T | ||||||
|  | --- @return T|nil | ||||||
| function M.fix_slashes(obj) | function M.fix_slashes(obj) | ||||||
|   if not M.is_os('win') then |   if not M.is_os('win') then | ||||||
|     return obj |     return obj | ||||||
|   end |   end | ||||||
|   if type(obj) == 'string' then |   if type(obj) == 'string' then | ||||||
|     local ret = obj:gsub('\\', '/') |     local ret = string.gsub(obj, '\\', '/') | ||||||
|     return ret |     return ret | ||||||
|   elseif type(obj) == 'table' then |   elseif type(obj) == 'table' then | ||||||
|     --- @cast obj table<any,any> |     --- @cast obj table<any,any> | ||||||
| @@ -482,7 +476,8 @@ function M.check_cores(app, force) -- luacheck: ignore | |||||||
|   -- "./Xtest-tmpdir/" => "Xtest%-tmpdir" |   -- "./Xtest-tmpdir/" => "Xtest%-tmpdir" | ||||||
|   local local_tmpdir = nil |   local local_tmpdir = nil | ||||||
|   if tmpdir_is_local and tmpdir then |   if tmpdir_is_local and tmpdir then | ||||||
|     local_tmpdir = vim.pesc(relpath(tmpdir):gsub('^[ ./]+', ''):gsub('%/+$', '')) |     local_tmpdir = | ||||||
|  |       vim.pesc(vim.fs.relpath(assert(vim.uv.cwd()), tmpdir):gsub('^[ ./]+', ''):gsub('%/+$', '')) | ||||||
|   end |   end | ||||||
|  |  | ||||||
|   local db_cmd --- @type string |   local db_cmd --- @type string | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 dundargoc
					dundargoc