Skip to content

refactor(filesystem): fix recursive expand of nodes #957

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jul 8, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lua/neo-tree/git/ignored.lua
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ M.mark_ignored = function(state, items, callback)
on_exit = function(self, code, _)
local result
if code ~= 0 then
log.debug("Failed to load ignored files for", state.path, ":", self:stderr_result())
log.debug("Failed to load ignored files for", folder, ":", self:stderr_result())
result = {}
else
result = self:result()
Expand Down
46 changes: 18 additions & 28 deletions lua/neo-tree/sources/common/commands.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

local vim = vim
local fs_actions = require("neo-tree.sources.filesystem.lib.fs_actions")
local fs = require("neo-tree.sources.filesystem")
local utils = require("neo-tree.utils")
local renderer = require("neo-tree.ui.renderer")
local events = require("neo-tree.events")
Expand All @@ -10,6 +11,7 @@ local popups = require("neo-tree.ui.popups")
local log = require("neo-tree.log")
local help = require("neo-tree.sources.common.help")
local Preview = require("neo-tree.sources.common.preview")
local async = require("plenary.async")

---Gets the node parent folder
---@param state table to look for nodes
Expand Down Expand Up @@ -108,35 +110,23 @@ M.add_directory = function(state, callback)
fs_actions.create_directory(in_directory, callback, using_root_directory)
end

M.expand_all_nodes = function(state, toggle_directory)
if toggle_directory == nil then
toggle_directory = function(_, node)
node:expand()
end
end
--state.explicitly_opened_directories = state.explicitly_opened_directories or {}

local expand_node
expand_node = function(node)
local id = node:get_id()
if node.type == "directory" and not node:is_expanded() then
toggle_directory(state, node)
node = state.tree:get_node(id)
end
local children = state.tree:get_nodes(id)
if children then
for _, child in ipairs(children) do
if child.type == "directory" then
expand_node(child)
end
---Expand all nodes
---@param state table The state of the source
---@param node table A node to expand
M.expand_all_nodes = function(state, node)
log.debug("Expanding all nodes under " .. node:get_id())
local task = function ()
fs.expand_directory(state, node)
end
async.run(
task,
function ()
log.debug("All nodes expanded - redrawing")
vim.schedule_wrap(function()
renderer.redraw(state)
end)
end
end
end

for _, node in ipairs(state.tree:get_nodes()) do
expand_node(node)
end
renderer.redraw(state)
)
end

M.close_node = function(state, callback)
Expand Down
5 changes: 1 addition & 4 deletions lua/neo-tree/sources/filesystem/commands.lua
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,7 @@ M.delete_visual = function(state, selected_nodes)
end

M.expand_all_nodes = function(state)
local toggle_dir_no_redraw = function(_state, node)
fs.toggle_directory(_state, node, nil, true, true)
end
cc.expand_all_nodes(state, toggle_dir_no_redraw)
cc.expand_all_nodes(state, state.tree:get_node(state.path))
end

---Shows the filter input, which will filter the tree.
Expand Down
73 changes: 71 additions & 2 deletions lua/neo-tree/sources/filesystem/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ M.setup = function(config, global_config)
end

---Expands or collapses the current node.
M.toggle_directory = function(state, node, path_to_reveal, skip_redraw, recursive)
M.toggle_directory = function(state, node, path_to_reveal, skip_redraw, recursive, callback)
local tree = state.tree
if not node then
node = tree:get_node()
Expand All @@ -406,7 +406,7 @@ M.toggle_directory = function(state, node, path_to_reveal, skip_redraw, recursiv
local id = node:get_id()
state.explicitly_opened_directories[id] = true
renderer.position.set(state, nil)
fs_scan.get_items(state, id, path_to_reveal, nil, false, recursive)
fs_scan.get_items(state, id, path_to_reveal, callback, false, recursive)
elseif node:has_children() then
local updated = false
if node:is_expanded() then
Expand All @@ -428,4 +428,73 @@ M.toggle_directory = function(state, node, path_to_reveal, skip_redraw, recursiv
end
end

--- Recursively expand all loaded nodes under the given node
--- returns table with all discovered nodes that need to be loaded
---@param node table a node to expand
---@param state table current state of the source
---@return table discovered nodes that need to be loaded
local function expand_loaded(node, state)
local function rec(_node, to_load)
if _node.loaded == false then
table.insert(to_load, _node)
else
if not _node:is_expanded() then
_node:expand()
state.explicitly_opened_directories[_node:get_id()] = true
end
local children = state.tree:get_nodes(_node:get_id())
log.debug("Expanding childrens of " .. _node:get_id())
for _, child in ipairs(children) do
if child.type == "directory" then
rec(child, to_load)
else
log.trace("Child: " .. child.name .. " is not a directory, skipping")
end
end
end
end

local to_load = {}
rec(node, to_load)
return to_load
end

--- Recursively expands all nodes under the given node
--- loading nodes if necessary.
--- async method
---@param node table a node to expand
---@param state table current state of the source
local function expand_and_load(node, state)
local function rec(to_load, progress)
local to_load_current = expand_loaded(node, state)
for _,v in ipairs(to_load_current) do
table.insert(to_load, v)
end
if progress <= #to_load then
M.expand_directory(state, to_load[progress])
rec(to_load, progress + 1)
end
end
rec({}, 1)
end

---Expands given node recursively loading all descendant nodes if needed
---async method
---@param state table current state of the source
---@param node table a node to expand
M.expand_directory = function(state, node)
log.debug("Expanding directory " .. node:get_id())
if node.type ~= "directory" then
return
end
state.explicitly_opened_directories = state.explicitly_opened_directories or {}
if node.loaded == false then
local id = node:get_id()
state.explicitly_opened_directories[id] = true
renderer.position.set(state, nil) -- todo should not be called recursively
fs_scan.get_dir_items_async(state, id, true)
end
expand_and_load(node, state)
end

return M
Loading