diff options
author | dundargoc <gocdundar@gmail.com> | 2024-12-30 16:01:00 +0100 |
---|---|---|
committer | dundargoc <33953936+dundargoc@users.noreply.github.com> | 2025-01-13 13:14:52 +0100 |
commit | 0631492f9c8044a378dc2a17ea257badfbda6d15 (patch) | |
tree | 9fca9c84d79c76df83e0689122874e4f1ff262f9 | |
parent | a3ef29d570dd892a1bcbfa80bb242d4aac89a06e (diff) | |
download | rneovim-0631492f9c8044a378dc2a17ea257badfbda6d15.tar.gz rneovim-0631492f9c8044a378dc2a17ea257badfbda6d15.tar.bz2 rneovim-0631492f9c8044a378dc2a17ea257badfbda6d15.zip |
feat: add vim.fs.relpath
This is needed to replace the nvim-lspconfig function is_descendant that
some lspconfg configurations still use.
-rw-r--r-- | runtime/doc/lua.txt | 17 | ||||
-rw-r--r-- | runtime/doc/news.txt | 1 | ||||
-rw-r--r-- | runtime/lua/vim/fs.lua | 33 | ||||
-rw-r--r-- | test/functional/lua/fs_spec.lua | 61 | ||||
-rw-r--r-- | test/testutil.lua | 17 |
5 files changed, 114 insertions, 15 deletions
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index a84a364847..44cbf238cf 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -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. diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 3b1c38b8d9..a1868e97d0 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -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 diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua index 04a6e43db1..91e06688b3 100644 --- a/runtime/lua/vim/fs.lua +++ b/runtime/lua/vim/fs.lua @@ -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 diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua index 6bc1ddbff6..0ba0948eee 100644 --- a/test/functional/lua/fs_spec.lua +++ b/test/functional/lua/fs_spec.lua @@ -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) diff --git a/test/testutil.lua b/test/testutil.lua index 007e017ac6..3226bfeb1e 100644 --- a/test/testutil.lua +++ b/test/testutil.lua @@ -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 |