From e3e6fadfd82861471c32fdcabe00bbef3de84563 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 20 May 2023 17:30:48 +0200 Subject: [PATCH] feat(fs): expose join_paths as `vim.fs.joinpath` (#23685) This is a small function but used a lot in some plugins. --- runtime/doc/lua.txt | 10 ++++++++++ runtime/lua/vim/fs.lua | 18 +++++++++--------- test/functional/lua/fs_spec.lua | 11 +++++++++++ 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 4eec4ee583..c6568b073d 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -2576,6 +2576,16 @@ find({names}, {opts}) *vim.fs.find()* (table) Normalized paths |vim.fs.normalize()| of all matching files or directories +joinpath({...}) *vim.fs.joinpath()* + Concatenate directories and/or file into a single path with normalization + (e.g., `"foo/"` and `"bar"` get joined to `"foo/bar"`) + + Parameters: ~ + • {...} (string) + + Return: ~ + (string) + normalize({path}, {opts}) *vim.fs.normalize()* Normalize a path to a standard format. A tilde (~) character at the beginning of the path is expanded to the user's home directory and any diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua index 7f9f3a2bce..864ba495f1 100644 --- a/runtime/lua/vim/fs.lua +++ b/runtime/lua/vim/fs.lua @@ -72,15 +72,15 @@ function M.basename(file) return file:match('[/\\]$') and '' or (file:match('[^\\/]*$'):gsub('\\', '/')) end ----@private +--- Concatenate directories and/or file into a single path with normalization +--- (e.g., `"foo/"` and `"bar"` get joined to `"foo/bar"`) +--- ---@param ... string ---@return string -function M._join_paths(...) +function M.joinpath(...) return (table.concat({ ... }, '/'):gsub('//+', '/')) end -local join_paths = M._join_paths - ---@alias Iterator fun(): string?, string? --- Return an iterator over the files and directories located in {path} @@ -120,14 +120,14 @@ function M.dir(path, opts) local dirs = { { path, 1 } } while #dirs > 0 do local dir0, level = unpack(table.remove(dirs, 1)) - local dir = level == 1 and dir0 or join_paths(path, dir0) + local dir = level == 1 and dir0 or M.joinpath(path, dir0) local fs = vim.loop.fs_scandir(M.normalize(dir)) while fs do local name, t = vim.loop.fs_scandir_next(fs) if not name then break end - local f = level == 1 and name or join_paths(dir0, name) + local f = level == 1 and name or M.joinpath(dir0, name) coroutine.yield(f, t) if opts.depth @@ -234,7 +234,7 @@ function M.find(names, opts) local t = {} for name, type in M.dir(p) do if (not opts.type or opts.type == type) and names(name, p) then - table.insert(t, join_paths(p, name)) + table.insert(t, M.joinpath(p, name)) end end return t @@ -243,7 +243,7 @@ function M.find(names, opts) test = function(p) local t = {} for _, name in ipairs(names) do - local f = join_paths(p, name) + local f = M.joinpath(p, name) local stat = vim.loop.fs_stat(f) if stat and (not opts.type or opts.type == stat.type) then t[#t + 1] = f @@ -280,7 +280,7 @@ function M.find(names, opts) end for other, type_ in M.dir(dir) do - local f = join_paths(dir, other) + local f = M.joinpath(dir, other) if type(names) == 'function' then if (not opts.type or opts.type == type_) and names(other, dir) then if add(f) then diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua index f646e676c6..aae0ed91a7 100644 --- a/test/functional/lua/fs_spec.lua +++ b/test/functional/lua/fs_spec.lua @@ -266,6 +266,17 @@ describe('vim.fs', function() end) end) + describe('joinpath()', function() + it('works', function() + eq('foo/bar/baz', exec_lua([[ + return vim.fs.joinpath('foo', 'bar', 'baz') + ]], nvim_dir)) + eq('foo/bar/baz', exec_lua([[ + return vim.fs.joinpath('foo', '/bar/', '/baz') + ]], nvim_dir)) + end) + end) + describe('normalize()', function() it('works with backward slashes', function() eq('C:/Users/jdoe', exec_lua [[ return vim.fs.normalize('C:\\Users\\jdoe') ]])