Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: ungrouping empty directories #2647

Merged
merged 5 commits into from
Feb 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions doc/nvim-tree-lua.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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` 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()|
Expand Down Expand Up @@ -1848,6 +1849,12 @@ 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.

*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.
Open file otherwise.
Expand Down Expand Up @@ -2196,6 +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', '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'))
Expand Down
7 changes: 4 additions & 3 deletions lua/nvim-tree/api.lua
Original file line number Diff line number Diff line change
Expand Up @@ -175,13 +175,13 @@ 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)
else
lib.expand_or_collapse(node, toggle_group)
elseif not toggle_group then
edit(mode, node)
juefeiyan marked this conversation as resolved.
Show resolved Hide resolved
end
end
Expand All @@ -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_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")

Expand Down
1 change: 1 addition & 0 deletions lua/nvim-tree/keymap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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_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'))
Expand Down
62 changes: 58 additions & 4 deletions lua/nvim-tree/lib.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -86,6 +87,34 @@ function M.get_last_group_node(node)
return node
end

---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 = 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

---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

---@param node Node
---@return Node[]
function M.get_all_nodes_in_group(node)
Expand All @@ -98,8 +127,21 @@ function M.get_all_nodes_in_group(node)
return nodes
end

-- 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

---@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
Expand All @@ -108,9 +150,20 @@ 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 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
next_open = open
else
next_open = not open
end
for _, n in ipairs(M.get_all_nodes_in_group(head_node)) do
n.open = next_open
end

renderer.draw()
Expand Down Expand Up @@ -213,6 +266,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
Loading