Skip to content

Commit 0f22edc

Browse files
authored
feat!: show file stats in columns, add sort commands (#1107)
To disable the new columns, see: #1107 (comment)
1 parent e62babc commit 0f22edc

File tree

16 files changed

+605
-41
lines changed

16 files changed

+605
-41
lines changed

README.md

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,20 @@ Neo-tree is a Neovim plugin to browse the file system and other tree like
44
structures in whatever style suits you, including sidebars, floating windows,
55
netrw split style, or all of them at once!
66

7-
![Neo-tree file system](https://github.com/nvim-neo-tree/resources/blob/main/images/Neo-tree-with-right-aligned-symbols.png)
7+
### Neo-tree filesystem as Sidebar:
8+
9+
This screenshot shows Neo-tree opened in the traditional sidebar layout:
10+
11+
![Neo-tree file system sidebar](https://github.com/nvim-neo-tree/resources/blob/main/images/Neo-tree-with-right-aligned-symbols.png)
12+
13+
### Neo-tree filesystem as Split
14+
15+
The below screenshot shows Neo-tree opened as a normal split (`:Neo-tree position=current`). When opened in this way,
16+
there is more room so the extra detail columns can be shown. This screenshot also shows how the contents can be
17+
sorted on any column. In this example, we are sorted on "Size" descending:
18+
19+
![Neo-tree file system
20+
details](https://github.com/nvim-neo-tree/resources/blob/main/images/Neo-tree-with-file-details-and-sort.png)
821

922
### Breaking Changes BAD :bomb: :imp:
1023

@@ -190,6 +203,23 @@ use {
190203
conflict = "",
191204
}
192205
},
206+
-- If you don't want to use these columns, you can set `enabled = false` for each of them individually
207+
file_size = {
208+
enabled = true,
209+
required_width = 64, -- min width of window required to show this column
210+
},
211+
type = {
212+
enabled = true,
213+
required_width = 122, -- min width of window required to show this column
214+
},
215+
last_modified = {
216+
enabled = true,
217+
required_width = 88, -- min width of window required to show this column
218+
},
219+
created = {
220+
enabled = true,
221+
required_width = 110, -- min width of window required to show this column
222+
},
193223
},
194224
-- A list of functions, each representing a global custom command
195225
-- that will be available in all sources (if not overridden in `opts[source_name].commands`)
@@ -252,6 +282,14 @@ use {
252282
["?"] = "show_help",
253283
["<"] = "prev_source",
254284
[">"] = "next_source",
285+
["i"] = "show_file_details",
286+
["o"] = { "show_help", nowait=false, config = { title = "Order by", prefix_key = "o" }},
287+
["oc"] = { "order_by_created", nowait = false },
288+
["od"] = { "order_by_diagnostics", nowait = false },
289+
["om"] = { "order_by_modified", nowait = false },
290+
["on"] = { "order_by_name", nowait = false },
291+
["os"] = { "order_by_size", nowait = false },
292+
["ot"] = { "order_by_type", nowait = false },
255293
}
256294
},
257295
nesting_rules = {},

doc/neo-tree.txt

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,9 @@ A = add_directory: Create a new directory, in this mode it does not
270270
d = delete: Delete the selected file or directory.
271271
Supports visual selection.~
272272

273+
i = show_file_details Show file details in popup window, such as size
274+
and last modified date.
275+
273276
r = rename: Rename the selected file or directory.
274277

275278
y = copy_to_clipboard: Mark file to be copied.
@@ -290,11 +293,25 @@ m = move: Move the selected file or directory.
290293

291294

292295
VIEW CHANGES *neo-tree-view-changes*
293-
H = toggle_hidden: Toggle whether hidden (filtered items) are shown or not.
296+
H = toggle_hidden: Toggle whether hidden (filtered items) are shown or not.
297+
298+
R = refresh: Rescan the filesystem and redraw the tree. Changes made
299+
within nvim should be detected automatically, but this is
300+
useful for changes made elsewhere.
301+
302+
o = order_by... Show help menu for order by choices.
303+
304+
oc = ...created: Sort the tree by created date.
305+
306+
od = ...diagnostics: Sort by diagnostic severity.
307+
308+
om = ...modified: Sort by last modified date.
309+
310+
om = ...name: Sort by name (default sort).
311+
312+
os = ...size: Sort by size.
294313

295-
R = refresh: Rescan the filesystem and redraw the tree. Changes made
296-
within nvim should be detected automatically, but this is
297-
useful for changes made elsewhere.
314+
ot = ...type: Sort by type.
298315

299316

300317
FILTER *neo-tree-filter*
@@ -1230,6 +1247,8 @@ NeoTreeExpander Used for collapsed/expanded icons.
12301247
NeoTreeNormal |hl-Normal| override in Neo-tree window.
12311248
NeoTreeNormalNC |hl-NormalNC| override in Neo-tree window.
12321249
NeoTreeSignColumn |hl-SignColumn| override in Neo-tree window.
1250+
NeoTreeStats Used for "stat" columns like size, last modified, etc.
1251+
NeoTreeStatsHeader Used for the header (top line) of the above columns.
12331252
NeoTreeStatusLine |hl-StatusLine| override in Neo-tree window.
12341253
NeoTreeStatusLineNC |hl-StatusLineNC| override in Neo-tree window.
12351254
NeoTreeVertSplit |hl-VertSplit| override in Neo-tree window.

lua/neo-tree/defaults.lua

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,23 @@ local config = {
234234
},
235235
align = "right",
236236
},
237+
-- If you don't want to use these columns, you can set `enabled = false` for each of them individually
238+
file_size = {
239+
enabled = true,
240+
required_width = 64, -- min width of window required to show this column
241+
},
242+
type = {
243+
enabled = true,
244+
required_width = 122, -- min width of window required to show this column
245+
},
246+
last_modified = {
247+
enabled = true,
248+
required_width = 88, -- min width of window required to show this column
249+
},
250+
created = {
251+
enabled = true,
252+
required_width = 110, -- min width of window required to show this column
253+
},
237254
},
238255
renderers = {
239256
directory = {
@@ -251,7 +268,11 @@ local config = {
251268
-- },
252269
{ "clipboard", zindex = 10 },
253270
{ "diagnostics", errors_only = true, zindex = 20, align = "right", hide_when_expanded = true },
254-
{ "git_status", zindex = 20, align = "right", hide_when_expanded = true },
271+
{ "git_status", zindex = 10, align = "right", hide_when_expanded = true },
272+
{ "file_size", zindex = 10, align = "right" },
273+
{ "type", zindex = 10, align = "right" },
274+
{ "last_modified", zindex = 10, align = "right" },
275+
{ "created", zindex = 10, align = "right" },
255276
},
256277
},
257278
},
@@ -274,7 +295,11 @@ local config = {
274295
{ "bufnr", zindex = 10 },
275296
{ "modified", zindex = 20, align = "right" },
276297
{ "diagnostics", zindex = 20, align = "right" },
277-
{ "git_status", zindex = 20, align = "right" },
298+
{ "git_status", zindex = 10, align = "right" },
299+
{ "file_size", zindex = 10, align = "right" },
300+
{ "type", zindex = 10, align = "right" },
301+
{ "last_modified", zindex = 10, align = "right" },
302+
{ "created", zindex = 10, align = "right" },
278303
},
279304
},
280305
},
@@ -372,6 +397,14 @@ local config = {
372397
["?"] = "show_help",
373398
["<"] = "prev_source",
374399
[">"] = "next_source",
400+
["i"] = "show_file_details",
401+
["o"] = { "show_help", nowait=false, config = { title = "Order by", prefix_key = "o" }},
402+
["oc"] = { "order_by_created", nowait = false },
403+
["od"] = { "order_by_diagnostics", nowait = false },
404+
["om"] = { "order_by_modified", nowait = false },
405+
["on"] = { "order_by_name", nowait = false },
406+
["os"] = { "order_by_size", nowait = false },
407+
["ot"] = { "order_by_type", nowait = false },
375408
},
376409
},
377410
filesystem = {

lua/neo-tree/sources/buffers/lib/items.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ M.get_opened_buffers = function(state)
100100
for id, _ in pairs(context.folders) do
101101
table.insert(state.default_expanded_nodes, id)
102102
end
103-
file_items.deep_sort(root.children)
103+
file_items.advanced_sort(root.children, state)
104104
renderer.show_nodes(root_folders, state)
105105
state.loading = false
106106
end

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

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,10 +407,133 @@ M.prev_source = function(state)
407407
})
408408
end
409409

410+
local function set_sort(state, label)
411+
local sort = state.sort or { label = "Name", direction = -1}
412+
if sort.label == label then
413+
sort.direction = sort.direction * -1
414+
else
415+
sort.label = label
416+
sort.direction = -1
417+
end
418+
state.sort = sort
419+
end
420+
421+
M.order_by_created = function (state)
422+
set_sort(state, "Created")
423+
state.sort_field_provider = function (node)
424+
local stat = utils.get_stat(node)
425+
return stat.birthtime and stat.birthtime.sec or 0
426+
end
427+
require("neo-tree.sources.manager").refresh(state.name)
428+
end
429+
430+
M.order_by_modified = function (state)
431+
set_sort(state, "Last Modified")
432+
state.sort_field_provider = function (node)
433+
local stat = utils.get_stat(node)
434+
return stat.mtime and stat.mtime.sec or 0
435+
end
436+
require("neo-tree.sources.manager").refresh(state.name)
437+
end
438+
439+
M.order_by_name = function (state)
440+
set_sort(state, "Name")
441+
state.sort_field_provider = nil
442+
require("neo-tree.sources.manager").refresh(state.name)
443+
end
444+
445+
M.order_by_size = function (state)
446+
set_sort(state, "Size")
447+
state.sort_field_provider = function (node)
448+
local stat = utils.get_stat(node)
449+
return stat.size or 0
450+
end
451+
require("neo-tree.sources.manager").refresh(state.name)
452+
end
453+
454+
M.order_by_type = function (state)
455+
set_sort(state, "Type")
456+
state.sort_field_provider = function (node)
457+
return node.ext or node.type
458+
end
459+
require("neo-tree.sources.manager").refresh(state.name)
460+
end
461+
462+
M.order_by_git_status = function (state)
463+
set_sort(state, "Git Status")
464+
465+
state.sort_field_provider = function (node)
466+
local git_status_lookup = state.git_status_lookup or {}
467+
local git_status = git_status_lookup[node.path]
468+
if git_status then
469+
return git_status
470+
end
471+
472+
if node.filtered_by and node.filtered_by.gitignored then
473+
return "!!"
474+
else
475+
return ""
476+
end
477+
end
478+
479+
require("neo-tree.sources.manager").refresh(state.name)
480+
end
481+
482+
M.order_by_diagnostics = function (state)
483+
set_sort(state, "Diagnostics")
484+
485+
state.sort_field_provider = function (node)
486+
local diag = state.diagnostics_lookup or {}
487+
local diagnostics = diag[node.path]
488+
if not diagnostics then
489+
return 0
490+
end
491+
if not diagnostics.severity_number then
492+
return 0
493+
end
494+
-- lower severity number means higher severity
495+
return 5 - diagnostics.severity_number
496+
end
497+
498+
require("neo-tree.sources.manager").refresh(state.name)
499+
end
500+
410501
M.show_debug_info = function(state)
411502
print(vim.inspect(state))
412503
end
413504

505+
M.show_file_details = function (state)
506+
local node = state.tree:get_node()
507+
if node.type == "message" then
508+
return
509+
end
510+
local stat = utils.get_stat(node)
511+
local left = {}
512+
local right = {}
513+
table.insert(left, "Name")
514+
table.insert(right, node.name)
515+
table.insert(left, "Path")
516+
table.insert(right, node:get_id())
517+
table.insert(left, "Type")
518+
table.insert(right, node.type)
519+
if stat.size then
520+
table.insert(left, "Size")
521+
table.insert(right, utils.filesize(stat.size))
522+
table.insert(left, "Created")
523+
table.insert(right, os.date("%Y-%m-%d %I:%M %p", stat.birthtime.sec))
524+
table.insert(left, "Modified")
525+
table.insert(right, os.date("%Y-%m-%d %I:%M %p", stat.mtime.sec))
526+
end
527+
528+
local lines = {}
529+
for i, v in ipairs(left) do
530+
local line = string.format("%9s: %s", v, right[i])
531+
table.insert(lines, line)
532+
end
533+
534+
popups.alert("File Details", lines)
535+
end
536+
414537
---Pastes all items from the clipboard to the current directory.
415538
---@param state table The state of the source
416539
---@param callback function The callback to call when the command is done. Called with the parent node as the argument.
@@ -737,7 +860,9 @@ M.vsplit_with_window_picker = function(state, toggle_directory)
737860
end
738861

739862
M.show_help = function(state)
740-
help.show(state)
863+
local title = state.config and state.config.title or nil
864+
local prefix_key = state.config and state.config.prefix_key or nil
865+
help.show(state, title, prefix_key)
741866
end
742867

743868
return M

0 commit comments

Comments
 (0)