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`) | ||||
|         (`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()* | ||||
|     WARNING: This feature is experimental/unstable. | ||||
|  | ||||
|   | ||||
| @@ -284,6 +284,7 @@ LUA | ||||
|   supporting two new parameters, `encoding` and `strict_indexing`. | ||||
| • |vim.json.encode()| has an option to enable forward slash escaping | ||||
| • |vim.fs.abspath()| converts paths to absolute paths. | ||||
| • |vim.fs.relpath()| gets relative path compared to base path. | ||||
|  | ||||
| OPTIONS | ||||
|  | ||||
|   | ||||
| @@ -741,4 +741,37 @@ function M.abspath(path) | ||||
|   return M.joinpath(cwd, path) | ||||
| 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 | ||||
|   | ||||
| @@ -168,8 +168,8 @@ describe('vim.fs', function() | ||||
|  | ||||
|       local function run(dir, depth, skip) | ||||
|         return exec_lua(function() | ||||
|           local r = {} | ||||
|           local skip_f | ||||
|           local r = {} --- @type table<string, string> | ||||
|           local skip_f --- @type function | ||||
|           if skip then | ||||
|             skip_f = function(n0) | ||||
|               if vim.tbl_contains(skip or {}, n0) then | ||||
| @@ -493,8 +493,8 @@ describe('vim.fs', function() | ||||
|   end) | ||||
|  | ||||
|   describe('abspath()', function() | ||||
|     local cwd = is_os('win') and vim.uv.cwd():gsub('\\', '/') or vim.uv.cwd() | ||||
|     local home = is_os('win') and vim.uv.os_homedir():gsub('\\', '/') or vim.uv.os_homedir() | ||||
|     local cwd = assert(t.fix_slashes(assert(vim.uv.cwd()))) | ||||
|     local home = t.fix_slashes(assert(vim.uv.os_homedir())) | ||||
|  | ||||
|     it('works', function() | ||||
|       eq(cwd .. '/foo', vim.fs.abspath('foo')) | ||||
| @@ -526,4 +526,57 @@ describe('vim.fs', function() | ||||
|       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) | ||||
|   | ||||
| @@ -22,13 +22,6 @@ local M = { | ||||
|   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 | ||||
| --- @return boolean | ||||
| function M.isdir(path) | ||||
| @@ -45,14 +38,15 @@ end | ||||
| --- (Only on Windows) Replaces yucky "\\" slashes with delicious "/" slashes in a string, or all | ||||
| --- string values in a table (recursively). | ||||
| --- | ||||
| --- @param obj string|table | ||||
| --- @return any | ||||
| --- @generic T: string|table | ||||
| --- @param obj T | ||||
| --- @return T|nil | ||||
| function M.fix_slashes(obj) | ||||
|   if not M.is_os('win') then | ||||
|     return obj | ||||
|   end | ||||
|   if type(obj) == 'string' then | ||||
|     local ret = obj:gsub('\\', '/') | ||||
|     local ret = string.gsub(obj, '\\', '/') | ||||
|     return ret | ||||
|   elseif type(obj) == 'table' then | ||||
|     --- @cast obj table<any,any> | ||||
| @@ -482,7 +476,8 @@ function M.check_cores(app, force) -- luacheck: ignore | ||||
|   -- "./Xtest-tmpdir/" => "Xtest%-tmpdir" | ||||
|   local local_tmpdir = nil | ||||
|   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 | ||||
|  | ||||
|   local db_cmd --- @type string | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 dundargoc
					dundargoc