From 71c519b5585003004bc53fd4e39ef9476adb3d0c Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 9 Sep 2024 16:25:37 +1000 Subject: [PATCH 01/44] refactor(#2875): multi instance renderer --- lua/nvim-tree/actions/reloaders.lua | 73 +++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 lua/nvim-tree/actions/reloaders.lua diff --git a/lua/nvim-tree/actions/reloaders.lua b/lua/nvim-tree/actions/reloaders.lua new file mode 100644 index 00000000000..bec976d9c67 --- /dev/null +++ b/lua/nvim-tree/actions/reloaders.lua @@ -0,0 +1,73 @@ +local git = require "nvim-tree.git" +local view = require "nvim-tree.view" +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() + local explorer = core.get_explorer() + if event_running or not explorer or vim.v.exiting ~= vim.NIL then + return + end + event_running = true + + local projects = git.reload() + refresh_nodes(explorer, projects) + if view.is_visible() then + explorer.renderer:draw() + end + event_running = false +end + +function M.reload_git() + local explorer = core.get_explorer() + if not explorer or not git.config.git.enable or event_running then + return + end + event_running = true + + local projects = git.reload() + M.reload_node_status(explorer, projects) + explorer.renderer:draw() + event_running = false +end + +return M From 760b1bc4961d96a207c13210c52baec74954e446 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 14 Sep 2024 15:48:24 +1000 Subject: [PATCH 02/44] refactor(#2875): multi instance renderer --- lua/nvim-tree/actions/reloaders.lua | 73 ----------------------------- 1 file changed, 73 deletions(-) delete mode 100644 lua/nvim-tree/actions/reloaders.lua diff --git a/lua/nvim-tree/actions/reloaders.lua b/lua/nvim-tree/actions/reloaders.lua deleted file mode 100644 index bec976d9c67..00000000000 --- a/lua/nvim-tree/actions/reloaders.lua +++ /dev/null @@ -1,73 +0,0 @@ -local git = require "nvim-tree.git" -local view = require "nvim-tree.view" -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() - local explorer = core.get_explorer() - if event_running or not explorer or vim.v.exiting ~= vim.NIL then - return - end - event_running = true - - local projects = git.reload() - refresh_nodes(explorer, projects) - if view.is_visible() then - explorer.renderer:draw() - end - event_running = false -end - -function M.reload_git() - local explorer = core.get_explorer() - if not explorer or not git.config.git.enable or event_running then - return - end - event_running = true - - local projects = git.reload() - M.reload_node_status(explorer, projects) - explorer.renderer:draw() - event_running = false -end - -return M From 2ce5f69fd6afe2963b441c57d7fa1495d0af9deb Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 14 Sep 2024 16:10:31 +1000 Subject: [PATCH 03/44] refactor(#2875): multi instance renderer From 15e65eadb5a606439beb4c7676d09cebfa12be37 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 15 Sep 2024 13:04:01 +1000 Subject: [PATCH 04/44] refactor(#2875): multi instance renderer From 646ce63426be9093712435fa285b68de8724d6ca Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 15 Sep 2024 16:54:08 +1000 Subject: [PATCH 05/44] node classes and constructors --- lua/nvim-tree/actions/fs/create-file.lua | 27 +++++------ lua/nvim-tree/enum.lua | 8 ++++ lua/nvim-tree/explorer/init.lua | 21 +++++---- lua/nvim-tree/node.lua | 36 -------------- lua/nvim-tree/node/directory.lua | 46 ++++++++++++++++++ lua/nvim-tree/node/file.lua | 34 ++++++++++++++ lua/nvim-tree/node/init.lua | 31 ++++++++++++ lua/nvim-tree/node/link.lua | 60 ++++++++++++++++++++++++ lua/nvim-tree/utils.lua | 12 +++++ 9 files changed, 216 insertions(+), 59 deletions(-) delete mode 100644 lua/nvim-tree/node.lua create mode 100644 lua/nvim-tree/node/directory.lua create mode 100644 lua/nvim-tree/node/file.lua create mode 100644 lua/nvim-tree/node/init.lua create mode 100644 lua/nvim-tree/node/link.lua diff --git a/lua/nvim-tree/actions/fs/create-file.lua b/lua/nvim-tree/actions/fs/create-file.lua index dbd1bc7e99c..9b285b7cbf4 100644 --- a/lua/nvim-tree/actions/fs/create-file.lua +++ b/lua/nvim-tree/actions/fs/create-file.lua @@ -30,14 +30,16 @@ local function get_num_nodes(iter) return i end ----@param node Node +---@param has_children boolean +---@param absolute_path string +---@param name string ---@return string -local function get_containing_folder(node) - if node.nodes ~= nil then - return utils.path_add_trailing(node.absolute_path) +local function get_containing_folder(has_children, absolute_path, name) + if has_children then + return utils.path_add_trailing(absolute_path) end - local node_name_size = #(node.name or "") - return node.absolute_path:sub(0, -node_name_size - 1) + local node_name_size = #(name or "") + return absolute_path:sub(0, -node_name_size - 1) end ---@param node Node|nil @@ -48,17 +50,14 @@ function M.fn(node) end node = node and lib.get_last_group_node(node) + + local containing_folder if not node or node.name == ".." then - node = { - absolute_path = cwd, - name = "", - nodes = core.get_explorer().nodes, - open = true, - } + containing_folder = get_containing_folder(core.get_explorer().nodes ~= nil, cwd, "") + else + containing_folder = get_containing_folder(node.nodes ~= nil, node.absolute_path, node.name) end - local containing_folder = get_containing_folder(node) - local input_opts = { prompt = "Create file ", default = containing_folder, diff --git a/lua/nvim-tree/enum.lua b/lua/nvim-tree/enum.lua index 9c50bc27638..740fa04a5ea 100644 --- a/lua/nvim-tree/enum.lua +++ b/lua/nvim-tree/enum.lua @@ -1,5 +1,13 @@ local M = {} +---Roughly synced with uv.fs_stat.result +---@enum (key) NODE_TYPE +M.NODE_TYPE = { + directory = 1, + file = 2, + link = 4, +} + ---Setup options for "highlight_*" ---@enum HL_POSITION M.HL_POSITION = { diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index 6ae149b6d86..014ab123f13 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -1,4 +1,3 @@ -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") @@ -7,9 +6,13 @@ local view = require("nvim-tree.view") local watch = require("nvim-tree.explorer.watch") local explorer_node = require("nvim-tree.explorer.node") +local DirectoryNode = require("nvim-tree.node.directory") +local FileNode = require("nvim-tree.node.file") +local LinkNode = require("nvim-tree.node.link") +local Watcher = require("nvim-tree.watcher") + local Iterator = require("nvim-tree.iterators.node-iterator") local NodeIterator = require("nvim-tree.iterators.node-iterator") -local Watcher = require("nvim-tree.watcher") local Filters = require("nvim-tree.explorer.filters") local Marks = require("nvim-tree.marks") @@ -155,11 +158,11 @@ function Explorer:reload(node, git_status) if not nodes_by_path[abs] then local new_child = nil if t == "directory" and vim.loop.fs_access(abs, "R") and Watcher.is_fs_event_capable(abs) then - new_child = builders.folder(node, abs, name, stat) + new_child = DirectoryNode:new(self, node, abs, name, stat) elseif t == "file" then - new_child = builders.file(node, abs, name, stat) + new_child = FileNode:new(self, node, abs, name, stat) elseif t == "link" then - local link = builders.link(node, abs, name, stat) + local link = LinkNode:new(self, node, abs, name, stat) if link.link_to ~= nil then new_child = link end @@ -171,7 +174,7 @@ function Explorer:reload(node, git_status) else local n = nodes_by_path[abs] if n then - n.executable = builders.is_executable(abs) or false + n.executable = utils.is_executable(abs) or false n.fs_stat = stat end end @@ -372,11 +375,11 @@ function Explorer:populate_children(handle, cwd, node, git_status, parent) local t = stat and stat.type or nil local child = nil if t == "directory" and vim.loop.fs_access(abs, "R") then - child = builders.folder(node, abs, name, stat) + child = DirectoryNode:new(self, node, abs, name, stat) elseif t == "file" then - child = builders.file(node, abs, name, stat) + child = FileNode:new(self, node, abs, name, stat) elseif t == "link" then - local link = builders.link(node, abs, name, stat) + local link = LinkNode:new(self, node, abs, name, stat) if link.link_to ~= nil then child = link end diff --git a/lua/nvim-tree/node.lua b/lua/nvim-tree/node.lua deleted file mode 100644 index cf8aa671c39..00000000000 --- a/lua/nvim-tree/node.lua +++ /dev/null @@ -1,36 +0,0 @@ ----@meta - ----@class ParentNode ----@field name string - ----@class BaseNode ----@field absolute_path string ----@field executable boolean ----@field fs_stat uv.fs_stat.result|nil ----@field git_status GitStatus|nil ----@field hidden boolean ----@field is_dot boolean ----@field name string ----@field parent DirNode ----@field type string ----@field watcher function|nil ----@field diag_status DiagStatus|nil - ----@class DirNode: BaseNode ----@field has_children boolean ----@field group_next Node|nil ----@field nodes Node[] ----@field open boolean ----@field hidden_stats table -- Each field of this table is a key for source and value for count - ----@class FileNode: BaseNode ----@field extension string - ----@class SymlinkDirNode: DirNode ----@field link_to string - ----@class SymlinkFileNode: FileNode ----@field link_to string - ----@alias SymlinkNode SymlinkDirNode|SymlinkFileNode ----@alias Node ParentNode|DirNode|FileNode|SymlinkNode|Explorer diff --git a/lua/nvim-tree/node/directory.lua b/lua/nvim-tree/node/directory.lua new file mode 100644 index 00000000000..f759a5275e8 --- /dev/null +++ b/lua/nvim-tree/node/directory.lua @@ -0,0 +1,46 @@ +local watch = require("nvim-tree.explorer.watch") + +local BaseNode = require("nvim-tree.node.init") + +---@class (exact) DirectoryNode: BaseNode +---@field has_children boolean +---@field group_next Node|nil +---@field nodes Node[] +---@field open boolean +---@field hidden_stats table -- Each field of this table is a key for source and value for count +local DirectoryNode = BaseNode:new() + +---@param explorer Explorer +-----@param parent DirectoryNode -- TODO +---@param absolute_path string +---@param name string +---@param fs_stat uv.fs_stat.result|nil +---@return DirectoryNode +function DirectoryNode:new(explorer, parent, absolute_path, name, fs_stat) + local handle = vim.loop.fs_scandir(absolute_path) + local has_children = handle and vim.loop.fs_scandir_next(handle) ~= nil + + local o = BaseNode.new(self, { + type = "directory", + explorer = explorer, + absolute_path = absolute_path, + executable = false, + fs_stat = fs_stat, + hidden = false, + is_dot = false, + name = name, + parent = parent, + + has_children = has_children, + group_next = nil, -- If node is grouped, this points to the next child dir/link node + nodes = {}, + open = false, + }) + ---@cast o DirectoryNode + + o.watcher = watch.create_watcher(o) + + return o +end + +return DirectoryNode diff --git a/lua/nvim-tree/node/file.lua b/lua/nvim-tree/node/file.lua new file mode 100644 index 00000000000..e5793a5c10a --- /dev/null +++ b/lua/nvim-tree/node/file.lua @@ -0,0 +1,34 @@ +local utils = require("nvim-tree.utils") + +local BaseNode = require("nvim-tree.node.init") + +---@class (exact) FileNode: BaseNode +---@field extension string +local FileNode = BaseNode:new() + +---@param explorer Explorer +-----@param parent DirectoryNode -- TODO +---@param absolute_path string +---@param name string +---@param fs_stat uv.fs_stat.result|nil +---@return FileNode +function FileNode:new(explorer, parent, absolute_path, name, fs_stat) + local o = BaseNode.new(self, { + type = "file", + explorer = explorer, + absolute_path = absolute_path, + executable = utils.is_executable(absolute_path), + fs_stat = fs_stat, + name = name, + parent = parent, + hidden = false, + is_dot = false, + + extension = string.match(name, ".?[^.]+%.(.*)") or "", + }) + ---@cast o FileNode + + return o +end + +return FileNode diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua new file mode 100644 index 00000000000..ea599f5d569 --- /dev/null +++ b/lua/nvim-tree/node/init.lua @@ -0,0 +1,31 @@ +---@class ParentNode +---@field name string + +---@class (exact) BaseNode +---@field type NODE_TYPE +---@field explorer Explorer +---@field absolute_path string +---@field executable boolean +---@field fs_stat uv.fs_stat.result|nil +---@field git_status GitStatus|nil +---@field hidden boolean +---@field is_dot boolean +---@field name string +---@field parent DirectoryNode +---@field watcher Watcher|nil +---@field diag_status DiagStatus|nil +local BaseNode = {} + +---@alias Node DirectoryNode|FileNode|LinkNode|Explorer + +---@param o BaseNode|nil +---@return BaseNode +function BaseNode:new(o) + o = o or {} + + setmetatable(o, { __index = self }) + + return o +end + +return BaseNode diff --git a/lua/nvim-tree/node/link.lua b/lua/nvim-tree/node/link.lua new file mode 100644 index 00000000000..d26d845476e --- /dev/null +++ b/lua/nvim-tree/node/link.lua @@ -0,0 +1,60 @@ +local watch = require("nvim-tree.explorer.watch") + +local BaseNode = require("nvim-tree.node.init") + +---@class (exact) LinkNode: BaseNode +---@field link_to string absolute path +local LinkNode = BaseNode:new() + +---@param explorer Explorer +-----@param parent DirectoryNode -- TODO +---@param absolute_path string +---@param name string +---@param fs_stat uv.fs_stat.result|nil +---@return LinkNode +function LinkNode:new(explorer, parent, absolute_path, name, fs_stat) + local link_to = vim.loop.fs_realpath(absolute_path) + local open, nodes, has_children + + -- TODO-INFO: sometimes fs_realpath returns nil + -- I expect this be a bug in glibc, because it fails to retrieve the path for some + -- links (for instance libr2.so in /usr/lib) and thus even with a C program realpath fails + -- when it has no real reason to. Maybe there is a reason, but errno is definitely wrong. + -- So we need to check for link_to ~= nil when adding new links to the main tree + local is_dir_link = (link_to ~= nil) and vim.loop.fs_stat(link_to).type == "directory" + + if is_dir_link and link_to then + local handle = vim.loop.fs_scandir(link_to) + has_children = handle and vim.loop.fs_scandir_next(handle) ~= nil + open = false + nodes = {} + end + + local o = BaseNode.new(self, { + type = "link", + explorer = explorer, + absolute_path = absolute_path, + executable = false, + fs_stat = fs_stat, + hidden = false, + is_dot = false, + name = name, + parent = parent, + + link_to = link_to, + + has_children = has_children, + group_next = nil, -- If node is grouped, this points to the next child dir/link node + nodes = nodes, + open = open, + }) + ---@cast o LinkNode + + if is_dir_link then + o.watcher = watch.create_watcher(o) + end + + return o +end + +return LinkNode diff --git a/lua/nvim-tree/utils.lua b/lua/nvim-tree/utils.lua index 0c341c9ea14..722d60db37e 100644 --- a/lua/nvim-tree/utils.lua +++ b/lua/nvim-tree/utils.lua @@ -578,4 +578,16 @@ function M.is_nvim_tree_buf(bufnr) return false end +--- path is an executable file or directory +---@param absolute_path string +---@return boolean +function M.is_executable(absolute_path) + if M.is_windows or M.is_wsl then + --- executable detection on windows is buggy and not performant hence it is disabled + return false + else + return vim.loop.fs_access(absolute_path, "X") or false + end +end + return M From 9193ec9cca0a20af77630cce949bfbce333fa934 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 15 Sep 2024 17:32:43 +1000 Subject: [PATCH 06/44] node methods --- lua/nvim-tree/explorer/init.lua | 21 ++++++------- lua/nvim-tree/explorer/node.lua | 25 ---------------- lua/nvim-tree/git/init.lua | 2 +- lua/nvim-tree/lib.lua | 3 +- lua/nvim-tree/node/directory.lua | 2 +- lua/nvim-tree/node/file.lua | 2 +- lua/nvim-tree/node/init.lua | 33 +++++++++++++++++++-- lua/nvim-tree/node/link.lua | 2 +- lua/nvim-tree/renderer/decorator/hidden.lua | 5 ++-- 9 files changed, 48 insertions(+), 47 deletions(-) diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index 014ab123f13..07c136dffbb 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -6,6 +6,7 @@ local view = require("nvim-tree.view") local watch = require("nvim-tree.explorer.watch") local explorer_node = require("nvim-tree.explorer.node") +local BaseNode = require("nvim-tree.node") local DirectoryNode = require("nvim-tree.node.directory") local FileNode = require("nvim-tree.node.file") local LinkNode = require("nvim-tree.node.link") @@ -25,7 +26,7 @@ local FILTER_REASON = require("nvim-tree.enum").FILTER_REASON local config ----@class Explorer +---@class Explorer: BaseNode ---@field opts table user options ---@field absolute_path string ---@field nodes Node[] @@ -37,7 +38,7 @@ local config ---@field sorters Sorter ---@field marks Marks ---@field clipboard Clipboard -local Explorer = {} +local Explorer = BaseNode:new() ---@param path string|nil ---@return Explorer|nil @@ -84,7 +85,7 @@ end function Explorer:destroy() local function iterate(node) - explorer_node.node_destroy(node) + node:destroy() if node.nodes then for _, child in pairs(node.nodes) do iterate(child) @@ -114,7 +115,7 @@ function Explorer:reload(node, git_status) local remain_childs = {} - local node_ignored = explorer_node.is_git_ignored(node) + local node_ignored = node:is_git_ignored() ---@type table local nodes_by_path = utils.key_by(node.nodes, "absolute_path") @@ -150,7 +151,7 @@ function Explorer:reload(node, git_status) if n.type ~= t then utils.array_remove(node.nodes, n) - explorer_node.node_destroy(n) + n:destroy() nodes_by_path[abs] = nil end end @@ -193,14 +194,14 @@ function Explorer:reload(node, git_status) if remain_childs[n.absolute_path] then return remain_childs[n.absolute_path] else - explorer_node.node_destroy(n) + n:destroy() return false end end, node.nodes) ) local is_root = not node.parent - local child_folder_only = explorer_node.has_one_child_folder(node) and node.nodes[1] + local child_folder_only = node:has_one_child_folder() and node.nodes[1] if config.renderer.group_empty and not is_root and child_folder_only then node.group_next = child_folder_only local ns = self:reload(child_folder_only, git_status) @@ -329,7 +330,7 @@ function Explorer:update_parent_statuses(node, project, root) end -- update status - explorer_node.update_git_status(node, explorer_node.is_git_ignored(node.parent), project) + explorer_node.update_git_status(node, node.parent and node.parent:is_git_ignored(), project) -- maybe parent node = node.parent @@ -343,7 +344,7 @@ end ---@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 node_ignored = node:is_git_ignored() local nodes_by_path = utils.bool_record(node.nodes, "absolute_path") local filter_status = parent.filters:prepare(git_status) @@ -419,7 +420,7 @@ function Explorer:explore(node, status, parent) 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] + local child_folder_only = node:has_one_child_folder() 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) diff --git a/lua/nvim-tree/explorer/node.lua b/lua/nvim-tree/explorer/node.lua index 27e31b131c5..41a9a503ef7 100644 --- a/lua/nvim-tree/explorer/node.lua +++ b/lua/nvim-tree/explorer/node.lua @@ -35,12 +35,6 @@ local function get_git_status(parent_ignored, status, absolute_path) return { file = file_status } end ----@param node Node ----@return boolean -function M.has_one_child_folder(node) - return #node.nodes == 1 and node.nodes[1].nodes and vim.loop.fs_access(node.nodes[1].absolute_path, "R") or false -end - ---@param node Node ---@param parent_ignored boolean ---@param status table|nil @@ -141,25 +135,6 @@ function M.reload_node_status(parent_node, projects) end end ----@param node Node ----@return boolean -function M.is_git_ignored(node) - return node and node.git_status ~= nil and node.git_status.file == "!!" -end - ----@param node Node ----@return boolean -function M.is_dotfile(node) - if node == nil then - return false - end - if node.is_dot or (node.name and (node.name:sub(1, 1) == ".")) or M.is_dotfile(node.parent) then - node.is_dot = true - return true - end - return false -end - ---@param node Node function M.node_destroy(node) if not node then diff --git a/lua/nvim-tree/git/init.lua b/lua/nvim-tree/git/init.lua index caea8517a5e..1c93d45b0f6 100644 --- a/lua/nvim-tree/git/init.lua +++ b/lua/nvim-tree/git/init.lua @@ -208,7 +208,7 @@ local function reload_tree_at(toplevel) Iterator.builder(root_node.nodes) :hidden() :applier(function(node) - local parent_ignored = explorer_node.is_git_ignored(node.parent) + local parent_ignored = node.parent and node.parent:is_git_ignored() explorer_node.update_git_status(node, parent_ignored, git_status) end) :recursor(function(node) diff --git a/lua/nvim-tree/lib.lua b/lua/nvim-tree/lib.lua index 0ad23687da8..d5beec5f828 100644 --- a/lua/nvim-tree/lib.lua +++ b/lua/nvim-tree/lib.lua @@ -3,7 +3,6 @@ local core = require("nvim-tree.core") local utils = require("nvim-tree.utils") local events = require("nvim-tree.events") local notify = require("nvim-tree.notify") -local explorer_node = require("nvim-tree.explorer.node") ---@class LibOpenOpts ---@field path string|nil path @@ -101,7 +100,7 @@ end ---@return Node[] function M.group_empty_folders(node) local is_root = not node.parent - local child_folder_only = explorer_node.has_one_child_folder(node) and node.nodes[1] + local child_folder_only = node:has_one_child_folder() and node.nodes[1] if M.group_empty and not is_root and child_folder_only then node.group_next = child_folder_only local ns = M.group_empty_folders(child_folder_only) diff --git a/lua/nvim-tree/node/directory.lua b/lua/nvim-tree/node/directory.lua index f759a5275e8..d6d3aba38c3 100644 --- a/lua/nvim-tree/node/directory.lua +++ b/lua/nvim-tree/node/directory.lua @@ -1,6 +1,6 @@ local watch = require("nvim-tree.explorer.watch") -local BaseNode = require("nvim-tree.node.init") +local BaseNode = require("nvim-tree.node") ---@class (exact) DirectoryNode: BaseNode ---@field has_children boolean diff --git a/lua/nvim-tree/node/file.lua b/lua/nvim-tree/node/file.lua index e5793a5c10a..de6375b7e5a 100644 --- a/lua/nvim-tree/node/file.lua +++ b/lua/nvim-tree/node/file.lua @@ -1,6 +1,6 @@ local utils = require("nvim-tree.utils") -local BaseNode = require("nvim-tree.node.init") +local BaseNode = require("nvim-tree.node") ---@class (exact) FileNode: BaseNode ---@field extension string diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index ea599f5d569..6b7db4cbe4e 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -1,6 +1,3 @@ ----@class ParentNode ----@field name string - ---@class (exact) BaseNode ---@field type NODE_TYPE ---@field explorer Explorer @@ -28,4 +25,34 @@ function BaseNode:new(o) return o end +function BaseNode:destroy() + if self.watcher then + self.watcher:destroy() + self.watcher = nil + end +end + +---@return boolean +function BaseNode:has_one_child_folder() + return #self.nodes == 1 and self.nodes[1].nodes and vim.loop.fs_access(self.nodes[1].absolute_path, "R") or false +end + +---@return boolean +function BaseNode:is_git_ignored() + return self.git_status ~= nil and self.git_status.file == "!!" +end + +---@return boolean +function BaseNode:is_dotfile() + if + self.is_dot -- + or (self.name and (self.name:sub(1, 1) == ".")) -- + or (self.parent and self.parent:is_dotfile()) + then + self.is_dot = true + return true + end + return false +end + return BaseNode diff --git a/lua/nvim-tree/node/link.lua b/lua/nvim-tree/node/link.lua index d26d845476e..a7d35265488 100644 --- a/lua/nvim-tree/node/link.lua +++ b/lua/nvim-tree/node/link.lua @@ -1,6 +1,6 @@ local watch = require("nvim-tree.explorer.watch") -local BaseNode = require("nvim-tree.node.init") +local BaseNode = require("nvim-tree.node") ---@class (exact) LinkNode: BaseNode ---@field link_to string absolute path diff --git a/lua/nvim-tree/renderer/decorator/hidden.lua b/lua/nvim-tree/renderer/decorator/hidden.lua index d6c125ae117..7ce4d457be1 100644 --- a/lua/nvim-tree/renderer/decorator/hidden.lua +++ b/lua/nvim-tree/renderer/decorator/hidden.lua @@ -1,6 +1,5 @@ local HL_POSITION = require("nvim-tree.enum").HL_POSITION local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT -local explorer_node = require("nvim-tree.explorer.node") local Decorator = require("nvim-tree.renderer.decorator") ---@class (exact) DecoratorHidden: Decorator @@ -34,7 +33,7 @@ end ---@param node Node ---@return HighlightedString[]|nil icons function DecoratorHidden:calculate_icons(node) - if self.enabled and explorer_node.is_dotfile(node) then + if self.enabled and node:is_dotfile() then return { self.icon } end end @@ -43,7 +42,7 @@ end ---@param node Node ---@return string|nil group function DecoratorHidden:calculate_highlight(node) - if not self.enabled or self.hl_pos == HL_POSITION.none or (not explorer_node.is_dotfile(node)) then + if not self.enabled or self.hl_pos == HL_POSITION.none or not node:is_dotfile() then return nil end From d3946a16bab43f0202767313fc0d8de365d832aa Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 16 Sep 2024 14:06:14 +1000 Subject: [PATCH 07/44] refactor(#2875): multi instance renderer From 69663ff9efe4a01bd1bb4ba389fd9ac2918dc399 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 16 Sep 2024 14:48:47 +1000 Subject: [PATCH 08/44] node classes and constructors --- lua/nvim-tree/actions/moves/sibling.lua | 2 +- lua/nvim-tree/explorer/init.lua | 32 ++++++++++++++++--------- lua/nvim-tree/git/init.lua | 2 +- lua/nvim-tree/node/directory.lua | 2 +- lua/nvim-tree/node/file.lua | 2 +- lua/nvim-tree/node/init.lua | 8 ++++--- lua/nvim-tree/node/link.lua | 2 +- lua/nvim-tree/utils.lua | 2 +- 8 files changed, 32 insertions(+), 20 deletions(-) diff --git a/lua/nvim-tree/actions/moves/sibling.lua b/lua/nvim-tree/actions/moves/sibling.lua index afab9ef3efa..cf5b492d387 100644 --- a/lua/nvim-tree/actions/moves/sibling.lua +++ b/lua/nvim-tree/actions/moves/sibling.lua @@ -15,7 +15,7 @@ function M.fn(direction) local first, last, next, prev = nil, nil, nil, nil local found = false local parent = node.parent or core.get_explorer() - Iterator.builder(parent.nodes) + Iterator.builder(parent and parent.nodes or {}) :recursor(function() return nil end) diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index 07c136dffbb..f746bbd87f7 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -55,17 +55,27 @@ function Explorer:new(path) return end - local o = { - opts = config, + ---@type Explorer + local placeholder + + local o = BaseNode.new(self, { + type = "directory", + explorer = placeholder, absolute_path = path, + executable = false, + hidden = false, + is_dot = false, + + has_children = false, + group_next = nil, nodes = {}, open = true, - sorters = Sorters:new(config), - } - - setmetatable(o, self) - self.__index = self + }) + ---@cast o Explorer + o.explorer = self + o.opts = config + o.sorters = Sorters:new(config) o.watcher = watch.create_watcher(o) o.renderer = Renderer:new(config, o) o.filters = Filters:new(config, o) @@ -216,7 +226,7 @@ function Explorer:reload(node, git_status) return node.nodes end ----TODO #2837 #2871 move this and similar to node +---TODO #2837 #2871 #2886 move this and similar to node ---Refresh contents and git status for a single node ---@param node Node ---@param callback function @@ -291,7 +301,7 @@ function Explorer:update_status(nodes_by_path, node_ignored, status) end end ----TODO #2837 #2871 move this and similar to node +---TODO #2837 #2871 #2886 move this and similar to node ---@private ---@param path string ---@param callback fun(toplevel: string|nil, project: table|nil) @@ -303,7 +313,7 @@ function Explorer:reload_and_get_git_project(path, callback) end) end ----TODO #2837 #2871 move this and similar to node +---TODO #2837 #2871 #2886 move this and similar to node ---@private ---@param node Node ---@param project table|nil @@ -330,7 +340,7 @@ function Explorer:update_parent_statuses(node, project, root) end -- update status - explorer_node.update_git_status(node, node.parent and node.parent:is_git_ignored(), project) + explorer_node.update_git_status(node, node.parent and node.parent:is_git_ignored() or false, project) -- maybe parent node = node.parent diff --git a/lua/nvim-tree/git/init.lua b/lua/nvim-tree/git/init.lua index 1c93d45b0f6..9a68da8e7fe 100644 --- a/lua/nvim-tree/git/init.lua +++ b/lua/nvim-tree/git/init.lua @@ -208,7 +208,7 @@ local function reload_tree_at(toplevel) Iterator.builder(root_node.nodes) :hidden() :applier(function(node) - local parent_ignored = node.parent and node.parent:is_git_ignored() + local parent_ignored = node.parent and node.parent:is_git_ignored() or false explorer_node.update_git_status(node, parent_ignored, git_status) end) :recursor(function(node) diff --git a/lua/nvim-tree/node/directory.lua b/lua/nvim-tree/node/directory.lua index d6d3aba38c3..31da13446f5 100644 --- a/lua/nvim-tree/node/directory.lua +++ b/lua/nvim-tree/node/directory.lua @@ -11,7 +11,7 @@ local BaseNode = require("nvim-tree.node") local DirectoryNode = BaseNode:new() ---@param explorer Explorer ------@param parent DirectoryNode -- TODO +-----@param parent DirectoryNode -- TODO #2871 #2886 ---@param absolute_path string ---@param name string ---@param fs_stat uv.fs_stat.result|nil diff --git a/lua/nvim-tree/node/file.lua b/lua/nvim-tree/node/file.lua index de6375b7e5a..014cd1ff92f 100644 --- a/lua/nvim-tree/node/file.lua +++ b/lua/nvim-tree/node/file.lua @@ -7,7 +7,7 @@ local BaseNode = require("nvim-tree.node") local FileNode = BaseNode:new() ---@param explorer Explorer ------@param parent DirectoryNode -- TODO +-----@param parent DirectoryNode -- TODO #2871 #2886 ---@param absolute_path string ---@param name string ---@param fs_stat uv.fs_stat.result|nil diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index 6b7db4cbe4e..88fb09c60ae 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -1,4 +1,5 @@ ---@class (exact) BaseNode +---@field private __index? table ---@field type NODE_TYPE ---@field explorer Explorer ---@field absolute_path string @@ -7,8 +8,8 @@ ---@field git_status GitStatus|nil ---@field hidden boolean ---@field is_dot boolean ----@field name string ----@field parent DirectoryNode +---@field name string|nil +---@field parent DirectoryNode|nil ---@field watcher Watcher|nil ---@field diag_status DiagStatus|nil local BaseNode = {} @@ -20,7 +21,8 @@ local BaseNode = {} function BaseNode:new(o) o = o or {} - setmetatable(o, { __index = self }) + setmetatable(o, self) + self.__index = self return o end diff --git a/lua/nvim-tree/node/link.lua b/lua/nvim-tree/node/link.lua index a7d35265488..13828b2ac0d 100644 --- a/lua/nvim-tree/node/link.lua +++ b/lua/nvim-tree/node/link.lua @@ -7,7 +7,7 @@ local BaseNode = require("nvim-tree.node") local LinkNode = BaseNode:new() ---@param explorer Explorer ------@param parent DirectoryNode -- TODO +-----@param parent DirectoryNode -- TODO #2871 #2886 ---@param absolute_path string ---@param name string ---@param fs_stat uv.fs_stat.result|nil diff --git a/lua/nvim-tree/utils.lua b/lua/nvim-tree/utils.lua index 722d60db37e..2a704872a79 100644 --- a/lua/nvim-tree/utils.lua +++ b/lua/nvim-tree/utils.lua @@ -179,7 +179,7 @@ end ---@return Node node or parent function M.get_parent_of_group(node) while node and node.parent and node.parent.group_next do - node = node.parent + node = node.parent or node end return node end From 5ae0a90802ca5d5c2d62d41fa690e52ee474792c Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 16 Sep 2024 17:24:27 +1000 Subject: [PATCH 09/44] explorer is a directory node --- lua/nvim-tree.lua | 2 +- lua/nvim-tree/explorer/init.lua | 32 ++++++++------------------------ lua/nvim-tree/node/directory.lua | 8 ++++---- lua/nvim-tree/node/init.lua | 2 +- lua/nvim-tree/node/link.lua | 4 +++- 5 files changed, 17 insertions(+), 31 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 4bca0dce450..c202d71ddc1 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -849,7 +849,7 @@ function M.setup(conf) require("nvim-tree.keymap").setup(opts) require("nvim-tree.appearance").setup() require("nvim-tree.diagnostics").setup(opts) - require("nvim-tree.explorer").setup(opts) + require("nvim-tree.explorer"):setup(opts) require("nvim-tree.git").setup(opts) require("nvim-tree.git.utils").setup(opts) require("nvim-tree.view").setup(opts) diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index f746bbd87f7..5e869f09e7e 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -3,7 +3,6 @@ local log = require("nvim-tree.log") local notify = require("nvim-tree.notify") 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 BaseNode = require("nvim-tree.node") @@ -26,19 +25,15 @@ local FILTER_REASON = require("nvim-tree.enum").FILTER_REASON local config ----@class Explorer: BaseNode +---@class (exact) Explorer: DirectoryNode ---@field opts table user options ----@field absolute_path string ----@field nodes Node[] ----@field open boolean ----@field watcher Watcher|nil ---@field renderer Renderer ---@field filters Filters ---@field live_filter LiveFilter ---@field sorters Sorter ---@field marks Marks ---@field clipboard Clipboard -local Explorer = BaseNode:new() +local Explorer = BaseNode.new(DirectoryNode) -- TODO do not inherit, add a root node to separate Explorer and Node ---@param path string|nil ---@return Explorer|nil @@ -56,27 +51,16 @@ function Explorer:new(path) end ---@type Explorer - local placeholder - - local o = BaseNode.new(self, { - type = "directory", - explorer = placeholder, - absolute_path = path, - executable = false, - hidden = false, - is_dot = false, - - has_children = false, - group_next = nil, - nodes = {}, - open = true, - }) + local placeholder = nil + + local o = DirectoryNode.new(self, placeholder, nil, path, nil, nil) ---@cast o Explorer o.explorer = self + o.open = true + o.opts = config o.sorters = Sorters:new(config) - o.watcher = watch.create_watcher(o) o.renderer = Renderer:new(config, o) o.filters = Filters:new(config, o) o.live_filter = LiveFilter:new(config, o) @@ -492,7 +476,7 @@ function Explorer:reload_git() event_running = false end -function Explorer.setup(opts) +function Explorer:setup(opts) config = opts require("nvim-tree.explorer.node").setup(opts) require("nvim-tree.explorer.watch").setup(opts) diff --git a/lua/nvim-tree/node/directory.lua b/lua/nvim-tree/node/directory.lua index 31da13446f5..9d6e47e19db 100644 --- a/lua/nvim-tree/node/directory.lua +++ b/lua/nvim-tree/node/directory.lua @@ -3,8 +3,8 @@ local watch = require("nvim-tree.explorer.watch") local BaseNode = require("nvim-tree.node") ---@class (exact) DirectoryNode: BaseNode ----@field has_children boolean ----@field group_next Node|nil +---@field has_children boolean -- TODO remove this and just test nodes +---@field group_next Node|nil -- If node is grouped, this points to the next child dir/link node ---@field nodes Node[] ---@field open boolean ---@field hidden_stats table -- Each field of this table is a key for source and value for count @@ -13,7 +13,7 @@ local DirectoryNode = BaseNode:new() ---@param explorer Explorer -----@param parent DirectoryNode -- TODO #2871 #2886 ---@param absolute_path string ----@param name string +---@param name string|nil ---@param fs_stat uv.fs_stat.result|nil ---@return DirectoryNode function DirectoryNode:new(explorer, parent, absolute_path, name, fs_stat) @@ -32,7 +32,7 @@ function DirectoryNode:new(explorer, parent, absolute_path, name, fs_stat) parent = parent, has_children = has_children, - group_next = nil, -- If node is grouped, this points to the next child dir/link node + group_next = nil, nodes = {}, open = false, }) diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index 88fb09c60ae..7022d28faf9 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -14,7 +14,7 @@ ---@field diag_status DiagStatus|nil local BaseNode = {} ----@alias Node DirectoryNode|FileNode|LinkNode|Explorer +---@alias Node DirectoryNode|FileNode|LinkNode ---@param o BaseNode|nil ---@return BaseNode diff --git a/lua/nvim-tree/node/link.lua b/lua/nvim-tree/node/link.lua index 13828b2ac0d..27b9e3ca34f 100644 --- a/lua/nvim-tree/node/link.lua +++ b/lua/nvim-tree/node/link.lua @@ -3,6 +3,8 @@ local watch = require("nvim-tree.explorer.watch") local BaseNode = require("nvim-tree.node") ---@class (exact) LinkNode: BaseNode +---@field has_children boolean -- TODO remove this and just test nodes +---@field group_next Node|nil -- If node is grouped, this points to the next child dir/link node ---@field link_to string absolute path local LinkNode = BaseNode:new() @@ -44,7 +46,7 @@ function LinkNode:new(explorer, parent, absolute_path, name, fs_stat) link_to = link_to, has_children = has_children, - group_next = nil, -- If node is grouped, this points to the next child dir/link node + group_next = nil, nodes = nodes, open = open, }) From 0f222fffc873922aa79b728fa2cc70d5cae312c4 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 16 Sep 2024 17:37:19 +1000 Subject: [PATCH 10/44] extract methods from explore_node --- lua/nvim-tree/explorer/init.lua | 6 ++-- lua/nvim-tree/explorer/node.lua | 55 +-------------------------------- lua/nvim-tree/git/init.lua | 36 +++++++++++++++++++-- lua/nvim-tree/node/init.lua | 21 +++++++++++++ 4 files changed, 59 insertions(+), 59 deletions(-) diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index 5e869f09e7e..8dd7ad8de12 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -279,7 +279,7 @@ end function Explorer:update_status(nodes_by_path, node_ignored, status) return function(node) if nodes_by_path[node.absolute_path] then - explorer_node.update_git_status(node, node_ignored, status) + node:update_git_status(node_ignored, status) end return node end @@ -324,7 +324,7 @@ function Explorer:update_parent_statuses(node, project, root) end -- update status - explorer_node.update_git_status(node, node.parent and node.parent:is_git_ignored() or false, project) + node:update_git_status(node.parent and node.parent:is_git_ignored() or false, project) -- maybe parent node = node.parent @@ -382,7 +382,7 @@ function Explorer:populate_children(handle, cwd, node, git_status, parent) 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) + child:update_git_status(node_ignored, git_status) end else for reason, value in pairs(FILTER_REASON) do diff --git a/lua/nvim-tree/explorer/node.lua b/lua/nvim-tree/explorer/node.lua index 41a9a503ef7..0a6c21bbaae 100644 --- a/lua/nvim-tree/explorer/node.lua +++ b/lua/nvim-tree/explorer/node.lua @@ -2,59 +2,6 @@ local git = {} -- circular dependencies local M = {} ----@class GitStatus ----@field file string|nil ----@field dir table|nil - ----@param parent_ignored boolean ----@param status table|nil ----@param absolute_path string ----@return GitStatus|nil -local function get_dir_git_status(parent_ignored, status, absolute_path) - if parent_ignored then - return { file = "!!" } - end - - if status then - return { - file = status.files and status.files[absolute_path], - dir = status.dirs and { - direct = status.dirs.direct[absolute_path], - indirect = status.dirs.indirect[absolute_path], - }, - } - end -end - ----@param parent_ignored boolean ----@param status table ----@param absolute_path string ----@return GitStatus -local function get_git_status(parent_ignored, status, absolute_path) - local file_status = parent_ignored and "!!" or (status and status.files and status.files[absolute_path]) - return { file = file_status } -end - ----@param node Node ----@param parent_ignored boolean ----@param status table|nil -function M.update_git_status(node, parent_ignored, status) - local get_status - if node.nodes then - get_status = get_dir_git_status - else - get_status = get_git_status - end - - -- status of the node's absolute path - node.git_status = get_status(parent_ignored, status, node.absolute_path) - - -- status of the link target, if the link itself is not dirty - if node.link_to and not node.git_status then - node.git_status = get_status(parent_ignored, status, node.link_to) - end -end - ---@param node Node ---@return GitStatus|nil function M.get_git_status(node) @@ -128,7 +75,7 @@ function M.reload_node_status(parent_node, projects) 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) + node:update_git_status(M.is_git_ignored(parent_node), status) if node.nodes and #node.nodes > 0 then M.reload_node_status(node, projects) end diff --git a/lua/nvim-tree/git/init.lua b/lua/nvim-tree/git/init.lua index 9a68da8e7fe..0cdf0723ec1 100644 --- a/lua/nvim-tree/git/init.lua +++ b/lua/nvim-tree/git/init.lua @@ -4,7 +4,10 @@ local git_utils = require("nvim-tree.git.utils") local Runner = require("nvim-tree.git.runner") local Watcher = require("nvim-tree.watcher").Watcher local Iterator = require("nvim-tree.iterators.node-iterator") -local explorer_node = require("nvim-tree.explorer.node") + +---@class GitStatus +---@field file string|nil +---@field dir table|nil local M = { config = {}, @@ -209,7 +212,7 @@ local function reload_tree_at(toplevel) :hidden() :applier(function(node) local parent_ignored = node.parent and node.parent:is_git_ignored() or false - explorer_node.update_git_status(node, parent_ignored, git_status) + node:update_git_status(parent_ignored, git_status) end) :recursor(function(node) return node.nodes and #node.nodes > 0 and node.nodes @@ -283,6 +286,35 @@ function M.load_project_status(path) end end +---@param parent_ignored boolean +---@param status table|nil +---@param absolute_path string +---@return GitStatus|nil +function M.get_dir_git_status(parent_ignored, status, absolute_path) + if parent_ignored then + return { file = "!!" } + end + + if status then + return { + file = status.files and status.files[absolute_path], + dir = status.dirs and { + direct = status.dirs.direct[absolute_path], + indirect = status.dirs.indirect[absolute_path], + }, + } + end +end + +---@param parent_ignored boolean +---@param status table +---@param absolute_path string +---@return GitStatus +function M.get_git_status(parent_ignored, status, absolute_path) + local file_status = parent_ignored and "!!" or (status and status.files and status.files[absolute_path]) + return { file = file_status } +end + function M.purge_state() log.line("git", "purge_state") diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index 7022d28faf9..8dc3e4c88c2 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -1,3 +1,5 @@ +local git = require("nvim-tree.git") + ---@class (exact) BaseNode ---@field private __index? table ---@field type NODE_TYPE @@ -39,6 +41,25 @@ function BaseNode:has_one_child_folder() return #self.nodes == 1 and self.nodes[1].nodes and vim.loop.fs_access(self.nodes[1].absolute_path, "R") or false end +---@param parent_ignored boolean +---@param status table|nil +function BaseNode:update_git_status(parent_ignored, status) + local get_status + if self.nodes then + get_status = git.get_dir_git_status + else + get_status = git.get_git_status + end + + -- status of the node's absolute path + self.git_status = get_status(parent_ignored, status, self.absolute_path) + + -- status of the link target, if the link itself is not dirty + if self.link_to and not self.git_status then + self.git_status = get_status(parent_ignored, status, self.link_to) + end +end + ---@return boolean function BaseNode:is_git_ignored() return self.git_status ~= nil and self.git_status.file == "!!" From f5f58ffa141bb64200870188e1f93e3f9128597c Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 16 Sep 2024 18:22:20 +1000 Subject: [PATCH 11/44] extract methods from explore_node --- lua/nvim-tree/actions/moves/item.lua | 3 +- lua/nvim-tree/explorer/init.lua | 4 +- lua/nvim-tree/git/init.lua | 4 +- lua/nvim-tree/node/init.lua | 79 +++++++++++++++++++++++- lua/nvim-tree/renderer/decorator/git.lua | 5 +- 5 files changed, 82 insertions(+), 13 deletions(-) diff --git a/lua/nvim-tree/actions/moves/item.lua b/lua/nvim-tree/actions/moves/item.lua index c38618e9c74..74e27422542 100644 --- a/lua/nvim-tree/actions/moves/item.lua +++ b/lua/nvim-tree/actions/moves/item.lua @@ -2,7 +2,6 @@ local utils = require("nvim-tree.utils") local view = require("nvim-tree.view") local core = require("nvim-tree.core") local lib = require("nvim-tree.lib") -local explorer_node = require("nvim-tree.explorer.node") local diagnostics = require("nvim-tree.diagnostics") local M = {} @@ -16,7 +15,7 @@ local MAX_DEPTH = 100 ---@return boolean local function status_is_valid(node, what, skip_gitignored) if what == "git" then - local git_status = explorer_node.get_git_status(node) + local git_status = node:get_git_status() return git_status ~= nil and (not skip_gitignored or git_status[1] ~= "!!") elseif what == "diag" then local diag_status = diagnostics.get_diag_status(node) diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index 8dd7ad8de12..fac875e4ca6 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -3,7 +3,6 @@ local log = require("nvim-tree.log") local notify = require("nvim-tree.notify") local utils = require("nvim-tree.utils") local view = require("nvim-tree.view") -local explorer_node = require("nvim-tree.explorer.node") local BaseNode = require("nvim-tree.node") local DirectoryNode = require("nvim-tree.node.directory") @@ -471,14 +470,13 @@ function Explorer:reload_git() event_running = true local projects = git.reload() - explorer_node.reload_node_status(self, projects) + self:reload_node_status(projects) self.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) end diff --git a/lua/nvim-tree/git/init.lua b/lua/nvim-tree/git/init.lua index 0cdf0723ec1..67682df8604 100644 --- a/lua/nvim-tree/git/init.lua +++ b/lua/nvim-tree/git/init.lua @@ -290,7 +290,7 @@ end ---@param status table|nil ---@param absolute_path string ---@return GitStatus|nil -function M.get_dir_git_status(parent_ignored, status, absolute_path) +function M.git_status_dir(parent_ignored, status, absolute_path) if parent_ignored then return { file = "!!" } end @@ -310,7 +310,7 @@ end ---@param status table ---@param absolute_path string ---@return GitStatus -function M.get_git_status(parent_ignored, status, absolute_path) +function M.git_status_file(parent_ignored, status, absolute_path) local file_status = parent_ignored and "!!" or (status and status.files and status.files[absolute_path]) return { file = file_status } end diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index 8dc3e4c88c2..c17d2076051 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -16,7 +16,7 @@ local git = require("nvim-tree.git") ---@field diag_status DiagStatus|nil local BaseNode = {} ----@alias Node DirectoryNode|FileNode|LinkNode +---@alias Node BaseNode|DirectoryNode|FileNode|LinkNode ---@param o BaseNode|nil ---@return BaseNode @@ -46,9 +46,9 @@ end function BaseNode:update_git_status(parent_ignored, status) local get_status if self.nodes then - get_status = git.get_dir_git_status + get_status = git.git_status_file else - get_status = git.get_git_status + get_status = git.git_status_file end -- status of the node's absolute path @@ -60,6 +60,79 @@ function BaseNode:update_git_status(parent_ignored, status) end end +---@return GitStatus|nil +function BaseNode:get_git_status() + if not self.git_status then + -- status doesn't exist + return nil + end + + if not self.nodes then + -- file + return self.git_status.file and { self.git_status.file } + end + + -- dir + if not self.explorer.opts.git.show_on_dirs then + return nil + end + + local status = {} + if not require("nvim-tree.lib").get_last_group_node(self).open or self.explorer.opts.git.show_on_open_dirs then + -- dir is closed or we should show on open_dirs + if self.git_status.file ~= nil then + table.insert(status, self.git_status.file) + end + if self.git_status.dir ~= nil then + if self.git_status.dir.direct ~= nil then + for _, s in pairs(self.git_status.dir.direct) do + table.insert(status, s) + end + end + if self.git_status.dir.indirect ~= nil then + for _, s in pairs(self.git_status.dir.indirect) do + table.insert(status, s) + end + end + end + else + -- dir is open and we shouldn't show on open_dirs + if self.git_status.file ~= nil then + table.insert(status, self.git_status.file) + end + if self.git_status.dir ~= nil and self.git_status.dir.direct ~= nil then + local deleted = { + [" D"] = true, + ["D "] = true, + ["RD"] = true, + ["DD"] = true, + } + for _, s in pairs(self.git_status.dir.direct) do + if deleted[s] then + table.insert(status, s) + end + end + end + end + if #status == 0 then + return nil + else + return status + end +end + +---@param projects table +function BaseNode:reload_node_status(projects) + local toplevel = git.get_toplevel(self.absolute_path) + local status = projects[toplevel] or {} + for _, node in ipairs(self.nodes) do + node:update_git_status(self:is_git_ignored(), status) + if node.nodes and #node.nodes > 0 then + self:reload_node_status(projects) + end + end +end + ---@return boolean function BaseNode:is_git_ignored() return self.git_status ~= nil and self.git_status.file == "!!" diff --git a/lua/nvim-tree/renderer/decorator/git.lua b/lua/nvim-tree/renderer/decorator/git.lua index cd3f9bb8969..cb3b2a4bab4 100644 --- a/lua/nvim-tree/renderer/decorator/git.lua +++ b/lua/nvim-tree/renderer/decorator/git.lua @@ -1,5 +1,4 @@ local notify = require("nvim-tree.notify") -local explorer_node = require("nvim-tree.explorer.node") local HL_POSITION = require("nvim-tree.enum").HL_POSITION local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT @@ -147,7 +146,7 @@ function DecoratorGit:calculate_icons(node) return nil end - local git_status = explorer_node.get_git_status(node) + local git_status = node:get_git_status() if git_status == nil then return nil end @@ -208,7 +207,7 @@ function DecoratorGit:calculate_highlight(node) return nil end - local git_status = explorer_node.get_git_status(node) + local git_status = node:get_git_status() if not git_status then return nil end From d0977054dac199149f10a743191215003db947c7 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 16 Sep 2024 18:24:44 +1000 Subject: [PATCH 12/44] extract methods from explore_node --- lua/nvim-tree/git/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/nvim-tree/git/init.lua b/lua/nvim-tree/git/init.lua index 67682df8604..c8fab9127ac 100644 --- a/lua/nvim-tree/git/init.lua +++ b/lua/nvim-tree/git/init.lua @@ -307,7 +307,7 @@ function M.git_status_dir(parent_ignored, status, absolute_path) end ---@param parent_ignored boolean ----@param status table +---@param status table|nil ---@param absolute_path string ---@return GitStatus function M.git_status_file(parent_ignored, status, absolute_path) From 16bbe8989208f9a6331dd7b53a3bbff3aad0ed99 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 16 Sep 2024 18:38:05 +1000 Subject: [PATCH 13/44] extract methods from lib --- lua/nvim-tree/actions/fs/clipboard.lua | 2 +- lua/nvim-tree/actions/fs/create-file.lua | 3 +-- lua/nvim-tree/actions/fs/rename-file.lua | 2 +- lua/nvim-tree/actions/moves/parent.lua | 3 +-- .../actions/tree/modifiers/expand-all.lua | 3 +-- lua/nvim-tree/api.lua | 2 +- lua/nvim-tree/lib.lua | 13 +------------ lua/nvim-tree/node/init.lua | 14 +++++++++++++- lua/nvim-tree/renderer/builder.lua | 4 ++-- 9 files changed, 22 insertions(+), 24 deletions(-) diff --git a/lua/nvim-tree/actions/fs/clipboard.lua b/lua/nvim-tree/actions/fs/clipboard.lua index c6808eb550c..b1915d04835 100644 --- a/lua/nvim-tree/actions/fs/clipboard.lua +++ b/lua/nvim-tree/actions/fs/clipboard.lua @@ -217,7 +217,7 @@ end ---@param action ACTION ---@param action_fn fun(source: string, dest: string) function Clipboard:do_paste(node, action, action_fn) - node = lib.get_last_group_node(node) + node = node:last_group_node() local explorer = core.get_explorer() if node.name == ".." and explorer then node = explorer diff --git a/lua/nvim-tree/actions/fs/create-file.lua b/lua/nvim-tree/actions/fs/create-file.lua index 9b285b7cbf4..f4419dbb627 100644 --- a/lua/nvim-tree/actions/fs/create-file.lua +++ b/lua/nvim-tree/actions/fs/create-file.lua @@ -1,6 +1,5 @@ local utils = require("nvim-tree.utils") local events = require("nvim-tree.events") -local lib = require("nvim-tree.lib") local core = require("nvim-tree.core") local notify = require("nvim-tree.notify") @@ -49,7 +48,7 @@ function M.fn(node) return end - node = node and lib.get_last_group_node(node) + node = node and node:last_group_node() local containing_folder if not node or node.name == ".." then diff --git a/lua/nvim-tree/actions/fs/rename-file.lua b/lua/nvim-tree/actions/fs/rename-file.lua index 9539cd7e730..a06fb201c56 100644 --- a/lua/nvim-tree/actions/fs/rename-file.lua +++ b/lua/nvim-tree/actions/fs/rename-file.lua @@ -120,7 +120,7 @@ function M.fn(default_modifier) return end - node = lib.get_last_group_node(node) + node = node:last_group_node() if node.name == ".." then return end diff --git a/lua/nvim-tree/actions/moves/parent.lua b/lua/nvim-tree/actions/moves/parent.lua index e00bc49e7e5..3e82ed723d7 100644 --- a/lua/nvim-tree/actions/moves/parent.lua +++ b/lua/nvim-tree/actions/moves/parent.lua @@ -1,7 +1,6 @@ local view = require("nvim-tree.view") local utils = require("nvim-tree.utils") local core = require("nvim-tree.core") -local lib = require("nvim-tree.lib") local M = {} @@ -12,7 +11,7 @@ function M.fn(should_close) return function(node) local explorer = core.get_explorer() - node = lib.get_last_group_node(node) + node = node:last_group_node() if should_close and node.open then node.open = false if explorer then diff --git a/lua/nvim-tree/actions/tree/modifiers/expand-all.lua b/lua/nvim-tree/actions/tree/modifiers/expand-all.lua index 25be0b90803..b7e24c9551f 100644 --- a/lua/nvim-tree/actions/tree/modifiers/expand-all.lua +++ b/lua/nvim-tree/actions/tree/modifiers/expand-all.lua @@ -1,7 +1,6 @@ local core = require("nvim-tree.core") local Iterator = require("nvim-tree.iterators.node-iterator") local notify = require("nvim-tree.notify") -local lib = require("nvim-tree.lib") local M = {} @@ -18,7 +17,7 @@ end ---@param node Node local function expand(node) - node = lib.get_last_group_node(node) + node = node:last_group_node() node.open = true if #node.nodes == 0 then core.get_explorer():expand(node) diff --git a/lua/nvim-tree/api.lua b/lua/nvim-tree/api.lua index 27da1d206df..f0f1c03f821 100644 --- a/lua/nvim-tree/api.lua +++ b/lua/nvim-tree/api.lua @@ -138,7 +138,7 @@ Api.tree.change_root_to_node = wrap_node(function(node) if node.name == ".." then actions.root.change_dir.fn("..") elseif node.nodes ~= nil then - actions.root.change_dir.fn(lib.get_last_group_node(node).absolute_path) + actions.root.change_dir.fn(node:last_group_node().absolute_path) end end) diff --git a/lua/nvim-tree/lib.lua b/lua/nvim-tree/lib.lua index d5beec5f828..77b44b9cd18 100644 --- a/lua/nvim-tree/lib.lua +++ b/lua/nvim-tree/lib.lua @@ -83,17 +83,6 @@ function M.get_nodes() return clone_node(core.get_explorer()) end --- If node is grouped, return the last node in the group. Otherwise, return the given node. ----@param node Node ----@return Node -function M.get_last_group_node(node) - while node and node.group_next do - node = node.group_next - end - - return node ---@diagnostic disable-line: return-type-mismatch -- it can't be nil -end - ---Group empty folders -- Recursively group nodes ---@param node Node @@ -164,7 +153,7 @@ function M.expand_or_collapse(node, toggle_group) toggle_group_folders(head_node) end - local open = M.get_last_group_node(node).open + local open = node:last_group_node().open local next_open if toggle_group then next_open = open diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index c17d2076051..409105f85ae 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -78,7 +78,7 @@ function BaseNode:get_git_status() end local status = {} - if not require("nvim-tree.lib").get_last_group_node(self).open or self.explorer.opts.git.show_on_open_dirs then + if not self:last_group_node().open or self.explorer.opts.git.show_on_open_dirs then -- dir is closed or we should show on open_dirs if self.git_status.file ~= nil then table.insert(status, self.git_status.file) @@ -151,4 +151,16 @@ function BaseNode:is_dotfile() return false end +-- If node is grouped, return the last node in the group. Otherwise, return the given node. +---@return Node +function BaseNode:last_group_node() + local node = self + + while node.group_next do + node = node.group_next + end + + return node +end + return BaseNode diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index 119efc26b22..c86ccf0f71a 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -137,7 +137,7 @@ function Builder:unwrap_highlighted_strings(highlighted_strings) end ---@private ----@param node table +---@param node Node ---@return HighlightedString icon ---@return HighlightedString name function Builder:build_folder(node) @@ -369,7 +369,7 @@ function Builder:build_line(node, idx, num_children) self.index = self.index + 1 - node = require("nvim-tree.lib").get_last_group_node(node) + node = node:last_group_node() if node.open then self.depth = self.depth + 1 self:build_lines(node) From 91f477d90a54a140653ecaa79d5fd8d73b6d7a75 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 21 Sep 2024 12:53:56 +1000 Subject: [PATCH 14/44] use .. name for root node for compatibility --- lua/nvim-tree/explorer/init.lua | 2 +- lua/nvim-tree/node/directory.lua | 2 +- lua/nvim-tree/node/init.lua | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index fac875e4ca6..875067283db 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -52,7 +52,7 @@ function Explorer:new(path) ---@type Explorer local placeholder = nil - local o = DirectoryNode.new(self, placeholder, nil, path, nil, nil) + local o = DirectoryNode.new(self, placeholder, nil, path, "..", nil) ---@cast o Explorer o.explorer = self diff --git a/lua/nvim-tree/node/directory.lua b/lua/nvim-tree/node/directory.lua index 9d6e47e19db..9dd302d92b3 100644 --- a/lua/nvim-tree/node/directory.lua +++ b/lua/nvim-tree/node/directory.lua @@ -13,7 +13,7 @@ local DirectoryNode = BaseNode:new() ---@param explorer Explorer -----@param parent DirectoryNode -- TODO #2871 #2886 ---@param absolute_path string ----@param name string|nil +---@param name string ---@param fs_stat uv.fs_stat.result|nil ---@return DirectoryNode function DirectoryNode:new(explorer, parent, absolute_path, name, fs_stat) diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index 409105f85ae..7de5160c331 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -10,7 +10,7 @@ local git = require("nvim-tree.git") ---@field git_status GitStatus|nil ---@field hidden boolean ---@field is_dot boolean ----@field name string|nil +---@field name string ---@field parent DirectoryNode|nil ---@field watcher Watcher|nil ---@field diag_status DiagStatus|nil From 6c274ddb3aef55aa75581b343a03351bfb3128af Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 21 Sep 2024 13:37:51 +1000 Subject: [PATCH 15/44] use node.explorer --- lua/nvim-tree/actions/fs/clipboard.lua | 5 ++--- lua/nvim-tree/explorer/init.lua | 2 +- lua/nvim-tree/explorer/watch.lua | 9 +++------ lua/nvim-tree/git/init.lua | 5 +---- lua/nvim-tree/utils.lua | 3 +-- 5 files changed, 8 insertions(+), 16 deletions(-) diff --git a/lua/nvim-tree/actions/fs/clipboard.lua b/lua/nvim-tree/actions/fs/clipboard.lua index b1915d04835..5fd2a4b899c 100644 --- a/lua/nvim-tree/actions/fs/clipboard.lua +++ b/lua/nvim-tree/actions/fs/clipboard.lua @@ -218,9 +218,8 @@ end ---@param action_fn fun(source: string, dest: string) function Clipboard:do_paste(node, action, action_fn) node = node:last_group_node() - local explorer = core.get_explorer() - if node.name == ".." and explorer then - node = explorer + if node.name == ".." then + node = self.explorer end local clip = self.data[action] if #clip == 0 then diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index 875067283db..36a91b1e085 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -55,7 +55,7 @@ function Explorer:new(path) local o = DirectoryNode.new(self, placeholder, nil, path, "..", nil) ---@cast o Explorer - o.explorer = self + o.explorer = o o.open = true o.opts = config diff --git a/lua/nvim-tree/explorer/watch.lua b/lua/nvim-tree/explorer/watch.lua index 317f3e54b7a..ce69daaf0f9 100644 --- a/lua/nvim-tree/explorer/watch.lua +++ b/lua/nvim-tree/explorer/watch.lua @@ -76,12 +76,9 @@ function M.create_watcher(node) else log.line("watcher", "node event executing refresh '%s'", node.absolute_path) end - local explorer = require("nvim-tree.core").get_explorer() - if explorer then - explorer:refresh_node(node, function() - explorer.renderer:draw() - end) - end + node.explorer:refresh_node(node, function() + node.explorer.renderer:draw() + end) end) end diff --git a/lua/nvim-tree/git/init.lua b/lua/nvim-tree/git/init.lua index c8fab9127ac..b963cfd7d3e 100644 --- a/lua/nvim-tree/git/init.lua +++ b/lua/nvim-tree/git/init.lua @@ -219,10 +219,7 @@ local function reload_tree_at(toplevel) end) :iterate() - local explorer = require("nvim-tree.core").get_explorer() - if explorer then - explorer.renderer:draw() - end + root_node.explorer.renderer:draw() end) end diff --git a/lua/nvim-tree/utils.lua b/lua/nvim-tree/utils.lua index 2a704872a79..b3f70760425 100644 --- a/lua/nvim-tree/utils.lua +++ b/lua/nvim-tree/utils.lua @@ -112,8 +112,7 @@ function M.find_node(nodes, fn) end) :iterate() i = require("nvim-tree.view").is_root_folder_visible() and i or i - 1 - local explorer = require("nvim-tree.core").get_explorer() - if explorer and explorer.live_filter.filter then + if node and node.explorer.live_filter.filter then i = i + 1 end return node, i From 739d1e4d278c09392ecc3db889e15d497d64b058 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 21 Sep 2024 15:17:09 +1000 Subject: [PATCH 16/44] extract node factory, remove unused code --- lua/nvim-tree/explorer/init.lua | 37 +++++++++++++-------------------- lua/nvim-tree/node/factory.lua | 33 +++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 22 deletions(-) create mode 100644 lua/nvim-tree/node/factory.lua diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index 36a91b1e085..5e71d67a42a 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -1,14 +1,13 @@ -local git = require("nvim-tree.git") -local log = require("nvim-tree.log") -local notify = require("nvim-tree.notify") -local utils = require("nvim-tree.utils") -local view = require("nvim-tree.view") - -local BaseNode = require("nvim-tree.node") -local DirectoryNode = require("nvim-tree.node.directory") -local FileNode = require("nvim-tree.node.file") -local LinkNode = require("nvim-tree.node.link") -local Watcher = require("nvim-tree.watcher") +local git = require "nvim-tree.git" +local log = require "nvim-tree.log" +local notify = require "nvim-tree.notify" +local utils = require "nvim-tree.utils" +local view = require "nvim-tree.view" +local node_factory = require "nvim-tree.node.factory" + +local BaseNode = require "nvim-tree.node" +local DirectoryNode = require "nvim-tree.node.directory" +local Watcher = require "nvim-tree.watcher" local Iterator = require("nvim-tree.iterators.node-iterator") local NodeIterator = require("nvim-tree.iterators.node-iterator") @@ -150,17 +149,7 @@ function Explorer:reload(node, git_status) end if not nodes_by_path[abs] then - local new_child = nil - if t == "directory" and vim.loop.fs_access(abs, "R") and Watcher.is_fs_event_capable(abs) then - new_child = DirectoryNode:new(self, node, abs, name, stat) - elseif t == "file" then - new_child = FileNode:new(self, node, abs, name, stat) - elseif t == "link" then - local link = LinkNode:new(self, node, abs, name, stat) - if link.link_to ~= nil then - new_child = link - end - end + local new_child = node_factory.create_node(self, node, abs, stat, name) if new_child then table.insert(node.nodes, new_child) nodes_by_path[abs] = new_child @@ -365,6 +354,7 @@ function Explorer:populate_children(handle, cwd, node, git_status, parent) local stat = vim.loop.fs_lstat(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 +<<<<<<< HEAD -- Type must come from fs_stat and not fs_scandir_next to maintain sshfs compatibility local t = stat and stat.type or nil local child = nil @@ -378,6 +368,9 @@ function Explorer:populate_children(handle, cwd, node, git_status, parent) child = link end end +======= + local child = node_factory.create_node(self, node, abs, stat, name) +>>>>>>> c02c98b (extract node factory, remove unused code) if child then table.insert(node.nodes, child) nodes_by_path[child.absolute_path] = true diff --git a/lua/nvim-tree/node/factory.lua b/lua/nvim-tree/node/factory.lua new file mode 100644 index 00000000000..fffdafe5fca --- /dev/null +++ b/lua/nvim-tree/node/factory.lua @@ -0,0 +1,33 @@ +local DirectoryNode = require("nvim-tree.node.directory") +local LinkNode = require("nvim-tree.node.link") +local FileNode = require("nvim-tree.node.file") +local Watcher = require("nvim-tree.watcher") + +local M = {} + +---@param explorer Explorer +-----@param parent DirectoryNode -- TODO #2871 #2886 +---@param abs string +---@param stat uv.fs_stat.result|nil +---@param name string +---@return Node|nil +function M.create_node(explorer, parent, abs, stat, name) + if not stat then + return nil + end + + if stat.type == "directory" and vim.loop.fs_access(abs, "R") and Watcher.is_fs_event_capable(abs) then + return DirectoryNode:new(explorer, parent, abs, name, stat) + elseif stat.type == "file" then + return FileNode:new(explorer, parent, abs, name, stat) + elseif stat.type == "link" then + local link = LinkNode:new(explorer, parent, abs, name, stat) + if link.link_to ~= nil then + return link + end + end + + return nil +end + +return M From b1d9655d39278965d20ecb250f9752d419812338 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 22 Sep 2024 14:57:23 +1000 Subject: [PATCH 17/44] factories for all nodes, add RootNode --- lua/nvim-tree/core.lua | 2 +- lua/nvim-tree/explorer/init.lua | 58 ++++++++++++-------------------- lua/nvim-tree/node/directory.lua | 24 ++++++++----- lua/nvim-tree/node/factory.lua | 25 +++++++------- lua/nvim-tree/node/file.lua | 21 +++++++----- lua/nvim-tree/node/init.lua | 14 ++++---- lua/nvim-tree/node/link.lua | 41 ++++++++++++---------- lua/nvim-tree/node/root.lua | 20 +++++++++++ 8 files changed, 115 insertions(+), 90 deletions(-) create mode 100644 lua/nvim-tree/node/root.lua diff --git a/lua/nvim-tree/core.lua b/lua/nvim-tree/core.lua index d3e6d20ffff..186b1ed74e1 100644 --- a/lua/nvim-tree/core.lua +++ b/lua/nvim-tree/core.lua @@ -15,7 +15,7 @@ function M.init(foldername) if TreeExplorer then TreeExplorer:destroy() end - TreeExplorer = require("nvim-tree.explorer"):new(foldername) + TreeExplorer = require("nvim-tree.explorer"):create(foldername) if not first_init_done then events._dispatch_ready() first_init_done = true diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index 5e71d67a42a..beabc5e3eb3 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -1,13 +1,12 @@ -local git = require "nvim-tree.git" -local log = require "nvim-tree.log" -local notify = require "nvim-tree.notify" -local utils = require "nvim-tree.utils" -local view = require "nvim-tree.view" -local node_factory = require "nvim-tree.node.factory" +local git = require("nvim-tree.git") +local log = require("nvim-tree.log") +local notify = require("nvim-tree.notify") +local utils = require("nvim-tree.utils") +local view = require("nvim-tree.view") +local node_factory = require("nvim-tree.node.factory") -local BaseNode = require "nvim-tree.node" -local DirectoryNode = require "nvim-tree.node.directory" -local Watcher = require "nvim-tree.watcher" +local RootNode = require("nvim-tree.node.root") +local Watcher = require("nvim-tree.watcher") local Iterator = require("nvim-tree.iterators.node-iterator") local NodeIterator = require("nvim-tree.iterators.node-iterator") @@ -23,7 +22,7 @@ local FILTER_REASON = require("nvim-tree.enum").FILTER_REASON local config ----@class (exact) Explorer: DirectoryNode +---@class (exact) Explorer: RootNode ---@field opts table user options ---@field renderer Renderer ---@field filters Filters @@ -31,11 +30,12 @@ local config ---@field sorters Sorter ---@field marks Marks ---@field clipboard Clipboard -local Explorer = BaseNode.new(DirectoryNode) -- TODO do not inherit, add a root node to separate Explorer and Node +local Explorer = RootNode:new() ----@param path string|nil ----@return Explorer|nil -function Explorer:new(path) +---Static factory method +---@param path string? +---@return Explorer? +function Explorer:create(path) local err if path then @@ -45,19 +45,19 @@ function Explorer:new(path) end if not path then notify.error(err) - return + return nil end ---@type Explorer - local placeholder = nil + local explorer_placeholder - local o = DirectoryNode.new(self, placeholder, nil, path, "..", nil) - ---@cast o Explorer + local o = RootNode.create(self, explorer_placeholder, path, "..", nil) --[[@as Explorer]] o.explorer = o - o.open = true + o.open = true o.opts = config + o.sorters = Sorters:new(config) o.renderer = Renderer:new(config, o) o.filters = Filters:new(config, o) @@ -149,7 +149,7 @@ function Explorer:reload(node, git_status) end if not nodes_by_path[abs] then - local new_child = node_factory.create_node(self, node, abs, stat, name) + local new_child = node_factory.create_node(self, node, abs, t, stat, name) if new_child then table.insert(node.nodes, new_child) nodes_by_path[abs] = new_child @@ -348,29 +348,15 @@ function Explorer:populate_children(handle, cwd, node, git_status, parent) local abs = utils.path_join({ cwd, name }) if Watcher.is_fs_event_capable(abs) then - local profile = log.profile_start("populate_children %s", abs) + local profile = log.profile_start("explore populate_children %s", abs) ---@type uv.fs_stat.result|nil local stat = vim.loop.fs_lstat(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 -<<<<<<< HEAD -- Type must come from fs_stat and not fs_scandir_next to maintain sshfs compatibility local t = stat and stat.type or nil - local child = nil - if t == "directory" and vim.loop.fs_access(abs, "R") then - child = DirectoryNode:new(self, node, abs, name, stat) - elseif t == "file" then - child = FileNode:new(self, node, abs, name, stat) - elseif t == "link" then - local link = LinkNode:new(self, node, abs, name, stat) - if link.link_to ~= nil then - child = link - end - end -======= - local child = node_factory.create_node(self, node, abs, stat, name) ->>>>>>> c02c98b (extract node factory, remove unused code) + local child = node_factory.create_node(self, node, abs, t, stat, name) if child then table.insert(node.nodes, child) nodes_by_path[child.absolute_path] = true diff --git a/lua/nvim-tree/node/directory.lua b/lua/nvim-tree/node/directory.lua index 9dd302d92b3..982390c4b85 100644 --- a/lua/nvim-tree/node/directory.lua +++ b/lua/nvim-tree/node/directory.lua @@ -3,40 +3,46 @@ local watch = require("nvim-tree.explorer.watch") local BaseNode = require("nvim-tree.node") ---@class (exact) DirectoryNode: BaseNode ----@field has_children boolean -- TODO remove this and just test nodes ----@field group_next Node|nil -- If node is grouped, this points to the next child dir/link node +---@field has_children boolean +---@field group_next Node? -- If node is grouped, this points to the next child dir/link node ---@field nodes Node[] ---@field open boolean ----@field hidden_stats table -- Each field of this table is a key for source and value for count +---@field hidden_stats table? -- Each field of this table is a key for source and value for count local DirectoryNode = BaseNode:new() +---Static factory method ---@param explorer Explorer ------@param parent DirectoryNode -- TODO #2871 #2886 +---@param parent Node? ---@param absolute_path string ---@param name string ---@param fs_stat uv.fs_stat.result|nil ---@return DirectoryNode -function DirectoryNode:new(explorer, parent, absolute_path, name, fs_stat) +function DirectoryNode:create(explorer, parent, absolute_path, name, fs_stat) local handle = vim.loop.fs_scandir(absolute_path) - local has_children = handle and vim.loop.fs_scandir_next(handle) ~= nil + local has_children = handle and vim.loop.fs_scandir_next(handle) ~= nil or false - local o = BaseNode.new(self, { + ---@type DirectoryNode + local o = { type = "directory", explorer = explorer, absolute_path = absolute_path, executable = false, fs_stat = fs_stat, + git_status = nil, hidden = false, is_dot = false, name = name, parent = parent, + watcher = nil, + diag_status = nil, has_children = has_children, group_next = nil, nodes = {}, open = false, - }) - ---@cast o DirectoryNode + hidden_stats = nil, + } + o = self:new(o) --[[@as DirectoryNode]] o.watcher = watch.create_watcher(o) diff --git a/lua/nvim-tree/node/factory.lua b/lua/nvim-tree/node/factory.lua index fffdafe5fca..bbf112576b0 100644 --- a/lua/nvim-tree/node/factory.lua +++ b/lua/nvim-tree/node/factory.lua @@ -5,26 +5,25 @@ local Watcher = require("nvim-tree.watcher") local M = {} +---Factory function to create the appropriate Node ---@param explorer Explorer ------@param parent DirectoryNode -- TODO #2871 #2886 +---@param parent Node ---@param abs string ----@param stat uv.fs_stat.result|nil +---@param t string? type from vim.loop.fs_scandir_next as stat.type is incorrectly reported as a file for links +---@param stat uv.fs_stat.result? ---@param name string ----@return Node|nil -function M.create_node(explorer, parent, abs, stat, name) +---@return Node? +function M.create_node(explorer, parent, abs, t, stat, name) if not stat then return nil end - if stat.type == "directory" and vim.loop.fs_access(abs, "R") and Watcher.is_fs_event_capable(abs) then - return DirectoryNode:new(explorer, parent, abs, name, stat) - elseif stat.type == "file" then - return FileNode:new(explorer, parent, abs, name, stat) - elseif stat.type == "link" then - local link = LinkNode:new(explorer, parent, abs, name, stat) - if link.link_to ~= nil then - return link - end + if t == "directory" and vim.loop.fs_access(abs, "R") and Watcher.is_fs_event_capable(abs) then + return DirectoryNode:create(explorer, parent, abs, name, stat) + elseif t == "file" then + return FileNode:create(explorer, parent, abs, name, stat) + elseif t == "link" then + return LinkNode:create(explorer, parent, abs, name, stat) end return nil diff --git a/lua/nvim-tree/node/file.lua b/lua/nvim-tree/node/file.lua index 014cd1ff92f..2a4140bd7b6 100644 --- a/lua/nvim-tree/node/file.lua +++ b/lua/nvim-tree/node/file.lua @@ -6,27 +6,32 @@ local BaseNode = require("nvim-tree.node") ---@field extension string local FileNode = BaseNode:new() +---Static factory method ---@param explorer Explorer ------@param parent DirectoryNode -- TODO #2871 #2886 +---@param parent Node ---@param absolute_path string ---@param name string ----@param fs_stat uv.fs_stat.result|nil +---@param fs_stat uv.fs_stat.result? ---@return FileNode -function FileNode:new(explorer, parent, absolute_path, name, fs_stat) - local o = BaseNode.new(self, { +function FileNode:create(explorer, parent, absolute_path, name, fs_stat) + ---@type FileNode + local o = { type = "file", explorer = explorer, absolute_path = absolute_path, executable = utils.is_executable(absolute_path), fs_stat = fs_stat, - name = name, - parent = parent, + git_status = nil, hidden = false, is_dot = false, + name = name, + parent = parent, + watcher = nil, + diag_status = nil, extension = string.match(name, ".?[^.]+%.(.*)") or "", - }) - ---@cast o FileNode + } + o = self:new(o) --[[@as FileNode]] return o end diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index 7de5160c331..cb6f15dcf6a 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -1,22 +1,24 @@ local git = require("nvim-tree.git") +---Abstract Node class. +---Uses the abstract factory pattern to instantiate child instances. ---@class (exact) BaseNode ---@field private __index? table ---@field type NODE_TYPE ---@field explorer Explorer ---@field absolute_path string ---@field executable boolean ----@field fs_stat uv.fs_stat.result|nil ----@field git_status GitStatus|nil +---@field fs_stat uv.fs_stat.result? +---@field git_status GitStatus? ---@field hidden boolean ---@field is_dot boolean ---@field name string ----@field parent DirectoryNode|nil ----@field watcher Watcher|nil ----@field diag_status DiagStatus|nil +---@field parent Node? +---@field watcher Watcher? +---@field diag_status DiagStatus? local BaseNode = {} ----@alias Node BaseNode|DirectoryNode|FileNode|LinkNode +---@alias Node RootNode|BaseNode|DirectoryNode|FileNode|LinkNode ---@param o BaseNode|nil ---@return BaseNode diff --git a/lua/nvim-tree/node/link.lua b/lua/nvim-tree/node/link.lua index 27b9e3ca34f..bb43384b62b 100644 --- a/lua/nvim-tree/node/link.lua +++ b/lua/nvim-tree/node/link.lua @@ -3,36 +3,42 @@ local watch = require("nvim-tree.explorer.watch") local BaseNode = require("nvim-tree.node") ---@class (exact) LinkNode: BaseNode ----@field has_children boolean -- TODO remove this and just test nodes ----@field group_next Node|nil -- If node is grouped, this points to the next child dir/link node +---@field has_children boolean +---@field group_next Node? -- If node is grouped, this points to the next child dir/link node ---@field link_to string absolute path +---@field nodes Node[] +---@field open boolean local LinkNode = BaseNode:new() +---Static factory method ---@param explorer Explorer ------@param parent DirectoryNode -- TODO #2871 #2886 +---@param parent Node ---@param absolute_path string ---@param name string ----@param fs_stat uv.fs_stat.result|nil ----@return LinkNode -function LinkNode:new(explorer, parent, absolute_path, name, fs_stat) - local link_to = vim.loop.fs_realpath(absolute_path) - local open, nodes, has_children - - -- TODO-INFO: sometimes fs_realpath returns nil +---@param fs_stat uv.fs_stat.result? +---@return LinkNode? nil on vim.loop.fs_realpath failure +function LinkNode:create(explorer, parent, absolute_path, name, fs_stat) + -- INFO: sometimes fs_realpath returns nil -- I expect this be a bug in glibc, because it fails to retrieve the path for some -- links (for instance libr2.so in /usr/lib) and thus even with a C program realpath fails -- when it has no real reason to. Maybe there is a reason, but errno is definitely wrong. - -- So we need to check for link_to ~= nil when adding new links to the main tree + local link_to = vim.loop.fs_realpath(absolute_path) + if not link_to then + return nil + end + + local open, nodes, has_children local is_dir_link = (link_to ~= nil) and vim.loop.fs_stat(link_to).type == "directory" if is_dir_link and link_to then local handle = vim.loop.fs_scandir(link_to) - has_children = handle and vim.loop.fs_scandir_next(handle) ~= nil + has_children = handle and vim.loop.fs_scandir_next(handle) ~= nil or false open = false nodes = {} end - local o = BaseNode.new(self, { + ---@type LinkNode + local o = { type = "link", explorer = explorer, absolute_path = absolute_path, @@ -42,15 +48,16 @@ function LinkNode:new(explorer, parent, absolute_path, name, fs_stat) is_dot = false, name = name, parent = parent, - - link_to = link_to, + watcher = nil, + diag_status = nil, has_children = has_children, group_next = nil, + link_to = link_to, nodes = nodes, open = open, - }) - ---@cast o LinkNode + } + o = self:new(o) --[[@as LinkNode]] if is_dir_link then o.watcher = watch.create_watcher(o) diff --git a/lua/nvim-tree/node/root.lua b/lua/nvim-tree/node/root.lua new file mode 100644 index 00000000000..4265d49d479 --- /dev/null +++ b/lua/nvim-tree/node/root.lua @@ -0,0 +1,20 @@ +local DirectoryNode = require("nvim-tree.node.directory") + +---@class (exact) RootNode: DirectoryNode +local RootNode = DirectoryNode:new() + +---Static factory method +---@param explorer Explorer +---@param absolute_path string +---@param name string +---@param fs_stat uv.fs_stat.result|nil +---@return RootNode +function RootNode:create(explorer, absolute_path, name, fs_stat) + local o = DirectoryNode:create(explorer, nil, absolute_path, name, fs_stat) + + o = self:new(o) --[[@as RootNode]] + + return o +end + +return RootNode From 47b1ccb43ffc12af635a18f3fdbfd59c3a601f61 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 22 Sep 2024 15:36:13 +1000 Subject: [PATCH 18/44] factories for all nodes, add RootNode --- lua/nvim-tree/explorer/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index beabc5e3eb3..817ded3eb54 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -49,7 +49,7 @@ function Explorer:create(path) end ---@type Explorer - local explorer_placeholder + local explorer_placeholder = nil local o = RootNode.create(self, explorer_placeholder, path, "..", nil) --[[@as Explorer]] From 32431b6a4c8fc23aa61fc8e570db79dd55941e23 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 22 Sep 2024 16:38:21 +1000 Subject: [PATCH 19/44] use factory pattern for decorators --- lua/nvim-tree/renderer/builder.lua | 16 ++++++++-------- lua/nvim-tree/renderer/decorator/bookmarks.lua | 12 +++++++----- lua/nvim-tree/renderer/decorator/copied.lua | 12 +++++++----- lua/nvim-tree/renderer/decorator/cut.lua | 12 ++++++------ .../renderer/decorator/diagnostics.lua | 12 +++++++----- lua/nvim-tree/renderer/decorator/git.lua | 18 ++++++++++-------- lua/nvim-tree/renderer/decorator/hidden.lua | 12 +++++++----- lua/nvim-tree/renderer/decorator/init.lua | 2 ++ lua/nvim-tree/renderer/decorator/modified.lua | 10 ++++++---- lua/nvim-tree/renderer/decorator/opened.lua | 10 ++++++---- 10 files changed, 66 insertions(+), 50 deletions(-) diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index c86ccf0f71a..e23ef7f87a1 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -68,14 +68,14 @@ function Builder:new(opts, explorer) virtual_lines = {}, decorators = { -- priority order - DecoratorCut:new(opts, explorer), - DecoratorCopied:new(opts, explorer), - DecoratorDiagnostics:new(opts, explorer), - DecoratorBookmarks:new(opts, explorer), - DecoratorModified:new(opts, explorer), - DecoratorHidden:new(opts, explorer), - DecoratorOpened:new(opts, explorer), - DecoratorGit:new(opts, explorer), + DecoratorCut:create(opts, explorer), + DecoratorCopied:create(opts, explorer), + DecoratorDiagnostics:create(opts, explorer), + DecoratorBookmarks:create(opts, explorer), + DecoratorModified:create(opts, explorer), + DecoratorHidden:create(opts, explorer), + DecoratorOpened:create(opts, explorer), + DecoratorGit:create(opts, explorer), }, hidden_display = Builder:setup_hidden_display_function(opts), } diff --git a/lua/nvim-tree/renderer/decorator/bookmarks.lua b/lua/nvim-tree/renderer/decorator/bookmarks.lua index 63138e002c6..6b33970fe90 100644 --- a/lua/nvim-tree/renderer/decorator/bookmarks.lua +++ b/lua/nvim-tree/renderer/decorator/bookmarks.lua @@ -4,20 +4,22 @@ local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT local Decorator = require("nvim-tree.renderer.decorator") ---@class (exact) DecoratorBookmarks: Decorator ----@field icon HighlightedString +---@field icon HighlightedString? local DecoratorBookmarks = Decorator:new() +---Static factory method ---@param opts table ---@param explorer Explorer ---@return DecoratorBookmarks -function DecoratorBookmarks:new(opts, explorer) - local o = Decorator.new(self, { +function DecoratorBookmarks:create(opts, explorer) + ---@type DecoratorBookmarks + local o = { explorer = explorer, enabled = true, hl_pos = HL_POSITION[opts.renderer.highlight_bookmarks] or HL_POSITION.none, icon_placement = ICON_PLACEMENT[opts.renderer.icons.bookmarks_placement] or ICON_PLACEMENT.none, - }) - ---@cast o DecoratorBookmarks + } + o = self:new(o) --[[@as DecoratorBookmarks]] if opts.renderer.icons.show.bookmarks then o.icon = { diff --git a/lua/nvim-tree/renderer/decorator/copied.lua b/lua/nvim-tree/renderer/decorator/copied.lua index b6c4cf5e9ee..57c4825212c 100644 --- a/lua/nvim-tree/renderer/decorator/copied.lua +++ b/lua/nvim-tree/renderer/decorator/copied.lua @@ -5,20 +5,22 @@ local Decorator = require("nvim-tree.renderer.decorator") ---@class (exact) DecoratorCopied: Decorator ---@field enabled boolean ----@field icon HighlightedString|nil +---@field icon HighlightedString? local DecoratorCopied = Decorator:new() +---Static factory method ---@param opts table ---@param explorer Explorer ---@return DecoratorCopied -function DecoratorCopied:new(opts, explorer) - local o = Decorator.new(self, { +function DecoratorCopied:create(opts, explorer) + ---@type DecoratorCopied + local o = { explorer = explorer, enabled = true, hl_pos = HL_POSITION[opts.renderer.highlight_clipboard] or HL_POSITION.none, icon_placement = ICON_PLACEMENT.none, - }) - ---@cast o DecoratorCopied + } + o = self:new(o) --[[@as DecoratorCopied]] return o end diff --git a/lua/nvim-tree/renderer/decorator/cut.lua b/lua/nvim-tree/renderer/decorator/cut.lua index 17c69a7fa73..b81642f6e79 100644 --- a/lua/nvim-tree/renderer/decorator/cut.lua +++ b/lua/nvim-tree/renderer/decorator/cut.lua @@ -4,21 +4,21 @@ local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT local Decorator = require("nvim-tree.renderer.decorator") ---@class (exact) DecoratorCut: Decorator ----@field enabled boolean ----@field icon HighlightedString|nil local DecoratorCut = Decorator:new() +---Static factory method ---@param opts table ---@param explorer Explorer ---@return DecoratorCut -function DecoratorCut:new(opts, explorer) - local o = Decorator.new(self, { +function DecoratorCut:create(opts, explorer) + ---@type DecoratorCut + local o = { explorer = explorer, enabled = true, hl_pos = HL_POSITION[opts.renderer.highlight_clipboard] or HL_POSITION.none, icon_placement = ICON_PLACEMENT.none, - }) - ---@cast o DecoratorCut + } + o = self:new(o) --[[@as DecoratorCut]] return o end diff --git a/lua/nvim-tree/renderer/decorator/diagnostics.lua b/lua/nvim-tree/renderer/decorator/diagnostics.lua index bf01533eb9e..3daee7bc03a 100644 --- a/lua/nvim-tree/renderer/decorator/diagnostics.lua +++ b/lua/nvim-tree/renderer/decorator/diagnostics.lua @@ -33,20 +33,22 @@ local ICON_KEYS = { } ---@class (exact) DecoratorDiagnostics: Decorator ----@field icons HighlightedString[] +---@field icons HighlightedString[]? local DecoratorDiagnostics = Decorator:new() +---Static factory method ---@param opts table ---@param explorer Explorer ---@return DecoratorDiagnostics -function DecoratorDiagnostics:new(opts, explorer) - local o = Decorator.new(self, { +function DecoratorDiagnostics:create(opts, explorer) + ---@type DecoratorDiagnostics + local o = { explorer = explorer, enabled = opts.diagnostics.enable, hl_pos = HL_POSITION[opts.renderer.highlight_diagnostics] or HL_POSITION.none, icon_placement = ICON_PLACEMENT[opts.renderer.icons.diagnostics_placement] or ICON_PLACEMENT.none, - }) - ---@cast o DecoratorDiagnostics + } + o = self:new(o) --[[@as DecoratorDiagnostics]] if not o.enabled then return o diff --git a/lua/nvim-tree/renderer/decorator/git.lua b/lua/nvim-tree/renderer/decorator/git.lua index cb3b2a4bab4..af2c8ccaa94 100644 --- a/lua/nvim-tree/renderer/decorator/git.lua +++ b/lua/nvim-tree/renderer/decorator/git.lua @@ -9,23 +9,25 @@ local Decorator = require("nvim-tree.renderer.decorator") ---@field ord number decreasing priority ---@class (exact) DecoratorGit: Decorator ----@field file_hl table by porcelain status e.g. "AM" ----@field folder_hl table by porcelain status ----@field icons_by_status HighlightedStringGit[] by human status ----@field icons_by_xy table by porcelain status +---@field file_hl table? by porcelain status e.g. "AM" +---@field folder_hl table? by porcelain status +---@field icons_by_status HighlightedStringGit[]? by human status +---@field icons_by_xy table? by porcelain status local DecoratorGit = Decorator:new() +---Static factory method ---@param opts table ---@param explorer Explorer ---@return DecoratorGit -function DecoratorGit:new(opts, explorer) - local o = Decorator.new(self, { +function DecoratorGit:create(opts, explorer) + ---@type DecoratorGit + local o = { explorer = explorer, enabled = opts.git.enable, hl_pos = HL_POSITION[opts.renderer.highlight_git] or HL_POSITION.none, icon_placement = ICON_PLACEMENT[opts.renderer.icons.git_placement] or ICON_PLACEMENT.none, - }) - ---@cast o DecoratorGit + } + o = self:new(o) --[[@as DecoratorGit]] if not o.enabled then return o diff --git a/lua/nvim-tree/renderer/decorator/hidden.lua b/lua/nvim-tree/renderer/decorator/hidden.lua index 7ce4d457be1..1df68c48295 100644 --- a/lua/nvim-tree/renderer/decorator/hidden.lua +++ b/lua/nvim-tree/renderer/decorator/hidden.lua @@ -3,20 +3,22 @@ local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT local Decorator = require("nvim-tree.renderer.decorator") ---@class (exact) DecoratorHidden: Decorator ----@field icon HighlightedString|nil +---@field icon HighlightedString? local DecoratorHidden = Decorator:new() +---Static factory method ---@param opts table ---@param explorer Explorer ---@return DecoratorHidden -function DecoratorHidden:new(opts, explorer) - local o = Decorator.new(self, { +function DecoratorHidden:create(opts, explorer) + ---@type DecoratorHidden + local o = { explorer = explorer, enabled = true, hl_pos = HL_POSITION[opts.renderer.highlight_hidden] or HL_POSITION.none, icon_placement = ICON_PLACEMENT[opts.renderer.icons.hidden_placement] or ICON_PLACEMENT.none, - }) - ---@cast o DecoratorHidden + } + o = self:new(o) --[[@as DecoratorHidden]] if opts.renderer.icons.show.hidden then o.icon = { diff --git a/lua/nvim-tree/renderer/decorator/init.lua b/lua/nvim-tree/renderer/decorator/init.lua index 92fcc579b38..a80ce615a05 100644 --- a/lua/nvim-tree/renderer/decorator/init.lua +++ b/lua/nvim-tree/renderer/decorator/init.lua @@ -1,6 +1,8 @@ local HL_POSITION = require("nvim-tree.enum").HL_POSITION local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT +---Abstract Decorator +---Uses the factory pattern to instantiate child instances. ---@class (exact) Decorator ---@field private __index? table ---@field protected explorer Explorer diff --git a/lua/nvim-tree/renderer/decorator/modified.lua b/lua/nvim-tree/renderer/decorator/modified.lua index 75bb59c8446..4665343f0ee 100644 --- a/lua/nvim-tree/renderer/decorator/modified.lua +++ b/lua/nvim-tree/renderer/decorator/modified.lua @@ -9,17 +9,19 @@ local Decorator = require("nvim-tree.renderer.decorator") ---@field icon HighlightedString|nil local DecoratorModified = Decorator:new() +---Static factory method ---@param opts table ---@param explorer Explorer ---@return DecoratorModified -function DecoratorModified:new(opts, explorer) - local o = Decorator.new(self, { +function DecoratorModified:create(opts, explorer) + ---@type DecoratorModified + local o = { explorer = explorer, enabled = opts.modified.enable, hl_pos = HL_POSITION[opts.renderer.highlight_modified] or HL_POSITION.none, icon_placement = ICON_PLACEMENT[opts.renderer.icons.modified_placement] or ICON_PLACEMENT.none, - }) - ---@cast o DecoratorModified + } + o = self:new(o) --[[@as DecoratorModified]] if not o.enabled then return o diff --git a/lua/nvim-tree/renderer/decorator/opened.lua b/lua/nvim-tree/renderer/decorator/opened.lua index 5a17c2da6bf..a942aa622ae 100644 --- a/lua/nvim-tree/renderer/decorator/opened.lua +++ b/lua/nvim-tree/renderer/decorator/opened.lua @@ -10,17 +10,19 @@ local Decorator = require("nvim-tree.renderer.decorator") ---@field icon HighlightedString|nil local DecoratorOpened = Decorator:new() +---Static factory method ---@param opts table ---@param explorer Explorer ---@return DecoratorOpened -function DecoratorOpened:new(opts, explorer) - local o = Decorator.new(self, { +function DecoratorOpened:create(opts, explorer) + ---@type DecoratorOpened + local o = { explorer = explorer, enabled = true, hl_pos = HL_POSITION[opts.renderer.highlight_opened_files] or HL_POSITION.none, icon_placement = ICON_PLACEMENT.none, - }) - ---@cast o DecoratorOpened + } + o = self:new(o) --[[@as DecoratorOpened]] return o end From 102847dfbf44ad401756571d183cb436cc6c3b26 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 22 Sep 2024 17:33:29 +1000 Subject: [PATCH 20/44] note regression and commit --- lua/nvim-tree/node/init.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index cb6f15dcf6a..f13e9e54446 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -62,6 +62,7 @@ function BaseNode:update_git_status(parent_ignored, status) end end +---TODO this broke git parent status at ddc1d5f1c12847fce19a8f23d9d742b1bbf0ed31 ---@return GitStatus|nil function BaseNode:get_git_status() if not self.git_status then From e5d96f06f05720abe56c573f440403b8f10e16b8 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 23 Sep 2024 10:55:37 +1000 Subject: [PATCH 21/44] fix dir git status regression --- lua/nvim-tree/node/init.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index f13e9e54446..608db947786 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -48,7 +48,7 @@ end function BaseNode:update_git_status(parent_ignored, status) local get_status if self.nodes then - get_status = git.git_status_file + get_status = git.git_status_dir else get_status = git.git_status_file end @@ -62,7 +62,6 @@ function BaseNode:update_git_status(parent_ignored, status) end end ----TODO this broke git parent status at ddc1d5f1c12847fce19a8f23d9d742b1bbf0ed31 ---@return GitStatus|nil function BaseNode:get_git_status() if not self.git_status then From abc21e01203339561d5a973197acbdeaa862c902 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 23 Sep 2024 11:30:35 +1000 Subject: [PATCH 22/44] destroy nodes, not explorer --- lua/nvim-tree/explorer/init.lua | 12 ------------ lua/nvim-tree/node/directory.lua | 9 +++++++++ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index 817ded3eb54..a198d5757e6 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -75,18 +75,6 @@ function Explorer:expand(node) self:_load(node) end -function Explorer:destroy() - local function iterate(node) - node:destroy() - if node.nodes then - for _, child in pairs(node.nodes) do - iterate(child) - end - end - end - iterate(self) -end - ---@param node Node ---@param git_status table|nil function Explorer:reload(node, git_status) diff --git a/lua/nvim-tree/node/directory.lua b/lua/nvim-tree/node/directory.lua index 982390c4b85..ad46d352db3 100644 --- a/lua/nvim-tree/node/directory.lua +++ b/lua/nvim-tree/node/directory.lua @@ -49,4 +49,13 @@ function DirectoryNode:create(explorer, parent, absolute_path, name, fs_stat) return o end +function DirectoryNode:destroy() + BaseNode.destroy(self) + if self.nodes then + for _, node in pairs(self.nodes) do + node:destroy() + end + end +end + return DirectoryNode From 2e1cc1a61942658f5253019ceffc886129fe7650 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 23 Sep 2024 12:08:33 +1000 Subject: [PATCH 23/44] add BaseNode:is --- lua/nvim-tree/marks/init.lua | 4 +++- lua/nvim-tree/node/factory.lua | 2 ++ lua/nvim-tree/node/init.lua | 17 +++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/lua/nvim-tree/marks/init.lua b/lua/nvim-tree/marks/init.lua index 8fec6c663fc..8092f8f146a 100644 --- a/lua/nvim-tree/marks/init.lua +++ b/lua/nvim-tree/marks/init.lua @@ -8,6 +8,8 @@ local rename_file = require("nvim-tree.actions.fs.rename-file") local trash = require("nvim-tree.actions.fs.trash") local utils = require("nvim-tree.utils") +local DirectoryNode = require "nvim-tree.node.directory" + ---@class Marks ---@field config table hydrated user opts.filters ---@field private explorer Explorer @@ -152,7 +154,7 @@ function Marks:bulk_move() local node_at_cursor = lib.get_node_at_cursor() local default_path = core.get_cwd() - if node_at_cursor and node_at_cursor.type == "directory" then + if node_at_cursor and node_at_cursor:is(DirectoryNode) then default_path = node_at_cursor.absolute_path elseif node_at_cursor and node_at_cursor.parent then default_path = node_at_cursor.parent.absolute_path diff --git a/lua/nvim-tree/node/factory.lua b/lua/nvim-tree/node/factory.lua index bbf112576b0..2961fc6026b 100644 --- a/lua/nvim-tree/node/factory.lua +++ b/lua/nvim-tree/node/factory.lua @@ -5,6 +5,8 @@ local Watcher = require("nvim-tree.watcher") local M = {} +--- TODO merge #2922 and pass just stat, as stat.type from lstat is correct + ---Factory function to create the appropriate Node ---@param explorer Explorer ---@param parent Node diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index 608db947786..bd4ccd97181 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -38,6 +38,23 @@ function BaseNode:destroy() end end +---From plenary +---Checks if the object is an instance +---This will start with the lowest class and loop over all the superclasses. +---@param self BaseNode +---@param T BaseNode +---@return boolean +function BaseNode:is(T) + local mt = getmetatable(self) + while mt do + if mt == T then + return true + end + mt = getmetatable(mt) + end + return false +end + ---@return boolean function BaseNode:has_one_child_folder() return #self.nodes == 1 and self.nodes[1].nodes and vim.loop.fs_access(self.nodes[1].absolute_path, "R") or false From 5a863b2f478c0ba79a930e59afaff64512db59d7 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 23 Sep 2024 12:45:43 +1000 Subject: [PATCH 24/44] revert changes to create-file, handle in #2924 --- lua/nvim-tree/actions/fs/create-file.lua | 28 +++++++++++++----------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/lua/nvim-tree/actions/fs/create-file.lua b/lua/nvim-tree/actions/fs/create-file.lua index f4419dbb627..626ce685615 100644 --- a/lua/nvim-tree/actions/fs/create-file.lua +++ b/lua/nvim-tree/actions/fs/create-file.lua @@ -29,16 +29,14 @@ local function get_num_nodes(iter) return i end ----@param has_children boolean ----@param absolute_path string ----@param name string +---@param node Node ---@return string -local function get_containing_folder(has_children, absolute_path, name) - if has_children then - return utils.path_add_trailing(absolute_path) +local function get_containing_folder(node) + if node.nodes ~= nil then + return utils.path_add_trailing(node.absolute_path) end - local node_name_size = #(name or "") - return absolute_path:sub(0, -node_name_size - 1) + local node_name_size = #(node.name or "") + return node.absolute_path:sub(0, -node_name_size - 1) end ---@param node Node|nil @@ -48,15 +46,19 @@ function M.fn(node) return end - node = node and node:last_group_node() - - local containing_folder if not node or node.name == ".." then - containing_folder = get_containing_folder(core.get_explorer().nodes ~= nil, cwd, "") + node = { + absolute_path = cwd, + name = "", + nodes = core.get_explorer().nodes, + open = true, + } else - containing_folder = get_containing_folder(node.nodes ~= nil, node.absolute_path, node.name) + node = node:last_group_node() end + local containing_folder = get_containing_folder(node) + local input_opts = { prompt = "Create file ", default = containing_folder, From bb9df1573cccb0d48da99a0092a39752533e0ede Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 23 Sep 2024 13:13:29 +1000 Subject: [PATCH 25/44] extract methods from explorer --- lua/nvim-tree/explorer/init.lua | 68 +------------------------------- lua/nvim-tree/explorer/watch.lua | 4 +- lua/nvim-tree/marks/init.lua | 2 +- lua/nvim-tree/node/init.lua | 56 ++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 71 deletions(-) diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index a198d5757e6..b3a7c488d7d 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -186,26 +186,6 @@ function Explorer:reload(node, git_status) return node.nodes end ----TODO #2837 #2871 #2886 move this and similar to node ----Refresh contents and git status for a single node ----@param node Node ----@param callback function -function Explorer:refresh_node(node, callback) - if type(node) ~= "table" then - callback() - end - - local parent_node = utils.get_parent_of_group(node) - - self:reload_and_get_git_project(node.absolute_path, function(toplevel, project) - self:reload(parent_node, project) - - self:update_parent_statuses(parent_node, project, toplevel) - - callback() - end) -end - ---Refresh contents of all nodes to a path: actual directory and links. ---Groups will be expanded if needed. ---@param path string absolute path @@ -233,7 +213,7 @@ function Explorer:refresh_parent_nodes_for_path(path) local project = git.get_project(toplevel) or {} self:reload(node, project) - self:update_parent_statuses(node, project, toplevel) + node:update_parent_statuses(project, toplevel) end log.profile_end(profile) @@ -261,52 +241,6 @@ function Explorer:update_status(nodes_by_path, node_ignored, status) end end ----TODO #2837 #2871 #2886 move this and similar to node ----@private ----@param path string ----@param callback fun(toplevel: string|nil, project: table|nil) -function Explorer:reload_and_get_git_project(path, callback) - local toplevel = git.get_toplevel(path) - - git.reload_project(toplevel, path, function() - callback(toplevel, git.get_project(toplevel) or {}) - end) -end - ----TODO #2837 #2871 #2886 move this and similar to node ----@private ----@param node Node ----@param project table|nil ----@param root string|nil -function Explorer:update_parent_statuses(node, project, root) - while project and node do - -- step up to the containing project - if node.absolute_path == root then - -- stop at the top of the tree - if not node.parent then - break - end - - root = git.get_toplevel(node.parent.absolute_path) - - -- stop when no more projects - if not root then - break - end - - -- update the containing project - project = git.get_project(root) - git.reload_project(root, node.absolute_path, nil) - end - - -- update status - node:update_git_status(node.parent and node.parent:is_git_ignored() or false, project) - - -- maybe parent - node = node.parent - end -end - ---@private ---@param handle uv.uv_fs_t ---@param cwd string diff --git a/lua/nvim-tree/explorer/watch.lua b/lua/nvim-tree/explorer/watch.lua index ce69daaf0f9..7fd13f4c3fb 100644 --- a/lua/nvim-tree/explorer/watch.lua +++ b/lua/nvim-tree/explorer/watch.lua @@ -76,9 +76,7 @@ function M.create_watcher(node) else log.line("watcher", "node event executing refresh '%s'", node.absolute_path) end - node.explorer:refresh_node(node, function() - node.explorer.renderer:draw() - end) + node:refresh() end) end diff --git a/lua/nvim-tree/marks/init.lua b/lua/nvim-tree/marks/init.lua index 8092f8f146a..c2da9009ad8 100644 --- a/lua/nvim-tree/marks/init.lua +++ b/lua/nvim-tree/marks/init.lua @@ -8,7 +8,7 @@ local rename_file = require("nvim-tree.actions.fs.rename-file") local trash = require("nvim-tree.actions.fs.trash") local utils = require("nvim-tree.utils") -local DirectoryNode = require "nvim-tree.node.directory" +local DirectoryNode = require("nvim-tree.node.directory") ---@class Marks ---@field config table hydrated user opts.filters diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index bd4ccd97181..5bc43e39e5c 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -1,4 +1,5 @@ local git = require("nvim-tree.git") +local utils = require("nvim-tree.utils") ---Abstract Node class. ---Uses the abstract factory pattern to instantiate child instances. @@ -182,4 +183,59 @@ function BaseNode:last_group_node() return node end +---@param path string +---@param callback fun(toplevel: string|nil, project: table|nil) +function BaseNode:reload_and_get_git_project(path, callback) + local toplevel = git.get_toplevel(path) + + git.reload_project(toplevel, path, function() + callback(toplevel, git.get_project(toplevel) or {}) + end) +end + +---@param project table|nil +---@param root string|nil +function BaseNode:update_parent_statuses(project, root) + local node = self + while project and node do + -- step up to the containing project + if node.absolute_path == root then + -- stop at the top of the tree + if not node.parent then + break + end + + root = git.get_toplevel(node.parent.absolute_path) + + -- stop when no more projects + if not root then + break + end + + -- update the containing project + project = git.get_project(root) + git.reload_project(root, node.absolute_path, nil) + end + + -- update status + node:update_git_status(node.parent and node.parent:is_git_ignored() or false, project) + + -- maybe parent + node = node.parent + end +end + +---Refresh contents and git status for a single node +function BaseNode:refresh() + local parent_node = utils.get_parent_of_group(self) + + self:reload_and_get_git_project(self.absolute_path, function(toplevel, project) + self.explorer:reload(parent_node, project) + + parent_node:update_parent_statuses(project, toplevel) + + self.explorer.renderer:draw() + end) +end + return BaseNode From 6dd9af76450960808ffdc84e36c4a3f6711557bf Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 23 Sep 2024 13:19:39 +1000 Subject: [PATCH 26/44] extract methods from explorer --- lua/nvim-tree/node/init.lua | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index 5bc43e39e5c..d2da55b6ec3 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -183,16 +183,6 @@ function BaseNode:last_group_node() return node end ----@param path string ----@param callback fun(toplevel: string|nil, project: table|nil) -function BaseNode:reload_and_get_git_project(path, callback) - local toplevel = git.get_toplevel(path) - - git.reload_project(toplevel, path, function() - callback(toplevel, git.get_project(toplevel) or {}) - end) -end - ---@param project table|nil ---@param root string|nil function BaseNode:update_parent_statuses(project, root) @@ -228,8 +218,11 @@ end ---Refresh contents and git status for a single node function BaseNode:refresh() local parent_node = utils.get_parent_of_group(self) + local toplevel = git.get_toplevel(self.absolute_path) + + git.reload_project(toplevel, self.absolute_path, function() + local project = git.get_project(toplevel) or {} - self:reload_and_get_git_project(self.absolute_path, function(toplevel, project) self.explorer:reload(parent_node, project) parent_node:update_parent_statuses(project, toplevel) From 448839f2cc174428e1dc77b6580f347317e302c8 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 23 Sep 2024 13:32:48 +1000 Subject: [PATCH 27/44] extract methods from explorer --- lua/nvim-tree/enum.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/nvim-tree/enum.lua b/lua/nvim-tree/enum.lua index 740fa04a5ea..a680c2b3fdc 100644 --- a/lua/nvim-tree/enum.lua +++ b/lua/nvim-tree/enum.lua @@ -1,6 +1,6 @@ local M = {} ----Roughly synced with uv.fs_stat.result +---Must be synced with uv.fs_stat.result as it is compared with it ---@enum (key) NODE_TYPE M.NODE_TYPE = { directory = 1, From 21ec9e1c414520194a88b3de09b4dc58d215f780 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 23 Sep 2024 13:47:35 +1000 Subject: [PATCH 28/44] use Node everywhere in luadoc --- lua/nvim-tree/actions/fs/create-file.lua | 2 +- lua/nvim-tree/actions/tree/modifiers/expand-all.lua | 6 +++--- lua/nvim-tree/api.lua | 2 +- lua/nvim-tree/buffers.lua | 4 ++-- lua/nvim-tree/explorer/init.lua | 2 +- lua/nvim-tree/explorer/live-filter.lua | 4 ++-- lua/nvim-tree/explorer/sorters.lua | 2 +- lua/nvim-tree/lib.lua | 8 +++++++- lua/nvim-tree/log.lua | 2 +- lua/nvim-tree/node/init.lua | 2 +- lua/nvim-tree/renderer/builder.lua | 2 +- lua/nvim-tree/renderer/components/diagnostics.lua | 4 ++-- lua/nvim-tree/renderer/components/padding.lua | 4 ++-- lua/nvim-tree/utils.lua | 6 +++--- 14 files changed, 28 insertions(+), 22 deletions(-) diff --git a/lua/nvim-tree/actions/fs/create-file.lua b/lua/nvim-tree/actions/fs/create-file.lua index 626ce685615..588c978fc92 100644 --- a/lua/nvim-tree/actions/fs/create-file.lua +++ b/lua/nvim-tree/actions/fs/create-file.lua @@ -39,7 +39,7 @@ local function get_containing_folder(node) return node.absolute_path:sub(0, -node_name_size - 1) end ----@param node Node|nil +---@param node Node? function M.fn(node) local cwd = core.get_cwd() if cwd == nil then diff --git a/lua/nvim-tree/actions/tree/modifiers/expand-all.lua b/lua/nvim-tree/actions/tree/modifiers/expand-all.lua index b7e24c9551f..ed898de2a30 100644 --- a/lua/nvim-tree/actions/tree/modifiers/expand-all.lua +++ b/lua/nvim-tree/actions/tree/modifiers/expand-all.lua @@ -61,10 +61,10 @@ local function gen_iterator() end end ----@param base_node table -function M.fn(base_node) +---@param node Node +function M.fn(node) local explorer = core.get_explorer() - local node = base_node.nodes and base_node or explorer + node = node.nodes and node or explorer if gen_iterator()(node) then notify.warn("expansion iteration was halted after " .. M.MAX_FOLDER_DISCOVERY .. " discovered folders") end diff --git a/lua/nvim-tree/api.lua b/lua/nvim-tree/api.lua index f0f1c03f821..b5fe7646d52 100644 --- a/lua/nvim-tree/api.lua +++ b/lua/nvim-tree/api.lua @@ -198,7 +198,7 @@ Api.fs.copy.basename = wrap_node(wrap_explorer_member("clipboard", "copy_basenam Api.fs.copy.relative_path = wrap_node(wrap_explorer_member("clipboard", "copy_path")) ---@param mode string ----@param node table +---@param node Node local function edit(mode, node) local path = node.absolute_path if node.link_to and not node.nodes then diff --git a/lua/nvim-tree/buffers.lua b/lua/nvim-tree/buffers.lua index 51ebe141a93..954c7e4011c 100644 --- a/lua/nvim-tree/buffers.lua +++ b/lua/nvim-tree/buffers.lua @@ -21,7 +21,7 @@ function M.reload_modified() end end ----@param node table +---@param node Node ---@return boolean function M.is_modified(node) return node @@ -32,7 +32,7 @@ function M.is_modified(node) end ---A buffer exists for the node's absolute path ----@param node table +---@param node Node ---@return boolean function M.is_opened(node) return node and vim.fn.bufloaded(node.absolute_path) > 0 diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index b3a7c488d7d..ad03fd675b9 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -228,7 +228,7 @@ function Explorer:_load(node) end ---@private ----@param nodes_by_path table +---@param nodes_by_path Node[] ---@param node_ignored boolean ---@param status table|nil ---@return fun(node: Node): table diff --git a/lua/nvim-tree/explorer/live-filter.lua b/lua/nvim-tree/explorer/live-filter.lua index 7cdfc35dd80..ca772b34b9b 100644 --- a/lua/nvim-tree/explorer/live-filter.lua +++ b/lua/nvim-tree/explorer/live-filter.lua @@ -23,7 +23,7 @@ function LiveFilter:new(opts, explorer) return o end ----@param node_ Node|nil +---@param node_ Node? local function reset_filter(self, node_) node_ = node_ or self.explorer @@ -85,7 +85,7 @@ local function matches(self, node) return vim.regex(self.filter):match_str(name) ~= nil end ----@param node_ Node|nil +---@param node_ Node? function LiveFilter:apply_filter(node_) if not self.filter or self.filter == "" then reset_filter(self, node_) diff --git a/lua/nvim-tree/explorer/sorters.lua b/lua/nvim-tree/explorer/sorters.lua index 4ec4c3d596e..bcf55900af5 100644 --- a/lua/nvim-tree/explorer/sorters.lua +++ b/lua/nvim-tree/explorer/sorters.lua @@ -111,7 +111,7 @@ local function split_merge(t, first, last, comparator) end ---Perform a merge sort using sorter option. ----@param t table nodes +---@param t Node[] function Sorter:sort(t) if self.user then local t_user = {} diff --git a/lua/nvim-tree/lib.lua b/lua/nvim-tree/lib.lua index 77b44b9cd18..092b412471c 100644 --- a/lua/nvim-tree/lib.lua +++ b/lua/nvim-tree/lib.lua @@ -42,8 +42,9 @@ function M.get_node_at_cursor() return utils.get_nodes_by_line(core.get_explorer().nodes, core.get_nodes_starting_line())[cursor[1]] end +---TODO move to node ---Create a sanitized partial copy of a node, populating children recursively. ----@param node Node|nil +---@param node Node? ---@return Node|nil cloned node local function clone_node(node) if not node then @@ -83,6 +84,7 @@ function M.get_nodes() return clone_node(core.get_explorer()) end +---TODO move to node ---Group empty folders -- Recursively group nodes ---@param node Node @@ -99,6 +101,7 @@ function M.group_empty_folders(node) return node.nodes end +---TODO move to node ---Ungroup empty folders -- If a node is grouped, ungroup it: put node.group_next to the node.nodes and set node.group_next to nil ---@param node Node @@ -111,6 +114,7 @@ function M.ungroup_empty_folders(node) end end +---TODO move to node ---@param node Node ---@return Node[] function M.get_all_nodes_in_group(node) @@ -123,6 +127,7 @@ function M.get_all_nodes_in_group(node) return nodes end +---TODO move to node -- Toggle group empty folders ---@param head_node Node local function toggle_group_folders(head_node) @@ -135,6 +140,7 @@ local function toggle_group_folders(head_node) end end +---TODO move to node ---@param node Node function M.expand_or_collapse(node, toggle_group) local explorer = core.get_explorer() diff --git a/lua/nvim-tree/log.lua b/lua/nvim-tree/log.lua index ad07a8562ef..8e796b9e6c8 100644 --- a/lua/nvim-tree/log.lua +++ b/lua/nvim-tree/log.lua @@ -71,7 +71,7 @@ end --- Write to log file the inspection of a node --- defaults to the node under cursor if none is provided ---@param typ string as per log.types config ----@param node table|nil node to be inspected +---@param node Node? node to be inspected ---@param fmt string for string.format ---@vararg any arguments for string.format function M.node(typ, node, fmt, ...) diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index d2da55b6ec3..3ef6ee5f8af 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -21,7 +21,7 @@ local BaseNode = {} ---@alias Node RootNode|BaseNode|DirectoryNode|FileNode|LinkNode ----@param o BaseNode|nil +---@param o BaseNode? ---@return BaseNode function BaseNode:new(o) o = o or {} diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index e23ef7f87a1..81d82c9b029 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -189,7 +189,7 @@ function Builder:build_symlink(node) end ---@private ----@param node table +---@param node Node ---@return HighlightedString icon ---@return HighlightedString name function Builder:build_file(node) diff --git a/lua/nvim-tree/renderer/components/diagnostics.lua b/lua/nvim-tree/renderer/components/diagnostics.lua index 8f749343fef..e51712e7746 100644 --- a/lua/nvim-tree/renderer/components/diagnostics.lua +++ b/lua/nvim-tree/renderer/components/diagnostics.lua @@ -14,7 +14,7 @@ local M = { } ---Diagnostics highlight group and position when highlight_diagnostics. ----@param node table +---@param node Node ---@return HL_POSITION position none when no status ---@return string|nil group only when status function M.get_highlight(node) @@ -38,7 +38,7 @@ function M.get_highlight(node) end ---diagnostics icon if there is a status ----@param node table +---@param node Node ---@return HighlightedString|nil modified icon function M.get_icon(node) if node and M.config.diagnostics.enable and M.config.renderer.icons.show.diagnostics then diff --git a/lua/nvim-tree/renderer/components/padding.lua b/lua/nvim-tree/renderer/components/padding.lua index 2d808cc671a..8ca25e8a6cf 100644 --- a/lua/nvim-tree/renderer/components/padding.lua +++ b/lua/nvim-tree/renderer/components/padding.lua @@ -59,7 +59,7 @@ end ---@param depth integer ---@param idx integer ---@param nodes_number integer ----@param node table +---@param node Node ---@param markers table ---@return HighlightedString[] function M.get_indent_markers(depth, idx, nodes_number, node, markers, early_stop) @@ -79,7 +79,7 @@ function M.get_indent_markers(depth, idx, nodes_number, node, markers, early_sto return { str = str, hl = { "NvimTreeIndentMarker" } } end ----@param node table +---@param node Node ---@return HighlightedString[]|nil function M.get_arrows(node) if not M.config.icons.show.folder_arrow then diff --git a/lua/nvim-tree/utils.lua b/lua/nvim-tree/utils.lua index b3f70760425..d5902d3fc98 100644 --- a/lua/nvim-tree/utils.lua +++ b/lua/nvim-tree/utils.lua @@ -120,7 +120,7 @@ end -- Find the line number of a node. -- Return -1 is node is nil or not found. ----@param node Node|nil +---@param node Node? ---@return integer function M.find_node_line(node) if not node then @@ -472,7 +472,7 @@ end ---Focus node passed as parameter if visible, otherwise focus first visible parent. ---If none of the parents is visible focus root. ---If node is nil do nothing. ----@param node Node|nil node to focus +---@param node Node? node to focus function M.focus_node_or_parent(node) local explorer = require("nvim-tree.core").get_explorer() @@ -548,7 +548,7 @@ function M.array_remove_nils(array) end, array) end ----@param f fun(node: Node|nil) +---@param f fun(node: Node?) ---@return function function M.inject_node(f) return function() From 447efc92a0a9001db908c07acb8ccf98b76e4cc2 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 23 Sep 2024 15:56:16 +1000 Subject: [PATCH 29/44] extract methods from lib --- lua/nvim-tree/lib.lua | 41 +++----------------------------- lua/nvim-tree/node/directory.lua | 18 ++++++++++++++ lua/nvim-tree/node/file.lua | 10 ++++++++ lua/nvim-tree/node/init.lua | 26 ++++++++++++++++++++ lua/nvim-tree/node/link.lua | 20 ++++++++++++++++ 5 files changed, 77 insertions(+), 38 deletions(-) diff --git a/lua/nvim-tree/lib.lua b/lua/nvim-tree/lib.lua index 092b412471c..f8490698efc 100644 --- a/lua/nvim-tree/lib.lua +++ b/lua/nvim-tree/lib.lua @@ -42,46 +42,11 @@ function M.get_node_at_cursor() return utils.get_nodes_by_line(core.get_explorer().nodes, core.get_nodes_starting_line())[cursor[1]] end ----TODO move to node ----Create a sanitized partial copy of a node, populating children recursively. ----@param node Node? ----@return Node|nil cloned node -local function clone_node(node) - if not node then - node = core.get_explorer() - if not node then - return nil - end - end - - local n = { - absolute_path = node.absolute_path, - executable = node.executable, - extension = node.extension, - git_status = node.git_status, - has_children = node.has_children, - hidden = node.hidden, - link_to = node.link_to, - name = node.name, - open = node.open, - type = node.type, - fs_stat = node.fs_stat, - } - - if type(node.nodes) == "table" then - n.nodes = {} - for _, child in ipairs(node.nodes) do - table.insert(n.nodes, clone_node(child)) - end - end - - return n -end - ---Api.tree.get_nodes ----@return Node[]|nil +---@return Node[]? function M.get_nodes() - return clone_node(core.get_explorer()) + local explorer = core.get_explorer() + return explorer and explorer:clone() end ---TODO move to node diff --git a/lua/nvim-tree/node/directory.lua b/lua/nvim-tree/node/directory.lua index ad46d352db3..050d3e35b8f 100644 --- a/lua/nvim-tree/node/directory.lua +++ b/lua/nvim-tree/node/directory.lua @@ -58,4 +58,22 @@ function DirectoryNode:destroy() end end +---Create a sanitized partial copy of a node, populating children recursively. +---@return DirectoryNode cloned +function DirectoryNode:clone() + local clone = BaseNode.clone(self) --[[@as DirectoryNode]] + + clone.has_children = self.has_children + clone.group_next = nil + clone.nodes = {} + clone.open = self.open + clone.hidden_stats = nil + + for _, child in ipairs(self.nodes) do + table.insert(clone.nodes, child:clone()) + end + + return clone +end + return DirectoryNode diff --git a/lua/nvim-tree/node/file.lua b/lua/nvim-tree/node/file.lua index 2a4140bd7b6..f504631b7fb 100644 --- a/lua/nvim-tree/node/file.lua +++ b/lua/nvim-tree/node/file.lua @@ -36,4 +36,14 @@ function FileNode:create(explorer, parent, absolute_path, name, fs_stat) return o end +---Create a sanitized partial copy of a node, populating children recursively. +---@return FileNode cloned +function FileNode:clone() + local clone = BaseNode.clone(self) --[[@as FileNode]] + + clone.extension = self.extension + + return clone +end + return FileNode diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index 3ef6ee5f8af..19623ef0ab6 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -231,4 +231,30 @@ function BaseNode:refresh() end) end +---Create a sanitized partial copy of a node, populating children recursively. +---@return BaseNode cloned +function BaseNode:clone() + + ---@type Explorer + local placeholder + + ---@type BaseNode + local clone = { + type = self.type, + explorer = placeholder, + absolute_path = self.absolute_path, + executable = self.executable, + fs_stat = self.fs_stat, + git_status = self.git_status, + hidden = self.hidden, + is_dot = self.is_dot, + name = self.name, + parent = nil, + watcher = nil, + diag_status = nil, + } + + return clone +end + return BaseNode diff --git a/lua/nvim-tree/node/link.lua b/lua/nvim-tree/node/link.lua index bb43384b62b..2df9d920092 100644 --- a/lua/nvim-tree/node/link.lua +++ b/lua/nvim-tree/node/link.lua @@ -66,4 +66,24 @@ function LinkNode:create(explorer, parent, absolute_path, name, fs_stat) return o end +---Create a sanitized partial copy of a node, populating children recursively. +---@return LinkNode cloned +function LinkNode:clone() + local clone = BaseNode.clone(self) --[[@as LinkNode]] + + clone.has_children = self.has_children + clone.group_next = nil + clone.link_to = self.link_to + clone.nodes = {} + clone.open = self.open + + if self.nodes then + for _, child in ipairs(self.nodes) do + table.insert(clone.nodes, child:clone()) + end + end + + return clone +end + return LinkNode From b9704a4e7c7c4be953b1e85bb57f9072a337f3b5 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 23 Sep 2024 16:06:43 +1000 Subject: [PATCH 30/44] extract methods from lib --- lua/nvim-tree.lua | 2 +- lua/nvim-tree/actions/moves/parent.lua | 2 +- lua/nvim-tree/lib.lua | 17 ++--------------- lua/nvim-tree/node/init.lua | 25 ++++++++++++++++++++++--- lua/nvim-tree/utils.lua | 10 ---------- 5 files changed, 26 insertions(+), 30 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index c202d71ddc1..c2369a1cbcc 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -125,7 +125,7 @@ function M.place_cursor_on_node() if not node or node.name == ".." then return end - node = utils.get_parent_of_group(node) + node = node:get_parent_of_group() local line = vim.api.nvim_get_current_line() local cursor = vim.api.nvim_win_get_cursor(0) diff --git a/lua/nvim-tree/actions/moves/parent.lua b/lua/nvim-tree/actions/moves/parent.lua index 3e82ed723d7..88eca47567a 100644 --- a/lua/nvim-tree/actions/moves/parent.lua +++ b/lua/nvim-tree/actions/moves/parent.lua @@ -20,7 +20,7 @@ function M.fn(should_close) return end - local parent = utils.get_parent_of_group(node).parent + local parent = node:get_parent_of_group().parent if not parent or not parent.parent then return view.set_cursor({ 1, 0 }) diff --git a/lua/nvim-tree/lib.lua b/lua/nvim-tree/lib.lua index f8490698efc..256bc55dd5b 100644 --- a/lua/nvim-tree/lib.lua +++ b/lua/nvim-tree/lib.lua @@ -79,19 +79,6 @@ function M.ungroup_empty_folders(node) end end ----TODO move to node ----@param node Node ----@return Node[] -function M.get_all_nodes_in_group(node) - local next_node = utils.get_parent_of_group(node) - local nodes = {} - while next_node do - table.insert(nodes, next_node) - next_node = next_node.group_next - end - return nodes -end - ---TODO move to node -- Toggle group empty folders ---@param head_node Node @@ -119,7 +106,7 @@ function M.expand_or_collapse(node, toggle_group) explorer:expand(node) end - local head_node = utils.get_parent_of_group(node) + local head_node = node:get_parent_of_group() if toggle_group then toggle_group_folders(head_node) end @@ -131,7 +118,7 @@ function M.expand_or_collapse(node, toggle_group) else next_open = not open end - for _, n in ipairs(M.get_all_nodes_in_group(head_node)) do + for _, n in ipairs(head_node:get_all_nodes_in_group()) do n.open = next_open end diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index 19623ef0ab6..879e9a6d072 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -1,5 +1,4 @@ local git = require("nvim-tree.git") -local utils = require("nvim-tree.utils") ---Abstract Node class. ---Uses the abstract factory pattern to instantiate child instances. @@ -217,7 +216,7 @@ end ---Refresh contents and git status for a single node function BaseNode:refresh() - local parent_node = utils.get_parent_of_group(self) + local parent_node = self:get_parent_of_group() local toplevel = git.get_toplevel(self.absolute_path) git.reload_project(toplevel, self.absolute_path, function() @@ -231,10 +230,30 @@ function BaseNode:refresh() end) end +---Get the highest parent of grouped nodes +---@return Node node or parent +function BaseNode:get_parent_of_group() + local node = self + while node and node.parent and node.parent.group_next do + node = node.parent or node + end + return node +end + +---@return Node[] +function BaseNode:get_all_nodes_in_group() + local next_node = self:get_parent_of_group() + local nodes = {} + while next_node do + table.insert(nodes, next_node) + next_node = next_node.group_next + end + return nodes +end + ---Create a sanitized partial copy of a node, populating children recursively. ---@return BaseNode cloned function BaseNode:clone() - ---@type Explorer local placeholder diff --git a/lua/nvim-tree/utils.lua b/lua/nvim-tree/utils.lua index d5902d3fc98..3d39c882820 100644 --- a/lua/nvim-tree/utils.lua +++ b/lua/nvim-tree/utils.lua @@ -173,16 +173,6 @@ function M.get_node_from_path(path) :iterate() end ----Get the highest parent of grouped nodes ----@param node Node ----@return Node node or parent -function M.get_parent_of_group(node) - while node and node.parent and node.parent.group_next do - node = node.parent or node - end - return node -end - M.default_format_hidden_count = function(hidden_count, simple) local parts = {} local total_count = 0 From be1d8b8e0d3f796ecc01dcb23fd8e818f224db07 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 29 Sep 2024 17:56:05 +1000 Subject: [PATCH 31/44] lint --- lua/nvim-tree/node/init.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index 879e9a6d072..ad543a6b78f 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -255,12 +255,12 @@ end ---@return BaseNode cloned function BaseNode:clone() ---@type Explorer - local placeholder + local explorer_placeholder = nil ---@type BaseNode local clone = { type = self.type, - explorer = placeholder, + explorer = explorer_placeholder, absolute_path = self.absolute_path, executable = self.executable, fs_stat = self.fs_stat, From 9c1c201ab870cf9bb9a585e1695b56dc259de465 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 6 Oct 2024 10:42:10 +1100 Subject: [PATCH 32/44] remove unused code --- lua/nvim-tree/explorer/node-builders.lua | 107 ----------------------- lua/nvim-tree/explorer/node.lua | 105 ---------------------- 2 files changed, 212 deletions(-) delete mode 100644 lua/nvim-tree/explorer/node-builders.lua delete mode 100644 lua/nvim-tree/explorer/node.lua diff --git a/lua/nvim-tree/explorer/node-builders.lua b/lua/nvim-tree/explorer/node-builders.lua deleted file mode 100644 index 10e958168aa..00000000000 --- a/lua/nvim-tree/explorer/node-builders.lua +++ /dev/null @@ -1,107 +0,0 @@ -local utils = require("nvim-tree.utils") -local watch = require("nvim-tree.explorer.watch") - -local M = {} - ----@param parent Node ----@param absolute_path string ----@param name string ----@param fs_stat uv.fs_stat.result|nil ----@return Node -function M.folder(parent, absolute_path, name, fs_stat) - local handle = vim.loop.fs_scandir(absolute_path) - local has_children = handle and vim.loop.fs_scandir_next(handle) ~= nil - - local node = { - type = "directory", - absolute_path = absolute_path, - fs_stat = fs_stat, - group_next = nil, -- If node is grouped, this points to the next child dir/link node - has_children = has_children, - name = name, - nodes = {}, - open = false, - parent = parent, - } - - node.watcher = watch.create_watcher(node) - - return node -end - ---- path is an executable file or directory ----@param absolute_path string ----@return boolean|nil -function M.is_executable(absolute_path) - if utils.is_windows or utils.is_wsl then - --- executable detection on windows is buggy and not performant hence it is disabled - return false - else - return vim.loop.fs_access(absolute_path, "X") - end -end - ----@param parent Node ----@param absolute_path string ----@param name string ----@param fs_stat uv.fs_stat.result|nil ----@return Node -function M.file(parent, absolute_path, name, fs_stat) - local ext = string.match(name, ".?[^.]+%.(.*)") or "" - - return { - type = "file", - absolute_path = absolute_path, - executable = M.is_executable(absolute_path), - extension = ext, - fs_stat = fs_stat, - name = name, - parent = parent, - } -end - --- TODO-INFO: sometimes fs_realpath returns nil --- I expect this be a bug in glibc, because it fails to retrieve the path for some --- links (for instance libr2.so in /usr/lib) and thus even with a C program realpath fails --- when it has no real reason to. Maybe there is a reason, but errno is definitely wrong. --- So we need to check for link_to ~= nil when adding new links to the main tree ----@param parent Node ----@param absolute_path string ----@param name string ----@param fs_stat uv.fs_stat.result|nil ----@return Node -function M.link(parent, absolute_path, name, fs_stat) - --- I dont know if this is needed, because in my understanding, there isn't hard links in windows, but just to be sure i changed it. - local link_to = vim.loop.fs_realpath(absolute_path) - local open, nodes, has_children - - local is_dir_link = (link_to ~= nil) and vim.loop.fs_stat(link_to).type == "directory" - - if is_dir_link and link_to then - local handle = vim.loop.fs_scandir(link_to) - has_children = handle and vim.loop.fs_scandir_next(handle) ~= nil - open = false - nodes = {} - end - - local node = { - type = "link", - absolute_path = absolute_path, - fs_stat = fs_stat, - group_next = nil, -- If node is grouped, this points to the next child dir/link node - has_children = has_children, - link_to = link_to, - name = name, - nodes = nodes, - open = open, - parent = parent, - } - - if is_dir_link then - node.watcher = watch.create_watcher(node) - end - - return node -end - -return M diff --git a/lua/nvim-tree/explorer/node.lua b/lua/nvim-tree/explorer/node.lua deleted file mode 100644 index 0a6c21bbaae..00000000000 --- a/lua/nvim-tree/explorer/node.lua +++ /dev/null @@ -1,105 +0,0 @@ -local git = {} -- circular dependencies - -local M = {} - ----@param node Node ----@return GitStatus|nil -function M.get_git_status(node) - local git_status = node and node.git_status - if not git_status then - -- status doesn't exist - return nil - end - - if not node.nodes then - -- file - return git_status.file and { git_status.file } - end - - -- dir - if not M.config.git.show_on_dirs then - return nil - end - - local status = {} - if not require("nvim-tree.lib").get_last_group_node(node).open or M.config.git.show_on_open_dirs then - -- dir is closed or we should show on open_dirs - if git_status.file ~= nil then - table.insert(status, git_status.file) - end - if git_status.dir ~= nil then - if git_status.dir.direct ~= nil then - for _, s in pairs(node.git_status.dir.direct) do - table.insert(status, s) - end - end - if git_status.dir.indirect ~= nil then - for _, s in pairs(node.git_status.dir.indirect) do - table.insert(status, s) - end - end - end - else - -- dir is open and we shouldn't show on open_dirs - if git_status.file ~= nil then - table.insert(status, git_status.file) - end - if git_status.dir ~= nil and git_status.dir.direct ~= nil then - local deleted = { - [" D"] = true, - ["D "] = true, - ["RD"] = true, - ["DD"] = true, - } - for _, s in pairs(node.git_status.dir.direct) do - if deleted[s] then - table.insert(status, s) - end - end - end - end - if #status == 0 then - return nil - else - return status - 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 - node:update_git_status(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 -function M.node_destroy(node) - if not node then - return - end - - if node.watcher then - node.watcher:destroy() - node.watcher = nil - end -end - -function M.setup(opts) - M.config = { - git = opts.git, - } - - git = require("nvim-tree.git") -end - -return M From f91975e3f8924676b82d3ec83f92c9002de9fd69 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 7 Oct 2024 09:34:02 +1100 Subject: [PATCH 33/44] don't call methods on fake root node --- lua/nvim-tree/actions/fs/clipboard.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lua/nvim-tree/actions/fs/clipboard.lua b/lua/nvim-tree/actions/fs/clipboard.lua index 5fd2a4b899c..cc75be4d13f 100644 --- a/lua/nvim-tree/actions/fs/clipboard.lua +++ b/lua/nvim-tree/actions/fs/clipboard.lua @@ -217,9 +217,10 @@ end ---@param action ACTION ---@param action_fn fun(source: string, dest: string) function Clipboard:do_paste(node, action, action_fn) - node = node:last_group_node() if node.name == ".." then node = self.explorer + else + node = node:last_group_node() end local clip = self.data[action] if #clip == 0 then From fe466d3a0bdb6db94320bcc85212c574759d9eac Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 7 Oct 2024 09:51:36 +1100 Subject: [PATCH 34/44] get_node_at_cursor returns explorer (root) node instead of { name = '..' } --- lua/nvim-tree/lib.lua | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lua/nvim-tree/lib.lua b/lua/nvim-tree/lib.lua index 256bc55dd5b..9d6c7669259 100644 --- a/lua/nvim-tree/lib.lua +++ b/lua/nvim-tree/lib.lua @@ -14,6 +14,7 @@ local M = { } ---Cursor position as per vim.api.nvim_win_get_cursor +---nil on no explorer or invalid view win ---@return integer[]|nil function M.get_cursor_position() if not core.get_explorer() then @@ -30,16 +31,21 @@ end ---@return Node|nil function M.get_node_at_cursor() + local explorer = core.get_explorer() + if not explorer then + return + end + local cursor = M.get_cursor_position() if not cursor then return end if cursor[1] == 1 and view.is_root_folder_visible(core.get_cwd()) then - return { name = ".." } + return explorer end - return utils.get_nodes_by_line(core.get_explorer().nodes, core.get_nodes_starting_line())[cursor[1]] + return utils.get_nodes_by_line(explorer.nodes, core.get_nodes_starting_line())[cursor[1]] end ---Api.tree.get_nodes From 3a55b5d53684f4a7e2499bb969595dfb6a4c59cb Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 7 Oct 2024 09:52:07 +1100 Subject: [PATCH 35/44] remove unused inject_node --- lua/nvim-tree/utils.lua | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lua/nvim-tree/utils.lua b/lua/nvim-tree/utils.lua index 3d39c882820..495e6679f14 100644 --- a/lua/nvim-tree/utils.lua +++ b/lua/nvim-tree/utils.lua @@ -538,14 +538,6 @@ function M.array_remove_nils(array) end, array) end ----@param f fun(node: Node?) ----@return function -function M.inject_node(f) - return function() - f(require("nvim-tree.lib").get_node_at_cursor()) - end -end - --- Is the buffer named NvimTree_[0-9]+ a tree? filetype is "NvimTree" or not readable file. --- This is cheap, as the readable test should only ever be needed when resuming a vim session. ---@param bufnr number|nil may be 0 or nil for current From 7ae7a53594bb08ceabf2f7fec36f271ab86c8c70 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 14 Sep 2024 16:10:31 +1000 Subject: [PATCH 36/44] refactor(#2875): multi instance renderer From a1dff3cbfbedaba8cbeaa8c3bcbb9baf96bf723f Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 15 Sep 2024 13:04:01 +1000 Subject: [PATCH 37/44] refactor(#2875): multi instance renderer From 98debc73ab6e87179a1fdf187b0d10b559a74225 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 16 Sep 2024 14:06:14 +1000 Subject: [PATCH 38/44] refactor(#2875): multi instance renderer From 966ef402a124b5c68d61ec84cd11ae6779270540 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 30 Sep 2024 12:44:04 +1000 Subject: [PATCH 39/44] extract methods from lib --- lua/nvim-tree/actions/moves/item.lua | 4 +- lua/nvim-tree/api.lua | 2 +- lua/nvim-tree/lib.lua | 78 ---------------------------- lua/nvim-tree/node/init.lua | 66 +++++++++++++++++++++++ lua/nvim-tree/renderer/builder.lua | 2 +- 5 files changed, 70 insertions(+), 82 deletions(-) diff --git a/lua/nvim-tree/actions/moves/item.lua b/lua/nvim-tree/actions/moves/item.lua index 74e27422542..ec73d010b5f 100644 --- a/lua/nvim-tree/actions/moves/item.lua +++ b/lua/nvim-tree/actions/moves/item.lua @@ -74,7 +74,7 @@ local function expand_node(node) if not node.open then -- Expand the node. -- Should never collapse since we checked open. - lib.expand_or_collapse(node) + node:expand_or_collapse() end end @@ -97,7 +97,7 @@ local function move_next_recursive(what, skip_gitignored) valid = status_is_valid(node_init, what, skip_gitignored) end if node_init.nodes ~= nil and valid and not node_init.open then - lib.expand_or_collapse(node_init) + node_init:expand_or_collapse() end move("next", what, skip_gitignored) diff --git a/lua/nvim-tree/api.lua b/lua/nvim-tree/api.lua index b5fe7646d52..c153c07ad60 100644 --- a/lua/nvim-tree/api.lua +++ b/lua/nvim-tree/api.lua @@ -214,7 +214,7 @@ local function open_or_expand_or_dir_up(mode, toggle_group) if node.name == ".." then actions.root.change_dir.fn("..") elseif node.nodes then - lib.expand_or_collapse(node, toggle_group) + node:expand_or_collapse(toggle_group) elseif not toggle_group then edit(mode, node) end diff --git a/lua/nvim-tree/lib.lua b/lua/nvim-tree/lib.lua index 9d6c7669259..15ccb337aa1 100644 --- a/lua/nvim-tree/lib.lua +++ b/lua/nvim-tree/lib.lua @@ -55,84 +55,6 @@ function M.get_nodes() return explorer and explorer:clone() end ----TODO move to node ----Group empty folders --- Recursively group nodes ----@param node Node ----@return Node[] -function M.group_empty_folders(node) - local is_root = not node.parent - local child_folder_only = node:has_one_child_folder() and node.nodes[1] - if M.group_empty and not is_root and child_folder_only then - node.group_next = child_folder_only - local ns = M.group_empty_folders(child_folder_only) - node.nodes = ns or {} - return ns - end - return node.nodes -end - ----TODO move to node ----Ungroup empty folders --- If a node is grouped, ungroup it: put node.group_next to the node.nodes and set node.group_next to nil ----@param node Node -function M.ungroup_empty_folders(node) - local cur = node - while cur and cur.group_next do - cur.nodes = { cur.group_next } - cur.group_next = nil - cur = cur.nodes[1] - end -end - ----TODO move to node --- Toggle group empty folders ----@param head_node Node -local function toggle_group_folders(head_node) - local is_grouped = head_node.group_next ~= nil - - if is_grouped then - M.ungroup_empty_folders(head_node) - else - M.group_empty_folders(head_node) - end -end - ----TODO move to node ----@param node Node -function M.expand_or_collapse(node, toggle_group) - local explorer = core.get_explorer() - - toggle_group = toggle_group or false - if node.has_children then - node.has_children = false - end - - if #node.nodes == 0 and explorer then - explorer:expand(node) - end - - local head_node = node:get_parent_of_group() - if toggle_group then - toggle_group_folders(head_node) - end - - local open = node:last_group_node().open - local next_open - if toggle_group then - next_open = open - else - next_open = not open - end - for _, n in ipairs(head_node:get_all_nodes_in_group()) do - n.open = next_open - end - - if explorer then - explorer.renderer:draw() - end -end - function M.set_target_win() local id = vim.api.nvim_get_current_win() local tree_id = view.get_winnr() diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index ad543a6b78f..758c9c9af2c 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -251,6 +251,72 @@ function BaseNode:get_all_nodes_in_group() return nodes end +-- Toggle group empty folders +function BaseNode:toggle_group_folders() + local is_grouped = self.group_next ~= nil + + if is_grouped then + self:ungroup_empty_folders() + else + self:group_empty_folders() + end +end + +---Group empty folders +-- Recursively group nodes +---@return Node[] +function BaseNode:group_empty_folders() + local is_root = not self.parent + local child_folder_only = self:has_one_child_folder() and self.nodes[1] + if self.explorer.opts.renderer.group_empty and not is_root and child_folder_only then + self.group_next = child_folder_only + local ns = child_folder_only:group_empty_folders() + self.nodes = ns or {} + return ns + end + return self.nodes +end + +---Ungroup empty folders +-- If a node is grouped, ungroup it: put node.group_next to the node.nodes and set node.group_next to nil +function BaseNode:ungroup_empty_folders() + local cur = self + while cur and cur.group_next do + cur.nodes = { cur.group_next } + cur.group_next = nil + cur = cur.nodes[1] + end +end + +function BaseNode:expand_or_collapse(toggle_group) + toggle_group = toggle_group or false + if self.has_children then + self.has_children = false + end + + if #self.nodes == 0 then + self.explorer:expand(self) + end + + local head_node = self:get_parent_of_group() + if toggle_group then + head_node:toggle_group_folders() + end + + local open = self:last_group_node().open + local next_open + if toggle_group then + next_open = open + else + next_open = not open + end + for _, n in ipairs(head_node:get_all_nodes_in_group()) do + n.open = next_open + end + + self.explorer.renderer:draw() +end + ---Create a sanitized partial copy of a node, populating children recursively. ---@return BaseNode cloned function BaseNode:clone() diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index 81d82c9b029..2071bdabcac 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -487,7 +487,7 @@ function Builder:build() return self end ----TODO refactor back to function; this was left here to reduce PR noise +---@private ---@param opts table ---@return fun(node: Node): string|nil function Builder:setup_hidden_display_function(opts) From 56ae3812b057c61a3565cb94725f43b9e4863ac4 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 30 Sep 2024 12:57:08 +1000 Subject: [PATCH 40/44] node factory uses stat only --- lua/nvim-tree/explorer/init.lua | 11 +++-------- lua/nvim-tree/node/factory.lua | 13 +++++-------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index ad03fd675b9..7d43d00f1b8 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -122,14 +122,11 @@ function Explorer:reload(node, git_status) if filter_reason == FILTER_REASON.none then remain_childs[abs] = true - -- Type must come from fs_stat and not fs_scandir_next to maintain sshfs compatibility - local t = stat and stat.type or nil - -- Recreate node if type changes. if nodes_by_path[abs] then local n = nodes_by_path[abs] - if n.type ~= t then + if not stat or n.type ~= stat.type then utils.array_remove(node.nodes, n) n:destroy() nodes_by_path[abs] = nil @@ -137,7 +134,7 @@ function Explorer:reload(node, git_status) end if not nodes_by_path[abs] then - local new_child = node_factory.create_node(self, node, abs, t, stat, name) + local new_child = node_factory.create_node(self, node, abs, stat, name) if new_child then table.insert(node.nodes, new_child) nodes_by_path[abs] = new_child @@ -276,9 +273,7 @@ function Explorer:populate_children(handle, cwd, node, git_status, parent) local stat = vim.loop.fs_lstat(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 - -- Type must come from fs_stat and not fs_scandir_next to maintain sshfs compatibility - local t = stat and stat.type or nil - local child = node_factory.create_node(self, node, abs, t, stat, name) + local child = node_factory.create_node(self, node, abs, stat, name) if child then table.insert(node.nodes, child) nodes_by_path[child.absolute_path] = true diff --git a/lua/nvim-tree/node/factory.lua b/lua/nvim-tree/node/factory.lua index 2961fc6026b..a46057da111 100644 --- a/lua/nvim-tree/node/factory.lua +++ b/lua/nvim-tree/node/factory.lua @@ -5,26 +5,23 @@ local Watcher = require("nvim-tree.watcher") local M = {} ---- TODO merge #2922 and pass just stat, as stat.type from lstat is correct - ---Factory function to create the appropriate Node ---@param explorer Explorer ---@param parent Node ---@param abs string ----@param t string? type from vim.loop.fs_scandir_next as stat.type is incorrectly reported as a file for links ----@param stat uv.fs_stat.result? +---@param stat uv.fs_stat.result? -- on nil stat return nil Node ---@param name string ---@return Node? -function M.create_node(explorer, parent, abs, t, stat, name) +function M.create_node(explorer, parent, abs, stat, name) if not stat then return nil end - if t == "directory" and vim.loop.fs_access(abs, "R") and Watcher.is_fs_event_capable(abs) then + if stat.type == "directory" and vim.loop.fs_access(abs, "R") and Watcher.is_fs_event_capable(abs) then return DirectoryNode:create(explorer, parent, abs, name, stat) - elseif t == "file" then + elseif stat.type == "file" then return FileNode:create(explorer, parent, abs, name, stat) - elseif t == "link" then + elseif stat.type == "link" then return LinkNode:create(explorer, parent, abs, name, stat) end From 43282b8d03d6f6db5a27052014ec3954adfdc3da Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 5 Oct 2024 12:36:05 +1000 Subject: [PATCH 41/44] temporary DirectoryNode casting until method extraction into child classes --- lua/nvim-tree/node/init.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index 758c9c9af2c..b915df7df1f 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -173,7 +173,7 @@ end -- If node is grouped, return the last node in the group. Otherwise, return the given node. ---@return Node function BaseNode:last_group_node() - local node = self + local node = self --[[@as BaseNode]] while node.group_next do node = node.group_next @@ -269,6 +269,7 @@ function BaseNode:group_empty_folders() local is_root = not self.parent local child_folder_only = self:has_one_child_folder() and self.nodes[1] if self.explorer.opts.renderer.group_empty and not is_root and child_folder_only then + ---@cast self DirectoryNode -- TODO move this to the class self.group_next = child_folder_only local ns = child_folder_only:group_empty_folders() self.nodes = ns or {} @@ -291,6 +292,7 @@ end function BaseNode:expand_or_collapse(toggle_group) toggle_group = toggle_group or false if self.has_children then + ---@cast self DirectoryNode -- TODO move this to the class self.has_children = false end From 94ae821e19e57cca78efdf19f217ffbb4f5b5924 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 7 Oct 2024 11:57:07 +1100 Subject: [PATCH 42/44] lua-language-server 3.10.5 -> 3.11.0 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index feac234f786..d7885547302 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,7 +69,7 @@ jobs: strategy: matrix: nvim_version: [ stable, nightly ] - luals_version: [ 3.10.5 ] + luals_version: [ 3.11.0 ] steps: - uses: actions/checkout@v4 From a7ae7ccb66249e15e0c1052514f6883cb3cd14d5 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 7 Oct 2024 12:10:08 +1100 Subject: [PATCH 43/44] explicitly call Explorer constructor --- lua/nvim-tree/explorer/init.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index 7d43d00f1b8..7cbab2317db 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -51,7 +51,9 @@ function Explorer:create(path) ---@type Explorer local explorer_placeholder = nil - local o = RootNode.create(self, explorer_placeholder, path, "..", nil) --[[@as Explorer]] + local o = RootNode.create(self, explorer_placeholder, path, "..", nil) + + o = self:new(o) --[[@as Explorer]] o.explorer = o @@ -267,7 +269,7 @@ function Explorer:populate_children(handle, cwd, node, git_status, parent) local abs = utils.path_join({ cwd, name }) if Watcher.is_fs_event_capable(abs) then - local profile = log.profile_start("explore populate_children %s", abs) + local profile = log.profile_start("populate_children %s", abs) ---@type uv.fs_stat.result|nil local stat = vim.loop.fs_lstat(abs) From ea994a62192beb5c239423d75189a569992de00b Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 7 Oct 2024 13:26:22 +1100 Subject: [PATCH 44/44] normalise explorer RootNode new call, tidy annotations --- lua/nvim-tree/explorer/init.lua | 2 +- lua/nvim-tree/renderer/decorator/copied.lua | 1 - lua/nvim-tree/renderer/decorator/opened.lua | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index 7cbab2317db..0045ba9b243 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -51,7 +51,7 @@ function Explorer:create(path) ---@type Explorer local explorer_placeholder = nil - local o = RootNode.create(self, explorer_placeholder, path, "..", nil) + local o = RootNode:create(explorer_placeholder, path, "..", nil) o = self:new(o) --[[@as Explorer]] diff --git a/lua/nvim-tree/renderer/decorator/copied.lua b/lua/nvim-tree/renderer/decorator/copied.lua index 57c4825212c..0debcc632bb 100644 --- a/lua/nvim-tree/renderer/decorator/copied.lua +++ b/lua/nvim-tree/renderer/decorator/copied.lua @@ -4,7 +4,6 @@ local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT local Decorator = require("nvim-tree.renderer.decorator") ---@class (exact) DecoratorCopied: Decorator ----@field enabled boolean ---@field icon HighlightedString? local DecoratorCopied = Decorator:new() diff --git a/lua/nvim-tree/renderer/decorator/opened.lua b/lua/nvim-tree/renderer/decorator/opened.lua index a942aa622ae..6f2ad58bbfc 100644 --- a/lua/nvim-tree/renderer/decorator/opened.lua +++ b/lua/nvim-tree/renderer/decorator/opened.lua @@ -6,7 +6,6 @@ local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT local Decorator = require("nvim-tree.renderer.decorator") ---@class (exact) DecoratorOpened: Decorator ----@field enabled boolean ---@field icon HighlightedString|nil local DecoratorOpened = Decorator:new()