From 67cbaf58c41a3db19c5014587e72d06be9e3d58e Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Sun, 15 May 2022 14:38:19 -0600 Subject: [PATCH] feat(fs): add vim.fs.parents() vim.fs.parents() is a Lua iterator that returns the next parent directory of the given file or directory on each iteration. --- runtime/doc/lua.txt | 28 ++++++++++++++++++++++++++ runtime/lua/vim/_editor.lua | 1 + runtime/lua/vim/fs.lua | 35 +++++++++++++++++++++++++++++++++ scripts/gen_vimdoc.py | 3 +++ test/functional/lua/fs_spec.lua | 33 +++++++++++++++++++++++++++++++ 5 files changed, 100 insertions(+) create mode 100644 runtime/lua/vim/fs.lua create mode 100644 test/functional/lua/fs_spec.lua diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index dd1843ade3..8f74dca418 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -2147,4 +2147,32 @@ set({mode}, {lhs}, {rhs}, {opts}) *vim.keymap.set()* See also: ~ |nvim_set_keymap()| + +============================================================================== +Lua module: fs *lua-fs* + +parents({start}) *vim.fs.parents()* + Iterate over all the parents of the given file or directory. + + Example: > + + local root_dir + for dir in vim.fs.parents(vim.api.nvim_buf_get_name(0)) do + if vim.fn.isdirectory(dir .. "/.git") == 1 then + root_dir = dir + break + end + end + + if root_dir then + print("Found git repository at", root_dir) + end +< + + Parameters: ~ + {start} (string) Initial file or directory. + + Return: ~ + (function) Iterator + vim:tw=78:ts=8:ft=help:norl: diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index c8a0aa8260..453aa6ac81 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -50,6 +50,7 @@ for k, v in pairs({ keymap = true, ui = true, health = true, + fs = true, }) do vim._submodules[k] = v end diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua new file mode 100644 index 0000000000..08d2e495d2 --- /dev/null +++ b/runtime/lua/vim/fs.lua @@ -0,0 +1,35 @@ +local M = {} + +--- Iterate over all the parents of the given file or directory. +--- +--- Example: +---
+--- local root_dir
+--- for dir in vim.fs.parents(vim.api.nvim_buf_get_name(0)) do
+---   if vim.fn.isdirectory(dir .. "/.git") == 1 then
+---     root_dir = dir
+---     break
+---   end
+--- end
+---
+--- if root_dir then
+---   print("Found git repository at", root_dir)
+--- end
+--- 
+--- +---@param start (string) Initial file or directory. +---@return (function) Iterator +function M.parents(start) + return function(_, dir) + local parent = vim.fn.fnamemodify(dir, ":h") + if parent == dir then + return nil + end + + return parent + end, + nil, + start +end + +return M diff --git a/scripts/gen_vimdoc.py b/scripts/gen_vimdoc.py index 755749cef6..790c2ba52d 100755 --- a/scripts/gen_vimdoc.py +++ b/scripts/gen_vimdoc.py @@ -134,6 +134,7 @@ CONFIG = { 'ui.lua', 'filetype.lua', 'keymap.lua', + 'fs.lua', ], 'files': [ 'runtime/lua/vim/_editor.lua', @@ -142,6 +143,7 @@ CONFIG = { 'runtime/lua/vim/ui.lua', 'runtime/lua/vim/filetype.lua', 'runtime/lua/vim/keymap.lua', + 'runtime/lua/vim/fs.lua', ], 'file_patterns': '*.lua', 'fn_name_prefix': '', @@ -167,6 +169,7 @@ CONFIG = { 'ui': 'vim.ui', 'filetype': 'vim.filetype', 'keymap': 'vim.keymap', + 'fs': 'vim.fs', }, 'append_only': [ 'shared.lua', diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua new file mode 100644 index 0000000000..69eb8cd539 --- /dev/null +++ b/test/functional/lua/fs_spec.lua @@ -0,0 +1,33 @@ +local helpers = require('test.functional.helpers')(after_each) + +local clear = helpers.clear +local exec_lua = helpers.exec_lua +local eq = helpers.eq +local mkdir_p = helpers.mkdir_p +local rmdir = helpers.rmdir +local nvim_dir = helpers.nvim_dir +local test_build_dir = helpers.test_build_dir + +before_each(clear) + +describe('vim.fs', function() + describe('parents()', function() + it('works', function() + local test_dir = nvim_dir .. '/test' + mkdir_p(test_dir) + local dirs = exec_lua([[ + local test_dir, test_build_dir = ... + local dirs = {} + for dir in vim.fs.parents(test_dir .. "/foo.txt") do + dirs[#dirs + 1] = dir + if dir == test_build_dir then + break + end + end + return dirs + ]], test_dir, test_build_dir) + eq({test_dir, nvim_dir, test_build_dir}, dirs) + rmdir(test_dir) + end) + end) +end)