Skip to content

Commit 9913b0d

Browse files
authored
feat: file nesting (#164)
1 parent 1ee4ae0 commit 9913b0d

File tree

12 files changed

+254
-61
lines changed

12 files changed

+254
-61
lines changed

README.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,20 @@ use {
7878
indent = {
7979
indent_size = 2,
8080
padding = 1, -- extra padding on left hand side
81+
-- indent guides
8182
with_markers = true,
8283
indent_marker = "",
8384
last_indent_marker = "",
8485
highlight = "NeoTreeIndentMarker",
86+
-- expander config, needed for nesting files
87+
with_expanders = nil, -- if nil and file nesting is enabled, will enable expanders
88+
expander_collapsed = "",
89+
expander_expanded = "",
90+
expander_highlight = "NeoTreeExpander",
8591
},
8692
icon = {
87-
folder_closed = "",
88-
folder_open = "",
93+
folder_closed = "",
94+
folder_open = "",
8995
folder_empty = "",
9096
default = "*",
9197
},
@@ -136,6 +142,7 @@ use {
136142
["q"] = "close_window",
137143
}
138144
},
145+
nesting_rules = {},
139146
filesystem = {
140147
filtered_items = {
141148
visible = false, -- when true, they will just be displayed differently than normal items
@@ -325,6 +332,10 @@ automatically change the directory without prompting. This option implies
325332

326333
See `:h neo-tree-commands` for details and a full listing of available arguments.
327334

335+
### File Nesting
336+
337+
See `:h neo-tree-file-nesting` for mmore details about file nesting
338+
328339

329340
### Netrw Hijack
330341

doc/neo-tree.txt

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ Configuration ............... |neo-tree-configuration|
1616
Git Status ................ |neo-tree-git-status|
1717
Diagnostics ............... |neo-tree-diagnostics|
1818
Indent markers ............ |neo-tree-indent-markers|
19+
Expanders ................. |neo-tree-expanders|
20+
File nesting .............. |neo-tree-file-nesting|
1921
Highlights ................ |neo-tree-highlights|
2022
Events .................... |neo-tree-events|
2123
Components and Renderers .. |neo-tree-renderers|
@@ -612,6 +614,41 @@ To change highlight of indent markers, you need configure `NeoTreeIndentMarker`
612614
highlight group. By default, it refers to `Normal` highlight.
613615

614616

617+
EXPANDERS *neo-tree-expanders*
618+
Is hightly recommended enable if file nesting is enabled (this is the default
619+
behavior if `with_expanders` is nil). The config can be done inside the `indent`
620+
component:
621+
>
622+
require("neo-tree").setup({
623+
default_component_configs = {
624+
indent = {
625+
with_expanders = true,
626+
expander_collapsed = "",
627+
expander_expanded = "",
628+
expander_highlight = "NeoTreeExpander",
629+
},
630+
},
631+
})
632+
<
633+
634+
FILE NESTING *neo-tree-file-nesting*
635+
636+
By default, file nesting is disabled since `nesting_rules` table is empty,
637+
there is not files to apply the nesting, this can be enabled filling the
638+
`nesting_rules` table with the following structure:
639+
>
640+
require("neo-tree").setup({
641+
nesting_rules = {
642+
["js"] = { "js.map" }
643+
}
644+
})
645+
<
646+
This will render:
647+
>
648+
FILENAME.js
649+
FILENAME.js.map
650+
<
651+
615652
HIGHLIGHTS *neo-tree-highlights*
616653

617654
The following highlight groups are defined by this plugin. If you set any of
@@ -643,6 +680,7 @@ NeoTreeGitUntracked File name when the git status is untracked.
643680
NeoTreeHiddenByName Used for icons and names when `hide_by_name` is used.
644681
NeoTreeIndentMarker The style of indentation markers (guides). By default,
645682
the "Normal" highlight is used.
683+
NeoTreeExpander Used for collapsed/expanded icons.
646684
NeoTreeNormal |hl-Normal| override in Neo-tree window.
647685
NeoTreeNormalNC |hi-NormalNC| override in Neo-tree window.
648686
NeoTreeRootName The name of the root node.

lua/neo-tree/defaults.lua

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,21 @@ local config = {
5454
indent = {
5555
indent_size = 2,
5656
padding = 1,
57-
with_markers = false,
57+
-- indent guides
58+
with_markers = true,
5859
indent_marker = "",
5960
last_indent_marker = "",
6061
highlight = "NeoTreeIndentMarker",
62+
-- expander config, needed for nesting files
63+
with_expanders = nil, -- if nil and file nesting is enabled, will enable expanders
64+
expander_collapsed = "",
65+
expander_expanded = "",
66+
expander_highlight = "NeoTreeExpander",
6167
},
6268
icon = {
63-
folder_closed = "",
64-
folder_open = "",
69+
folder_closed = "",
70+
folder_open = "",
71+
folder_empty = "",
6572
default = "*",
6673
},
6774
name = {
@@ -151,6 +158,7 @@ local config = {
151158
{ "git_status" },
152159
},
153160
},
161+
nesting_rules = {},
154162
filesystem = {
155163
window = {
156164
mappings = {

lua/neo-tree/setup/init.lua

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ local defaults = require("neo-tree.defaults")
33
local mapping_helper = require("neo-tree.setup.mapping-helper")
44
local events = require("neo-tree.events")
55
local log = require("neo-tree.log")
6+
local file_nesting = require("neo-tree.sources.common.file-nesting")
67
local highlights = require("neo-tree.ui.highlights")
78
local manager = require("neo-tree.sources.manager")
89
local netrw = require("neo-tree.setup.netrw")
@@ -193,7 +194,6 @@ M.win_enter_event = function()
193194
end
194195
end
195196

196-
197197
M.set_log_level = function(level)
198198
log.set_level(level)
199199
end
@@ -243,8 +243,10 @@ M.merge_config = function(config, is_auto_config)
243243
local migrations = require("neo-tree.setup.deprecations").migrate(config)
244244
if #migrations > 0 then
245245
-- defer to make sure it is the last message printed
246-
vim.defer_fn(function ()
247-
vim.cmd("echohl WarningMsg | echo 'Some options have changed, please run `:Neotree migrations` to see the changes' | echohl NONE")
246+
vim.defer_fn(function()
247+
vim.cmd(
248+
"echohl WarningMsg | echo 'Some options have changed, please run `:Neotree migrations` to see the changes' | echohl NONE"
249+
)
248250
end, 50)
249251
end
250252

@@ -289,13 +291,14 @@ M.merge_config = function(config, is_auto_config)
289291
"force",
290292
default_config.window or {},
291293
source_config.window or {},
292-
config.window or {})
294+
config.window or {}
295+
)
293296
source_config.renderers = source_config.renderers or {}
294297
-- if source does not specify a renderer, use the global default
295298
for name, renderer in pairs(default_config.renderers or {}) do
296299
if source_config.renderers[name] == nil then
297300
local r = {}
298-
for _, value in ipairs(renderer) do
301+
for _, value in ipairs(renderer) do
299302
if value[1] and source_config.components[value[1]] ~= nil then
300303
table.insert(r, value)
301304
end
@@ -331,6 +334,8 @@ M.merge_config = function(config, is_auto_config)
331334
-- apply the users config
332335
M.config = vim.tbl_deep_extend("force", default_config, config)
333336

337+
file_nesting.setup(M.config.nesting_rules)
338+
334339
for _, source_name in ipairs(sources) do
335340
for name, rndr in pairs(M.config[source_name].renderers) do
336341
M.config[source_name].renderers[name] = merge_global_components_config(rndr, M.config)

lua/neo-tree/sources/common/commands.lua

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,31 @@ local utils = require("neo-tree.utils")
66
local renderer = require("neo-tree.ui.renderer")
77
local log = require("neo-tree.log")
88

9+
---Gets the node parent folder recursively
10+
---@param tree tree to look for nodes
11+
---@param node node to look for folder parent
12+
---@return node
13+
local function get_folder_node(tree, node)
14+
if node.type == "directory" then
15+
return node
16+
end
17+
return get_folder_node(tree, tree:get_node(node:get_parent_id()))
18+
end
19+
920
local M = {}
1021

1122
---Add a new file or dir at the current node
1223
---@param state table The state of the source
1324
---@param callback function The callback to call when the command is done. Called with the parent node as the argument.
1425
M.add = function(state, callback)
1526
local tree = state.tree
16-
local node = tree:get_node()
17-
if node.type == "file" then
18-
node = tree:get_node(node:get_parent_id())
19-
end
27+
local node = get_folder_node(tree, tree:get_node())
28+
2029
fs_actions.create_node(node:get_id(), callback)
2130
end
2231

2332
M.close_all_nodes = function(state)
2433
renderer.collapse_all_nodes(state.tree)
25-
state.tree:get_nodes()[1]:expand()
2634
state.tree:render()
2735
end
2836

@@ -32,13 +40,13 @@ M.close_node = function(state, callback)
3240
local parent_node = tree:get_node(node:get_parent_id())
3341
local target_node
3442

35-
if node.type == "directory" and node:is_expanded() then
43+
if node:has_children() and node:is_expanded() then
3644
target_node = node
3745
else
3846
target_node = parent_node
3947
end
4048

41-
if target_node then
49+
if target_node and target_node:has_children() then
4250
target_node:collapse()
4351
tree:render()
4452
renderer.focus_node(state, target_node:get_id())
@@ -90,12 +98,7 @@ end
9098
---@param callback function The callback to call when the command is done. Called with the parent node as the argument.
9199
M.paste_from_clipboard = function(state, callback)
92100
if state.clipboard then
93-
local at_node = state.tree:get_node()
94-
local folder = at_node:get_id()
95-
if at_node.type == "file" then
96-
folder = at_node:get_parent_id()
97-
end
98-
101+
local folder = get_folder_node(state.tree, state.tree:get_node()):get_id()
99102
-- Convert to list so to make it easier to pop items from the stack.
100103
local clipboard_list = {}
101104
for _, item in pairs(state.clipboard) do
@@ -177,10 +180,20 @@ local open_with_cmd = function(state, open_cmd, toggle_directory)
177180
log.debug("Could not get node.")
178181
return
179182
end
180-
if node.type == "directory" then
181-
if toggle_directory then
183+
184+
local function open()
185+
local path = node:get_id()
186+
utils.open_file(state, path, open_cmd)
187+
end
188+
189+
if utils.is_expandable(node) then
190+
if toggle_directory and node.type == "directory" then
182191
toggle_directory(node)
183192
elseif node:has_children() then
193+
if node:is_expanded() and node.type == "file" then
194+
return open()
195+
end
196+
184197
local updated = false
185198
if node:is_expanded() then
186199
updated = node:collapse()
@@ -191,10 +204,8 @@ local open_with_cmd = function(state, open_cmd, toggle_directory)
191204
tree:render()
192205
end
193206
end
194-
return nil
195207
else
196-
local path = node:get_id()
197-
utils.open_file(state, path, open_cmd)
208+
open()
198209
end
199210
end
200211

@@ -248,8 +259,6 @@ M.toggle_directory = function(state)
248259
end
249260
if updated then
250261
tree:render()
251-
else
252-
tree:render()
253262
end
254263
end
255264
end

0 commit comments

Comments
 (0)