diff --git a/lua/nvim-tree/actions/finders/find-file.lua b/lua/nvim-tree/actions/finders/find-file.lua index 55e2f23d337..4f5d8089a85 100644 --- a/lua/nvim-tree/actions/finders/find-file.lua +++ b/lua/nvim-tree/actions/finders/find-file.lua @@ -32,7 +32,7 @@ function M.fn(path) local profile = log.profile_start("find file %s", path_real) -- refresh the contents of all parents, expanding groups as needed - if utils.get_node_from_path(path_real) == nil then + if explorer:get_node_from_path(path_real) == nil then explorer:refresh_parent_nodes_for_path(vim.fn.fnamemodify(path_real, ":h")) end diff --git a/lua/nvim-tree/actions/moves/item.lua b/lua/nvim-tree/actions/moves/item.lua index 8aacaae3b56..449cb2212c0 100644 --- a/lua/nvim-tree/actions/moves/item.lua +++ b/lua/nvim-tree/actions/moves/item.lua @@ -1,4 +1,3 @@ -local utils = require("nvim-tree.utils") local view = require("nvim-tree.view") local core = require("nvim-tree.core") local diagnostics = require("nvim-tree.diagnostics") @@ -36,7 +35,7 @@ end ---@param skip_gitignored boolean? default false local function move(explorer, where, what, skip_gitignored) local first_node_line = core.get_nodes_starting_line() - local nodes_by_line = utils.get_nodes_by_line(explorer.nodes, first_node_line) + local nodes_by_line = explorer:get_nodes_by_line(first_node_line) local iter_start, iter_end, iter_step, cur, first, nex local cursor = explorer:get_cursor_position() @@ -191,7 +190,7 @@ local function move_prev_recursive(explorer, what, skip_gitignored) if node_init.name == ".." then -- root node view.set_cursor({ 1, 0 }) -- move to root node (position 1) else - local node_init_line = utils.find_node_line(node_init) + local node_init_line = explorer:find_node_line(node_init) if node_init_line < 0 then return end diff --git a/lua/nvim-tree/actions/moves/parent.lua b/lua/nvim-tree/actions/moves/parent.lua index 32ca8398116..555bd6e1105 100644 --- a/lua/nvim-tree/actions/moves/parent.lua +++ b/lua/nvim-tree/actions/moves/parent.lua @@ -1,6 +1,4 @@ local view = require("nvim-tree.view") -local utils = require("nvim-tree.utils") - local DirectoryNode = require("nvim-tree.node.directory") local M = {} @@ -29,7 +27,7 @@ function M.fn(should_close) return end - local _, line = utils.find_node(parent.explorer.nodes, function(n) + local _, line = parent.explorer:find_node(function(n) return n.absolute_path == parent.absolute_path end) diff --git a/lua/nvim-tree/actions/moves/sibling.lua b/lua/nvim-tree/actions/moves/sibling.lua index cf5b492d387..bfb5b5e2fa0 100644 --- a/lua/nvim-tree/actions/moves/sibling.lua +++ b/lua/nvim-tree/actions/moves/sibling.lua @@ -1,4 +1,3 @@ -local utils = require("nvim-tree.utils") local core = require("nvim-tree.core") local Iterator = require("nvim-tree.iterators.node-iterator") @@ -12,9 +11,14 @@ function M.fn(direction) return end + local explorer = core.get_explorer() + if not explorer then + return + end + local first, last, next, prev = nil, nil, nil, nil local found = false - local parent = node.parent or core.get_explorer() + local parent = node.parent or explorer Iterator.builder(parent and parent.nodes or {}) :recursor(function() return nil @@ -45,7 +49,7 @@ function M.fn(direction) end if target_node then - utils.focus_file(target_node.absolute_path) + explorer:focus_node_or_parent(target_node) end end end diff --git a/lua/nvim-tree/actions/tree/modifiers/collapse.lua b/lua/nvim-tree/actions/tree/modifiers/collapse.lua index 62da5f9ab4c..51a15f3d464 100644 --- a/lua/nvim-tree/actions/tree/modifiers/collapse.lua +++ b/lua/nvim-tree/actions/tree/modifiers/collapse.lua @@ -56,7 +56,7 @@ local function collapse(node, opts) :iterate() explorer.renderer:draw() - utils.focus_node_or_parent(node_at_cursor) + explorer:focus_node_or_parent(node_at_cursor) end diff --git a/lua/nvim-tree/explorer/filters.lua b/lua/nvim-tree/explorer/filters.lua index 62230687e40..fda0a79fbaf 100644 --- a/lua/nvim-tree/explorer/filters.lua +++ b/lua/nvim-tree/explorer/filters.lua @@ -280,7 +280,7 @@ function Filters:toggle(type) local node = self.explorer:get_node_at_cursor() self.explorer:reload_explorer() if node then - utils.focus_node_or_parent(node) + self.explorer:focus_node_or_parent(node) end end diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index 58972164afe..afd1b182cee 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -527,7 +527,7 @@ function Explorer:get_node_at_cursor() return self end - return utils.get_nodes_by_line(self.nodes, core.get_nodes_starting_line())[cursor[1]] + return self:get_nodes_by_line(core.get_nodes_starting_line())[cursor[1]] end function Explorer:place_cursor_on_node() @@ -551,6 +551,114 @@ function Explorer:place_cursor_on_node() end end +-- Find the line number of a node. +---@param node Node? +---@return integer -1 not found +function Explorer:find_node_line(node) + if not node then + return -1 + end + + local first_node_line = core.get_nodes_starting_line() + local nodes_by_line = self:get_nodes_by_line(first_node_line) + local iter_start, iter_end = first_node_line, #nodes_by_line + + for line = iter_start, iter_end, 1 do + if nodes_by_line[line] == node then + return line + end + end + + return -1 +end + +-- get the node in the tree state depending on the absolute path of the node +-- (grouped or hidden too) +---@param path string +---@return Node|nil +---@return number|nil +function Explorer:get_node_from_path(path) + if self.absolute_path == path then + return self + end + + return Iterator.builder(self.nodes) + :hidden() + :matcher(function(node) + return node.absolute_path == path or node.link_to == path + end) + :recursor(function(node) + if node.group_next then + return { node.group_next } + end + if node.nodes then + return node.nodes + end + end) + :iterate() +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? node to focus +function Explorer:focus_node_or_parent(node) + while node do + local found_node, i = self:find_node(function(node_) + return node_.absolute_path == node.absolute_path + end) + + if found_node or node.parent == nil then + view.set_cursor({ i + 1, 1 }) + break + end + + node = node.parent + end +end + +--- Get the node and index of the node from the tree that matches the predicate. +--- The explored nodes are those displayed on the view. +---@param fn fun(node: Node): boolean +---@return table|nil +---@return number +function Explorer:find_node(fn) + local node, i = Iterator.builder(self.nodes) + :matcher(fn) + :recursor(function(node) + return node.group_next and { node.group_next } or (node.open and #node.nodes > 0 and node.nodes) + end) + :iterate() + i = view.is_root_folder_visible() and i or i - 1 + if node and node.explorer.live_filter.filter then + i = i + 1 + end + return node, i +end + +--- Return visible nodes indexed by line +---@param line_start number +---@return table +function Explorer:get_nodes_by_line(line_start) + local nodes_by_line = {} + local line = line_start + + Iterator.builder(self.nodes) + :applier(function(node) + if node.group_next then + return + end + nodes_by_line[line] = node + line = line + 1 + end) + :recursor(function(node) + return node.group_next and { node.group_next } or (node.open and #node.nodes > 0 and node.nodes) + end) + :iterate() + + return nodes_by_line +end + ---Api.tree.get_nodes ---@return nvim_tree.api.Node function Explorer:get_nodes() diff --git a/lua/nvim-tree/explorer/live-filter.lua b/lua/nvim-tree/explorer/live-filter.lua index 62a7dd9ef64..43e683165b2 100644 --- a/lua/nvim-tree/explorer/live-filter.lua +++ b/lua/nvim-tree/explorer/live-filter.lua @@ -220,9 +220,9 @@ function LiveFilter:clear_filter() self.explorer.renderer:draw() if node then - utils.focus_file(node.absolute_path) + self.explorer:focus_node_or_parent(node) elseif last_node then - utils.focus_file(last_node.absolute_path) + self.explorer:focus_node_or_parent(last_node) end end diff --git a/lua/nvim-tree/git/init.lua b/lua/nvim-tree/git/init.lua index 663e57c39a1..6277a6a4f78 100644 --- a/lua/nvim-tree/git/init.lua +++ b/lua/nvim-tree/git/init.lua @@ -233,7 +233,13 @@ local function reload_tree_at(toplevel) end log.line("watcher", "git event executing '%s'", toplevel) - local root_node = utils.get_node_from_path(toplevel) + + local explorer = require("nvim-tree.core").get_explorer() + if not explorer then + return nil + end + + local root_node = explorer:get_node_from_path(toplevel) if not root_node then return end @@ -252,7 +258,7 @@ local function reload_tree_at(toplevel) end) :iterate() - root_node.explorer.renderer:draw() + explorer.renderer:draw() end) end diff --git a/lua/nvim-tree/marks/init.lua b/lua/nvim-tree/marks/init.lua index c940f999983..22ac572dee0 100644 --- a/lua/nvim-tree/marks/init.lua +++ b/lua/nvim-tree/marks/init.lua @@ -227,9 +227,9 @@ function Marks:navigate(up) end if up then - utils.focus_node_or_parent(prev or last) + self.explorer:focus_node_or_parent(prev or last) else - utils.focus_node_or_parent(next or first) + self.explorer:focus_node_or_parent(next or first) end end @@ -263,7 +263,7 @@ function Marks:navigate_select() if node and not node:is(DirectoryNode) and not utils.get_win_buf_from_path(node.absolute_path) then open_file.fn("edit", node.absolute_path) elseif node then - utils.focus_file(node.absolute_path) + self.explorer:focus_node_or_parent(node) end end) end diff --git a/lua/nvim-tree/utils.lua b/lua/nvim-tree/utils.lua index b51e29ac49e..b98301e6701 100644 --- a/lua/nvim-tree/utils.lua +++ b/lua/nvim-tree/utils.lua @@ -1,5 +1,3 @@ -local Iterator = require("nvim-tree.iterators.node-iterator") - local M = { debouncers = {}, } @@ -114,48 +112,6 @@ end M.path_separator = path_separator ---- Get the node and index of the node from the tree that matches the predicate. ---- The explored nodes are those displayed on the view. ----@param nodes Node[] ----@param fn fun(node: Node): boolean ----@return table|nil ----@return number -function M.find_node(nodes, fn) - local node, i = Iterator.builder(nodes) - :matcher(fn) - :recursor(function(node) - return node.group_next and { node.group_next } or (node.open and #node.nodes > 0 and node.nodes) - end) - :iterate() - i = require("nvim-tree.view").is_root_folder_visible() and i or i - 1 - if node and node.explorer.live_filter.filter then - i = i + 1 - end - return node, i -end - --- Find the line number of a node. --- Return -1 is node is nil or not found. ----@param node Node? ----@return integer -function M.find_node_line(node) - if not node then - return -1 - end - - local first_node_line = require("nvim-tree.core").get_nodes_starting_line() - local nodes_by_line = M.get_nodes_by_line(require("nvim-tree.core").get_explorer().nodes, first_node_line) - local iter_start, iter_end = first_node_line, #nodes_by_line - - for line = iter_start, iter_end, 1 do - if nodes_by_line[line] == node then - return line - end - end - - return -1 -end - ---@param extmarks vim.api.keyset.get_extmark_item[] as per vim.api.nvim_buf_get_extmarks ---@return number function M.extmarks_length(extmarks) @@ -171,39 +127,6 @@ function M.extmarks_length(extmarks) return length end --- get the node in the tree state depending on the absolute path of the node --- (grouped or hidden too) ----@param path string ----@return Node|nil ----@return number|nil -function M.get_node_from_path(path) - local explorer = require("nvim-tree.core").get_explorer() - - -- tree may not yet be loaded - if not explorer then - return - end - - if explorer.absolute_path == path then - return explorer - end - - return Iterator.builder(explorer.nodes) - :hidden() - :matcher(function(node) - return node.absolute_path == path or node.link_to == path - end) - :recursor(function(node) - if node.group_next then - return { node.group_next } - end - if node.nodes then - return node.nodes - end - end) - :iterate() -end - M.default_format_hidden_count = function(hidden_count, simple) local parts = {} local total_count = 0 @@ -224,30 +147,6 @@ M.default_format_hidden_count = function(hidden_count, simple) return nil end ---- Return visible nodes indexed by line ----@param nodes_all Node[] ----@param line_start number ----@return table -function M.get_nodes_by_line(nodes_all, line_start) - local nodes_by_line = {} - local line = line_start - - Iterator.builder(nodes_all) - :applier(function(node) - if node.group_next then - return - end - nodes_by_line[line] = node - line = line + 1 - end) - :recursor(function(node) - return node.group_next and { node.group_next } or (node.open and #node.nodes > 0 and node.nodes) - end) - :iterate() - - return nodes_by_line -end - function M.rename_loaded_buffers(old_path, new_path) -- delete new if it exists for _, buf in pairs(vim.api.nvim_list_bufs()) do @@ -469,38 +368,6 @@ function M.debounce(context, timeout, callback) end) end -function M.focus_file(path) - local _, i = M.find_node(require("nvim-tree.core").get_explorer().nodes, function(node) - return node.absolute_path == path - end) - require("nvim-tree.view").set_cursor({ i + 1, 1 }) -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? node to focus -function M.focus_node_or_parent(node) - local explorer = require("nvim-tree.core").get_explorer() - - if explorer == nil then - return - end - - while node do - local found_node, i = M.find_node(explorer.nodes, function(node_) - return node_.absolute_path == node.absolute_path - end) - - if found_node or node.parent == nil then - require("nvim-tree.view").set_cursor({ i + 1, 1 }) - break - end - - node = node.parent - end -end - ---@param path string ---@return integer|nil ---@return integer|nil