diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index e42e13212e..24bb3570d3 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -2972,6 +2972,7 @@ vim.fs.dir({path}, {opts}) *vim.fs.dir()* • skip: (fun(dir_name: string): boolean)|nil Predicate to control traversal. Return false to stop searching the current directory. Only useful when depth > 1 + • follow: boolean|nil Follow symbolic links. (default: true) Return: ~ (`Iterator`) over items in {path}. Each iteration yields two values: diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua index fbf0009c27..1adfff8af0 100644 --- a/runtime/lua/vim/fs.lua +++ b/runtime/lua/vim/fs.lua @@ -127,6 +127,7 @@ end --- - skip: (fun(dir_name: string): boolean)|nil Predicate --- to control traversal. Return false to stop searching the current directory. --- Only useful when depth > 1 +--- - follow: boolean|nil Follow symbolic links. (default: true) --- ---@return Iterator over items in {path}. Each iteration yields two values: "name" and "type". --- "name" is the basename of the item relative to {path}. @@ -138,6 +139,7 @@ function M.dir(path, opts) vim.validate('path', path, 'string') vim.validate('depth', opts.depth, 'number', true) vim.validate('skip', opts.skip, 'function', true) + vim.validate('follow', opts.follow, 'boolean', true) path = M.normalize(path) if not opts.depth or opts.depth == 1 then @@ -168,7 +170,9 @@ function M.dir(path, opts) if opts.depth and level < opts.depth - and t == 'directory' + and (t == 'directory' or (t == 'link' and opts.follow ~= false and (vim.uv.fs_stat( + M.joinpath(path, f) + ) or {}).type == 'directory')) and (not opts.skip or opts.skip(f) ~= false) then dirs[#dirs + 1] = { f, level + 1 } diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua index 83e93e1f5e..4714283a2f 100644 --- a/test/functional/lua/fs_spec.lua +++ b/test/functional/lua/fs_spec.lua @@ -152,7 +152,7 @@ describe('vim.fs', function() ) end) - it('works with opts.depth and opts.skip', function() + it('works with opts.depth, opts.skip and opts.follow', function() io.open('testd/a1', 'w'):close() io.open('testd/b1', 'w'):close() io.open('testd/c1', 'w'):close() @@ -166,7 +166,7 @@ describe('vim.fs', function() io.open('testd/a/b/c/b4', 'w'):close() io.open('testd/a/b/c/c4', 'w'):close() - local function run(dir, depth, skip) + local function run(dir, depth, skip, follow) return exec_lua(function() local r = {} local skip_f @@ -177,7 +177,7 @@ describe('vim.fs', function() end end end - for name, type_ in vim.fs.dir(dir, { depth = depth, skip = skip_f }) do + for name, type_ in vim.fs.dir(dir, { depth = depth, skip = skip_f, follow = follow }) do r[name] = type_ end return r @@ -197,6 +197,7 @@ describe('vim.fs', function() exp['a/b2'] = 'file' exp['a/c2'] = 'file' exp['a/b'] = 'directory' + local lexp = vim.deepcopy(exp) eq(exp, run('testd', 2)) @@ -213,6 +214,16 @@ describe('vim.fs', function() exp['a/b/c/c4'] = 'file' eq(exp, run('testd', 999)) + + vim.uv.fs_symlink('a', 'testd/l', { junction = true, dir = true }) + lexp['l'] = 'link' + eq(lexp, run('testd', 2, nil, false)) + + lexp['l/a2'] = 'file' + lexp['l/b2'] = 'file' + lexp['l/c2'] = 'file' + lexp['l/b'] = 'directory' + eq(lexp, run('testd', 2, nil, true)) end) end)