refactor(#2882, #2883): multi instance explore, reloaders (#2897)

* refactor(#2883): multi instance explore

* refactor(#2882): multi instance reloaders

* style
This commit is contained in:
Alexander Courtis 2024-09-14 15:35:31 +10:00 committed by GitHub
parent 03f737e574
commit cd9c6db77f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 247 additions and 115 deletions

View File

@ -201,7 +201,10 @@ local function setup_autocommands(opts)
create_nvim_tree_autocmd("BufWritePost", {
callback = function()
if opts.auto_reload_on_write and not opts.filesystem_watchers.enable then
actions.reloaders.reload_explorer()
local explorer = core.get_explorer()
if explorer then
explorer:reload_explorer()
end
end
end,
})
@ -217,7 +220,7 @@ local function setup_autocommands(opts)
(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()
explorer:reload_explorer()
end)
end
end,
@ -234,7 +237,7 @@ local function setup_autocommands(opts)
(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()
explorer:reload_explorer()
end)
end
end,
@ -244,7 +247,10 @@ local function setup_autocommands(opts)
pattern = { "FugitiveChanged", "NeogitStatusRefreshed" },
callback = function()
if not opts.filesystem_watchers.enable and opts.git.enable then
actions.reloaders.reload_git()
local explorer = core.get_explorer()
if explorer then
explorer:reload_git()
end
end
end,
})
@ -292,7 +298,10 @@ local function setup_autocommands(opts)
callback = function()
if utils.is_nvim_tree_buf(0) then
if vim.fn.getcwd() ~= core.get_cwd() or (opts.reload_on_bufenter and not opts.filesystem_watchers.enable) then
actions.reloaders.reload_explorer()
local explorer = core.get_explorer()
if explorer then
explorer:reload_explorer()
end
end
end
end,
@ -343,7 +352,10 @@ local function setup_autocommands(opts)
callback = function()
utils.debounce("Buf:modified", opts.view.debounce_delay, function()
buffers.reload_modified()
actions.reloaders.reload_explorer()
local explorer = core.get_explorer()
if explorer then
explorer:reload_explorer()
end
end)
end,
})

View File

@ -5,7 +5,6 @@ local core = require "nvim-tree.core"
local events = require "nvim-tree.events"
local notify = require "nvim-tree.notify"
local renderer = require "nvim-tree.renderer"
local reloaders = require "nvim-tree.actions.reloaders"
local find_file = require("nvim-tree.actions.finders.find-file").fn
@ -248,7 +247,7 @@ function Clipboard:do_paste(node, action, action_fn)
self.data[action] = {}
if not self.config.filesystem_watchers.enable then
reloaders.reload_explorer()
self.explorer:reload_explorer()
end
end

View File

@ -1,3 +1,4 @@
local core = require "nvim-tree.core"
local utils = require "nvim-tree.utils"
local events = require "nvim-tree.events"
local view = require "nvim-tree.view"
@ -116,8 +117,9 @@ function M.fn(node)
local function do_remove()
M.remove(node)
if not M.config.filesystem_watchers.enable then
require("nvim-tree.actions.reloaders").reload_explorer()
local explorer = core.get_explorer()
if not M.config.filesystem_watchers.enable and explorer then
explorer:reload_explorer()
end
end

View File

@ -1,3 +1,4 @@
local core = require "nvim-tree.core"
local lib = require "nvim-tree.lib"
local utils = require "nvim-tree.utils"
local events = require "nvim-tree.events"
@ -155,7 +156,10 @@ function M.fn(default_modifier)
M.rename(node, prepend .. new_file_path .. append)
if not M.config.filesystem_watchers.enable then
require("nvim-tree.actions.reloaders").reload_explorer()
local explorer = core.get_explorer()
if explorer then
explorer:reload_explorer()
end
end
find_file(utils.path_remove_trailing(new_file_path))

View File

@ -1,6 +1,6 @@
local core = require "nvim-tree.core"
local lib = require "nvim-tree.lib"
local notify = require "nvim-tree.notify"
local reloaders = require "nvim-tree.actions.reloaders"
local M = {
config = {},
@ -52,6 +52,8 @@ function M.remove(node)
end
end
local explorer = core.get_explorer()
if node.nodes ~= nil and not node.link_to then
trash_path(function(_, rc)
if rc ~= 0 then
@ -59,8 +61,8 @@ function M.remove(node)
return
end
events._dispatch_folder_removed(node.absolute_path)
if not M.config.filesystem_watchers.enable then
reloaders.reload_explorer()
if not M.config.filesystem_watchers.enable and explorer then
explorer:reload_explorer()
end
end)
else
@ -72,8 +74,8 @@ function M.remove(node)
end
events._dispatch_file_removed(node.absolute_path)
clear_buffer(node.absolute_path)
if not M.config.filesystem_watchers.enable then
reloaders.reload_explorer()
if not M.config.filesystem_watchers.enable and explorer then
explorer:reload_explorer()
end
end)
end

View File

@ -4,7 +4,6 @@ M.finders = require "nvim-tree.actions.finders"
M.fs = require "nvim-tree.actions.fs"
M.moves = require "nvim-tree.actions.moves"
M.node = require "nvim-tree.actions.node"
M.reloaders = require "nvim-tree.actions.reloaders"
M.root = require "nvim-tree.actions.root"
M.tree = require "nvim-tree.actions.tree"

View File

@ -1,72 +0,0 @@
local git = require "nvim-tree.git"
local view = require "nvim-tree.view"
local renderer = require "nvim-tree.renderer"
local core = require "nvim-tree.core"
local explorer_node = require "nvim-tree.explorer.node"
local Iterator = require "nvim-tree.iterators.node-iterator"
local M = {}
---@param explorer Explorer|nil
---@param projects table
local function refresh_nodes(explorer, projects)
Iterator.builder({ explorer })
:applier(function(n)
if n.nodes then
local toplevel = git.get_toplevel(n.cwd or n.link_to or n.absolute_path)
if explorer then
explorer:reload(n, projects[toplevel] or {})
end
end
end)
:recursor(function(n)
return n.group_next and { n.group_next } or (n.open and n.nodes)
end)
:iterate()
end
---@param parent_node Node|nil
---@param projects table
function M.reload_node_status(parent_node, projects)
if parent_node == nil then
return
end
local toplevel = git.get_toplevel(parent_node.absolute_path)
local status = projects[toplevel] or {}
for _, node in ipairs(parent_node.nodes) do
explorer_node.update_git_status(node, explorer_node.is_git_ignored(parent_node), status)
if node.nodes and #node.nodes > 0 then
M.reload_node_status(node, projects)
end
end
end
local event_running = false
function M.reload_explorer()
if event_running or not core.get_explorer() or vim.v.exiting ~= vim.NIL then
return
end
event_running = true
local projects = git.reload()
refresh_nodes(core.get_explorer(), projects)
if view.is_visible() then
renderer.draw()
end
event_running = false
end
function M.reload_git()
if not core.get_explorer() or not git.config.git.enable or event_running then
return
end
event_running = true
local projects = git.reload()
M.reload_node_status(core.get_explorer(), projects)
renderer.draw()
event_running = false
end
return M

View File

@ -1,12 +1,12 @@
local lib = require "nvim-tree.lib"
local utils = require "nvim-tree.utils"
local reloaders = require "nvim-tree.actions.reloaders"
local core = require "nvim-tree.core"
local M = {}
local function reload()
---@param explorer Explorer
local function reload(explorer)
local node = lib.get_node_at_cursor()
reloaders.reload_explorer()
explorer:reload_explorer()
utils.focus_node_or_parent(node)
end
@ -19,39 +19,46 @@ local function wrap_explorer(fn)
end
end
---@param explorer Explorer
local function custom(explorer)
explorer.filters.config.filter_custom = not explorer.filters.config.filter_custom
reload()
reload(explorer)
end
---@param explorer Explorer
local function git_ignored(explorer)
explorer.filters.config.filter_git_ignored = not explorer.filters.config.filter_git_ignored
reload()
reload(explorer)
end
---@param explorer Explorer
local function git_clean(explorer)
explorer.filters.config.filter_git_clean = not explorer.filters.config.filter_git_clean
reload()
reload(explorer)
end
---@param explorer Explorer
local function no_buffer(explorer)
explorer.filters.config.filter_no_buffer = not explorer.filters.config.filter_no_buffer
reload()
reload(explorer)
end
---@param explorer Explorer
local function no_bookmark(explorer)
explorer.filters.config.filter_no_bookmark = not explorer.filters.config.filter_no_bookmark
reload()
reload(explorer)
end
---@param explorer Explorer
local function dotfiles(explorer)
explorer.filters.config.filter_dotfiles = not explorer.filters.config.filter_dotfiles
reload()
reload(explorer)
end
---@param explorer Explorer
local function enable(explorer)
explorer.filters.config.enable = not explorer.filters.config.enable
reload()
reload(explorer)
end
M.custom = wrap_explorer(custom)

View File

@ -72,6 +72,19 @@ local function wrap_node_or_nil(fn)
end
end
---Invoke a method on the singleton explorer.
---Print error when setup not called.
---@param explorer_method string explorer method name
---@return fun(...) : any
local function wrap_explorer(explorer_method)
return wrap(function(...)
local explorer = core.get_explorer()
if explorer then
return explorer[explorer_method](explorer, ...)
end
end)
end
---Invoke a member's method on the singleton explorer.
---Print error when setup not called.
---@param explorer_member string explorer member name
@ -108,7 +121,7 @@ Api.tree.toggle = wrap(actions.tree.toggle.fn)
Api.tree.close = wrap(view.close)
Api.tree.close_in_this_tab = wrap(view.close_this_tab_only)
Api.tree.close_in_all_tabs = wrap(view.close_all_tabs)
Api.tree.reload = wrap(actions.reloaders.reload_explorer)
Api.tree.reload = wrap_explorer "reload_explorer"
---@class ApiTreeResizeOpts
---@field width string|function|number|table|nil
@ -243,7 +256,7 @@ Api.node.navigate.diagnostics.prev_recursive = wrap_node(actions.moves.item.fn {
Api.node.navigate.opened.next = wrap_node(actions.moves.item.fn { where = "next", what = "opened" })
Api.node.navigate.opened.prev = wrap_node(actions.moves.item.fn { where = "prev", what = "opened" })
Api.git.reload = wrap(actions.reloaders.reload_git)
Api.git.reload = wrap_explorer "reload_git"
Api.events.subscribe = events.subscribe
Api.events.Event = events.Event

View File

@ -2,10 +2,13 @@ local builders = require "nvim-tree.explorer.node-builders"
local git = require "nvim-tree.git"
local log = require "nvim-tree.log"
local notify = require "nvim-tree.notify"
local renderer = {} -- circular dependency, will become a member
local utils = require "nvim-tree.utils"
local view = require "nvim-tree.view"
local watch = require "nvim-tree.explorer.watch"
local explorer_node = require "nvim-tree.explorer.node"
local Iterator = require "nvim-tree.iterators.node-iterator"
local NodeIterator = require "nvim-tree.iterators.node-iterator"
local Watcher = require "nvim-tree.watcher"
@ -30,8 +33,6 @@ local config
---@field clipboard Clipboard
local Explorer = {}
Explorer.explore = require("nvim-tree.explorer.explore").explore
---@param path string|nil
---@return Explorer|nil
function Explorer:new(path)
@ -264,17 +265,7 @@ end
function Explorer:_load(node)
local cwd = node.link_to or node.absolute_path
local git_status = git.load_project_status(cwd)
Explorer.explore(node, git_status, self)
end
function Explorer.setup(opts)
config = opts
require("nvim-tree.explorer.node").setup(opts)
require("nvim-tree.explorer.explore").setup(opts)
require("nvim-tree.explorer.watch").setup(opts)
Marks = require "nvim-tree.marks"
Clipboard = require "nvim-tree.actions.fs.clipboard"
self:explore(node, git_status, self)
end
---@private
@ -337,4 +328,158 @@ function Explorer:update_parent_statuses(node, project, root)
end
end
---@private
---@param handle uv.uv_fs_t
---@param cwd string
---@param node Node
---@param git_status table
---@param parent Explorer
function Explorer: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 = parent.filters:prepare(git_status)
node.hidden_stats = vim.tbl_deep_extend("force", node.hidden_stats or {}, {
git = 0,
buf = 0,
dotfile = 0,
custom = 0,
bookmark = 0,
})
while true do
local name, t = vim.loop.fs_scandir_next(handle)
if not name then
break
end
local abs = utils.path_join { cwd, name }
if Watcher.is_fs_event_capable(abs) then
local profile = log.profile_start("populate_children %s", abs)
---@type uv.fs_stat.result|nil
local stat = vim.loop.fs_stat(abs)
local filter_reason = parent.filters:should_filter_as_reason(abs, stat, filter_status)
if filter_reason == FILTER_REASON.none and not nodes_by_path[abs] then
local child = nil
if t == "directory" and vim.loop.fs_access(abs, "R") then
child = builders.folder(node, abs, name, stat)
elseif t == "file" then
child = builders.file(node, abs, name, stat)
elseif t == "link" then
local link = builders.link(node, abs, name, stat)
if link.link_to ~= nil then
child = link
end
end
if child then
table.insert(node.nodes, child)
nodes_by_path[child.absolute_path] = true
explorer_node.update_git_status(child, node_ignored, git_status)
end
else
for reason, value in pairs(FILTER_REASON) do
if filter_reason == value then
node.hidden_stats[reason] = node.hidden_stats[reason] + 1
end
end
end
log.profile_end(profile)
end
end
end
---@private
---@param node Node
---@param status table
---@param parent Explorer
---@return Node[]|nil
function Explorer:explore(node, status, parent)
local cwd = node.link_to or node.absolute_path
local handle = vim.loop.fs_scandir(cwd)
if not handle then
return
end
local profile = log.profile_start("explore %s", node.absolute_path)
self: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]
if config.renderer.group_empty and not is_root and child_folder_only then
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 = self:explore(child_folder_only, child_status, parent)
node.nodes = ns or {}
log.profile_end(profile)
return ns
end
parent.sorters:sort(node.nodes)
parent.live_filter:apply_filter(node)
log.profile_end(profile)
return node.nodes
end
---@private
---@param projects table
function Explorer:refresh_nodes(projects)
Iterator.builder({ self })
:applier(function(n)
if n.nodes then
local toplevel = git.get_toplevel(n.cwd or n.link_to or n.absolute_path)
self:reload(n, projects[toplevel] or {})
end
end)
:recursor(function(n)
return n.group_next and { n.group_next } or (n.open and n.nodes)
end)
:iterate()
end
local event_running = false
function Explorer:reload_explorer()
if event_running or vim.v.exiting ~= vim.NIL then
return
end
event_running = true
local projects = git.reload()
self:refresh_nodes(projects)
if view.is_visible() then
renderer.draw()
end
event_running = false
end
function Explorer:reload_git()
if not git.config.git.enable or event_running then
return
end
event_running = true
local projects = git.reload()
explorer_node.reload_node_status(self, projects)
renderer.draw()
event_running = false
end
function Explorer.setup(opts)
config = opts
require("nvim-tree.explorer.node").setup(opts)
require("nvim-tree.explorer.watch").setup(opts)
renderer = require "nvim-tree.renderer"
Marks = require "nvim-tree.marks"
Clipboard = require "nvim-tree.actions.fs.clipboard"
end
return Explorer

View File

@ -1,3 +1,5 @@
local git = {} -- circular dependencies
local M = {}
---@class GitStatus
@ -122,6 +124,23 @@ function M.get_git_status(node)
end
end
---@param parent_node Node|nil
---@param projects table
function M.reload_node_status(parent_node, projects)
if parent_node == nil then
return
end
local toplevel = git.get_toplevel(parent_node.absolute_path)
local status = projects[toplevel] or {}
for _, node in ipairs(parent_node.nodes) do
M.update_git_status(node, M.is_git_ignored(parent_node), status)
if node.nodes and #node.nodes > 0 then
M.reload_node_status(node, projects)
end
end
end
---@param node Node
---@return boolean
function M.is_git_ignored(node)
@ -157,6 +176,8 @@ function M.setup(opts)
M.config = {
git = opts.git,
}
git = require "nvim-tree.git"
end
return M

View File

@ -38,7 +38,7 @@ end
function Marks:clear_reload()
self:clear()
if not self.config.filesystem_watchers.enable then
require("nvim-tree.actions.reloaders").reload_explorer()
self.explorer:reload_explorer()
end
end