Skip to content

Commit 1b93ce0

Browse files
committed
feat(show_file_size): Support hidding size information when width goes below a cutoff
1 parent 8d44388 commit 1b93ce0

File tree

7 files changed

+131
-40
lines changed

7 files changed

+131
-40
lines changed

doc/nvim-tree-lua.txt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,8 @@ Following is the default configuration. See |nvim-tree-opts| for details.
444444
},
445445
size = {
446446
enable = false,
447-
column_width = 12,
447+
width_cutoff = 18,
448+
column_width = 10,
448449
show_folder_size = false,
449450
format_unit = "double",
450451
noshow_folder_size_glyph = "•",
@@ -963,10 +964,16 @@ Configuration for file size display column
963964
Determine if we should render file size information.
964965
Type: `boolean`, Default: `false`
965966

967+
*nvim-tree.renderer.size.width_cutoff*
968+
Whenever nvim-tree window has less width than this cutoff the
969+
size information is hidden. If it goes back to having bigger width
970+
then the cutoff, the information is shown again.
971+
Type: `integer`, Default: `18`
972+
966973
*nvim-tree.renderer.size.column_width*
967974
Determines the amount of space (in characters) the
968975
file size information will take.
969-
Type: `integer`, Default: `12`
976+
Type: `integer`, Default: `10`
970977

971978
*nvim-tree.renderer.size.show_folder_size*
972979
Whether to show the size for folder as well.
@@ -2960,6 +2967,7 @@ highlight group is not, hard linking as follows: >
29602967
|nvim-tree.renderer.size.format_unit|
29612968
|nvim-tree.renderer.size.noshow_folder_size_glyph|
29622969
|nvim-tree.renderer.size.show_folder_size|
2970+
|nvim-tree.renderer.size.width_cutoff|
29632971
|nvim-tree.renderer.special_files|
29642972
|nvim-tree.renderer.symlink_destination|
29652973
|nvim-tree.respect_buf_cwd|

lua/nvim-tree.lua

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,19 @@ local function setup_autocommands(opts)
338338
})
339339
end
340340

341+
if opts.renderer.size.enable then
342+
create_nvim_tree_autocmd({ "WinResized", "VimResized" }, {
343+
-- NOTE: for some reason WinResized doesn't work with pattern
344+
-- I don't really know why
345+
-- pattern = "NvimTree_*",
346+
callback = function(event)
347+
if view.is_visible() and utils.is_nvim_tree_buf(event.buf) then
348+
renderer.on_resize()
349+
end
350+
end,
351+
})
352+
end
353+
341354
if opts.modified.enable then
342355
create_nvim_tree_autocmd({ "BufModifiedSet", "BufWritePost" }, {
343356
callback = function()
@@ -419,7 +432,8 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
419432
},
420433
size = {
421434
enable = false,
422-
column_width = 12,
435+
width_cutoff = 18,
436+
column_width = 10,
423437
show_folder_size = false,
424438
format_unit = "double",
425439
noshow_folder_size_glyph = "",
@@ -656,6 +670,7 @@ local ACCEPTED_TYPES = {
656670
renderer = {
657671
size = {
658672
enable = { "boolean" },
673+
width_cutoff = { "integer" },
659674
column_width = { "integer" },
660675
show_folder_size = { "boolean" },
661676
format_unit = { "function", "string" },
@@ -845,7 +860,7 @@ function M.setup(conf)
845860
end
846861

847862
if M.config.renderer.size.column_width < 6 then
848-
notify.warn "`size.right_padding` is a small number, problably won't show any size numbers, try using 12."
863+
notify.warn "`size.right_padding` is a small number, problably won't show any size numbers, try using 10."
849864
end
850865

851866
if M.config.renderer.size.format_unit == "single" then

lua/nvim-tree/commands.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
local api = require "nvim-tree.api"
22
local view = require "nvim-tree.view"
3+
local renderer = require "nvim-tree.renderer"
34

45
local M = {}
56

lua/nvim-tree/renderer/builder.lua

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ local M = {
4444
---@field lines string[] includes icons etc.
4545
---@field hl_args AddHighlightArgs[] line highlights
4646
---@field signs string[] line signs
47+
---@field extmarks table<integer, HighlightedString[]>
48+
---@field size_extmarks table<integer, HighlightedString[]>
4749
---@field private root_cwd string absolute path
4850
---@field private index number
4951
---@field private depth number
@@ -63,6 +65,7 @@ function Builder:new()
6365
markers = {},
6466
signs = {},
6567
extmarks = {},
68+
size_extmarks = {}, -- Need to be separate from `extmarks` because of resize feature
6669
}
6770
setmetatable(o, self)
6871
self.__index = self
@@ -201,7 +204,7 @@ function Builder:format_line(indent_markers, arrows, icon, name, node)
201204
local added_len = 0
202205
local function add_to_end(t1, t2)
203206
if not t2 then
204-
return
207+
return t1
205208
end
206209
for _, v in ipairs(t2) do
207210
if added_len > 0 then
@@ -216,6 +219,7 @@ function Builder:format_line(indent_markers, arrows, icon, name, node)
216219
for _, v in ipairs(t2) do
217220
added_len = added_len + #v.str
218221
end
222+
return t1
219223
end
220224

221225
local line = { indent_markers, arrows }
@@ -239,6 +243,11 @@ function Builder:format_line(indent_markers, arrows, icon, name, node)
239243
self.extmarks[self.index] = rights
240244
end
241245

246+
local size_extmarks = add_to_end({}, M.decorator_size:icons_right_align(node))
247+
if #size_extmarks > 0 then
248+
self.size_extmarks[self.index] = size_extmarks
249+
end
250+
242251
return line
243252
end
244253

@@ -446,9 +455,9 @@ end
446455
function Builder.setup(opts)
447456
M.opts = opts
448457

449-
-- priority order
458+
M.decorator_size = DecoratorSize:new(opts)
459+
450460
M.decorators = {
451-
DecoratorSize:new(opts),
452461
DecoratorCut:new(opts),
453462
DecoratorCopied:new(opts),
454463
DecoratorDiagnostics:new(opts),

lua/nvim-tree/renderer/decorator/size.lua

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,39 @@
11
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
22
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
3+
local view = require "nvim-tree.view"
4+
35
local Decorator = require "nvim-tree.renderer.decorator"
46

57
---@class DecoratorSize: Decorator
6-
---@field icon HighlightedString|nil
8+
---@field width_cutoff integer
9+
---@field noshow_folder_size_glyph string
10+
---@field column_width integer
11+
---@field show_folder_size boolean
12+
---@field units string[]
13+
---@field format_unit function
14+
---@field format_size function
715
local DecoratorSize = Decorator:new()
816

917
---@param opts table
1018
---@return DecoratorSize
1119
function DecoratorSize:new(opts)
1220
local o = Decorator.new(self, {
1321
enabled = opts.renderer.size.enable,
14-
noshow_folder_size_glyph = opts.renderer.size.noshow_folder_size_glyph or "",
15-
column_width = opts.renderer.size.column_width,
16-
show_folder_size = opts.renderer.size.show_folder_size,
17-
format_unit = opts.renderer.size.format_unit, -- Assumed to be a function
18-
units = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" },
22+
hl_pos = HL_POSITION.none,
1923
icon_placement = ICON_PLACEMENT.right_align,
2024
})
25+
---@cast o DecoratorSize
26+
27+
if not o.enabled then
28+
return o
29+
end
2130

31+
o.width_cutoff = opts.renderer.size.width_cutoff
32+
o.noshow_folder_size_glyph = opts.renderer.size.noshow_folder_size_glyph or ""
33+
o.column_width = opts.renderer.size.column_width
34+
o.show_folder_size = opts.renderer.size.show_folder_size
35+
o.units = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }
36+
o.format_unit = opts.renderer.size.format_unit -- guaranteed to be a function
2237
o.format_size = function(size)
2338
local formatted = string
2439
.format("%.2f", size)
@@ -32,16 +47,11 @@ function DecoratorSize:new(opts)
3247
return o
3348
end
3449

35-
---@param node Node
36-
---@return nil
37-
function DecoratorSize:calculate_highlight(_)
38-
return nil
39-
end
40-
4150
--- Convert a size to a human-readable format (e.g., KB, MB, GB) with fixed width
4251
---@private
4352
---@param size number size in bytes
4453
---@return string
54+
--- edit: Since then I've moved a lot of ifs around getting down to only three, but I'll keep the comment just in case.
4555
---NOTE: This function still try it's best to minified the string
4656
--- generated, but this implies that we have more than 3 branchs
4757
--- to determined how much bytes can we shave from the string to
@@ -50,7 +60,6 @@ end
5060
--- on self.column_width once at this object's construction.
5161
--- Basically, instead of this method, we would baking all ifs first to decide which function to bind to possible field `self.human_readable_size`
5262
--- I don't actually know if it would be faster without test.
53-
--- edit: Since then I've moved a lot of ifs around getting down to only three, but I'll keep the comment just in case.
5463
function DecoratorSize:human_readable_size(size)
5564
-- Check for nan, negative, etc.
5665
if type(size) ~= "number" or size ~= size or size < 0 then
@@ -74,11 +83,11 @@ function DecoratorSize:human_readable_size(size)
7483
local result = size_str .. unit_str
7584

7685
-- We Need a max length to align size redering properly
77-
-- So the result must at at most this column width
86+
-- So the result must have at most this column width
7887
local max_length = self.column_width
7988

8089
if #result > max_length then
81-
if (index + 1) < #self.units then
90+
if index <= #self.units then
8291
size = size / 1024
8392
index = index + 1
8493
size_str = self.format_size(size)
@@ -97,7 +106,7 @@ function DecoratorSize:human_readable_size(size)
97106
-- If still too big after all that,
98107
-- then we just set to empty string
99108
if #result > max_length then
100-
result = ""
109+
result = string.format("%" .. max_length .. "s", "")
101110
end
102111

103112
return result
@@ -106,6 +115,10 @@ end
106115
---@param node Node
107116
---@return HighlightedString[]|nil icons
108117
function DecoratorSize:calculate_icons(node)
118+
if not self.enabled or view.get_current_width() < self.width_cutoff then
119+
return nil
120+
end
121+
109122
local size = node and node.fs_stat and node.fs_stat.size or 0
110123
local folder_size_str = self.column_width > 0 and string.rep(" ", self.column_width - 1) .. self.noshow_folder_size_glyph or ""
111124
local icon = {

lua/nvim-tree/renderer/init.lua

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@ local SIGN_GROUP = "NvimTreeRendererSigns"
1414

1515
local namespace_highlights_id = vim.api.nvim_create_namespace "NvimTreeHighlights"
1616
local namespace_extmarks_id = vim.api.nvim_create_namespace "NvimTreeExtmarks"
17+
local namespace_size_extmarks_id = vim.api.nvim_create_namespace "NvimTreeSizeExtmarks"
1718

1819
---@param bufnr number
1920
---@param lines string[]
2021
---@param hl_args AddHighlightArgs[]
2122
---@param signs string[]
22-
local function _draw(bufnr, lines, hl_args, signs, extmarks)
23+
---@param extmarks table<integer, HighlightedString[]>
24+
---@param size_extmarks table<integer, HighlightedString[]>
25+
local function _draw(bufnr, lines, hl_args, signs, extmarks, size_extmarks)
2326
if vim.fn.has "nvim-0.10" == 1 then
2427
vim.api.nvim_set_option_value("modifiable", true, { buf = bufnr })
2528
else
@@ -40,16 +43,8 @@ local function _draw(bufnr, lines, hl_args, signs, extmarks)
4043
vim.fn.sign_place(0, SIGN_GROUP, sign_name, bufnr, { lnum = i + 1 })
4144
end
4245

43-
vim.api.nvim_buf_clear_namespace(bufnr, namespace_extmarks_id, 0, -1)
44-
for i, extname in pairs(extmarks) do
45-
for _, mark in ipairs(extname) do
46-
vim.api.nvim_buf_set_extmark(bufnr, namespace_extmarks_id, i, -1, {
47-
virt_text = { { mark.str, mark.hl } },
48-
virt_text_pos = "right_align",
49-
hl_mode = "combine",
50-
})
51-
end
52-
end
46+
M.render_extmarks(bufnr, namespace_extmarks_id, extmarks)
47+
M.render_extmarks(bufnr, namespace_size_extmarks_id, size_extmarks)
5348
end
5449

5550
function M.render_hl(bufnr, hl)
@@ -66,6 +61,50 @@ function M.render_hl(bufnr, hl)
6661
end
6762
end
6863

64+
function M.render_extmarks(bufnr, ns_id, extmarks)
65+
if not bufnr or not vim.api.nvim_buf_is_loaded(bufnr) then
66+
return
67+
end
68+
vim.api.nvim_buf_clear_namespace(bufnr, ns_id, 0, -1)
69+
for i, extname in pairs(extmarks) do
70+
for _, mark in ipairs(extname) do
71+
vim.api.nvim_buf_set_extmark(bufnr, ns_id, i, -1, {
72+
virt_text = { { mark.str, mark.hl } },
73+
virt_text_pos = "right_align",
74+
hl_mode = "combine",
75+
})
76+
end
77+
end
78+
end
79+
80+
-- Here we do a partial redraw of only a subsection of extra marks.
81+
-- We could simply call reloaders.reload(), but that would be substantially slower.
82+
-- Calling `nvim_buf_clear_namespace` to hide size information
83+
-- and `render_extmarks` to show again is preferable in place of
84+
-- reloading all decorators, nodes and lines from scratch, since resize does not trigger a reload.
85+
local redraw_size_extmarks = false
86+
function M.on_resize()
87+
if M.builder == nil then
88+
return
89+
end
90+
91+
local bufnr = view.get_bufnr()
92+
93+
if view.get_current_width() < M.config.size.width_cutoff then
94+
redraw_size_extmarks = true
95+
vim.api.nvim_buf_clear_namespace(bufnr, namespace_size_extmarks_id, 0, -1)
96+
return
97+
end
98+
99+
-- If we got here, we only need to know if we should redraw
100+
-- We don't have to check if decorator_size is enbaled, because if it's
101+
-- not, then size_extmarks would've been empty
102+
if redraw_size_extmarks then
103+
redraw_size_extmarks = false
104+
M.render_extmarks(bufnr, namespace_size_extmarks_id, M.builder.size_extmarks)
105+
end
106+
end
107+
69108
function M.draw()
70109
local bufnr = view.get_bufnr()
71110
if not core.get_explorer() or not bufnr or not vim.api.nvim_buf_is_loaded(bufnr) then
@@ -77,11 +116,11 @@ function M.draw()
77116
local cursor = vim.api.nvim_win_get_cursor(view.get_winnr() or 0)
78117
icon_component.reset_config()
79118

80-
local builder = Builder:new():build()
81-
82-
_draw(bufnr, builder.lines, builder.hl_args, builder.signs, builder.extmarks)
119+
redraw_size_extmarks = false
120+
M.builder = Builder:new():build()
121+
_draw(bufnr, M.builder.lines, M.builder.hl_args, M.builder.signs, M.builder.extmarks, M.builder.size_extmarks)
83122

84-
if cursor and #builder.lines >= cursor[1] then
123+
if cursor and #M.builder.lines >= cursor[1] then
85124
vim.api.nvim_win_set_cursor(view.get_winnr() or 0, cursor)
86125
end
87126

@@ -94,11 +133,10 @@ end
94133

95134
function M.setup(opts)
96135
M.config = opts.renderer
97-
136+
M.builder = nil
98137
_padding.setup(opts)
99138
full_name.setup(opts)
100139
icon_component.setup(opts)
101-
102140
Builder.setup(opts)
103141
end
104142

lua/nvim-tree/view.lua

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,13 @@ function M.configure_width(width)
576576
end
577577
end
578578

579+
---Get effective width, works on float window
580+
---@return integer
581+
function M.get_current_width()
582+
local view_winnr = M.get_winnr()
583+
return view_winnr and vim.api.nvim_win_get_width(view_winnr or 0) or 0
584+
end
585+
579586
function M.setup(opts)
580587
local options = opts.view or {}
581588
M.View.centralize_selection = options.centralize_selection

0 commit comments

Comments
 (0)