diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index f3260c47ac2..42c4a4f0cc5 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -9,7 +9,6 @@ local actions = require "nvim-tree.actions" local legacy = require "nvim-tree.legacy" local core = require "nvim-tree.core" local git = require "nvim-tree.git" -local filters = require "nvim-tree.explorer.filters" local buffers = require "nvim-tree.buffers" local notify = require "nvim-tree.notify" @@ -210,7 +209,13 @@ local function setup_autocommands(opts) create_nvim_tree_autocmd("BufReadPost", { callback = function(data) -- update opened file buffers - if (filters.config.filter_no_buffer or renderer.config.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == "" then + local explorer = core.get_explorer() + if not explorer then + return + end + if + (explorer.filters.config.filter_no_buffer or renderer.config.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == "" + then utils.debounce("Buf:filter_buffer", opts.view.debounce_delay, function() actions.reloaders.reload_explorer() end) @@ -221,7 +226,13 @@ local function setup_autocommands(opts) create_nvim_tree_autocmd("BufUnload", { callback = function(data) -- update opened file buffers - if (filters.config.filter_no_buffer or renderer.config.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == "" then + local explorer = core.get_explorer() + if not explorer then + return + end + if + (explorer.filters.config.filter_no_buffer or renderer.config.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == "" + then utils.debounce("Buf:filter_buffer", opts.view.debounce_delay, function() actions.reloaders.reload_explorer() end) diff --git a/lua/nvim-tree/actions/finders/search-node.lua b/lua/nvim-tree/actions/finders/search-node.lua index 5e3b612d315..49678002b5c 100644 --- a/lua/nvim-tree/actions/finders/search-node.lua +++ b/lua/nvim-tree/actions/finders/search-node.lua @@ -1,5 +1,4 @@ local core = require "nvim-tree.core" -local filters = require "nvim-tree.explorer.filters" local find_file = require("nvim-tree.actions.finders.find-file").fn local M = {} @@ -9,6 +8,11 @@ local M = {} ---@return string|nil local function search(search_dir, input_path) local realpaths_searched = {} + local explorer = core.get_explorer() + + if not explorer then + return + end if not search_dir then return @@ -19,7 +23,7 @@ local function search(search_dir, input_path) local function iter(dir) local realpath, path, name, stat, handle, _ - local filter_status = filters.prepare() + local filter_status = explorer.filters:prepare() handle, _ = vim.loop.fs_scandir(dir) if not handle then @@ -42,7 +46,7 @@ local function search(search_dir, input_path) break end - if not filters.should_filter(path, stat, filter_status) then + if not explorer.filters:should_filter(path, stat, filter_status) then if string.find(path, "/" .. input_path .. "$") then return path end diff --git a/lua/nvim-tree/actions/tree/modifiers/toggles.lua b/lua/nvim-tree/actions/tree/modifiers/toggles.lua index 1d0c4e472ab..fdcb21d777d 100644 --- a/lua/nvim-tree/actions/tree/modifiers/toggles.lua +++ b/lua/nvim-tree/actions/tree/modifiers/toggles.lua @@ -1,8 +1,7 @@ local lib = require "nvim-tree.lib" local utils = require "nvim-tree.utils" -local filters = require "nvim-tree.explorer.filters" local reloaders = require "nvim-tree.actions.reloaders" - +local core = require "nvim-tree.core" local M = {} local function reload() @@ -11,39 +10,56 @@ local function reload() utils.focus_node_or_parent(node) end -function M.custom() - filters.config.filter_custom = not filters.config.filter_custom +local function wrap_explorer(fn) + return function(...) + local explorer = core.get_explorer() + if explorer then + return fn(explorer, ...) + end + end +end + +local function custom(explorer) + explorer.filters.config.filter_custom = not explorer.filters.config.filter_custom reload() end -function M.git_ignored() - filters.config.filter_git_ignored = not filters.config.filter_git_ignored +local function git_ignored(explorer) + explorer.filters.config.filter_git_ignored = not explorer.filters.config.filter_git_ignored reload() end -function M.git_clean() - filters.config.filter_git_clean = not filters.config.filter_git_clean +local function git_clean(explorer) + explorer.filters.config.filter_git_clean = not explorer.filters.config.filter_git_clean reload() end -function M.no_buffer() - filters.config.filter_no_buffer = not filters.config.filter_no_buffer +local function no_buffer(explorer) + explorer.filters.config.filter_no_buffer = not explorer.filters.config.filter_no_buffer reload() end -function M.no_bookmark() - filters.config.filter_no_bookmark = not filters.config.filter_no_bookmark +local function no_bookmark(explorer) + explorer.filters.config.filter_no_bookmark = not explorer.filters.config.filter_no_bookmark reload() end -function M.dotfiles() - filters.config.filter_dotfiles = not filters.config.filter_dotfiles +local function dotfiles(explorer) + explorer.filters.config.filter_dotfiles = not explorer.filters.config.filter_dotfiles reload() end -function M.enable() - filters.config.enable = not filters.config.enable +local function enable(explorer) + explorer.filters.config.enable = not explorer.filters.config.enable reload() end +M.custom = wrap_explorer(custom) +M.git_ignored = wrap_explorer(git_ignored) +M.git_clean = wrap_explorer(git_clean) +M.no_buffer = wrap_explorer(no_buffer) +M.no_bookmark = wrap_explorer(no_bookmark) +M.dotfiles = wrap_explorer(dotfiles) +M.enable = wrap_explorer(enable) + return M diff --git a/lua/nvim-tree/explorer/explore.lua b/lua/nvim-tree/explorer/explore.lua index 665c47c1641..8cb4bc4a350 100644 --- a/lua/nvim-tree/explorer/explore.lua +++ b/lua/nvim-tree/explorer/explore.lua @@ -3,7 +3,6 @@ local builders = require "nvim-tree.explorer.node-builders" local explorer_node = require "nvim-tree.explorer.node" local git = require "nvim-tree.git" local sorters = require "nvim-tree.explorer.sorters" -local filters = require "nvim-tree.explorer.filters" local live_filter = require "nvim-tree.live-filter" local log = require "nvim-tree.log" @@ -15,10 +14,11 @@ local M = {} ---@param cwd string ---@param node Node ---@param git_status table -local function populate_children(handle, cwd, node, git_status) +---@param parent Explorer +local function populate_children(handle, cwd, node, git_status, parent) local node_ignored = explorer_node.is_git_ignored(node) local nodes_by_path = utils.bool_record(node.nodes, "absolute_path") - local filter_status = filters.prepare(git_status) + local filter_status = parent.filters:prepare(git_status) while true do local name, t = vim.loop.fs_scandir_next(handle) if not name then @@ -31,7 +31,7 @@ local function populate_children(handle, cwd, node, git_status) ---@type uv.fs_stat.result|nil local stat = vim.loop.fs_stat(abs) - if not filters.should_filter(abs, stat, filter_status) and not nodes_by_path[abs] and Watcher.is_fs_event_capable(abs) then + if not parent.filters:should_filter(abs, stat, filter_status) and not nodes_by_path[abs] and Watcher.is_fs_event_capable(abs) then local child = nil if t == "directory" and vim.loop.fs_access(abs, "R") then child = builders.folder(node, abs, name, stat) @@ -56,8 +56,9 @@ end ---@param node Node ---@param status table +---@param parent Explorer ---@return Node[]|nil -function M.explore(node, status) +function M.explore(node, status, parent) local cwd = node.link_to or node.absolute_path local handle = vim.loop.fs_scandir(cwd) if not handle then @@ -66,7 +67,7 @@ function M.explore(node, status) local profile = log.profile_start("explore init %s", node.absolute_path) - populate_children(handle, cwd, node, status) + populate_children(handle, cwd, node, status, parent) local is_root = not node.parent local child_folder_only = explorer_node.has_one_child_folder(node) and node.nodes[1] @@ -74,7 +75,7 @@ function M.explore(node, status) local child_cwd = child_folder_only.link_to or child_folder_only.absolute_path local child_status = git.load_project_status(child_cwd) node.group_next = child_folder_only - local ns = M.explore(child_folder_only, child_status) + local ns = M.explore(child_folder_only, child_status, parent) node.nodes = ns or {} log.profile_end(profile) diff --git a/lua/nvim-tree/explorer/filters.lua b/lua/nvim-tree/explorer/filters.lua index 7b8be1315f7..a1eb80da784 100644 --- a/lua/nvim-tree/explorer/filters.lua +++ b/lua/nvim-tree/explorer/filters.lua @@ -1,15 +1,52 @@ local utils = require "nvim-tree.utils" -local M = { - ignore_list = {}, - exclude_list = {}, - custom_function = nil, -} +---@class Filters to handle all opts.filters and related API +---@field config table hydrated user opts.filters +---@field private explorer Explorer +---@field private exclude_list string[] filters.exclude +---@field private ignore_list string[] filters.custom string table +---@field private custom_function (fun(absolute_path: string): boolean)|nil filters.custom function +local Filters = {} + +---@param opts table user options +---@param explorer Explorer +---@return Filters +function Filters:new(opts, explorer) + local o = { + explorer = explorer, + ignore_list = {}, + exclude_list = opts.filters.exclude, + custom_function = nil, + config = { + enable = opts.filters.enable, + filter_custom = true, + filter_dotfiles = opts.filters.dotfiles, + filter_git_ignored = opts.filters.git_ignored, + filter_git_clean = opts.filters.git_clean, + filter_no_buffer = opts.filters.no_buffer, + filter_no_bookmark = opts.filters.no_bookmark, + }, + } + + local custom_filter = opts.filters.custom + if type(custom_filter) == "function" then + o.custom_function = custom_filter + else + if custom_filter and #custom_filter > 0 then + for _, filter_name in pairs(custom_filter) do + o.ignore_list[filter_name] = true + end + end + end + setmetatable(o, self) + self.__index = self + return o +end ---@param path string ---@return boolean -local function is_excluded(path) - for _, node in ipairs(M.exclude_list) do +local function is_excluded(self, path) + for _, node in ipairs(self.exclude_list) do if path:match(node) then return true end @@ -21,7 +58,7 @@ end ---@param path string Absolute path ---@param git_status table from prepare ---@return boolean -local function git(path, git_status) +local function git(self, path, git_status) if type(git_status) ~= "table" or type(git_status.files) ~= "table" or type(git_status.dirs) ~= "table" then return false end @@ -32,12 +69,12 @@ local function git(path, git_status) status = status or git_status.dirs.indirect[path] and git_status.dirs.indirect[path][1] -- filter ignored; overrides clean as they are effectively dirty - if M.config.filter_git_ignored and status == "!!" then + if self.config.filter_git_ignored and status == "!!" then return true end -- filter clean - if M.config.filter_git_clean and not status then + if self.config.filter_git_clean and not status then return true end @@ -48,8 +85,8 @@ end ---@param path string Absolute path ---@param bufinfo table vim.fn.getbufinfo { buflisted = 1 } ---@return boolean -local function buf(path, bufinfo) - if not M.config.filter_no_buffer or type(bufinfo) ~= "table" then +local function buf(self, path, bufinfo) + if not self.config.filter_no_buffer or type(bufinfo) ~= "table" then return false end @@ -65,15 +102,15 @@ end ---@param path string ---@return boolean -local function dotfile(path) - return M.config.filter_dotfiles and utils.path_basename(path):sub(1, 1) == "." +local function dotfile(self, path) + return self.config.filter_dotfiles and utils.path_basename(path):sub(1, 1) == "." end ---@param path string ---@param path_type string|nil filetype of path ---@param bookmarks table path, filetype table of bookmarked files -local function bookmark(path, path_type, bookmarks) - if not M.config.filter_no_bookmark then +local function bookmark(self, path, path_type, bookmarks) + if not self.config.filter_no_bookmark then return false end -- if bookmark is empty, we should see a empty filetree @@ -107,21 +144,21 @@ end ---@param path string ---@return boolean -local function custom(path) - if not M.config.filter_custom then +local function custom(self, path) + if not self.config.filter_custom then return false end local basename = utils.path_basename(path) -- filter user's custom function - if M.custom_function and M.custom_function(path) then + if self.custom_function and self.custom_function(path) then return true end -- filter custom regexes local relpath = utils.path_relative(path, vim.loop.cwd()) - for pat, _ in pairs(M.ignore_list) do + for pat, _ in pairs(self.ignore_list) do if vim.fn.match(relpath, pat) ~= -1 or vim.fn.match(basename, pat) ~= -1 then return true end @@ -129,7 +166,7 @@ local function custom(path) local idx = path:match ".+()%.[^.]+$" if idx then - if M.ignore_list["*" .. string.sub(path, idx)] == true then + if self.ignore_list["*" .. string.sub(path, idx)] == true then return true end end @@ -143,14 +180,14 @@ end --- git_status: reference --- bufinfo: empty unless no_buffer set: vim.fn.getbufinfo { buflisted = 1 } --- bookmarks: absolute paths to boolean -function M.prepare(git_status) +function Filters:prepare(git_status) local status = { git_status = git_status or {}, bufinfo = {}, bookmarks = {}, } - if M.config.filter_no_buffer then + if self.config.filter_no_buffer then status.bufinfo = vim.fn.getbufinfo { buflisted = 1 } end @@ -169,47 +206,21 @@ end ---@param fs_stat uv.fs_stat.result|nil fs_stat of file ---@param status table from prepare ---@return boolean -function M.should_filter(path, fs_stat, status) - if not M.config.enable then +function Filters:should_filter(path, fs_stat, status) + if not self.config.enable then return false end -- exclusions override all filters - if is_excluded(path) then + if is_excluded(self, path) then return false end - return git(path, status.git_status) - or buf(path, status.bufinfo) - or dotfile(path) - or custom(path) - or bookmark(path, fs_stat and fs_stat.type, status.bookmarks) -end - -function M.setup(opts) - M.config = { - enable = opts.filters.enable, - filter_custom = true, - filter_dotfiles = opts.filters.dotfiles, - filter_git_ignored = opts.filters.git_ignored, - filter_git_clean = opts.filters.git_clean, - filter_no_buffer = opts.filters.no_buffer, - filter_no_bookmark = opts.filters.no_bookmark, - } - - M.ignore_list = {} - M.exclude_list = opts.filters.exclude - - local custom_filter = opts.filters.custom - if type(custom_filter) == "function" then - M.custom_function = custom_filter - else - if custom_filter and #custom_filter > 0 then - for _, filter_name in pairs(custom_filter) do - M.ignore_list[filter_name] = true - end - end - end + return git(self, path, status.git_status) + or buf(self, path, status.bufinfo) + or dotfile(self, path) + or custom(self, path) + or bookmark(self, path, fs_stat and fs_stat.type, status.bookmarks) end -return M +return Filters diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index 25ad242ecf0..5b682b72c55 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -2,6 +2,7 @@ local git = require "nvim-tree.git" local notify = require "nvim-tree.notify" local watch = require "nvim-tree.explorer.watch" local explorer_node = require "nvim-tree.explorer.node" +local Filters = require "nvim-tree.explorer.filters" local Marks = require "nvim-tree.marks" local M = {} @@ -41,6 +42,7 @@ function Explorer.new(path) marks = Marks:new(), }, Explorer) explorer.watcher = watch.create_watcher(explorer) + explorer.filters = Filters:new(M.config, explorer) explorer:_load(explorer) return explorer end @@ -50,7 +52,7 @@ end function Explorer:_load(node) local cwd = node.link_to or node.absolute_path local git_status = git.load_project_status(cwd) - M.explore(node, git_status) + M.explore(node, git_status, self) end ---@param node Node @@ -71,9 +73,9 @@ function Explorer:destroy() end function M.setup(opts) + M.config = opts require("nvim-tree.explorer.node").setup(opts) require("nvim-tree.explorer.explore").setup(opts) - require("nvim-tree.explorer.filters").setup(opts) require("nvim-tree.explorer.sorters").setup(opts) require("nvim-tree.explorer.reload").setup(opts) require("nvim-tree.explorer.watch").setup(opts) diff --git a/lua/nvim-tree/explorer/reload.lua b/lua/nvim-tree/explorer/reload.lua index 9d2ddcab5b7..3243861ea6d 100644 --- a/lua/nvim-tree/explorer/reload.lua +++ b/lua/nvim-tree/explorer/reload.lua @@ -1,7 +1,6 @@ local utils = require "nvim-tree.utils" local builders = require "nvim-tree.explorer.node-builders" local explorer_node = require "nvim-tree.explorer.node" -local filters = require "nvim-tree.explorer.filters" local sorters = require "nvim-tree.explorer.sorters" local live_filter = require "nvim-tree.live-filter" local git = require "nvim-tree.git" @@ -70,6 +69,10 @@ end ---@param node Node ---@param git_status table function M.reload(node, git_status) + local explorer = require("nvim-tree.core").get_explorer() + if not explorer then + return + end local cwd = node.link_to or node.absolute_path local handle = vim.loop.fs_scandir(cwd) if not handle then @@ -78,7 +81,7 @@ function M.reload(node, git_status) local profile = log.profile_start("reload %s", node.absolute_path) - local filter_status = filters.prepare(git_status) + local filter_status = explorer.filters:prepare(git_status) if node.group_next then node.nodes = { node.group_next } @@ -100,7 +103,7 @@ function M.reload(node, git_status) ---@type uv.fs_stat.result|nil local stat = vim.loop.fs_stat(abs) - if not filters.should_filter(abs, stat, filter_status) then + if not explorer.filters:should_filter(abs, stat, filter_status) then remain_childs[abs] = true -- Recreate node if type changes. diff --git a/lua/nvim-tree/live-filter.lua b/lua/nvim-tree/live-filter.lua index 350043aae6b..cc305da6af4 100644 --- a/lua/nvim-tree/live-filter.lua +++ b/lua/nvim-tree/live-filter.lua @@ -1,7 +1,6 @@ local view = require "nvim-tree.view" local utils = require "nvim-tree.utils" local Iterator = require "nvim-tree.iterators.node-iterator" -local filters = require "nvim-tree.explorer.filters" local M = { filter = nil, @@ -57,7 +56,8 @@ end ---@param node Node ---@return boolean local function matches(node) - if not filters.config.enable then + local explorer = require("nvim-tree.core").get_explorer() + if not explorer or not explorer.filters.config.enable then return true end