From d27bcb8152b748cb7cb6b77a45f101d87f9c0049 Mon Sep 17 00:00:00 2001 From: evertonse Date: Sun, 14 Jul 2024 00:13:57 -0300 Subject: [PATCH 01/15] feat(icon_placement): Allow right_align icon_placemente for decorator using ext_marks nvim api --- doc/nvim-tree-lua.txt | 12 ++++++++---- lua/nvim-tree/enum.lua | 1 + lua/nvim-tree/renderer/builder.lua | 9 +++++++++ lua/nvim-tree/renderer/decorator/init.lua | 11 +++++++++++ lua/nvim-tree/renderer/init.lua | 13 +++++++++++-- 5 files changed, 40 insertions(+), 6 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 19fe4d60bf6..9acde94b9a2 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -974,25 +974,29 @@ Icon order and sign column precedence: *nvim-tree.renderer.icons.git_placement* Place where the git icons will be rendered. Can be `"after"` or `"before"` filename (after the file/folders icons) - or `"signcolumn"` (requires |nvim-tree.view.signcolumn| enabled). + or `"signcolumn"` (requires |nvim-tree.view.signcolumn| enabled) or + `"right_align"` (requires |nvim_buf_set_extmark|). Type: `string`, Default: `"before"` *nvim-tree.renderer.icons.diagnostics_placement* Place where the diagnostics icon will be rendered. Can be `"after"` or `"before"` filename (after the file/folders icons) - or `"signcolumn"` (requires |nvim-tree.view.signcolumn| enabled). + or `"signcolumn"` (requires |nvim-tree.view.signcolumn| enabled) or + `"right_align"` (requires |nvim_buf_set_extmark|). Type: `string`, Default: `"signcolumn"` *nvim-tree.renderer.icons.modified_placement* Place where the modified icon will be rendered. Can be `"after"` or `"before"` filename (after the file/folders icons) - or `"signcolumn"` (requires |nvim-tree.view.signcolumn| enabled). + or `"signcolumn"` (requires |nvim-tree.view.signcolumn| enabled) or + `"right_align"` (requires |nvim_buf_set_extmark|). Type: `string`, Default: `"after"` *nvim-tree.renderer.icons.bookmarks_placement* Place where the bookmarks icon will be rendered. Can be `"after"` or `"before"` filename (after the file/folders icons) - or `"signcolumn"` (requires |nvim-tree.view.signcolumn| enabled). + or `"signcolumn"` (requires |nvim-tree.view.signcolumn| enabled) or + `"right_align"` (requires |nvim_buf_set_extmark|). Type: `string`, Default: `signcolumn` *nvim-tree.renderer.icons.padding* diff --git a/lua/nvim-tree/enum.lua b/lua/nvim-tree/enum.lua index 92ea2bb4ca0..054c463f46c 100644 --- a/lua/nvim-tree/enum.lua +++ b/lua/nvim-tree/enum.lua @@ -16,6 +16,7 @@ M.ICON_PLACEMENT = { signcolumn = 1, before = 2, after = 3, + right_align = 4, } return M diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index 52c6c7e59c4..c3c2f14115b 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -60,6 +60,7 @@ function Builder:new() lines = {}, markers = {}, signs = {}, + extmarks = {}, } setmetatable(o, self) self.__index = self @@ -228,6 +229,14 @@ function Builder:format_line(indent_markers, arrows, icon, name, node) add_to_end(line, M.decorators[i]:icons_after(node)) end + local rights = {} + for i = #M.decorators, 1, -1 do + add_to_end(rights, M.decorators[i]:icons_right_align(node)) + end + if #rights > 0 then + self.extmarks[self.index] = rights + end + return line end diff --git a/lua/nvim-tree/renderer/decorator/init.lua b/lua/nvim-tree/renderer/decorator/init.lua index 7748b11cf49..f2d047767b5 100644 --- a/lua/nvim-tree/renderer/decorator/init.lua +++ b/lua/nvim-tree/renderer/decorator/init.lua @@ -74,6 +74,17 @@ function Decorator:icons_after(node) return self:calculate_icons(node) end +---Icons when ICON_PLACEMENT.right_align +---@param node Node +---@return HighlightedString[]|nil icons +function Decorator:icons_right_align(node) + if not self.enabled or self.icon_placement ~= ICON_PLACEMENT.right_align then + return + end + + return self:calculate_icons(node) +end + ---Maybe icons, optionally implemented ---@protected ---@param _ Node diff --git a/lua/nvim-tree/renderer/init.lua b/lua/nvim-tree/renderer/init.lua index 27ef3acaa71..b6c55e0fcdf 100644 --- a/lua/nvim-tree/renderer/init.lua +++ b/lua/nvim-tree/renderer/init.lua @@ -18,7 +18,7 @@ local namespace_id = vim.api.nvim_create_namespace "NvimTreeHighlights" ---@param lines string[] ---@param hl_args AddHighlightArgs[] ---@param signs string[] -local function _draw(bufnr, lines, hl_args, signs) +local function _draw(bufnr, lines, hl_args, signs, extmarks) if vim.fn.has "nvim-0.10" == 1 then vim.api.nvim_set_option_value("modifiable", true, { buf = bufnr }) else @@ -38,6 +38,15 @@ local function _draw(bufnr, lines, hl_args, signs) for i, sign_name in pairs(signs) do vim.fn.sign_place(0, SIGN_GROUP, sign_name, bufnr, { lnum = i + 1 }) end + for i, extname in pairs(extmarks) do + for _, mark in ipairs(extname) do + vim.api.nvim_buf_set_extmark(bufnr, namespace_id, i, -1, { + virt_text = { { mark.str, mark.hl } }, + virt_text_pos = "right_align", + hl_mode = "combine", + }) + end + end end function M.render_hl(bufnr, hl) @@ -67,7 +76,7 @@ function M.draw() local builder = Builder:new():build() - _draw(bufnr, builder.lines, builder.hl_args, builder.signs) + _draw(bufnr, builder.lines, builder.hl_args, builder.signs, builder.extmarks) if cursor and #builder.lines >= cursor[1] then vim.api.nvim_win_set_cursor(view.get_winnr() or 0, cursor) From 6d336de891589292ed0f760e975f46db77a2e5fd Mon Sep 17 00:00:00 2001 From: evertonse Date: Sun, 14 Jul 2024 00:13:57 -0300 Subject: [PATCH 02/15] feat(icon_placement): Allow right_align icon_placemente for decorator using ext_marks nvim api feat(icon_placement): Allow right_align icon_placemente for decorator using ext_marks nvim api --- lua/nvim-tree.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 343196a0f66..9feb6e55a05 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -672,10 +672,10 @@ local ACCEPTED_STRINGS = { highlight_diagnostics = { "none", "icon", "name", "all" }, highlight_clipboard = { "none", "icon", "name", "all" }, icons = { - git_placement = { "before", "after", "signcolumn" }, - modified_placement = { "before", "after", "signcolumn" }, - diagnostics_placement = { "before", "after", "signcolumn" }, - bookmarks_placement = { "before", "after", "signcolumn" }, + git_placement = { "before", "after", "signcolumn", "right_align" }, + modified_placement = { "before", "after", "signcolumn", "right_align" }, + diagnostics_placement = { "before", "after", "signcolumn", "right_align" }, + bookmarks_placement = { "before", "after", "signcolumn", "right_align" }, }, }, help = { From 6b7b4f25817f923134fd477bb937e106b9d6d07b Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sun, 21 Jul 2024 14:44:20 +1000 Subject: [PATCH 03/15] feat(icon_placement): consolidate doc --- doc/nvim-tree-lua.txt | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 9acde94b9a2..fd215fd5cf8 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -944,6 +944,12 @@ Configuration options for icons. Icon order and sign column precedence: git < modified < bookmarked < diagnostics +`renderer.icons.*_placement` options may be: +- `"before"` : before file/folder, after the file/folders icons +- `"after"` : after file/folder +- `"signcolumn"` : far left, requires |nvim-tree.view.signcolumn| enabled +- `"right_align"` : far right + *nvim-tree.renderer.icons.web_devicons* Configure optional plugin `"nvim-tree/nvim-web-devicons"` @@ -972,31 +978,19 @@ Icon order and sign column precedence: Type: `boolean`, Default: `true` *nvim-tree.renderer.icons.git_placement* - Place where the git icons will be rendered. - Can be `"after"` or `"before"` filename (after the file/folders icons) - or `"signcolumn"` (requires |nvim-tree.view.signcolumn| enabled) or - `"right_align"` (requires |nvim_buf_set_extmark|). + Git icons placement. Type: `string`, Default: `"before"` *nvim-tree.renderer.icons.diagnostics_placement* - Place where the diagnostics icon will be rendered. - Can be `"after"` or `"before"` filename (after the file/folders icons) - or `"signcolumn"` (requires |nvim-tree.view.signcolumn| enabled) or - `"right_align"` (requires |nvim_buf_set_extmark|). + Diganostic icon placement. Type: `string`, Default: `"signcolumn"` *nvim-tree.renderer.icons.modified_placement* - Place where the modified icon will be rendered. - Can be `"after"` or `"before"` filename (after the file/folders icons) - or `"signcolumn"` (requires |nvim-tree.view.signcolumn| enabled) or - `"right_align"` (requires |nvim_buf_set_extmark|). + Modified icon placement. Type: `string`, Default: `"after"` *nvim-tree.renderer.icons.bookmarks_placement* - Place where the bookmarks icon will be rendered. - Can be `"after"` or `"before"` filename (after the file/folders icons) - or `"signcolumn"` (requires |nvim-tree.view.signcolumn| enabled) or - `"right_align"` (requires |nvim_buf_set_extmark|). + Bookmark icon placement. Type: `string`, Default: `signcolumn` *nvim-tree.renderer.icons.padding* From cb56c0d76104db80aaf6fd35697ef34f0e483f5d Mon Sep 17 00:00:00 2001 From: evertonse Date: Mon, 22 Jul 2024 02:53:24 -0300 Subject: [PATCH 04/15] fix: extra namespace added to avoid colision between right_align and full_name features --- doc/nvim-tree-lua.txt | 4 +--- lua/nvim-tree/renderer/init.lua | 5 ++++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index f554ef7a87f..5eb96650e0e 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -1001,9 +1001,7 @@ Icon order and sign column precedence: Type: `string`, Default: `"after"` *nvim-tree.renderer.icons.hidden_placement* - Place where the hidden (dotfile) icon will be rendered. - Can be `"after"` or `"before"` filename (after the file/folders icons) - or `"signcolumn"` (requires |nvim-tree.view.signcolumn| enabled). + Hidden icon placement. Type: `string`, Default: `"after"` *nvim-tree.renderer.icons.bookmarks_placement* diff --git a/lua/nvim-tree/renderer/init.lua b/lua/nvim-tree/renderer/init.lua index b6c55e0fcdf..41c8fd21477 100644 --- a/lua/nvim-tree/renderer/init.lua +++ b/lua/nvim-tree/renderer/init.lua @@ -13,6 +13,7 @@ local M = {} local SIGN_GROUP = "NvimTreeRendererSigns" local namespace_id = vim.api.nvim_create_namespace "NvimTreeHighlights" +local namespace_extmarks_id = vim.api.nvim_create_namespace "NvimTreeExtmarks" ---@param bufnr number ---@param lines string[] @@ -38,9 +39,11 @@ local function _draw(bufnr, lines, hl_args, signs, extmarks) for i, sign_name in pairs(signs) do vim.fn.sign_place(0, SIGN_GROUP, sign_name, bufnr, { lnum = i + 1 }) end + + vim.api.nvim_buf_clear_namespace(bufnr, namespace_extmarks_id, 0, -1) for i, extname in pairs(extmarks) do for _, mark in ipairs(extname) do - vim.api.nvim_buf_set_extmark(bufnr, namespace_id, i, -1, { + vim.api.nvim_buf_set_extmark(bufnr, namespace_extmarks_id, i, -1, { virt_text = { { mark.str, mark.hl } }, virt_text_pos = "right_align", hl_mode = "combine", From c41c7526c2268f12d45b1fc91e2601afac76ec60 Mon Sep 17 00:00:00 2001 From: evertonse Date: Mon, 22 Jul 2024 15:47:59 -0300 Subject: [PATCH 05/15] feat(hidden_display): Allow fine grained rendering of hidden files in a folder --- doc/nvim-tree-lua.txt | 6 ++++++ lua/nvim-tree/appearance/init.lua | 1 + lua/nvim-tree/explorer/explore.lua | 24 ++++++++++++++++++++++++ lua/nvim-tree/renderer/builder.lua | 1 + lua/nvim-tree/view.lua | 1 + 5 files changed, 33 insertions(+) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 5eb96650e0e..ff4267b8833 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -1004,6 +1004,12 @@ Icon order and sign column precedence: Hidden icon placement. Type: `string`, Default: `"after"` + *nvim-tree.renderer.icons.hidden_placement* + Place where the hidden (dotfile) icon will be rendered. + Can be `"after"` or `"before"` filename (after the file/folders icons) + or `"signcolumn"` (requires |nvim-tree.view.signcolumn| enabled). + Type: `string`, Default: `"after"` + *nvim-tree.renderer.icons.bookmarks_placement* Bookmark icon placement. Type: `string`, Default: `signcolumn` diff --git a/lua/nvim-tree/appearance/init.lua b/lua/nvim-tree/appearance/init.lua index 4b4f33ff597..7600ab2c05d 100644 --- a/lua/nvim-tree/appearance/init.lua +++ b/lua/nvim-tree/appearance/init.lua @@ -14,6 +14,7 @@ M.HIGHLIGHT_GROUPS = { -- Standard { group = "NvimTreeNormal", link = "Normal" }, { group = "NvimTreeNormalFloat", link = "NormalFloat" }, + { group = "NvimTreeNormalFloatBorder", link = "FloatBorder" }, { group = "NvimTreeNormalNC", link = "NvimTreeNormal" }, { group = "NvimTreeLineNr", link = "LineNr" }, diff --git a/lua/nvim-tree/explorer/explore.lua b/lua/nvim-tree/explorer/explore.lua index 665c47c1641..ea376e89327 100644 --- a/lua/nvim-tree/explorer/explore.lua +++ b/lua/nvim-tree/explorer/explore.lua @@ -15,9 +15,11 @@ local M = {} ---@param cwd string ---@param node Node ---@param git_status table +---@return integer filtered_count local function populate_children(handle, cwd, node, git_status) local node_ignored = explorer_node.is_git_ignored(node) local nodes_by_path = utils.bool_record(node.nodes, "absolute_path") + local filter_status = filters.prepare(git_status) while true do local name, t = vim.loop.fs_scandir_next(handle) @@ -68,6 +70,13 @@ function M.explore(node, status) populate_children(handle, cwd, node, status) + local child_hidden_count = 0 + for _, child_node in ipairs(node.nodes) do + if child_node then + child_hidden_count = child_hidden_count + 1 + end + end + local is_root = not node.parent local child_folder_only = explorer_node.has_one_child_folder(node) and node.nodes[1] if M.config.group_empty and not is_root and child_folder_only then @@ -84,6 +93,21 @@ function M.explore(node, status) sorters.sort(node.nodes) live_filter.apply_filter(node) + if true or child_hidden_count ~= 0 then + table.insert(node.nodes, { + absolute_path = "", + git_status = {}, + + has_children = false, + name = "(" .. tostring(child_hidden_count) .. " hidden items)", + nodes = {}, + open = false, + + parent = node, + type = "file", + }) + end + log.profile_end(profile) return node.nodes end diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index 940d2b7523d..00cd868678c 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -381,6 +381,7 @@ function Builder:build_lines(node) end local num_children = self:get_nodes_number(node.nodes) local idx = 1 + -- table.insert(node.nodes, { name = "cock", path = "cock" }) for _, n in ipairs(node.nodes) do if not n.hidden then self:build_signs(n) diff --git a/lua/nvim-tree/view.lua b/lua/nvim-tree/view.lua index 6cfa1dde3f2..1e9a412a875 100644 --- a/lua/nvim-tree/view.lua +++ b/lua/nvim-tree/view.lua @@ -50,6 +50,7 @@ M.View = { "Normal:NvimTreeNormal", "NormalNC:NvimTreeNormalNC", "NormalFloat:NvimTreeNormalFloat", + "FloatBorder:NvimTreeNormalFloatBorder", }, ","), }, } From 9053a6ddcd441a3acaec9425fdc9bb7a0c3967db Mon Sep 17 00:00:00 2001 From: evertonse Date: Wed, 24 Jul 2024 02:39:52 -0300 Subject: [PATCH 06/15] feat(hidden_display): update defaults in Builder to allow rendering --- doc/nvim-tree-lua.txt | 42 +++++++++++++++ lua/nvim-tree.lua | 3 ++ lua/nvim-tree/appearance/init.lua | 3 ++ lua/nvim-tree/explorer/explore.lua | 52 +++++++++---------- lua/nvim-tree/explorer/filters.lua | 63 ++++++++++++++++++----- lua/nvim-tree/explorer/reload.lua | 21 +++++++- lua/nvim-tree/lib.lua | 5 ++ lua/nvim-tree/live-filter.lua | 13 +++++ lua/nvim-tree/node.lua | 1 + lua/nvim-tree/renderer/builder.lua | 82 +++++++++++++++++++++++++++++- lua/nvim-tree/renderer/init.lua | 17 +++++-- lua/nvim-tree/utils.lua | 76 +++++++++++++++++++++++++++ 12 files changed, 333 insertions(+), 45 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index ff4267b8833..5539818864c 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -423,6 +423,7 @@ Following is the default configuration. See |nvim-tree-opts| for details. root_folder_label = ":~:s?$?/..?", indent_width = 2, special_files = { "Cargo.toml", "Makefile", "README.md", "readme.md" }, + hidden_display_function = nil, symlink_destination = true, highlight_git = "none", highlight_diagnostics = "none", @@ -878,6 +879,46 @@ Number of spaces for an each tree nesting level. Minimum 1. A list of filenames that gets highlighted with `NvimTreeSpecialFile`. Type: `table`, Default: `{ "Cargo.toml", "Makefile", "README.md", "readme.md", }` +*nvim-tree.renderer.hidden_display_function +Determines the rendering of hidden files in a folder. + Type: function | string, Default: "none" +Possible string values are: + - "none": Doesn't inform anything about hidden files. + - "simple": Shows how many hidden files are in a folder. + - "all": Shows how many files are hidden and the number of hidden files per reason why they're hidden. + +Example "all": +If a folder has 14 hidden items for various reasons, the display might show: +``(14 total git: 5, dotfile: 9)``. + +If a function is provided, it receives a table `hidden_count` where keys are reasons and values are the count of hidden files for that reason. +The `hidden_count` argument is structured as follows, where is the number +of hidden files related to the field. + +hidden_count = { + bookmark = , + buf = , + custom = , + dotfile = , + git = , + live_filter = , +} + +Example of function that can be passed: + +function(hidden_count) + local total_count = 0 + for reason, count in pairs(hidden_count) do + total_count = total_count + count + end + + if total_count > 0 then + return "(" .. tostring(total_count) .. " hidden")" + end + return nil +end + + *nvim-tree.renderer.symlink_destination* Whether to show the destination of the symlink. Type: `boolean`, Default: `true` @@ -2901,6 +2942,7 @@ highlight group is not, hard linking as follows: > |nvim-tree.renderer.icons.glyphs.modified| |nvim-tree.renderer.icons.glyphs.symlink| |nvim-tree.renderer.icons.hidden_placement| +|nvim-tree.renderer.icons.hidden_placement| |nvim-tree.renderer.icons.modified_placement| |nvim-tree.renderer.icons.padding| |nvim-tree.renderer.icons.show| diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 0972af864c9..0356f0a7e46 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -387,6 +387,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS root_folder_label = ":~:s?$?/..?", indent_width = 2, special_files = { "Cargo.toml", "Makefile", "README.md", "readme.md" }, + hidden_display_function = "none", symlink_destination = true, highlight_git = "none", highlight_diagnostics = "none", @@ -636,6 +637,7 @@ local ACCEPTED_TYPES = { }, }, renderer = { + hidden_display_function = { "function", "string" }, group_empty = { "boolean", "function" }, root_folder_label = { "function", "string", "boolean" }, }, @@ -669,6 +671,7 @@ local ACCEPTED_STRINGS = { signcolumn = { "yes", "no", "auto" }, }, renderer = { + hidden_display_function = { "none", "simple", "all" }, highlight_git = { "none", "icon", "name", "all" }, highlight_opened_files = { "none", "icon", "name", "all" }, highlight_modified = { "none", "icon", "name", "all" }, diff --git a/lua/nvim-tree/appearance/init.lua b/lua/nvim-tree/appearance/init.lua index 7600ab2c05d..9a8c67efe67 100644 --- a/lua/nvim-tree/appearance/init.lua +++ b/lua/nvim-tree/appearance/init.lua @@ -82,6 +82,9 @@ M.HIGHLIGHT_GROUPS = { { group = "NvimTreeHiddenFileHL", link = "NvimTreeHiddenIcon" }, { group = "NvimTreeHiddenFolderHL", link = "NvimTreeHiddenFileHL" }, + -- Hidden Display + { group = "NvimTreeHiddenDisplay", link = "Conceal" }, + -- Opened { group = "NvimTreeOpenedHL", link = "Special" }, diff --git a/lua/nvim-tree/explorer/explore.lua b/lua/nvim-tree/explorer/explore.lua index ea376e89327..6b3a876ec80 100644 --- a/lua/nvim-tree/explorer/explore.lua +++ b/lua/nvim-tree/explorer/explore.lua @@ -6,7 +6,9 @@ local sorters = require "nvim-tree.explorer.sorters" local filters = require "nvim-tree.explorer.filters" local live_filter = require "nvim-tree.live-filter" local log = require "nvim-tree.log" +-- local explorer_module = require "nvim-tree.explorer" +local FILTER_REASON = filters.FILTER_REASON local Watcher = require "nvim-tree.watcher" local M = {} @@ -21,21 +23,31 @@ local function populate_children(handle, cwd, node, git_status) local nodes_by_path = utils.bool_record(node.nodes, "absolute_path") local filter_status = filters.prepare(git_status) + + node.hidden_count = vim.tbl_deep_extend("force", node.hidden_count or {}, { + git = 0, + buf = 0, + dotfile = 0, + custom = 0, + bookmark = 0, + }) + while true do local name, t = vim.loop.fs_scandir_next(handle) if not name then break end + local is_dir = t == "directory" local abs = utils.path_join { cwd, name } local profile = log.profile_start("explore populate_children %s", abs) ---@type uv.fs_stat.result|nil local stat = vim.loop.fs_stat(abs) - - if not filters.should_filter(abs, stat, filter_status) and not nodes_by_path[abs] and Watcher.is_fs_event_capable(abs) then + local filter_reason = filters.should_filter_as_reason(abs, stat, filter_status) + if filter_reason == FILTER_REASON.none and not nodes_by_path[abs] and Watcher.is_fs_event_capable(abs) then local child = nil - if t == "directory" and vim.loop.fs_access(abs, "R") then + if is_dir and vim.loop.fs_access(abs, "R") then child = builders.folder(node, abs, name, stat) elseif t == "file" then child = builders.file(node, abs, name, stat) @@ -50,10 +62,18 @@ local function populate_children(handle, cwd, node, git_status) nodes_by_path[child.absolute_path] = true explorer_node.update_git_status(child, node_ignored, git_status) end + else + for reason, value in pairs(FILTER_REASON) do + if filter_reason == value then + node.hidden_count[reason] = node.hidden_count[reason] + 1 + end + end end log.profile_end(profile) end + + -- explorer_module.reload(node) end ---@param node Node @@ -70,13 +90,6 @@ function M.explore(node, status) populate_children(handle, cwd, node, status) - local child_hidden_count = 0 - for _, child_node in ipairs(node.nodes) do - if child_node then - child_hidden_count = child_hidden_count + 1 - end - end - local is_root = not node.parent local child_folder_only = explorer_node.has_one_child_folder(node) and node.nodes[1] if M.config.group_empty and not is_root and child_folder_only then @@ -89,26 +102,13 @@ function M.explore(node, status) log.profile_end(profile) return ns end - + local old_num = #node.nodes sorters.sort(node.nodes) live_filter.apply_filter(node) - if true or child_hidden_count ~= 0 then - table.insert(node.nodes, { - absolute_path = "", - git_status = {}, - - has_children = false, - name = "(" .. tostring(child_hidden_count) .. " hidden items)", - nodes = {}, - open = false, - - parent = node, - type = "file", - }) - end - log.profile_end(profile) + local new_num = #node.nodes + assert(old_num == new_num, vim.inspect { old_num = old_num, new_num = new_num }) return node.nodes end diff --git a/lua/nvim-tree/explorer/filters.lua b/lua/nvim-tree/explorer/filters.lua index 7b8be1315f7..2ff841532d9 100644 --- a/lua/nvim-tree/explorer/filters.lua +++ b/lua/nvim-tree/explorer/filters.lua @@ -6,9 +6,19 @@ local M = { custom_function = nil, } +---@enum FILTER_REASON +M.FILTER_REASON = { + none = 0, -- It's not filtered + git = 1, + buf = 2, + dotfile = 4, + custom = 8, + bookmark = 16, +} + ---@param path string ---@return boolean -local function is_excluded(path) +M.is_excluded = function(path) for _, node in ipairs(M.exclude_list) do if path:match(node) then return true @@ -21,7 +31,7 @@ end ---@param path string Absolute path ---@param git_status table from prepare ---@return boolean -local function git(path, git_status) +M.git = function(path, git_status) if type(git_status) ~= "table" or type(git_status.files) ~= "table" or type(git_status.dirs) ~= "table" then return false end @@ -48,7 +58,7 @@ end ---@param path string Absolute path ---@param bufinfo table vim.fn.getbufinfo { buflisted = 1 } ---@return boolean -local function buf(path, bufinfo) +M.buf = function(path, bufinfo) if not M.config.filter_no_buffer or type(bufinfo) ~= "table" then return false end @@ -65,14 +75,14 @@ end ---@param path string ---@return boolean -local function dotfile(path) +M.dotfile = function(path) return M.config.filter_dotfiles and utils.path_basename(path):sub(1, 1) == "." end ---@param path string ---@param path_type string|nil filetype of path ---@param bookmarks table path, filetype table of bookmarked files -local function bookmark(path, path_type, bookmarks) +M.bookmark = function(path, path_type, bookmarks) if not M.config.filter_no_bookmark then return false end @@ -107,7 +117,7 @@ end ---@param path string ---@return boolean -local function custom(path) +M.custom = function(path) if not M.config.filter_custom then return false end @@ -175,15 +185,44 @@ function M.should_filter(path, fs_stat, status) end -- exclusions override all filters - if is_excluded(path) then + if M.is_excluded(path) then return false end - return git(path, status.git_status) - or buf(path, status.bufinfo) - or dotfile(path) - or custom(path) - or bookmark(path, fs_stat and fs_stat.type, status.bookmarks) + return M.git(path, status.git_status) + or M.buf(path, status.bufinfo) + or M.dotfile(path) + or M.custom(path) + or M.bookmark(path, fs_stat and fs_stat.type, status.bookmarks) +end + +---@param path string Absolute path +---@param fs_stat uv.fs_stat.result|nil fs_stat of file +---@param status table from prepare +---@return FILTER_REASON +function M.should_filter_as_reason(path, fs_stat, status) + if not M.config.enable then + return M.FILTER_REASON.none + end + + -- exclusions override all filters + if M.is_excluded(path) then + return M.FILTER_REASON.none + end + + if M.git(path, status.git_status) then + return M.FILTER_REASON.git + elseif M.buf(path, status.bufinfo) then + return M.FILTER_REASON.buf + elseif M.dotfile(path) then + return M.FILTER_REASON.dotfile + elseif M.custom(path) then + return M.FILTER_REASON.custom + elseif M.bookmark(path, fs_stat and fs_stat.type, status.bookmarks) then + return M.FILTER_REASON.bookmark + else + return M.FILTER_REASON.none + end end function M.setup(opts) diff --git a/lua/nvim-tree/explorer/reload.lua b/lua/nvim-tree/explorer/reload.lua index 9d2ddcab5b7..27cd5660817 100644 --- a/lua/nvim-tree/explorer/reload.lua +++ b/lua/nvim-tree/explorer/reload.lua @@ -7,6 +7,7 @@ local live_filter = require "nvim-tree.live-filter" local git = require "nvim-tree.git" local log = require "nvim-tree.log" +local FILTER_REASON = filters.FILTER_REASON local NodeIterator = require "nvim-tree.iterators.node-iterator" local Watcher = require "nvim-tree.watcher" @@ -79,6 +80,7 @@ function M.reload(node, git_status) local profile = log.profile_start("reload %s", node.absolute_path) local filter_status = filters.prepare(git_status) + local is_dir = node.type == "directory" if node.group_next then node.nodes = { node.group_next } @@ -90,6 +92,16 @@ function M.reload(node, git_status) local node_ignored = explorer_node.is_git_ignored(node) ---@type table local nodes_by_path = utils.key_by(node.nodes, "absolute_path") + + -- To reset we must 'zero' everything that we use + node.hidden_count = vim.tbl_deep_extend("force", node.hidden_count or {}, { + git = 0, + buf = 0, + dotfile = 0, + custom = 0, + bookmark = 0, + }) + while true do local name, t = vim.loop.fs_scandir_next(handle) if not name then @@ -100,7 +112,8 @@ function M.reload(node, git_status) ---@type uv.fs_stat.result|nil local stat = vim.loop.fs_stat(abs) - if not filters.should_filter(abs, stat, filter_status) then + local filter_reason = filters.should_filter_as_reason(abs, stat, filter_status) + if filter_reason == FILTER_REASON.none then remain_childs[abs] = true -- Recreate node if type changes. @@ -137,6 +150,12 @@ function M.reload(node, git_status) n.fs_stat = stat end end + else + for reason, value in pairs(FILTER_REASON) do + if filter_reason == value then + node.hidden_count[reason] = node.hidden_count[reason] + 1 + end + end end end diff --git a/lua/nvim-tree/lib.lua b/lua/nvim-tree/lib.lua index 8bdf9a97bbc..c2f9b8eeb13 100644 --- a/lua/nvim-tree/lib.lua +++ b/lua/nvim-tree/lib.lua @@ -5,6 +5,7 @@ local utils = require "nvim-tree.utils" local events = require "nvim-tree.events" local notify = require "nvim-tree.notify" local explorer_node = require "nvim-tree.explorer.node" +local actions_reloaders = require "nvim-tree.actions.reloaders" ---@class LibOpenOpts ---@field path string|nil path @@ -146,6 +147,10 @@ function M.expand_or_collapse(node, toggle_group) if node.has_children then node.has_children = false end + -- TODO: Inspect(node) + + -- node.hidden_count = utils.count_hidden_files(node.absolute_path) + -- node.hidden_count = 79 if #node.nodes == 0 then core.get_explorer():expand(node) diff --git a/lua/nvim-tree/live-filter.lua b/lua/nvim-tree/live-filter.lua index 350043aae6b..aa10f9ed9f0 100644 --- a/lua/nvim-tree/live-filter.lua +++ b/lua/nvim-tree/live-filter.lua @@ -15,6 +15,10 @@ end local function reset_filter(node_) node_ = node_ or require("nvim-tree.core").get_explorer() + node_.hidden_count = vim.tbl_deep_extend("force", node_.hidden_count or {}, { + live_filter = 0, + }) + if node_ == nil then return end @@ -23,6 +27,9 @@ local function reset_filter(node_) :hidden() :applier(function(node) node.hidden = false + node.hidden_count = vim.tbl_deep_extend("force", node.hidden_count or {}, { + live_filter = 0, + }) end) :iterate() end @@ -79,6 +86,10 @@ function M.apply_filter(node_) local filtered_nodes = 0 local nodes = node.group_next and { node.group_next } or node.nodes + node.hidden_count = vim.tbl_deep_extend("force", node.hidden_count or {}, { + live_filter = 0, + }) + if nodes then for _, n in pairs(nodes) do iterate(n) @@ -88,6 +99,8 @@ function M.apply_filter(node_) end end + node.hidden_count.live_filter = filtered_nodes + local has_nodes = nodes and (M.always_show_folders or #nodes > filtered_nodes) local ok, is_match = pcall(matches, node) node.hidden = not (has_nodes or (ok and is_match)) diff --git a/lua/nvim-tree/node.lua b/lua/nvim-tree/node.lua index f1344fe9e33..296bc7e74e7 100644 --- a/lua/nvim-tree/node.lua +++ b/lua/nvim-tree/node.lua @@ -21,6 +21,7 @@ ---@field group_next Node|nil ---@field nodes Node[] ---@field open boolean +---@field hidden_count table -- Each field of this table is a key for source and value for count ---@class FileNode: BaseNode ---@field extension string diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index 00cd868678c..3d78cc0ecbd 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -43,6 +43,8 @@ local M = { ---@field lines string[] includes icons etc. ---@field hl_args AddHighlightArgs[] line highlights ---@field signs string[] line signs +---@field extmarks table[] extra marks for right icon placement +---@field virtual_lines table[] virtual lines for hidden count display ---@field private root_cwd string absolute path ---@field private index number ---@field private depth number @@ -62,6 +64,7 @@ function Builder:new() markers = {}, signs = {}, extmarks = {}, + virtual_lines = {}, } setmetatable(o, self) self.__index = self @@ -220,6 +223,11 @@ function Builder:format_line(indent_markers, arrows, icon, name, node) local line = { indent_markers, arrows } add_to_end(line, { icon }) + if node == nil then + add_to_end(line, { name }) + return line + end + for i = #M.decorators, 1, -1 do add_to_end(line, M.decorators[i]:icons_before(node)) end @@ -351,11 +359,25 @@ function Builder:build_line(node, idx, num_children) self.index = self.index + 1 node = require("nvim-tree.lib").get_last_group_node(node) - if node.open then self.depth = self.depth + 1 self:build_lines(node) self.depth = self.depth - 1 + self:add_hidden_count_string(node, idx, num_children) + end +end + +---@private +function Builder:add_hidden_count_string(node, idx, num_children) + local hidden_count_string = M.opts.renderer.hidden_display_function(node.hidden_count) + if hidden_count_string and hidden_count_string ~= "" then + local indent_markers = pad.get_indent_markers(math.max(self.depth, 0), idx or 0, num_children or 0, node, self.markers) + local indent_width = M.opts.renderer.indent_width + local indent_string = string.rep(" ", indent_width) .. (indent_markers.str or "") + table.insert( + self.virtual_lines, + { indent_string = indent_string, depth = self.depth, line_nr = #self.lines - 1, text = hidden_count_string } + ) end end @@ -381,7 +403,6 @@ function Builder:build_lines(node) end local num_children = self:get_nodes_number(node.nodes) local idx = 1 - -- table.insert(node.nodes, { name = "cock", path = "cock" }) for _, n in ipairs(node.nodes) do if not n.hidden then self:build_signs(n) @@ -439,11 +460,68 @@ end function Builder:build() self:build_header() self:build_lines() + self:build_root_hidden_count() self:sanitize_lines() return self end +--- Add the hidden_count for root, since root dir is treated differently +--- from normal directories we need to do it again for root. +--- Also need to sort my depth +---@private +function Builder:build_root_hidden_count() + local root = core.get_explorer() + self:add_hidden_count_string(root) + -- Now that we're done, we must sort by depth, to ensure proper rendering + table.sort(self.virtual_lines, function(a, b) + return a.depth < b.depth + end) +end + +---@param opts table +local setup_hidden_display_function = function(opts) + local hidden_display = opts.renderer.hidden_display_function + -- options are already validated, so ´hidden_display_function´ can ONLY be `string` or `function` if type(hidden_display) == "string" then + if type(hidden_display) == "string" then + if hidden_display == "none" then + opts.renderer.hidden_display_function = function() + return nil + end + elseif hidden_display == "simple" then + opts.renderer.hidden_display_function = function(hidden_count) + return utils.default_format_hidden_count(hidden_count, true) + end + elseif hidden_display == "all" then + opts.renderer.hidden_display_function = function(hidden_count) + return utils.default_format_hidden_count(hidden_count, false) + end + end + elseif type(hidden_display) == "function" then + local safe_render = function(hidden_count) + -- In case of missing field such as live_filter we zero it, otherwise keep field as is + hidden_count = vim.tbl_deep_extend("force", { + live_filter = 0, + git = 0, + buf = 0, + dotfile = 0, + custom = 0, + bookmark = 0, + }, hidden_count or {}) + + local ok, result = pcall(hidden_display, hidden_count) + if not ok then + notify.warn "Problem occurred in ``opts.renderer.hidden_display_function`` see " + return nil + end + return result + end + + opts.renderer.hidden_display_function = safe_render + end +end + function Builder.setup(opts) + setup_hidden_display_function(opts) M.opts = opts -- priority order diff --git a/lua/nvim-tree/renderer/init.lua b/lua/nvim-tree/renderer/init.lua index 41c8fd21477..0110d6f1ad9 100644 --- a/lua/nvim-tree/renderer/init.lua +++ b/lua/nvim-tree/renderer/init.lua @@ -19,7 +19,7 @@ local namespace_extmarks_id = vim.api.nvim_create_namespace "NvimTreeExtmarks" ---@param lines string[] ---@param hl_args AddHighlightArgs[] ---@param signs string[] -local function _draw(bufnr, lines, hl_args, signs, extmarks) +local function _draw(bufnr, lines, hl_args, signs, extmarks, virtual_lines) if vim.fn.has "nvim-0.10" == 1 then vim.api.nvim_set_option_value("modifiable", true, { buf = bufnr }) else @@ -30,9 +30,9 @@ local function _draw(bufnr, lines, hl_args, signs, extmarks) M.render_hl(bufnr, hl_args) if vim.fn.has "nvim-0.10" == 1 then - vim.api.nvim_set_option_value("modifiable", false, { buf = bufnr }) + vim.api.nvim_set_option_value("modifiable", true, { buf = bufnr }) else - vim.api.nvim_buf_set_option(bufnr, "modifiable", false) ---@diagnostic disable-line: deprecated + vim.api.nvim_buf_set_option(bufnr, "modifiable", true) ---@diagnostic disable-line: deprecated end vim.fn.sign_unplace(SIGN_GROUP) @@ -50,6 +50,14 @@ local function _draw(bufnr, lines, hl_args, signs, extmarks) }) end end + + for _, vline in ipairs(virtual_lines) do + vim.api.nvim_buf_set_extmark(bufnr, namespace_extmarks_id, vline.line_nr, 0, { + virt_lines = { { { vline.indent_string or "", "NvimTreeIndentMarker" }, { vline.text, "NvimTreeHiddenDisplay" } } }, + virt_lines_above = false, + virt_lines_leftcol = true, + }) + end end function M.render_hl(bufnr, hl) @@ -79,7 +87,8 @@ function M.draw() local builder = Builder:new():build() - _draw(bufnr, builder.lines, builder.hl_args, builder.signs, builder.extmarks) + -- _draw(bufnr, builder.lines, builder.hl_args, builder.signs, builder.extmarks) + _draw(bufnr, builder.lines, builder.hl_args, builder.signs, builder.extmarks, builder.virtual_lines) if cursor and #builder.lines >= cursor[1] then vim.api.nvim_win_set_cursor(view.get_winnr() or 0, cursor) diff --git a/lua/nvim-tree/utils.lua b/lua/nvim-tree/utils.lua index 30f34edc44a..2c0503c9b46 100644 --- a/lua/nvim-tree/utils.lua +++ b/lua/nvim-tree/utils.lua @@ -1,5 +1,7 @@ local Iterator = require "nvim-tree.iterators.node-iterator" local notify = require "nvim-tree.notify" +-- local git = require "nvim-tree.git" +-- local filters = require "nvim-tree.explorer.filters" local M = { debouncers = {}, @@ -17,6 +19,49 @@ M.is_windows = vim.fn.has "win32" == 1 or vim.fn.has "win32unix" == 1 function M.str_find(haystack, needle) return vim.fn.stridx(haystack, needle) ~= -1 end +local uv = vim.loop + +local function is_dotfile(name) + return name:sub(1, 1) == "." +end + +M.count_hidden_files = function(node) + if true then + return 2 + end + local count = 0 + + local handle = uv.fs_scandir(node.absolute_path) + if not handle then + return {} + end + + if not handle then + print "Error: Unable to scan directory." + return count + end + + local cwd = node.link_to or node.absolute_path + local git_status = git.load_project_status(cwd) + + local filter_status = filters.prepare(git_status) + while true do + local name, type = uv.fs_scandir_next(handle) + if not name then + break + end + local abs = M.path_join { cwd, name } + + local abs = node.absolute_path + ---@type uv.fs_stat.result|nil + local stat = vim.loop.fs_stat(abs) + if not filters.should_filter(abs, stat, filter_status) then + count = count + 1 + end + end + + return count +end ---@param path string ---@return string|uv.uv_fs_t @@ -181,6 +226,26 @@ function M.get_parent_of_group(node) return node end +M.default_format_hidden_count = function(hidden_count, simple) + local parts = {} + local total_count = 0 + for reason, count in pairs(hidden_count) do + total_count = total_count + count + if count > 0 then + table.insert(parts, reason .. ": " .. tostring(count)) + end + end + + local hidden_count_string = table.concat(parts, ", ") -- if empty then is "" (empty string) + if simple then + hidden_count_string = "" + end + if total_count > 0 then + return "(" .. tostring(total_count) .. (simple and " hidden" or " total ") .. hidden_count_string .. ")" + end + return nil +end + --- Return visible nodes indexed by line ---@param nodes_all Node[] ---@param line_start number @@ -534,6 +599,17 @@ function M.inject_node(f) end end +---@param tbl table +---@return table +M.reverse_table = function(tbl) + local size = #tbl + local reversed = {} + for i = size, 1, -1 do + table.insert(reversed, tbl[i]) + end + return reversed +end + --- Is the buffer named NvimTree_[0-9]+ a tree? filetype is "NvimTree" or not readable file. --- This is cheap, as the readable test should only ever be needed when resuming a vim session. ---@param bufnr number|nil may be 0 or nil for current From 6bbc2ecb82498cdfb9beee6901b23d42bfc21943 Mon Sep 17 00:00:00 2001 From: evertonse Date: Sun, 28 Jul 2024 02:34:06 -0300 Subject: [PATCH 07/15] feat(hidden_display): Rename opts function name for the feature --- doc/nvim-tree-lua.txt | 4 +-- lua/nvim-tree.lua | 6 ++--- lua/nvim-tree/enum.lua | 11 ++++++++ lua/nvim-tree/explorer/explore.lua | 14 +++++----- lua/nvim-tree/explorer/filters.lua | 41 ++++++++++++++++++++++-------- lua/nvim-tree/explorer/reload.lua | 7 +++-- lua/nvim-tree/renderer/builder.lua | 27 +++++++++++--------- 7 files changed, 70 insertions(+), 40 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 6455eea8c38..eb9984f05b3 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -423,7 +423,7 @@ Following is the default configuration. See |nvim-tree-opts| for details. root_folder_label = ":~:s?$?/..?", indent_width = 2, special_files = { "Cargo.toml", "Makefile", "README.md", "readme.md" }, - hidden_display_function = nil, + hidden_display = "none", symlink_destination = true, highlight_git = "none", highlight_diagnostics = "none", @@ -879,7 +879,7 @@ Number of spaces for an each tree nesting level. Minimum 1. A list of filenames that gets highlighted with `NvimTreeSpecialFile`. Type: `table`, Default: `{ "Cargo.toml", "Makefile", "README.md", "readme.md", }` -*nvim-tree.renderer.hidden_display_function +*nvim-tree.renderer.hidden_display Determines the rendering of hidden files in a folder. Type: function | string, Default: "none" Possible string values are: diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 259e5e16e5c..f543ae8ae1e 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -398,7 +398,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS root_folder_label = ":~:s?$?/..?", indent_width = 2, special_files = { "Cargo.toml", "Makefile", "README.md", "readme.md" }, - hidden_display_function = "none", + hidden_display = "none", symlink_destination = true, highlight_git = "none", highlight_diagnostics = "none", @@ -648,7 +648,7 @@ local ACCEPTED_TYPES = { }, }, renderer = { - hidden_display_function = { "function", "string" }, + hidden_display = { "function", "string" }, group_empty = { "boolean", "function" }, root_folder_label = { "function", "string", "boolean" }, }, @@ -682,7 +682,7 @@ local ACCEPTED_STRINGS = { signcolumn = { "yes", "no", "auto" }, }, renderer = { - hidden_display_function = { "none", "simple", "all" }, + hidden_display = { "none", "simple", "all" }, highlight_git = { "none", "icon", "name", "all" }, highlight_opened_files = { "none", "icon", "name", "all" }, highlight_modified = { "none", "icon", "name", "all" }, diff --git a/lua/nvim-tree/enum.lua b/lua/nvim-tree/enum.lua index 054c463f46c..9c50bc27638 100644 --- a/lua/nvim-tree/enum.lua +++ b/lua/nvim-tree/enum.lua @@ -19,4 +19,15 @@ M.ICON_PLACEMENT = { right_align = 4, } +---Reason for filter in filter.lua +---@enum FILTER_REASON +M.FILTER_REASON = { + none = 0, -- It's not filtered + git = 1, + buf = 2, + dotfile = 4, + custom = 8, + bookmark = 16, +} + return M diff --git a/lua/nvim-tree/explorer/explore.lua b/lua/nvim-tree/explorer/explore.lua index aa6c88bba5a..66b49434029 100644 --- a/lua/nvim-tree/explorer/explore.lua +++ b/lua/nvim-tree/explorer/explore.lua @@ -6,7 +6,7 @@ local live_filter = require "nvim-tree.live-filter" local log = require "nvim-tree.log" -- local explorer_module = require "nvim-tree.explorer" -local FILTER_REASON = filters.FILTER_REASON +local FILTER_REASON = require("nvim-tree.enum").FILTER_REASON local Watcher = require "nvim-tree.watcher" local M = {} @@ -16,11 +16,11 @@ local M = {} ---@param node Node ---@param git_status table ---@return integer filtered_count -local function populate_children(handle, cwd, node, git_status) +local function populate_children(handle, cwd, node, git_status, parent) local node_ignored = explorer_node.is_git_ignored(node) local nodes_by_path = utils.bool_record(node.nodes, "absolute_path") - local filter_status = filters.prepare(git_status) + local filter_status = parent.filters:prepare(git_status) node.hidden_count = vim.tbl_deep_extend("force", node.hidden_count or {}, { git = 0, @@ -42,7 +42,7 @@ local function populate_children(handle, cwd, node, git_status) ---@type uv.fs_stat.result|nil local stat = vim.loop.fs_stat(abs) - local filter_reason = filters.should_filter_as_reason(abs, stat, filter_status) + local filter_reason = parent.filters:should_filter_as_reason(abs, stat, filter_status) if filter_reason == FILTER_REASON.none and not nodes_by_path[abs] and Watcher.is_fs_event_capable(abs) then local child = nil if is_dir and vim.loop.fs_access(abs, "R") then @@ -101,13 +101,11 @@ function M.explore(node, status, parent) log.profile_end(profile) return ns end - local old_num = #node.nodes - sorters.sort(node.nodes) + + parent.sorters:sort(node.nodes) live_filter.apply_filter(node) log.profile_end(profile) - local new_num = #node.nodes - assert(old_num == new_num, vim.inspect { old_num = old_num, new_num = new_num }) return node.nodes end diff --git a/lua/nvim-tree/explorer/filters.lua b/lua/nvim-tree/explorer/filters.lua index 58a61a74a2d..1d45aafb9b2 100644 --- a/lua/nvim-tree/explorer/filters.lua +++ b/lua/nvim-tree/explorer/filters.lua @@ -1,4 +1,5 @@ local utils = require "nvim-tree.utils" +local FILTER_REASON = require("nvim-tree.enum").FILTER_REASON ---@class Filters to handle all opts.filters and related API ---@field config table hydrated user opts.filters @@ -43,16 +44,6 @@ function Filters:new(opts, explorer) return o end ----@enum FILTER_REASON -M.FILTER_REASON = { - none = 0, -- It's not filtered - git = 1, - buf = 2, - dotfile = 4, - custom = 8, - bookmark = 16, -} - ---@param path string ---@return boolean local function is_excluded(self, path) @@ -221,7 +212,6 @@ function Filters:should_filter(path, fs_stat, status) return false end - -- exclusions override all filters if is_excluded(self, path) then return false end @@ -233,4 +223,33 @@ function Filters:should_filter(path, fs_stat, status) or bookmark(self, path, fs_stat and fs_stat.type, status.bookmarks) end +--- Check if the given path should be filtered, and provide the reason why it was +---@param path string Absolute path +---@param fs_stat uv.fs_stat.result|nil fs_stat of file +---@param status table from prepare +---@return FILTER_REASON +function Filters:should_filter_as_reason(path, fs_stat, status) + if not self.config.enable then + return FILTER_REASON.none + end + + if is_excluded(self, path) then + return FILTER_REASON.none + end + + if git(self, path, status.git_status) then + return FILTER_REASON.git + elseif buf(self, path, status.bufinfo) then + return FILTER_REASON.buf + elseif dotfile(self, path) then + return FILTER_REASON.dotfile + elseif custom(self, path) then + return FILTER_REASON.custom + elseif bookmark(self, path, fs_stat and fs_stat.type, status.bookmarks) then + return FILTER_REASON.bookmark + else + return FILTER_REASON.none + end +end + return Filters diff --git a/lua/nvim-tree/explorer/reload.lua b/lua/nvim-tree/explorer/reload.lua index 58d4b2ab951..f2eba1ba667 100644 --- a/lua/nvim-tree/explorer/reload.lua +++ b/lua/nvim-tree/explorer/reload.lua @@ -5,7 +5,7 @@ local live_filter = require "nvim-tree.live-filter" local git = require "nvim-tree.git" local log = require "nvim-tree.log" -local FILTER_REASON = filters.FILTER_REASON +local FILTER_REASON = require("nvim-tree.enum").FILTER_REASON local NodeIterator = require "nvim-tree.iterators.node-iterator" local Watcher = require "nvim-tree.watcher" @@ -81,8 +81,7 @@ function M.reload(node, git_status) local profile = log.profile_start("reload %s", node.absolute_path) - local filter_status = filters.prepare(git_status) - local is_dir = node.type == "directory" + local filter_status = explorer.filters:prepare(git_status) if node.group_next then node.nodes = { node.group_next } @@ -114,7 +113,7 @@ function M.reload(node, git_status) ---@type uv.fs_stat.result|nil local stat = vim.loop.fs_stat(abs) - local filter_reason = filters.should_filter_as_reason(abs, stat, filter_status) + local filter_reason = explorer.filters:should_filter_as_reason(abs, stat, filter_status) if filter_reason == FILTER_REASON.none then remain_childs[abs] = true diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index 3d78cc0ecbd..4c73dda0668 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -369,15 +369,18 @@ end ---@private function Builder:add_hidden_count_string(node, idx, num_children) - local hidden_count_string = M.opts.renderer.hidden_display_function(node.hidden_count) + local hidden_count_string = M.opts.renderer.hidden_display(node.hidden_count) if hidden_count_string and hidden_count_string ~= "" then local indent_markers = pad.get_indent_markers(math.max(self.depth, 0), idx or 0, num_children or 0, node, self.markers) local indent_width = M.opts.renderer.indent_width local indent_string = string.rep(" ", indent_width) .. (indent_markers.str or "") - table.insert( - self.virtual_lines, - { indent_string = indent_string, depth = self.depth, line_nr = #self.lines - 1, text = hidden_count_string } - ) + table.insert(self.virtual_lines, { + indent_string = indent_string, + depth = self.depth, + line_nr = #self.lines - 1, + -- Remove padding if we're in root + text = (node.parent == nil and "" or string.rep(" ", indent_width)) .. hidden_count_string, + }) end end @@ -480,19 +483,19 @@ end ---@param opts table local setup_hidden_display_function = function(opts) - local hidden_display = opts.renderer.hidden_display_function - -- options are already validated, so ´hidden_display_function´ can ONLY be `string` or `function` if type(hidden_display) == "string" then + local hidden_display = opts.renderer.hidden_display + -- options are already validated, so ´hidden_display´ can ONLY be `string` or `function` if type(hidden_display) == "string" then if type(hidden_display) == "string" then if hidden_display == "none" then - opts.renderer.hidden_display_function = function() + opts.renderer.hidden_display = function() return nil end elseif hidden_display == "simple" then - opts.renderer.hidden_display_function = function(hidden_count) + opts.renderer.hidden_display = function(hidden_count) return utils.default_format_hidden_count(hidden_count, true) end elseif hidden_display == "all" then - opts.renderer.hidden_display_function = function(hidden_count) + opts.renderer.hidden_display = function(hidden_count) return utils.default_format_hidden_count(hidden_count, false) end end @@ -510,13 +513,13 @@ local setup_hidden_display_function = function(opts) local ok, result = pcall(hidden_display, hidden_count) if not ok then - notify.warn "Problem occurred in ``opts.renderer.hidden_display_function`` see " + notify.warn "Problem occurred in ``opts.renderer.hidden_display_function`` see nvim-tree.renderer.hidden_display on :h nvim-tree" return nil end return result end - opts.renderer.hidden_display_function = safe_render + opts.renderer.hidden_display = safe_render end end From 702184867aad93db55d4888bb2b52140c703f122 Mon Sep 17 00:00:00 2001 From: "Everton Jr." <69195288+evertonse@users.noreply.github.com> Date: Sun, 28 Jul 2024 00:26:22 -0300 Subject: [PATCH 08/15] feat(#2349): add "right_align" option for renderer.icons.*_placement (#2846) * feat(icon_placement): Allow right_align icon_placemente for decorator using ext_marks nvim api * feat(icon_placement): Allow right_align icon_placemente for decorator using ext_marks nvim api feat(icon_placement): Allow right_align icon_placemente for decorator using ext_marks nvim api * feat(icon_placement): consolidate doc * fix: extra namespace added to avoid colision between right_align and full_name features * style: rename namespace_id --------- Co-authored-by: Alexander Courtis --- doc/nvim-tree-lua.txt | 6 ---- lua/nvim-tree/explorer/explore.lua | 5 ++- lua/nvim-tree/lib.lua | 5 --- lua/nvim-tree/renderer/builder.lua | 7 +--- lua/nvim-tree/renderer/init.lua | 11 +++--- lua/nvim-tree/utils.lua | 56 ------------------------------ 6 files changed, 8 insertions(+), 82 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index eb9984f05b3..c76699c8889 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -1045,12 +1045,6 @@ Icon order and sign column precedence: Hidden icon placement. Type: `string`, Default: `"after"` - *nvim-tree.renderer.icons.hidden_placement* - Place where the hidden (dotfile) icon will be rendered. - Can be `"after"` or `"before"` filename (after the file/folders icons) - or `"signcolumn"` (requires |nvim-tree.view.signcolumn| enabled). - Type: `string`, Default: `"after"` - *nvim-tree.renderer.icons.bookmarks_placement* Bookmark icon placement. Type: `string`, Default: `signcolumn` diff --git a/lua/nvim-tree/explorer/explore.lua b/lua/nvim-tree/explorer/explore.lua index 66b49434029..90d37ad8d1b 100644 --- a/lua/nvim-tree/explorer/explore.lua +++ b/lua/nvim-tree/explorer/explore.lua @@ -15,7 +15,7 @@ local M = {} ---@param cwd string ---@param node Node ---@param git_status table ----@return integer filtered_count +---@param parent Explorer local function populate_children(handle, cwd, node, git_status, parent) local node_ignored = explorer_node.is_git_ignored(node) local nodes_by_path = utils.bool_record(node.nodes, "absolute_path") @@ -35,7 +35,6 @@ local function populate_children(handle, cwd, node, git_status, parent) if not name then break end - local is_dir = t == "directory" local abs = utils.path_join { cwd, name } local profile = log.profile_start("explore populate_children %s", abs) @@ -45,7 +44,7 @@ local function populate_children(handle, cwd, node, git_status, parent) local filter_reason = parent.filters:should_filter_as_reason(abs, stat, filter_status) if filter_reason == FILTER_REASON.none and not nodes_by_path[abs] and Watcher.is_fs_event_capable(abs) then local child = nil - if is_dir and vim.loop.fs_access(abs, "R") then + if t == "directory" and vim.loop.fs_access(abs, "R") then child = builders.folder(node, abs, name, stat) elseif t == "file" then child = builders.file(node, abs, name, stat) diff --git a/lua/nvim-tree/lib.lua b/lua/nvim-tree/lib.lua index c2f9b8eeb13..8bdf9a97bbc 100644 --- a/lua/nvim-tree/lib.lua +++ b/lua/nvim-tree/lib.lua @@ -5,7 +5,6 @@ local utils = require "nvim-tree.utils" local events = require "nvim-tree.events" local notify = require "nvim-tree.notify" local explorer_node = require "nvim-tree.explorer.node" -local actions_reloaders = require "nvim-tree.actions.reloaders" ---@class LibOpenOpts ---@field path string|nil path @@ -147,10 +146,6 @@ function M.expand_or_collapse(node, toggle_group) if node.has_children then node.has_children = false end - -- TODO: Inspect(node) - - -- node.hidden_count = utils.count_hidden_files(node.absolute_path) - -- node.hidden_count = 79 if #node.nodes == 0 then core.get_explorer():expand(node) diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index 4c73dda0668..811d23d7146 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -223,11 +223,6 @@ function Builder:format_line(indent_markers, arrows, icon, name, node) local line = { indent_markers, arrows } add_to_end(line, { icon }) - if node == nil then - add_to_end(line, { name }) - return line - end - for i = #M.decorators, 1, -1 do add_to_end(line, M.decorators[i]:icons_before(node)) end @@ -470,7 +465,7 @@ end --- Add the hidden_count for root, since root dir is treated differently --- from normal directories we need to do it again for root. ---- Also need to sort my depth +--- Also need to sort by depth ---@private function Builder:build_root_hidden_count() local root = core.get_explorer() diff --git a/lua/nvim-tree/renderer/init.lua b/lua/nvim-tree/renderer/init.lua index 0110d6f1ad9..25df79e9097 100644 --- a/lua/nvim-tree/renderer/init.lua +++ b/lua/nvim-tree/renderer/init.lua @@ -12,7 +12,7 @@ local M = {} local SIGN_GROUP = "NvimTreeRendererSigns" -local namespace_id = vim.api.nvim_create_namespace "NvimTreeHighlights" +local namespace_highlights_id = vim.api.nvim_create_namespace "NvimTreeHighlights" local namespace_extmarks_id = vim.api.nvim_create_namespace "NvimTreeExtmarks" ---@param bufnr number @@ -30,9 +30,9 @@ local function _draw(bufnr, lines, hl_args, signs, extmarks, virtual_lines) M.render_hl(bufnr, hl_args) if vim.fn.has "nvim-0.10" == 1 then - vim.api.nvim_set_option_value("modifiable", true, { buf = bufnr }) + vim.api.nvim_set_option_value("modifiable", false, { buf = bufnr }) else - vim.api.nvim_buf_set_option(bufnr, "modifiable", true) ---@diagnostic disable-line: deprecated + vim.api.nvim_buf_set_option(bufnr, "modifiable", false) ---@diagnostic disable-line: deprecated end vim.fn.sign_unplace(SIGN_GROUP) @@ -64,11 +64,11 @@ function M.render_hl(bufnr, hl) if not bufnr or not vim.api.nvim_buf_is_loaded(bufnr) then return end - vim.api.nvim_buf_clear_namespace(bufnr, namespace_id, 0, -1) + vim.api.nvim_buf_clear_namespace(bufnr, namespace_highlights_id, 0, -1) for _, data in ipairs(hl) do if type(data[1]) == "table" then for _, group in ipairs(data[1]) do - vim.api.nvim_buf_add_highlight(bufnr, namespace_id, group, data[2], data[3], data[4]) + vim.api.nvim_buf_add_highlight(bufnr, namespace_highlights_id, group, data[2], data[3], data[4]) end end end @@ -87,7 +87,6 @@ function M.draw() local builder = Builder:new():build() - -- _draw(bufnr, builder.lines, builder.hl_args, builder.signs, builder.extmarks) _draw(bufnr, builder.lines, builder.hl_args, builder.signs, builder.extmarks, builder.virtual_lines) if cursor and #builder.lines >= cursor[1] then diff --git a/lua/nvim-tree/utils.lua b/lua/nvim-tree/utils.lua index 2c0503c9b46..c9711c4bff2 100644 --- a/lua/nvim-tree/utils.lua +++ b/lua/nvim-tree/utils.lua @@ -1,7 +1,5 @@ local Iterator = require "nvim-tree.iterators.node-iterator" local notify = require "nvim-tree.notify" --- local git = require "nvim-tree.git" --- local filters = require "nvim-tree.explorer.filters" local M = { debouncers = {}, @@ -19,49 +17,6 @@ M.is_windows = vim.fn.has "win32" == 1 or vim.fn.has "win32unix" == 1 function M.str_find(haystack, needle) return vim.fn.stridx(haystack, needle) ~= -1 end -local uv = vim.loop - -local function is_dotfile(name) - return name:sub(1, 1) == "." -end - -M.count_hidden_files = function(node) - if true then - return 2 - end - local count = 0 - - local handle = uv.fs_scandir(node.absolute_path) - if not handle then - return {} - end - - if not handle then - print "Error: Unable to scan directory." - return count - end - - local cwd = node.link_to or node.absolute_path - local git_status = git.load_project_status(cwd) - - local filter_status = filters.prepare(git_status) - while true do - local name, type = uv.fs_scandir_next(handle) - if not name then - break - end - local abs = M.path_join { cwd, name } - - local abs = node.absolute_path - ---@type uv.fs_stat.result|nil - local stat = vim.loop.fs_stat(abs) - if not filters.should_filter(abs, stat, filter_status) then - count = count + 1 - end - end - - return count -end ---@param path string ---@return string|uv.uv_fs_t @@ -599,17 +554,6 @@ function M.inject_node(f) end end ----@param tbl table ----@return table -M.reverse_table = function(tbl) - local size = #tbl - local reversed = {} - for i = size, 1, -1 do - table.insert(reversed, tbl[i]) - end - return reversed -end - --- Is the buffer named NvimTree_[0-9]+ a tree? filetype is "NvimTree" or not readable file. --- This is cheap, as the readable test should only ever be needed when resuming a vim session. ---@param bufnr number|nil may be 0 or nil for current From 8ef7e48a870b4d93df45b0c6f099a5c9380ddf26 Mon Sep 17 00:00:00 2001 From: evertonse Date: Sun, 28 Jul 2024 04:00:49 -0300 Subject: [PATCH 09/15] docs: update docs --- doc/nvim-tree-lua.txt | 1 - lua/nvim-tree/explorer/explore.lua | 3 --- lua/nvim-tree/explorer/filters.lua | 1 + lua/nvim-tree/live-filter.lua | 8 ++++---- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index c76699c8889..8d6e217d8ac 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -2932,7 +2932,6 @@ highlight group is not, hard linking as follows: > |nvim-tree.renderer.icons.glyphs.modified| |nvim-tree.renderer.icons.glyphs.symlink| |nvim-tree.renderer.icons.hidden_placement| -|nvim-tree.renderer.icons.hidden_placement| |nvim-tree.renderer.icons.modified_placement| |nvim-tree.renderer.icons.padding| |nvim-tree.renderer.icons.show| diff --git a/lua/nvim-tree/explorer/explore.lua b/lua/nvim-tree/explorer/explore.lua index 90d37ad8d1b..06985dbb957 100644 --- a/lua/nvim-tree/explorer/explore.lua +++ b/lua/nvim-tree/explorer/explore.lua @@ -4,7 +4,6 @@ local explorer_node = require "nvim-tree.explorer.node" local git = require "nvim-tree.git" local live_filter = require "nvim-tree.live-filter" local log = require "nvim-tree.log" --- local explorer_module = require "nvim-tree.explorer" local FILTER_REASON = require("nvim-tree.enum").FILTER_REASON local Watcher = require "nvim-tree.watcher" @@ -69,8 +68,6 @@ local function populate_children(handle, cwd, node, git_status, parent) log.profile_end(profile) end - - -- explorer_module.reload(node) end ---@param node Node diff --git a/lua/nvim-tree/explorer/filters.lua b/lua/nvim-tree/explorer/filters.lua index 1d45aafb9b2..6f2cd6df0d0 100644 --- a/lua/nvim-tree/explorer/filters.lua +++ b/lua/nvim-tree/explorer/filters.lua @@ -212,6 +212,7 @@ function Filters:should_filter(path, fs_stat, status) return false end + -- exclusions override all filters if is_excluded(self, path) then return false end diff --git a/lua/nvim-tree/live-filter.lua b/lua/nvim-tree/live-filter.lua index 6b2efb83f16..2ed4af5c7fe 100644 --- a/lua/nvim-tree/live-filter.lua +++ b/lua/nvim-tree/live-filter.lua @@ -14,14 +14,14 @@ end local function reset_filter(node_) node_ = node_ or require("nvim-tree.core").get_explorer() - node_.hidden_count = vim.tbl_deep_extend("force", node_.hidden_count or {}, { - live_filter = 0, - }) - if node_ == nil then return end + node_.hidden_count = vim.tbl_deep_extend("force", node_.hidden_count or {}, { + live_filter = 0, + }) + Iterator.builder(node_.nodes) :hidden() :applier(function(node) From 36954ff10bfb62591006918f93885d13cb340173 Mon Sep 17 00:00:00 2001 From: evertonse Date: Sun, 28 Jul 2024 17:24:22 -0300 Subject: [PATCH 10/15] feat(hidden_display): Simplification and better performance by not sorting and grouping virtual lines --- lua/nvim-tree/renderer/builder.lua | 41 ++++++++----------- lua/nvim-tree/renderer/components/padding.lua | 8 ++-- lua/nvim-tree/renderer/init.lua | 6 +-- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index 811d23d7146..fa30de7f765 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -358,23 +358,31 @@ function Builder:build_line(node, idx, num_children) self.depth = self.depth + 1 self:build_lines(node) self.depth = self.depth - 1 - self:add_hidden_count_string(node, idx, num_children) end end +---Add virtual lines for rendering hidden count information per node ---@private function Builder:add_hidden_count_string(node, idx, num_children) + if not node.open then + return + end local hidden_count_string = M.opts.renderer.hidden_display(node.hidden_count) if hidden_count_string and hidden_count_string ~= "" then - local indent_markers = pad.get_indent_markers(math.max(self.depth, 0), idx or 0, num_children or 0, node, self.markers) + local indent_markers = pad.get_indent_markers(self.depth, idx or 0, num_children or 0, node, self.markers, 1) local indent_width = M.opts.renderer.indent_width - local indent_string = string.rep(" ", indent_width) .. (indent_markers.str or "") - table.insert(self.virtual_lines, { - indent_string = indent_string, - depth = self.depth, - line_nr = #self.lines - 1, - -- Remove padding if we're in root - text = (node.parent == nil and "" or string.rep(" ", indent_width)) .. hidden_count_string, + + local indent_padding = string.rep(" ", indent_width) + local indent_string = indent_padding .. indent_markers.str + local line_nr = #self.lines - 1 + self.virtual_lines[line_nr] = self.virtual_lines[line_nr] or {} + + -- NOTE: We are inserting in depth order because of current traversal + -- if we change the traversal, we might need to sort by depth before rendering `self.virtual_lines` + -- to maintain proper ordering of parent and child folder hidden count info. + table.insert(self.virtual_lines[line_nr], { + { indent_string, indent_markers.hl }, + { string.rep(indent_padding, (node.parent == nil and 0 or 1)) .. hidden_count_string, "NvimTreeHiddenDisplay" }, }) end end @@ -408,6 +416,7 @@ function Builder:build_lines(node) idx = idx + 1 end end + self:add_hidden_count_string(node) end ---@private @@ -458,24 +467,10 @@ end function Builder:build() self:build_header() self:build_lines() - self:build_root_hidden_count() self:sanitize_lines() return self end ---- Add the hidden_count for root, since root dir is treated differently ---- from normal directories we need to do it again for root. ---- Also need to sort by depth ----@private -function Builder:build_root_hidden_count() - local root = core.get_explorer() - self:add_hidden_count_string(root) - -- Now that we're done, we must sort by depth, to ensure proper rendering - table.sort(self.virtual_lines, function(a, b) - return a.depth < b.depth - end) -end - ---@param opts table local setup_hidden_display_function = function(opts) local hidden_display = opts.renderer.hidden_display diff --git a/lua/nvim-tree/renderer/components/padding.lua b/lua/nvim-tree/renderer/components/padding.lua index d61a0b508de..fd51813bc42 100644 --- a/lua/nvim-tree/renderer/components/padding.lua +++ b/lua/nvim-tree/renderer/components/padding.lua @@ -19,7 +19,7 @@ local function check_siblings_for_folder(node, with_arrows) return false end -local function get_padding_indent_markers(depth, idx, nodes_number, markers, with_arrows, inline_arrows, node) +local function get_padding_indent_markers(depth, idx, nodes_number, markers, with_arrows, inline_arrows, node, early_stop) local base_padding = with_arrows and (not node.nodes or depth > 0) and " " or "" local padding = (inline_arrows or depth == 0) and base_padding or "" @@ -27,7 +27,7 @@ local function get_padding_indent_markers(depth, idx, nodes_number, markers, wit local has_folder_sibling = check_siblings_for_folder(node, with_arrows) local indent = string.rep(" ", M.config.indent_width - 1) markers[depth] = idx ~= nodes_number - for i = 1, depth do + for i = 1, depth - early_stop do local glyph if idx == nodes_number and i == depth then local bottom_width = M.config.indent_width - 2 + (with_arrows and not inline_arrows and has_folder_sibling and 2 or 0) @@ -62,7 +62,7 @@ end ---@param node table ---@param markers table ---@return HighlightedString[] -function M.get_indent_markers(depth, idx, nodes_number, node, markers) +function M.get_indent_markers(depth, idx, nodes_number, node, markers, early_stop) local str = "" local show_arrows = M.config.icons.show.folder_arrow @@ -71,7 +71,7 @@ function M.get_indent_markers(depth, idx, nodes_number, node, markers) local indent_width = M.config.indent_width if show_markers then - str = str .. get_padding_indent_markers(depth, idx, nodes_number, markers, show_arrows, inline_arrows, node) + str = str .. get_padding_indent_markers(depth, idx, nodes_number, markers, show_arrows, inline_arrows, node, early_stop or 0) else str = str .. string.rep(" ", depth * indent_width) end diff --git a/lua/nvim-tree/renderer/init.lua b/lua/nvim-tree/renderer/init.lua index 25df79e9097..4cabf6c0e53 100644 --- a/lua/nvim-tree/renderer/init.lua +++ b/lua/nvim-tree/renderer/init.lua @@ -51,9 +51,9 @@ local function _draw(bufnr, lines, hl_args, signs, extmarks, virtual_lines) end end - for _, vline in ipairs(virtual_lines) do - vim.api.nvim_buf_set_extmark(bufnr, namespace_extmarks_id, vline.line_nr, 0, { - virt_lines = { { { vline.indent_string or "", "NvimTreeIndentMarker" }, { vline.text, "NvimTreeHiddenDisplay" } } }, + for line_nr, vlines in pairs(virtual_lines) do + vim.api.nvim_buf_set_extmark(bufnr, namespace_extmarks_id, line_nr, 0, { + virt_lines = vlines, virt_lines_above = false, virt_lines_leftcol = true, }) From 8ef8f068ddd49d0a40d2206fc67abeb0cfc90d15 Mon Sep 17 00:00:00 2001 From: "Everton Jr." <69195288+evertonse@users.noreply.github.com> Date: Sun, 4 Aug 2024 21:07:47 -0300 Subject: [PATCH 11/15] Update doc/nvim-tree-lua.txt Co-authored-by: Alexander Courtis --- doc/nvim-tree-lua.txt | 79 ++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 8d6e217d8ac..38e4c46a52e 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -879,45 +879,48 @@ Number of spaces for an each tree nesting level. Minimum 1. A list of filenames that gets highlighted with `NvimTreeSpecialFile`. Type: `table`, Default: `{ "Cargo.toml", "Makefile", "README.md", "readme.md", }` -*nvim-tree.renderer.hidden_display +*nvim-tree.renderer.hidden_display* Determines the rendering of hidden files in a folder. - Type: function | string, Default: "none" -Possible string values are: - - "none": Doesn't inform anything about hidden files. - - "simple": Shows how many hidden files are in a folder. - - "all": Shows how many files are hidden and the number of hidden files per reason why they're hidden. - -Example "all": -If a folder has 14 hidden items for various reasons, the display might show: -``(14 total git: 5, dotfile: 9)``. - -If a function is provided, it receives a table `hidden_count` where keys are reasons and values are the count of hidden files for that reason. -The `hidden_count` argument is structured as follows, where is the number -of hidden files related to the field. - -hidden_count = { - bookmark = , - buf = , - custom = , - dotfile = , - git = , - live_filter = , -} - -Example of function that can be passed: - -function(hidden_count) - local total_count = 0 - for reason, count in pairs(hidden_count) do - total_count = total_count + count - end - - if total_count > 0 then - return "(" .. tostring(total_count) .. " hidden")" - end - return nil -end - + Type: `function | string`, Default: `"none"` + + Possible string values are: + - `"none"`: Doesn't inform anything about hidden files. + - `"simple"`: Shows how many hidden files are in a folder. + - `"all"`: Shows how many files are hidden and the number of hidden + files per reason why they're hidden. + + Example `"all"`: + If a folder has 14 hidden items for various reasons, the display might + show: > + (14 total git: 5, dotfile: 9) +< + If a function is provided, it receives a table `hidden_count` where keys are + reasons and values are the count of hidden files for that reason. + + The `hidden_count` argument is structured as follows, where is the + number of hidden files related to the field: > + hidden_count = { + bookmark = , + buf = , + custom = , + dotfile = , + git = , + live_filter = , + } +< + Example of function that can be passed: > + function(hidden_count) + local total_count = 0 + for reason, count in pairs(hidden_count) do + total_count = total_count + count + end + + if total_count > 0 then + return "(" .. tostring(total_count) .. " hidden")" + end + return nil + end +< *nvim-tree.renderer.symlink_destination* Whether to show the destination of the symlink. From 6dbbf9daffd91b546da8146ffddc3ce8ef0c1693 Mon Sep 17 00:00:00 2001 From: evertonse Date: Mon, 5 Aug 2024 01:09:32 -0300 Subject: [PATCH 12/15] style: hidden_stats is better --- lua/nvim-tree/explorer/explore.lua | 4 ++-- lua/nvim-tree/explorer/reload.lua | 4 ++-- lua/nvim-tree/live-filter.lua | 8 ++++---- lua/nvim-tree/node.lua | 2 +- lua/nvim-tree/renderer/builder.lua | 20 ++++++++++---------- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lua/nvim-tree/explorer/explore.lua b/lua/nvim-tree/explorer/explore.lua index 06985dbb957..4de172536e5 100644 --- a/lua/nvim-tree/explorer/explore.lua +++ b/lua/nvim-tree/explorer/explore.lua @@ -21,7 +21,7 @@ local function populate_children(handle, cwd, node, git_status, parent) local filter_status = parent.filters:prepare(git_status) - node.hidden_count = vim.tbl_deep_extend("force", node.hidden_count or {}, { + node.hidden_stats = vim.tbl_deep_extend("force", node.hidden_stats or {}, { git = 0, buf = 0, dotfile = 0, @@ -61,7 +61,7 @@ local function populate_children(handle, cwd, node, git_status, parent) else for reason, value in pairs(FILTER_REASON) do if filter_reason == value then - node.hidden_count[reason] = node.hidden_count[reason] + 1 + node.hidden_stats[reason] = node.hidden_stats[reason] + 1 end end end diff --git a/lua/nvim-tree/explorer/reload.lua b/lua/nvim-tree/explorer/reload.lua index f2eba1ba667..d76c3234abc 100644 --- a/lua/nvim-tree/explorer/reload.lua +++ b/lua/nvim-tree/explorer/reload.lua @@ -95,7 +95,7 @@ function M.reload(node, git_status) local nodes_by_path = utils.key_by(node.nodes, "absolute_path") -- To reset we must 'zero' everything that we use - node.hidden_count = vim.tbl_deep_extend("force", node.hidden_count or {}, { + node.hidden_stats = vim.tbl_deep_extend("force", node.hidden_stats or {}, { git = 0, buf = 0, dotfile = 0, @@ -154,7 +154,7 @@ function M.reload(node, git_status) else for reason, value in pairs(FILTER_REASON) do if filter_reason == value then - node.hidden_count[reason] = node.hidden_count[reason] + 1 + node.hidden_stats[reason] = node.hidden_stats[reason] + 1 end end end diff --git a/lua/nvim-tree/live-filter.lua b/lua/nvim-tree/live-filter.lua index 2ed4af5c7fe..5e4fef8ab3c 100644 --- a/lua/nvim-tree/live-filter.lua +++ b/lua/nvim-tree/live-filter.lua @@ -18,7 +18,7 @@ local function reset_filter(node_) return end - node_.hidden_count = vim.tbl_deep_extend("force", node_.hidden_count or {}, { + node_.hidden_stats = vim.tbl_deep_extend("force", node_.hidden_stats or {}, { live_filter = 0, }) @@ -26,7 +26,7 @@ local function reset_filter(node_) :hidden() :applier(function(node) node.hidden = false - node.hidden_count = vim.tbl_deep_extend("force", node.hidden_count or {}, { + node.hidden_stats = vim.tbl_deep_extend("force", node.hidden_stats or {}, { live_filter = 0, }) end) @@ -86,7 +86,7 @@ function M.apply_filter(node_) local filtered_nodes = 0 local nodes = node.group_next and { node.group_next } or node.nodes - node.hidden_count = vim.tbl_deep_extend("force", node.hidden_count or {}, { + node.hidden_stats = vim.tbl_deep_extend("force", node.hidden_stats or {}, { live_filter = 0, }) @@ -99,7 +99,7 @@ function M.apply_filter(node_) end end - node.hidden_count.live_filter = filtered_nodes + node.hidden_stats.live_filter = filtered_nodes local has_nodes = nodes and (M.always_show_folders or #nodes > filtered_nodes) local ok, is_match = pcall(matches, node) diff --git a/lua/nvim-tree/node.lua b/lua/nvim-tree/node.lua index 296bc7e74e7..cf8aa671c39 100644 --- a/lua/nvim-tree/node.lua +++ b/lua/nvim-tree/node.lua @@ -21,7 +21,7 @@ ---@field group_next Node|nil ---@field nodes Node[] ---@field open boolean ----@field hidden_count table -- Each field of this table is a key for source and value for count +---@field hidden_stats table -- Each field of this table is a key for source and value for count ---@class FileNode: BaseNode ---@field extension string diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index fa30de7f765..749af930447 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -367,7 +367,7 @@ function Builder:add_hidden_count_string(node, idx, num_children) if not node.open then return end - local hidden_count_string = M.opts.renderer.hidden_display(node.hidden_count) + local hidden_count_string = M.opts.renderer.hidden_display(node.hidden_stats) if hidden_count_string and hidden_count_string ~= "" then local indent_markers = pad.get_indent_markers(self.depth, idx or 0, num_children or 0, node, self.markers, 1) local indent_width = M.opts.renderer.indent_width @@ -481,29 +481,29 @@ local setup_hidden_display_function = function(opts) return nil end elseif hidden_display == "simple" then - opts.renderer.hidden_display = function(hidden_count) - return utils.default_format_hidden_count(hidden_count, true) + opts.renderer.hidden_display = function(hidden_stats) + return utils.default_format_hidden_count(hidden_stats, true) end elseif hidden_display == "all" then - opts.renderer.hidden_display = function(hidden_count) - return utils.default_format_hidden_count(hidden_count, false) + opts.renderer.hidden_display = function(hidden_stats) + return utils.default_format_hidden_count(hidden_stats, false) end end elseif type(hidden_display) == "function" then - local safe_render = function(hidden_count) + local safe_render = function(hidden_stats) -- In case of missing field such as live_filter we zero it, otherwise keep field as is - hidden_count = vim.tbl_deep_extend("force", { + hidden_stats = vim.tbl_deep_extend("force", { live_filter = 0, git = 0, buf = 0, dotfile = 0, custom = 0, bookmark = 0, - }, hidden_count or {}) + }, hidden_stats or {}) - local ok, result = pcall(hidden_display, hidden_count) + local ok, result = pcall(hidden_display, hidden_stats) if not ok then - notify.warn "Problem occurred in ``opts.renderer.hidden_display_function`` see nvim-tree.renderer.hidden_display on :h nvim-tree" + notify.warn "Problem occurred in the function ``opts.renderer.hidden_display`` see nvim-tree.renderer.hidden_display on :h nvim-tree" return nil end return result From a005a7fec37217702c8d38e4b2e4d4d257a23c6d Mon Sep 17 00:00:00 2001 From: evertonse Date: Mon, 5 Aug 2024 02:18:09 -0300 Subject: [PATCH 13/15] docs: change to hidden_stats --- doc/nvim-tree-lua.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 38e4c46a52e..c7872f3667c 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -894,12 +894,12 @@ Determines the rendering of hidden files in a folder. show: > (14 total git: 5, dotfile: 9) < - If a function is provided, it receives a table `hidden_count` where keys are + If a function is provided, it receives a table `hidden_stats` where keys are reasons and values are the count of hidden files for that reason. - The `hidden_count` argument is structured as follows, where is the + The `hidden_stats` argument is structured as follows, where is the number of hidden files related to the field: > - hidden_count = { + hidden_stats = { bookmark = , buf = , custom = , @@ -909,14 +909,14 @@ Determines the rendering of hidden files in a folder. } < Example of function that can be passed: > - function(hidden_count) + function(hidden_stats) local total_count = 0 - for reason, count in pairs(hidden_count) do + for reason, count in pairs(hidden_stats) do total_count = total_count + count end if total_count > 0 then - return "(" .. tostring(total_count) .. " hidden")" + return "(" .. tostring(total_count) .. " hidden)" end return nil end From 70159e2084bac2a1d1d962676be1ec6c0587f6f2 Mon Sep 17 00:00:00 2001 From: evertonse Date: Wed, 7 Aug 2024 01:36:25 -0300 Subject: [PATCH 14/15] add separate namespace for virtual lines --- doc/nvim-tree-lua.txt | 1 + lua/nvim-tree/renderer/init.lua | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index c7872f3667c..6c14af3ca26 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -2916,6 +2916,7 @@ highlight group is not, hard linking as follows: > |nvim-tree.renderer.add_trailing| |nvim-tree.renderer.full_name| |nvim-tree.renderer.group_empty| +|nvim-tree.renderer.hidden_display| |nvim-tree.renderer.highlight_bookmarks| |nvim-tree.renderer.highlight_clipboard| |nvim-tree.renderer.highlight_diagnostics| diff --git a/lua/nvim-tree/renderer/init.lua b/lua/nvim-tree/renderer/init.lua index 4cabf6c0e53..729164aea5b 100644 --- a/lua/nvim-tree/renderer/init.lua +++ b/lua/nvim-tree/renderer/init.lua @@ -14,6 +14,7 @@ local SIGN_GROUP = "NvimTreeRendererSigns" local namespace_highlights_id = vim.api.nvim_create_namespace "NvimTreeHighlights" local namespace_extmarks_id = vim.api.nvim_create_namespace "NvimTreeExtmarks" +local namespace_virtual_lines_id = vim.api.nvim_create_namespace "NvimTreeVirtualLines" ---@param bufnr number ---@param lines string[] @@ -51,8 +52,9 @@ local function _draw(bufnr, lines, hl_args, signs, extmarks, virtual_lines) end end + vim.api.nvim_buf_clear_namespace(bufnr, namespace_virtual_lines_id, 0, -1) for line_nr, vlines in pairs(virtual_lines) do - vim.api.nvim_buf_set_extmark(bufnr, namespace_extmarks_id, line_nr, 0, { + vim.api.nvim_buf_set_extmark(bufnr, namespace_virtual_lines_id, line_nr, 0, { virt_lines = vlines, virt_lines_above = false, virt_lines_leftcol = true, From 9c4ed7b6a54ae117eb0b5a935e6b8f5641e7e6ce Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Sat, 10 Aug 2024 11:33:14 +1000 Subject: [PATCH 15/15] help: add highlight group --- doc/nvim-tree-lua.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 6c14af3ca26..b89e947e4ca 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -880,7 +880,7 @@ A list of filenames that gets highlighted with `NvimTreeSpecialFile`. Type: `table`, Default: `{ "Cargo.toml", "Makefile", "README.md", "readme.md", }` *nvim-tree.renderer.hidden_display* -Determines the rendering of hidden files in a folder. +Show a summary of hidden files below the tree using `NvimTreeHiddenDisplay Type: `function | string`, Default: `"none"` Possible string values are: @@ -2505,6 +2505,9 @@ Hidden: > NvimTreeModifiedFileHL NvimTreeHiddenIcon NvimTreeModifiedFolderHL NvimTreeHiddenFileHL < +Hidden Display: > + NvimTreeHiddenDisplay Conceal +< Opened: > NvimTreeOpenedHL Special <