Skip to content

fix(#2415): builder refactor #2538

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Nov 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/nvim-tree-lua.txt
Original file line number Diff line number Diff line change
Expand Up @@ -893,7 +893,7 @@ Configuration options for tree indent markers.
Configuration options for icons.

Icon sign column precedence:
diagnostics > modified > git > bookmarked
diagnostics > bookmarked > modified > git

*nvim-tree.renderer.icons.web_devicons*
Configure optional plugin `"nvim-tree/nvim-web-devicons"`
Expand Down
157 changes: 31 additions & 126 deletions lua/nvim-tree/renderer/builder.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,23 @@ local notify = require "nvim-tree.notify"
local pad = require "nvim-tree.renderer.components.padding"
local icons = require "nvim-tree.renderer.components.icons"

local HL_POSITION = require("nvim-tree.enum").HL_POSITION
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT

--- @class Builder
--- @field decorators Decorator[]
--- @field deco Decorator[]
local Builder = {}
Builder.__index = Builder

local DEFAULT_ROOT_FOLDER_LABEL = ":~:s?$?/..?"

function Builder.new(root_cwd, decorators)
function Builder.new(root_cwd, deco)
return setmetatable({
index = 0,
depth = 0,
highlights = {},
lines = {},
markers = {},
signs = {},
sign_names = {},
root_cwd = root_cwd,
decorators = decorators,
deco = deco,
}, Builder)
end

Expand Down Expand Up @@ -195,95 +192,18 @@ function Builder:_build_file(node)
return icon, { str = node.name, hl = { hl } }
end

---@param node table
---@return HighlightedString[]|nil icon
function Builder:_get_git_icons(node)
local git_icons = self.decorators.git:get_icons(node)
if git_icons and #git_icons > 0 and self.decorators.git.icon_placement == ICON_PLACEMENT.signcolumn then
table.insert(self.signs, {
sign = git_icons[1].hl[1],
lnum = self.index + 1,
priority = 1,
})
git_icons = nil
end
return git_icons
end

---@param node table
---@return HighlightedString[]|nil icon
function Builder:_get_diagnostics_icon(node)
local diagnostics_icon = self.decorators.diagnostics:get_icon(node)
if diagnostics_icon and self.decorators.diagnostics.icon_placement == ICON_PLACEMENT.signcolumn then
table.insert(self.signs, {
sign = diagnostics_icon.hl[1],
lnum = self.index + 1,
priority = 2,
})
diagnostics_icon = nil
end
return diagnostics_icon
end

---@param node table
---@return HighlightedString|nil icon
function Builder:_get_modified_icon(node)
local modified_icon = self.decorators.modified:get_icon(node)
if modified_icon and self.decorators.modified.icon_placement == ICON_PLACEMENT.signcolumn then
table.insert(self.signs, {
sign = modified_icon.hl[1],
lnum = self.index + 1,
priority = 3,
})
modified_icon = nil
end
return modified_icon
end

---@param node table
---@return HighlightedString[]|nil icon
function Builder:_get_bookmark_icon(node)
local bookmark_icon = self.decorators.bookmarks:get_icon(node)
if bookmark_icon and self.decorators.bookmarks.icon_placement == ICON_PLACEMENT.signcolumn then
table.insert(self.signs, {
sign = bookmark_icon.hl[1],
lnum = self.index + 1,
priority = 4,
})
bookmark_icon = nil
end
return bookmark_icon
end

---Append optional highlighting to icon or name.
---@param node table
---@param decorator Decorator
---@param icon_hl string[] icons to append to
---@param name_hl string[] names to append to
function Builder:_append_dec_highlight(node, decorator, icon_hl, name_hl)
local hl = decorator:get_highlight(node)
if hl then
if decorator.hl_pos == HL_POSITION.all or decorator.hl_pos == HL_POSITION.icon then
table.insert(icon_hl, hl)
end
if decorator.hl_pos == HL_POSITION.all or decorator.hl_pos == HL_POSITION.name then
table.insert(name_hl, hl)
end
end
end

---@param indent_markers HighlightedString[]
---@param arrows HighlightedString[]|nil
---@param icon HighlightedString
---@param name HighlightedString
---@param git_icons HighlightedString[]|nil
---@param diagnostics_icon HighlightedString|nil
---@param modified_icon HighlightedString|nil
---@param bookmark_icon HighlightedString|nil
---@param node table
---@return HighlightedString[]
function Builder:_format_line(indent_markers, arrows, icon, name, git_icons, diagnostics_icon, modified_icon, bookmark_icon)
function Builder:_format_line(indent_markers, arrows, icon, name, node)
local added_len = 0
local function add_to_end(t1, t2)
if not t2 then
return
end
for _, v in ipairs(t2) do
if added_len > 0 then
table.insert(t1, { str = self.icon_padding })
Expand All @@ -301,32 +221,15 @@ function Builder:_format_line(indent_markers, arrows, icon, name, git_icons, dia

local line = { indent_markers, arrows }
add_to_end(line, { icon })
if git_icons and self.decorators.git.icon_placement == ICON_PLACEMENT.before then
add_to_end(line, git_icons)
end
if modified_icon and self.decorators.modified.icon_placement == ICON_PLACEMENT.before then
add_to_end(line, { modified_icon })
end
if diagnostics_icon and self.decorators.diagnostics.icon_placement == ICON_PLACEMENT.before then
add_to_end(line, { diagnostics_icon })
end
if bookmark_icon and self.decorators.bookmarks.icon_placement == ICON_PLACEMENT.before then
add_to_end(line, { bookmark_icon })

for i = #self.deco, 1, -1 do
add_to_end(line, self.deco[i]:icons_before(node))
end

add_to_end(line, { name })

if git_icons and self.decorators.git.icon_placement == ICON_PLACEMENT.after then
add_to_end(line, git_icons)
end
if modified_icon and self.decorators.modified.icon_placement == ICON_PLACEMENT.after then
add_to_end(line, { modified_icon })
end
if diagnostics_icon and self.decorators.diagnostics.icon_placement == ICON_PLACEMENT.after then
add_to_end(line, { diagnostics_icon })
end
if bookmark_icon and self.decorators.bookmarks.icon_placement == ICON_PLACEMENT.after then
add_to_end(line, { bookmark_icon })
for i = #self.deco, 1, -1 do
add_to_end(line, self.deco[i]:icons_after(node))
end

return line
Expand All @@ -337,11 +240,15 @@ function Builder:_build_line(node, idx, num_children)
local indent_markers = pad.get_indent_markers(self.depth, idx, num_children, node, self.markers)
local arrows = pad.get_arrows(node)

-- adds icons to signcolumn
local bookmark_icon = self:_get_bookmark_icon(node)
local git_icons = self:_get_git_icons(node)
local modified_icon = self:_get_modified_icon(node)
local diagnostics_icon = self:_get_diagnostics_icon(node)
-- signs, use the highest priority
local sign_name
for _, d in ipairs(self.deco) do
sign_name = d:sign_name(node)
if sign_name then
self.sign_names[self.index] = sign_name
break
end
end

-- main components
local is_folder = node.nodes ~= nil
Expand All @@ -355,16 +262,14 @@ function Builder:_build_line(node, idx, num_children)
icon, name = self:_build_file(node)
end

-- extra highighting
self:_append_dec_highlight(node, self.decorators.git, icon.hl, name.hl)
self:_append_dec_highlight(node, self.decorators.opened, icon.hl, name.hl)
self:_append_dec_highlight(node, self.decorators.modified, icon.hl, name.hl)
self:_append_dec_highlight(node, self.decorators.bookmarks, icon.hl, name.hl)
self:_append_dec_highlight(node, self.decorators.diagnostics, icon.hl, name.hl)
self:_append_dec_highlight(node, self.decorators.copied, icon.hl, name.hl)
self:_append_dec_highlight(node, self.decorators.cut, icon.hl, name.hl)
-- highighting
for _, d in ipairs(self.deco) do
local icon_group, name_group = d:groups_icon_name(node)
table.insert(icon.hl, icon_group)
table.insert(name.hl, name_group)
end

local line = self:_format_line(indent_markers, arrows, icon, name, git_icons, diagnostics_icon, modified_icon, bookmark_icon)
local line = self:_format_line(indent_markers, arrows, icon, name, node)
self:_insert_line(self:_unwrap_highlighted_strings(line))

self.index = self.index + 1
Expand Down Expand Up @@ -438,7 +343,7 @@ function Builder:build_header(show_header)
end

function Builder:unwrap()
return self.lines, self.highlights, self.signs
return self.lines, self.highlights, self.sign_names
end

return Builder
7 changes: 4 additions & 3 deletions lua/nvim-tree/renderer/decorator/bookmarks.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ local DecoratorBookmarks = Decorator:new()
--- @return DecoratorBookmarks
function DecoratorBookmarks:new(opts)
local o = Decorator.new(self, {
enabled = true,
hl_pos = HL_POSITION[opts.renderer.highlight_bookmarks] or HL_POSITION.none,
icon_placement = ICON_PLACEMENT[opts.renderer.icons.bookmarks_placement] or ICON_PLACEMENT.none,
})
Expand All @@ -30,14 +31,14 @@ function DecoratorBookmarks:new(opts)
end

--- Bookmark icon: renderer.icons.show.bookmarks and node is marked
function DecoratorBookmarks:get_icon(node)
function DecoratorBookmarks:calculate_icons(node)
if marks.get_mark(node) then
return self.icon
return { self.icon }
end
end

--- Bookmark highlight: renderer.highlight_bookmarks and node is marked
function DecoratorBookmarks:get_highlight(node)
function DecoratorBookmarks:calculate_highlight(node)
if self.hl_pos ~= HL_POSITION.none and marks.get_mark(node) then
return "NvimTreeBookmarkHL"
end
Expand Down
3 changes: 2 additions & 1 deletion lua/nvim-tree/renderer/decorator/copied.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ local DecoratorCopied = Decorator:new()
--- @return DecoratorCopied
function DecoratorCopied:new(opts)
local o = Decorator.new(self, {
enabled = true,
hl_pos = HL_POSITION[opts.renderer.highlight_clipboard] or HL_POSITION.none,
icon_placement = ICON_PLACEMENT.none,
})
Expand All @@ -26,7 +27,7 @@ function DecoratorCopied:new(opts)
end

--- Cut highlight: renderer.highlight_clipboard and node is copied
function DecoratorCopied:get_highlight(node)
function DecoratorCopied:calculate_highlight(node)
if self.hl_pos ~= HL_POSITION.none and copy_paste.is_copied(node) then
return "NvimTreeCopiedHL"
end
Expand Down
3 changes: 2 additions & 1 deletion lua/nvim-tree/renderer/decorator/cut.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ local DecoratorCut = Decorator:new()
--- @return DecoratorCut
function DecoratorCut:new(opts)
local o = Decorator.new(self, {
enabled = true,
hl_pos = HL_POSITION[opts.renderer.highlight_clipboard] or HL_POSITION.none,
icon_placement = ICON_PLACEMENT.none,
})
Expand All @@ -26,7 +27,7 @@ function DecoratorCut:new(opts)
end

--- Cut highlight: renderer.highlight_clipboard and node is cut
function DecoratorCut:get_highlight(node)
function DecoratorCut:calculate_highlight(node)
if self.hl_pos ~= HL_POSITION.none and copy_paste.is_cut(node) then
return "NvimTreeCutHL"
end
Expand Down
11 changes: 6 additions & 5 deletions lua/nvim-tree/renderer/decorator/diagnostics.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,19 @@ local ICON_KEYS = {
}

--- @class DecoratorDiagnostics: Decorator
--- @field enabled boolean
--- @field icons HighlightedString[]
local DecoratorDiagnostics = Decorator:new()

--- @param opts table
--- @return DecoratorDiagnostics
function DecoratorDiagnostics:new(opts)
local o = Decorator.new(self, {
enabled = opts.diagnostics.enable,
hl_pos = HL_POSITION[opts.renderer.highlight_diagnostics] or HL_POSITION.none,
icon_placement = ICON_PLACEMENT[opts.renderer.icons.diagnostics_placement] or ICON_PLACEMENT.none,
})
---@cast o DecoratorDiagnostics

o.enabled = opts.diagnostics.enable
if not o.enabled then
return o
end
Expand All @@ -64,14 +63,16 @@ function DecoratorDiagnostics:new(opts)
end

--- Diagnostic icon: diagnostics.enable, renderer.icons.show.diagnostics and node has status
function DecoratorDiagnostics:get_icon(node)
function DecoratorDiagnostics:calculate_icons(node)
if node and self.enabled and self.icons then
return self.icons[node.diag_status]
if node.diag_status then
return { self.icons[node.diag_status] }
end
end
end

--- Diagnostic highlight: diagnostics.enable, renderer.highlight_diagnostics and node has status
function DecoratorDiagnostics:get_highlight(node)
function DecoratorDiagnostics:calculate_highlight(node)
if not node or not self.enabled or self.hl_pos == HL_POSITION.none then
return nil
end
Expand Down
19 changes: 15 additions & 4 deletions lua/nvim-tree/renderer/decorator/git.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
local Decorator = require "nvim-tree.renderer.decorator"

--- @class DecoratorGit: Decorator
--- @field enabled boolean
--- @field file_hl string[]
--- @field folder_hl string[]
--- @field git_icons table
Expand Down Expand Up @@ -115,12 +114,12 @@ end
--- @return DecoratorGit
function DecoratorGit:new(opts)
local o = Decorator.new(self, {
enabled = opts.git.enable,
hl_pos = HL_POSITION[opts.renderer.highlight_git] or HL_POSITION.none,
icon_placement = ICON_PLACEMENT[opts.renderer.icons.git_placement] or ICON_PLACEMENT.none,
})
---@cast o DecoratorGit

o.enabled = opts.git.enable
if not o.enabled then
return o
end
Expand All @@ -140,7 +139,7 @@ end
--- Git icons: git.enable, renderer.icons.show.git and node has status
--- @param node table
--- @return HighlightedString[]|nil modified icon
function DecoratorGit:get_icons(node)
function DecoratorGit:calculate_icons(node)
if not node or not self.enabled or not self.git_icons then
return nil
end
Expand Down Expand Up @@ -184,8 +183,20 @@ function DecoratorGit:get_icons(node)
return iconss
end

--- Get the first icon as the sign if appropriate
function DecoratorGit:sign_name(node)
if self.icon_placement ~= ICON_PLACEMENT.signcolumn then
return
end

local icons = self:calculate_icons(node)
if icons and #icons > 0 then
return icons[1].hl[1]
end
end

--- Git highlight: git.enable, renderer.highlight_git and node has status
function DecoratorGit:get_highlight(node)
function DecoratorGit:calculate_highlight(node)
if not node or not self.enabled or self.hl_pos == HL_POSITION.none then
return nil
end
Expand Down
Loading