Skip to content
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

feat(#2948): add custom decorators, :help nvim-tree-decorators #2996

Merged
merged 30 commits into from
Dec 7, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ff3dd12
feat(#2948): add UserDecorator, proof of concept
alex-courtis Nov 9, 2024
4cada41
Merge branch 'master' into 2948-add-user-decorators
alex-courtis Nov 17, 2024
cbc34fb
Merge branch 'master' into 2948-add-user-decorators
alex-courtis Nov 21, 2024
5c3bf8f
feat(#2948): add UserDecorator, proof of concept
alex-courtis Nov 21, 2024
099de58
feat(#2948): add UserDecorator, proof of concept
alex-courtis Nov 21, 2024
24eb27e
feat(#2948): add UserDecorator
alex-courtis Nov 22, 2024
f2a926d
feat(#2948): add UserDecorator
alex-courtis Nov 22, 2024
ad368d9
feat(#2948): add UserDecorator
alex-courtis Nov 22, 2024
dd6b015
feat(#2948): add Decorator node icon override
alex-courtis Nov 22, 2024
1f1ad93
feat(#2948): add nvim_tree.api.* node classes
alex-courtis Nov 23, 2024
45a14f6
feat(#2948): extract _meta following nvim pattern
alex-courtis Nov 24, 2024
919a0a3
feat(#2948): extract _meta following nvim pattern
alex-courtis Nov 24, 2024
129c349
feat(#2948): add decorator registry and order
alex-courtis Nov 24, 2024
8e1e2aa
feat(#2948): add decorator registry and order
alex-courtis Nov 24, 2024
ff4ee07
Merge branch 'master' into 2948-add-user-decorators
alex-courtis Nov 24, 2024
294a96e
feat(#2948): tidy
alex-courtis Nov 24, 2024
93cf3f9
feat(#2948): document API
alex-courtis Nov 24, 2024
8b5f342
feat(#2948): document API
alex-courtis Nov 24, 2024
3ab3980
feat(#2948): document API
alex-courtis Nov 24, 2024
6148f69
feat(#2948): pass api nodes to user decorators
alex-courtis Nov 25, 2024
ba296e6
feat(#2948): document API
alex-courtis Nov 25, 2024
cb351ae
feat(#2948): use renderer.decorators to define order and register
alex-courtis Dec 1, 2024
4bf4a85
feat(#2948): tidy decorator args and complete documentation
alex-courtis Dec 1, 2024
3b60fa7
feat(#2948): decorator classes specified by prefix rather than suffix
alex-courtis Dec 1, 2024
fd49b1f
feat(#2948): improve doc
alex-courtis Dec 1, 2024
dcfcecb
feat(#2948): improve doc
alex-courtis Dec 1, 2024
9e30e9f
feat(#2948): improve doc
alex-courtis Dec 1, 2024
a063280
feat(#2948): additional user decorator safety
alex-courtis Dec 1, 2024
47156b3
feat(#2948): create nvim_tree.api.decorator.UserDecorator class in AP…
alex-courtis Dec 1, 2024
72ef08b
feat(#2948): improve doc
alex-courtis Dec 1, 2024
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 Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ check: luals
# subtasks
#
luacheck:
luacheck -q lua
luacheck --codes --quiet lua --exclude-files "**/_meta/**"

# --diagnosis-as-error does not function for workspace, hence we post-process the output
style-check:
Expand Down
140 changes: 118 additions & 22 deletions doc/nvim-tree-lua.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,16 @@ CONTENTS *nvim-tree*
8.2 Highlight: Overhaul |nvim-tree-highlight-overhaul|
9. Events |nvim-tree-events|
10. Prompts |nvim-tree-prompts|
11. OS Specific Restrictions |nvim-tree-os-specific|
12. Netrw |nvim-tree-netrw|
13. Legacy |nvim-tree-legacy|
13.1 Legacy: Opts |nvim-tree-legacy-opts|
13.2 Legacy: Highlight |nvim-tree-legacy-highlight|
14. Index |nvim-tree-index|
14.1 Index: Opts |nvim-tree-index-opts|
14.2 Index: API |nvim-tree-index-api|
11. Decorators |nvim-tree-decorators|
11.1 Decorator Example |nvim-tree-decorator-example|
12. OS Specific Restrictions |nvim-tree-os-specific|
13. Netrw |nvim-tree-netrw|
14. Legacy |nvim-tree-legacy|
14.1 Legacy: Opts |nvim-tree-legacy-opts|
14.2 Legacy: Highlight |nvim-tree-legacy-highlight|
15. Index |nvim-tree-index|
15.1 Index: Opts |nvim-tree-index-opts|
15.2 Index: API |nvim-tree-index-api|

==============================================================================
1. INTRODUCTION *nvim-tree-introduction*
Expand Down Expand Up @@ -425,6 +427,7 @@ Following is the default configuration. See |nvim-tree-opts| for details. >lua
special_files = { "Cargo.toml", "Makefile", "README.md", "readme.md" },
hidden_display = "none",
symlink_destination = true,
decorators = { "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", },
highlight_git = "none",
highlight_diagnostics = "none",
highlight_opened_files = "none",
Expand Down Expand Up @@ -842,9 +845,6 @@ Use nvim-tree in a floating window.
==============================================================================
5.3 OPTS: RENDERER *nvim-tree-opts-renderer*

Highlight precedence, additive:
git < opened < modified < bookmarked < diagnostics < copied < cut

*nvim-tree.renderer.add_trailing*
Appends a trailing slash to folder names.
Type: `boolean`, Default: `false`
Expand Down Expand Up @@ -927,6 +927,22 @@ Show a summary of hidden files below the tree using `NvimTreeHiddenDisplay
Whether to show the destination of the symlink.
Type: `boolean`, Default: `true`

*nvim-tree.renderer.decorators*
Highlighting and icons for the nodes, in increasing order of precedence.
Uses strings to specify builtin decorators otherwise specify your
`nvim_tree.api.decorator.UserDecorator` class.
Type: `nvim_tree.api.decorator.Name[]`, Default: >lua
{
"Git",
"Open",
"Hidden",
"Modified",
"Bookmark",
"Diagnostics",
"Copied",
"Cut",
}
<
*nvim-tree.renderer.highlight_git*
Enable highlight for git attributes using `NvimTreeGit*HL` highlight groups.
Requires |nvim-tree.git.enable|
Expand Down Expand Up @@ -996,9 +1012,6 @@ Configuration options for tree indent markers.
*nvim-tree.renderer.icons*
Configuration options for icons.

Icon order and sign column precedence:
git < hidden < modified < bookmarked < diagnostics

`renderer.icons.*_placement` options may be:
- `"before"` : before file/folder, after the file/folders icons
- `"after"` : after file/folder
Expand Down Expand Up @@ -2755,7 +2768,89 @@ configurations for different types of prompts.
send all bookmarked to trash during |nvim-tree-api.marks.bulk.trash()|

==============================================================================
11. OS SPECIFIC RESTRICTIONS *nvim-tree-os-specific*
11. DECORATORS *nvim-tree-decorators*

Highlighting and icons for nodes are is provided by Decorators. You may provide
your own in addition to the builtin decorators.

Decorators may:
- Add icons
- Set highlight group for the name or icons
- Override node icon

See `api_decorator.lua` for decorator class definition and full documentation.

Specify decorators and their precedence via |nvim-tree.renderer.decorators|
e.g. defaults with a user decorator being overridden only by Cut: >lua
{
"Git",
"Open",
"Hidden",
"Modified",
"Bookmark",
"Diagnostics",
"Copied",
MyDecorator,
"Cut",
}
<
==============================================================================
11.1. DECORATOR EXAMPLE *nvim-tree-decorator-example*
>lua
---Create your decorator class
---@class (exact) MyDecorator: nvim_tree.api.decorator.UserDecorator
---@field private my_icon nvim_tree.api.HighlightedString
local MyDecorator = require("nvim-tree.api").decorator.UserDecorator:extend()

---Mandatory constructor :new() will be called once per tree render, with no arguments.
function MyDecorator:new()
self.enabled = true
self.highlight_range = "all"
self.icon_placement = "signcolumn"

-- create your icon once, for convenience
self.my_icon = { str = "I", hl = { "MyIcon" } }

-- Define the icon sign only once
-- Only needed if you are using icon_placement = "signcolumn"
self:define_sign(self.my_icon)
end

---Override node icon
---@param node nvim_tree.api.Node
---@return nvim_tree.api.HighlightedString? icon_node
function MyDecorator:icon_node(node)
if node.name == "example" then
return self.my_icon
else
return nil
end
end

---Return one icon for DecoratorIconPlacement
---@param node nvim_tree.api.Node
---@return nvim_tree.api.HighlightedString[]? icons
function MyDecorator:icons(node)
if node.name == "example" then
return { self.my_icon }
else
return nil
end
end

---Exactly one highlight group for DecoratorHighlightRange
---@param node nvim_tree.api.Node
---@return string? highlight_group
function MyDecorator:highlight_group(node)
if node.name == "example" then
return "MyHighlight"
else
return nil
end
end
<
==============================================================================
12. OS SPECIFIC RESTRICTIONS *nvim-tree-os-specific*

Windows WSL and PowerShell
- Trash is synchronized
Expand All @@ -2767,7 +2862,7 @@ Windows WSL and PowerShell
issues or disable this feature.

==============================================================================
12. NETRW *nvim-tree-netrw*
13. NETRW *nvim-tree-netrw*

|netrw| is a standard neovim plugin that is enabled by default. It provides,
amongst other functionality, a file/directory browser.
Expand All @@ -2788,14 +2883,14 @@ keep using |netrw| without its browser features please ensure:
|nvim-tree.hijack_netrw| ` = true`

==============================================================================
13. LEGACY *nvim-tree-legacy*
14. LEGACY *nvim-tree-legacy*

Breaking refactors have been made however the legacy versions will be silently
migrated and used.
There are no plans to remove this migration.

==============================================================================
13.1 LEGACY: OPTS *nvim-tree-legacy-opts*
14.1 LEGACY: OPTS *nvim-tree-legacy-opts*

Legacy options are translated to the current, making type and value changes as
needed.
Expand All @@ -2813,7 +2908,7 @@ needed.
`renderer.icons.webdev_colors` |nvim-tree.renderer.icons.web_devicons.file.color|

==============================================================================
13.2 LEGACY: HIGHLIGHT *nvim-tree-legacy-highlight*
14.2 LEGACY: HIGHLIGHT *nvim-tree-legacy-highlight*

Legacy highlight group are still obeyed when they are defined and the current
highlight group is not, hard linking as follows: >
Expand Down Expand Up @@ -2862,10 +2957,10 @@ highlight group is not, hard linking as follows: >
NvimTreeLspDiagnosticsHintFolderText NvimTreeDiagnosticHintFolderHL
<
==============================================================================
14 INDEX *nvim-tree-index*
15 INDEX *nvim-tree-index*

==============================================================================
14.1 INDEX: OPTS *nvim-tree-index-opts*
15.1 INDEX: OPTS *nvim-tree-index-opts*

|nvim-tree.actions.change_dir|
|nvim-tree.actions.change_dir.enable|
Expand Down Expand Up @@ -2943,6 +3038,7 @@ highlight group is not, hard linking as follows: >
|nvim-tree.prefer_startup_root|
|nvim-tree.reload_on_bufenter|
|nvim-tree.renderer.add_trailing|
|nvim-tree.renderer.decorators|
|nvim-tree.renderer.full_name|
|nvim-tree.renderer.group_empty|
|nvim-tree.renderer.hidden_display|
Expand Down Expand Up @@ -3033,7 +3129,7 @@ highlight group is not, hard linking as follows: >
|nvim-tree.view.width.padding|

==============================================================================
14.2 INDEX: API *nvim-tree-index-api*
15.2 INDEX: API *nvim-tree-index-api*

|nvim-tree-api.commands.get()|
|nvim-tree-api.config.mappings.default_on_attach()|
Expand Down
1 change: 1 addition & 0 deletions lua/nvim-tree.lua
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
special_files = { "Cargo.toml", "Makefile", "README.md", "readme.md" },
hidden_display = "none",
symlink_destination = true,
decorators = { "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", },
highlight_git = "none",
highlight_diagnostics = "none",
highlight_opened_files = "none",
Expand Down
51 changes: 51 additions & 0 deletions lua/nvim-tree/_meta/api.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---@meta
error("Cannot require a meta file")

--
-- Nodes
--

---Base Node, Abstract
---@class (exact) nvim_tree.api.Node
---@field type "file" | "directory" | "link" uv.fs_stat.result.type
---@field absolute_path string
---@field executable boolean
---@field fs_stat uv.fs_stat.result?
---@field git_status GitNodeStatus?
---@field hidden boolean
---@field name string
---@field parent nvim_tree.api.DirectoryNode?
---@field diag_severity lsp.DiagnosticSeverity?

---File
---@class (exact) nvim_tree.api.FileNode: nvim_tree.api.Node
---@field extension string

---Directory
---@class (exact) nvim_tree.api.DirectoryNode: nvim_tree.api.Node
---@field has_children boolean
---@field nodes nvim_tree.api.Node[]
---@field open boolean

---Root Directory
---@class (exact) nvim_tree.api.RootNode: nvim_tree.api.DirectoryNode

---Link mixin
---@class (exact) nvim_tree.api.LinkNode
---@field link_to string
---@field fs_stat_target uv.fs_stat.result

---File Link
---@class (exact) nvim_tree.api.FileLinkNode: nvim_tree.api.FileNode, nvim_tree.api.LinkNode

---DirectoryLink
---@class (exact) nvim_tree.api.DirectoryLinkNode: nvim_tree.api.DirectoryNode, nvim_tree.api.LinkNode

--
-- Various Types
--

---A string for rendering, with optional highlight groups to apply to it
---@class (exact) nvim_tree.api.HighlightedString
---@field str string
---@field hl string[]
49 changes: 49 additions & 0 deletions lua/nvim-tree/_meta/api_decorator.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---@meta
error("Cannot require a meta file")

local nvim_tree = {}

---Highlight group range as per nvim-tree.renderer.highlight_*
---@alias nvim_tree.api.decorator.HighlightRange "none" | "icon" | "name" | "all"

---Icon position as per renderer.icons.*_placement
---@alias nvim_tree.api.decorator.IconPlacement "none" | "before" | "after" | "signcolumn" | "right_align"

---Names of builtin decorators or your decorator classes. Builtins are ordered lowest to highest priority.
---@alias nvim_tree.api.decorator.Name "Git" | "Opened" | "Hidden" | "Modified" | "Bookmarks" | "Diagnostics" | "Copied" | "Cut" | nvim_tree.api.decorator.UserDecorator

---Custom decorator, see :help nvim-tree-decorators
---
---@class (exact) nvim_tree.api.decorator.UserDecorator
---@field protected enabled boolean
---@field protected highlight_range nvim_tree.api.decorator.HighlightRange
---@field protected icon_placement nvim_tree.api.decorator.IconPlacement

---Abstract: no-args constructor must be implemented and will be called once per tree render.
---Must set all fields.
---
function nvim_tree.api.decorator.UserDecorator:new() end

---Abstract: optionally implement to set the node's icon
---
---@param node nvim_tree.api.Node
---@return nvim_tree.api.HighlightedString? icon_node
function nvim_tree.api.decorator.UserDecorator:icon_node(node) end

---Abstract: optionally implement to provide icons and the highlight groups for your icon_placement.
---
---@param node nvim_tree.api.Node
---@return nvim_tree.api.HighlightedString[]? icons
function nvim_tree.api.decorator.UserDecorator:icons(node) end

---Abstract: optionally implement to provide one highlight group to apply to your highlight_range.
---
---@param node nvim_tree.api.Node
---@return string? highlight_group
function nvim_tree.api.decorator.UserDecorator:highlight_group(node) end

---Define a sign. This should be called in the constructor.
---
---@protected
---@param icon nvim_tree.api.HighlightedString?
function nvim_tree.api.decorator.UserDecorator:define_sign(icon) end
7 changes: 7 additions & 0 deletions lua/nvim-tree/api.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ local notify = require("nvim-tree.notify")
local DirectoryNode = require("nvim-tree.node.directory")
local FileLinkNode = require("nvim-tree.node.file-link")
local RootNode = require("nvim-tree.node.root")
local UserDecorator = require("nvim-tree.renderer.decorator.user")

local Api = {
tree = {},
Expand Down Expand Up @@ -39,6 +40,7 @@ local Api = {
},
commands = {},
diagnostics = {},
decorator = {},
}

---Print error when setup not called.
Expand Down Expand Up @@ -311,4 +313,9 @@ Api.commands.get = wrap(function()
return require("nvim-tree.commands").get()
end)

---Create a decorator class by calling :extend()
---See :help nvim-tree-decorators
---@type nvim_tree.api.decorator.UserDecorator
Api.decorator.UserDecorator = UserDecorator --[[@as nvim_tree.api.decorator.UserDecorator]]

return Api
2 changes: 1 addition & 1 deletion lua/nvim-tree/explorer/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ function Explorer:place_cursor_on_node()
end

---Api.tree.get_nodes
---@return Node
---@return nvim_tree.api.Node
function Explorer:get_nodes()
return self:clone()
end
Expand Down
7 changes: 4 additions & 3 deletions lua/nvim-tree/node/directory-link.lua
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,10 @@ function DirectoryLinkNode:highlighted_name()
end

---Create a sanitized partial copy of a node, populating children recursively.
---@return DirectoryLinkNode cloned
function DirectoryLinkNode:clone()
local clone = DirectoryNode.clone(self) --[[@as DirectoryLinkNode]]
---@param api_nodes table<number, nvim_tree.api.Node>? optional map of uids to api node to populate
---@return nvim_tree.api.DirectoryLinkNode cloned
function DirectoryLinkNode:clone(api_nodes)
local clone = DirectoryNode.clone(self, api_nodes) --[[@as nvim_tree.api.DirectoryLinkNode]]

clone.link_to = self.link_to
clone.fs_stat_target = self.fs_stat_target
Expand Down
Loading
Loading