From 51c6b466c0cc25ee5ba9632e2e52189c597d1d0a Mon Sep 17 00:00:00 2001 From: juefei yan Date: Thu, 25 Jan 2024 23:17:15 -0800 Subject: [PATCH 1/5] feat: ungrouping empty directories --- lua/nvim-tree/lib.lua | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/lua/nvim-tree/lib.lua b/lua/nvim-tree/lib.lua index 09642281419..f040f2e3cbe 100644 --- a/lua/nvim-tree/lib.lua +++ b/lua/nvim-tree/lib.lua @@ -3,6 +3,7 @@ local view = require "nvim-tree.view" local core = require "nvim-tree.core" local utils = require "nvim-tree.utils" local events = require "nvim-tree.events" +local explorer_node = require "nvim-tree.explorer.node" ---@class LibOpenOpts ---@field path string|nil path @@ -86,6 +87,32 @@ function M.get_last_group_node(node) return node end +---Group empty folders +---@param node Node +---@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] + 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 + +---Group empty folders +---@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 + ---@param node Node ---@return Node[] function M.get_all_nodes_in_group(node) @@ -108,9 +135,17 @@ function M.expand_or_collapse(node) core.get_explorer():expand(node) end - local open = not M.get_last_group_node(node).open - for _, n in ipairs(M.get_all_nodes_in_group(node)) do - n.open = open + local open = M.get_last_group_node(node).open + local head_node = utils.get_parent_of_group(node) + local is_grouped = head_node.group_next ~= nil + + if open and is_grouped then + M.ungroup_empty_folders(head_node) + elseif open then + M.group_empty_folders(head_node) + end + for _, n in ipairs(M.get_all_nodes_in_group(head_node)) do + n.open = is_grouped or not open end renderer.draw() @@ -213,6 +248,7 @@ function M.setup(opts) M.hijack_directories = opts.hijack_directories M.respect_buf_cwd = opts.respect_buf_cwd M.select_prompts = opts.select_prompts + M.group_empty = opts.renderer.group_empty end return M From ac0e540ae5807f2424933d08efdbbc7d59664a6f Mon Sep 17 00:00:00 2001 From: juefei yan Date: Mon, 29 Jan 2024 22:32:31 -0800 Subject: [PATCH 2/5] add a new api to toggle empty folders --- doc/nvim-tree-lua.txt | 5 +++++ lua/nvim-tree/api.lua | 5 +++-- lua/nvim-tree/keymap.lua | 1 + lua/nvim-tree/lib.lua | 39 +++++++++++++++++++++++++++++---------- 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 32696f10999..11e032c3059 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -181,6 +181,7 @@ Show the mappings: `g?` `I` Toggle Filter: Git Ignore |nvim-tree-api.tree.toggle_gitignore_filter()| `J` Last Sibling |nvim-tree-api.node.navigate.sibling.last()| `K` First Sibling |nvim-tree-api.node.navigate.sibling.first()| +`L` Group or Ungroup Folders |nvim-tree-api.node.tree.toggle_grouped_folders()| `M` Toggle Filter: No Bookmark |nvim-tree-api.tree.toggle_no_bookmark_filter()| `m` Toggle Bookmark |nvim-tree-api.marks.toggle()| `o` Open |nvim-tree-api.node.open.edit()| @@ -1848,6 +1849,9 @@ node.open.vertical() *nvim-tree-api.node.open.vertical()* node.open.horizontal() *nvim-tree-api.node.open.horizontal()* |nvim-tree-api.node.edit()|, file will be opened in a new horizontal split. +node.open.toggle_grouped_folders() *nvim-tree-api.node.open.toggle_grouped_folders()* + |nvim-tree-api.node.edit()|, empty folders would be grouped or ungrouped. + node.open.drop() *nvim-tree-api.node.open.drop()* Switch to window with selected file if it exists. Open file otherwise. @@ -2196,6 +2200,7 @@ You are encouraged to copy these to your own |nvim-tree.on_attach| function. vim.keymap.set('n', 'I', api.tree.toggle_gitignore_filter, opts('Toggle Filter: Git Ignore')) vim.keymap.set('n', 'J', api.node.navigate.sibling.last, opts('Last Sibling')) vim.keymap.set('n', 'K', api.node.navigate.sibling.first, opts('First Sibling')) + vim.keymap.set('n', 'L', api.node.open.toggle_grouped_folders,opts('Toggle Grouped Folders')) vim.keymap.set('n', 'M', api.tree.toggle_no_bookmark_filter, opts('Toggle Filter: No Bookmark')) vim.keymap.set('n', 'm', api.marks.toggle, opts('Toggle Bookmark')) vim.keymap.set('n', 'o', api.node.open.edit, opts('Open')) diff --git a/lua/nvim-tree/api.lua b/lua/nvim-tree/api.lua index 3c85071e899..25f4d5208d6 100644 --- a/lua/nvim-tree/api.lua +++ b/lua/nvim-tree/api.lua @@ -175,12 +175,12 @@ end ---@param mode string ---@return fun(node: table) -local function open_or_expand_or_dir_up(mode) +local function open_or_expand_or_dir_up(mode, toggle_group) return function(node) if node.name == ".." then actions.root.change_dir.fn ".." elseif node.nodes then - lib.expand_or_collapse(node) + lib.expand_or_collapse(node, toggle_group) else edit(mode, node) end @@ -195,6 +195,7 @@ Api.node.open.no_window_picker = wrap_node(open_or_expand_or_dir_up "edit_no_pic Api.node.open.vertical = wrap_node(open_or_expand_or_dir_up "vsplit") Api.node.open.horizontal = wrap_node(open_or_expand_or_dir_up "split") Api.node.open.tab = wrap_node(open_or_expand_or_dir_up "tabnew") +Api.node.open.toggle_grouped_folders = wrap_node(open_or_expand_or_dir_up("toggle_grouped_folders", true)) Api.node.open.preview = wrap_node(open_or_expand_or_dir_up "preview") Api.node.open.preview_no_picker = wrap_node(open_or_expand_or_dir_up "preview_no_picker") diff --git a/lua/nvim-tree/keymap.lua b/lua/nvim-tree/keymap.lua index 700a479461e..ec769551325 100644 --- a/lua/nvim-tree/keymap.lua +++ b/lua/nvim-tree/keymap.lua @@ -72,6 +72,7 @@ function M.default_on_attach(bufnr) vim.keymap.set('n', 'I', api.tree.toggle_gitignore_filter, opts('Toggle Filter: Git Ignore')) vim.keymap.set('n', 'J', api.node.navigate.sibling.last, opts('Last Sibling')) vim.keymap.set('n', 'K', api.node.navigate.sibling.first, opts('First Sibling')) + vim.keymap.set('n', 'L', api.node.open.toggle_grouped_folders,opts('Toggle Grouped Folders')) vim.keymap.set('n', 'M', api.tree.toggle_no_bookmark_filter, opts('Toggle Filter: No Bookmark')) vim.keymap.set('n', 'm', api.marks.toggle, opts('Toggle Bookmark')) vim.keymap.set('n', 'o', api.node.open.edit, opts('Open')) diff --git a/lua/nvim-tree/lib.lua b/lua/nvim-tree/lib.lua index f040f2e3cbe..16d37580d3b 100644 --- a/lua/nvim-tree/lib.lua +++ b/lua/nvim-tree/lib.lua @@ -88,6 +88,7 @@ function M.get_last_group_node(node) end ---Group empty folders +-- Recursively group nodes ---@param node Node ---@return Node[] function M.group_empty_folders(node) @@ -102,7 +103,8 @@ function M.group_empty_folders(node) return node.nodes end ----Group empty folders +---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 @@ -125,8 +127,26 @@ function M.get_all_nodes_in_group(node) return nodes end +-- If a folder is grouped and closed -> group folder and open +-- If a folder is grouped and opened -> ungroup folder and open +-- If a folder is ungrouped and opened -> group folder and close +---@param head_node Node +---@param open boolean +---@return boolean +local function toggle_group_folders(head_node, open) + local is_grouped = head_node.group_next ~= nil + + if open and is_grouped then + M.ungroup_empty_folders(head_node) + elseif open then + M.group_empty_folders(head_node) + end + return is_grouped or not open +end + ---@param node Node -function M.expand_or_collapse(node) +function M.expand_or_collapse(node, toggle_group) + toggle_group = toggle_group or false if node.has_children then node.has_children = false end @@ -135,17 +155,16 @@ function M.expand_or_collapse(node) core.get_explorer():expand(node) end - local open = M.get_last_group_node(node).open local head_node = utils.get_parent_of_group(node) - local is_grouped = head_node.group_next ~= nil - - if open and is_grouped then - M.ungroup_empty_folders(head_node) - elseif open then - M.group_empty_folders(head_node) + local open = M.get_last_group_node(node).open + if toggle_group then + open = toggle_group_folders(head_node, open) + else + open = not open end + for _, n in ipairs(M.get_all_nodes_in_group(head_node)) do - n.open = is_grouped or not open + n.open = open end renderer.draw() From 60a25d7f99e8e0304a854cd4196d6601aca01cc3 Mon Sep 17 00:00:00 2001 From: juefei yan Date: Sat, 3 Feb 2024 15:15:19 -0800 Subject: [PATCH 3/5] solve comments --- doc/nvim-tree-lua.txt | 11 +++++++---- lua/nvim-tree/api.lua | 4 ++-- lua/nvim-tree/keymap.lua | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 11e032c3059..708145ebef6 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -181,7 +181,7 @@ Show the mappings: `g?` `I` Toggle Filter: Git Ignore |nvim-tree-api.tree.toggle_gitignore_filter()| `J` Last Sibling |nvim-tree-api.node.navigate.sibling.last()| `K` First Sibling |nvim-tree-api.node.navigate.sibling.first()| -`L` Group or Ungroup Folders |nvim-tree-api.node.tree.toggle_grouped_folders()| +`L` Group or Ungroup Folders |nvim-tree-api.node.tree.toggle_group_empty()| `M` Toggle Filter: No Bookmark |nvim-tree-api.tree.toggle_no_bookmark_filter()| `m` Toggle Bookmark |nvim-tree-api.marks.toggle()| `o` Open |nvim-tree-api.node.open.edit()| @@ -1849,8 +1849,11 @@ node.open.vertical() *nvim-tree-api.node.open.vertical()* node.open.horizontal() *nvim-tree-api.node.open.horizontal()* |nvim-tree-api.node.edit()|, file will be opened in a new horizontal split. -node.open.toggle_grouped_folders() *nvim-tree-api.node.open.toggle_grouped_folders()* - |nvim-tree-api.node.edit()|, empty folders would be grouped or ungrouped. + *nvim-tree-api.node.open.toggle_group_empty()* +node.open.toggle_group_empty() + Toggle |nvim-tree.renderer.group_empty| for a specific folder. + Does nothing on files. + Needs |nvim-tree.renderer.group_empty| set. node.open.drop() *nvim-tree-api.node.open.drop()* Switch to window with selected file if it exists. @@ -2200,7 +2203,7 @@ You are encouraged to copy these to your own |nvim-tree.on_attach| function. vim.keymap.set('n', 'I', api.tree.toggle_gitignore_filter, opts('Toggle Filter: Git Ignore')) vim.keymap.set('n', 'J', api.node.navigate.sibling.last, opts('Last Sibling')) vim.keymap.set('n', 'K', api.node.navigate.sibling.first, opts('First Sibling')) - vim.keymap.set('n', 'L', api.node.open.toggle_grouped_folders,opts('Toggle Grouped Folders')) + vim.keymap.set('n', 'L', api.node.open.toggle_group_empty,opts('Toggle Group Empty')) vim.keymap.set('n', 'M', api.tree.toggle_no_bookmark_filter, opts('Toggle Filter: No Bookmark')) vim.keymap.set('n', 'm', api.marks.toggle, opts('Toggle Bookmark')) vim.keymap.set('n', 'o', api.node.open.edit, opts('Open')) diff --git a/lua/nvim-tree/api.lua b/lua/nvim-tree/api.lua index 25f4d5208d6..aa2265a678a 100644 --- a/lua/nvim-tree/api.lua +++ b/lua/nvim-tree/api.lua @@ -181,7 +181,7 @@ local function open_or_expand_or_dir_up(mode, toggle_group) actions.root.change_dir.fn ".." elseif node.nodes then lib.expand_or_collapse(node, toggle_group) - else + elseif not toggle_group then edit(mode, node) end end @@ -195,7 +195,7 @@ Api.node.open.no_window_picker = wrap_node(open_or_expand_or_dir_up "edit_no_pic Api.node.open.vertical = wrap_node(open_or_expand_or_dir_up "vsplit") Api.node.open.horizontal = wrap_node(open_or_expand_or_dir_up "split") Api.node.open.tab = wrap_node(open_or_expand_or_dir_up "tabnew") -Api.node.open.toggle_grouped_folders = wrap_node(open_or_expand_or_dir_up("toggle_grouped_folders", true)) +Api.node.open.toggle_group_empty = wrap_node(open_or_expand_or_dir_up("toggle_group_empty", true)) Api.node.open.preview = wrap_node(open_or_expand_or_dir_up "preview") Api.node.open.preview_no_picker = wrap_node(open_or_expand_or_dir_up "preview_no_picker") diff --git a/lua/nvim-tree/keymap.lua b/lua/nvim-tree/keymap.lua index ec769551325..0b0797a8dd6 100644 --- a/lua/nvim-tree/keymap.lua +++ b/lua/nvim-tree/keymap.lua @@ -72,7 +72,7 @@ function M.default_on_attach(bufnr) vim.keymap.set('n', 'I', api.tree.toggle_gitignore_filter, opts('Toggle Filter: Git Ignore')) vim.keymap.set('n', 'J', api.node.navigate.sibling.last, opts('Last Sibling')) vim.keymap.set('n', 'K', api.node.navigate.sibling.first, opts('First Sibling')) - vim.keymap.set('n', 'L', api.node.open.toggle_grouped_folders,opts('Toggle Grouped Folders')) + vim.keymap.set('n', 'L', api.node.open.toggle_group_empty, opts('Toggle Group Empty')) vim.keymap.set('n', 'M', api.tree.toggle_no_bookmark_filter, opts('Toggle Filter: No Bookmark')) vim.keymap.set('n', 'm', api.marks.toggle, opts('Toggle Bookmark')) vim.keymap.set('n', 'o', api.node.open.edit, opts('Open')) From 9f233b314d5f8075819c932ed65446fb27f8cf9b Mon Sep 17 00:00:00 2001 From: juefei yan Date: Sat, 3 Feb 2024 18:21:27 -0800 Subject: [PATCH 4/5] solve comments --- lua/nvim-tree/lib.lua | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/lua/nvim-tree/lib.lua b/lua/nvim-tree/lib.lua index 16d37580d3b..900e9dcd298 100644 --- a/lua/nvim-tree/lib.lua +++ b/lua/nvim-tree/lib.lua @@ -127,21 +127,16 @@ function M.get_all_nodes_in_group(node) return nodes end --- If a folder is grouped and closed -> group folder and open --- If a folder is grouped and opened -> ungroup folder and open --- If a folder is ungrouped and opened -> group folder and close +-- Toggle group empty folders ---@param head_node Node ----@param open boolean ----@return boolean -local function toggle_group_folders(head_node, open) +local function toggle_group_folders(head_node) local is_grouped = head_node.group_next ~= nil - if open and is_grouped then + if is_grouped then M.ungroup_empty_folders(head_node) - elseif open then + else M.group_empty_folders(head_node) end - return is_grouped or not open end ---@param node Node @@ -156,15 +151,19 @@ function M.expand_or_collapse(node, toggle_group) end local head_node = utils.get_parent_of_group(node) + if toggle_group then + toggle_group_folders(head_node) + end + local open = M.get_last_group_node(node).open + local next_open if toggle_group then - open = toggle_group_folders(head_node, open) + next_open = open else - open = not open + next_open = not open end - for _, n in ipairs(M.get_all_nodes_in_group(head_node)) do - n.open = open + n.open = next_open end renderer.draw() From aae859995ffea9e5b1e6c3536915d032ddd9bab6 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 4 Feb 2024 16:46:15 +1100 Subject: [PATCH 5/5] update help --- doc/nvim-tree-lua.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 708145ebef6..fb586a50889 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -181,7 +181,7 @@ Show the mappings: `g?` `I` Toggle Filter: Git Ignore |nvim-tree-api.tree.toggle_gitignore_filter()| `J` Last Sibling |nvim-tree-api.node.navigate.sibling.last()| `K` First Sibling |nvim-tree-api.node.navigate.sibling.first()| -`L` Group or Ungroup Folders |nvim-tree-api.node.tree.toggle_group_empty()| +`L` Toggle Group Empty |nvim-tree-api.node.open.toggle_group_empty()| `M` Toggle Filter: No Bookmark |nvim-tree-api.tree.toggle_no_bookmark_filter()| `m` Toggle Bookmark |nvim-tree-api.marks.toggle()| `o` Open |nvim-tree-api.node.open.edit()| @@ -2203,7 +2203,7 @@ You are encouraged to copy these to your own |nvim-tree.on_attach| function. vim.keymap.set('n', 'I', api.tree.toggle_gitignore_filter, opts('Toggle Filter: Git Ignore')) vim.keymap.set('n', 'J', api.node.navigate.sibling.last, opts('Last Sibling')) vim.keymap.set('n', 'K', api.node.navigate.sibling.first, opts('First Sibling')) - vim.keymap.set('n', 'L', api.node.open.toggle_group_empty,opts('Toggle Group Empty')) + vim.keymap.set('n', 'L', api.node.open.toggle_group_empty, opts('Toggle Group Empty')) vim.keymap.set('n', 'M', api.tree.toggle_no_bookmark_filter, opts('Toggle Filter: No Bookmark')) vim.keymap.set('n', 'm', api.marks.toggle, opts('Toggle Bookmark')) vim.keymap.set('n', 'o', api.node.open.edit, opts('Open'))