diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index fcf0ef1bf3e..05df7e4e762 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -482,37 +482,31 @@ Icons And Highlighting *nvim-tree-icons-highlighting* Icons may be displayed before files and directories. Additional icons and highlighting may be displayed to indicate various states -for files and and directories. +for files and and directories. Highlighting is additive. -Highlighting is additive, with higher precedence overriding lower. +Decorators are responsible for providing the icons and highlighting. They +apply additively in order of precedence. -|nvim_tree.config.renderer| {decorators} controls which highlighting is -applied and its precedence. See |nvim-tree-decorators| for information on -creating custom decorators. -< -`ICON` +`DECORATOR` + See |nvim_tree.config.renderer.decorator| for available decorators and their + default precedence. + +`ICON?` Enable via |nvim_tree.config.renderer.icons.show `REQUIRES` - Feature must be enabled to show icons and highlighting. - -`PLACEMENT` *nvim_tree.config.renderer.icons.placement* - Where to place the icon: |nvim_tree.config.renderer.icons| {_placement} - • `before`: before file/folder, after the file/folders icons - • `after`: after file/folder - • `signcolumn`: far left, requires |nvim_tree.config.view| {signcolumn}. - • `right_align`: far right - -`HIGHLIGHT` *nvim_tree.config.renderer.highlight* - What should be highlighted: |nvim_tree.config.renderer| {highlight_} - • `none`: no highlighting - • `icon`: icon only - • `name`: name only - • `all`: icon and name - -`DEVICONS` + Features that must be enabled to show icons and highlighting. + +`PLACEMENT` + Where to place icons: |nvim_tree.config.renderer.icons.placement| + +`HIGHLIGHT` + What should be highlighted: |nvim_tree.config.renderer.highlight| + +`DEVICONS?` Glyphs and their colors will be overridden by optional plugin: - `nvim-tree/nvim-web-devicons` |nvim_tree.config.renderer.icons.web_devicons| + `nvim-tree/nvim-web-devicons` + See |nvim_tree.config.renderer.icons.web_devicons| `GLYPHS` Icon glyphs definitions. @@ -520,18 +514,20 @@ creating custom decorators. `GROUPS` Applicable highlight groups: |nvim-tree-highlight-groups| -Some defaults noted. In ascending order of default highlight precedence: +Some defaults noted. In ascending order of default decorator additive +precedence: -`WHAT ICON REQUIRES PLACEMENT HIGHLIGHT GLYPHS DEVICONS GROUPS` -File Icon {file} Y - - - |nvim_tree.config.renderer.icons.glyphs| {default} Y `NvimTreeNormal`, `NvimTreeFileIcon` -Folder Icon {folder} Y - - - |nvim_tree.config.renderer.icons.glyphs.folder| Y `NvimTree*FolderName`, `NvimTree*FolderIcon` -Git Status {git} Y |nvim_tree.config.git| {git_placement} `"before"` {highlight_git} `"none"` |nvim_tree.config.renderer.icons.glyphs.git| N `NvimTreeGit*` -|bufloaded()| - - - {highlight_opened_files}`"none"` - N ` NvimTreeOpened*` -Dotfiles {hidden} N - {hidden_placement} `"after"` {highlight_hidden} `"none"` |nvim_tree.config.renderer.icons.glyphs| {hidden} N `NvimTreeHidden*` -|'modified'| {modified} Y |nvim_tree.config.modified| {modified_placement} `"after"` {highlight_modified} `"none"` |nvim_tree.config.renderer.icons.glyphs| {modified} N `NvimTreeModified*` -Bookmarked {bookmarks} Y - {bookmarks_placement} `"signcolumn"` {highlight_bookmarks} `"none"` |nvim_tree.config.renderer.icons.glyphs| {bookmark} N `NvimTreeBookmark*` -Diag Status {diagnostics}Y |nvim_tree.config.diagnostics| {diagnostics_placement}`"signcolumn"` {highlight_diagnostics} `"none" ` |nvim_tree.config.diagnostics.icons| N `NvimTreeDiagnostic*` -Cut/Copied - - - {highlight_clipboard} `"name"` - N `NvimTreeCutHL`, `NvimTreeCopiedHL` +`WHAT DECORATOR ICON? REQUIRES PLACEMENT HIGHLIGHT GLYPHS DEVICONS? GROUPS` +File Icon - {file} Y - - - |nvim_tree.config.renderer.icons.glyphs| {default} Y `NvimTreeNormal`, `NvimTreeFileIcon` +Folder Icon - {folder} Y - - - |nvim_tree.config.renderer.icons.glyphs.folder| Y `NvimTree*FolderName`, `NvimTree*FolderIcon` +Git Status `"Git"` {git} Y |nvim_tree.config.git| {git_placement} `"before"` {highlight_git} `"none"` |nvim_tree.config.renderer.icons.glyphs.git| N `NvimTreeGit*` +|bufloaded()| `"Open"` - - - {highlight_opened_files}`"none"` - N ` NvimTreeOpened*` +Dotfiles `"Hidden"` {hidden} N - {hidden_placement} `"after"` {highlight_hidden} `"none"` |nvim_tree.config.renderer.icons.glyphs| {hidden} N `NvimTreeHidden*` +|'modified'| `"Modified"` {modified} Y |nvim_tree.config.modified| {modified_placement} `"after"` {highlight_modified} `"none"` |nvim_tree.config.renderer.icons.glyphs| {modified} N `NvimTreeModified*` +Bookmarked `"Bookmark"` {bookmarks} Y - {bookmarks_placement} `"signcolumn"` {highlight_bookmarks} `"none"` |nvim_tree.config.renderer.icons.glyphs| {bookmark} N `NvimTreeBookmark*` +Diag Status ` "Diagnostics"` {diagnostics}Y |nvim_tree.config.diagnostics| {diagnostics_placement}`"signcolumn"` {highlight_diagnostics} `"none" ` |nvim_tree.config.diagnostics.icons| N `NvimTreeDiagnostic*` +Copied `"Copied"` - - - {highlight_clipboard} `"name"` - N `NvimTreeCopiedHL` +Cut `"Cut"` - - - {highlight_clipboard} `"name"` - N `NvimTreeCutHL` ============================================================================== @@ -552,7 +548,8 @@ To view the nvim-tree highlight groups run |:NvimTreeHiTest| To view all active highlight groups run `:so $VIMRUNTIME/syntax/hitest.vim` as per |:highlight| -The `*HL` groups are additive as per |nvim_tree.config.renderer| precedence. +The `*HL` groups are additive, following |nvim_tree.config.renderer.decorator| +precedence. Only present attributes will clobber each other. In this example a modified, opened file will have magenta text, with cyan undercurl: >vim @@ -839,117 +836,6 @@ configurations for different types of prompts. - `nvimtree_bulk_trash` send all bookmarked to trash during |nvim_tree.api.marks.bulk.trash()| -============================================================================== -Decorators *nvim-tree-decorators* - -Highlighting and icons for nodes are 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 - -Create a `nvim_tree.api.decorator.UserDecorator` class and register it with -precedence via |nvim_tree.config.renderer| {decorators} - -See |nvim-tree-decorator-example| - -============================================================================== -Decorators: Example *nvim-tree-decorator-example* - -A decorator class for nodes named "example", overridind all builtin decorators -except for Cut. - -- Highlights node name with `IncSearch` -- Creates two icons `"1"` and `"2"` placed after the node name, highlighted with - `DiffAdd` and `DiffText` -- Replaces the node icon with `"N"`, highlighted with `Error ` - -Create a class file `~/.config/nvim/lua/my-decorator.lua` - -Require and register it during |nvim-tree-setup|: ->lua - local MyDecorator = require("my-decorator") - - require("nvim-tree").setup({ - renderer = { - decorators = { - "Git", - "Open", - "Hidden", - "Modified", - "Bookmark", - "Diagnostics", - "Copied", - MyDecorator, - "Cut", - }, - }, - }) -< -Contents of `my-decorator.lua`: ->lua - ---@class (exact) MyDecorator: nvim_tree.api.decorator.UserDecorator - ---@field private my_icon1 nvim_tree.api.HighlightedString - ---@field private my_icon2 nvim_tree.api.HighlightedString - ---@field private my_icon_node nvim_tree.api.HighlightedString - ---@field private my_highlight_group string - 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 = "name" - self.icon_placement = "after" - - -- create your icons and highlights once, applied to every node - self.my_icon1 = { str = "1", hl = { "DiffAdd" } } - self.my_icon2 = { str = "2", hl = { "DiffText" } } - self.my_icon_node = { str = "N", hl = { "Error" } } - self.my_highlight_group = "IncSearch" - - -- Define the icon signs only once - -- Only needed if you are using icon_placement = "signcolumn" - -- self:define_sign(self.my_icon1) - -- self:define_sign(self.my_icon2) - 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_node - else - return nil - end - end - - ---Return two icons for DecoratorIconPlacement "after" - ---@param node nvim_tree.api.Node - ---@return nvim_tree.api.HighlightedString[]? icons - function MyDecorator:icons(node) - if node.name == "example" then - return { self.my_icon1, self.my_icon2, } - else - return nil - end - end - - ---Exactly one highlight group for DecoratorHighlightRange "name" - ---@param node nvim_tree.api.Node - ---@return string? highlight_group - function MyDecorator:highlight_group(node) - if node.name == "example" then - return self.my_highlight_group - else - return nil - end - end - - return MyDecorator -< ============================================================================== OS Specific Restrictions *nvim-tree-os-specific* @@ -1208,9 +1094,9 @@ Config: sort *nvim-tree-config-sort* ---@param nodes nvim_tree.api.Node[] ---@return nvim_tree.config.sort.Sorter? local sorter = function(nodes) - table.sort(nodes, function(a, b) - return #a.name < #b.name - end) + table.sort(nodes, function(a, b) + return #a.name < #b.name + end) end < @@ -1281,12 +1167,12 @@ Config: view *nvim-tree-config-view* {open_win_config} is passed to |nvim_open_win()|, default: >lua { - relative = "editor", - border = "rounded", - width = 30, - height = 30, - row = 1, - col = 1, + relative = "editor", + border = "rounded", + width = 30, + height = 30, + row = 1, + col = 1, } < @@ -1319,8 +1205,31 @@ Config: renderer *nvim-tree-config-renderer* *nvim_tree.config.renderer* Controls the appearance of the tree. - See |nvim-tree-icons-highlighting| for {highlight_} and {decorators} - fields. + {highlight_} *nvim_tree.config.renderer.highlight* + + See |nvim-tree-icons-highlighting| + • `"none"`: no highlighting + • `"icon"`: icon only + • `"name"`: name only + • `"all"`: icon and name + + {decorators} *nvim_tree.config.renderer.decorator* + + See |nvim-tree-icons-highlighting| + + A builtin decorator name `string` or |nvim_tree.api.Decorator| class. + + Builtin decorators in their default order: + • `"Git"` + • `"Open"` + • `"Hidden"` + • `"Modified"` + • `"Bookmark"` + • `"Diagnostics"` + • `"Copied"` + • `"Cut"` + + Specify {decorators} is a list e.g. `{ "Git", MyDecorator, "Cut" }` {root_folder_label} has 3 forms: • `string`: |filename-modifiers| format string, default `":~:s?$?/..?"` @@ -1328,7 +1237,7 @@ Config: renderer *nvim-tree-config-renderer* • `fun(root_cwd: string): string`: return a literal string from root's absolute path e.g. >lua my_root_folder_label = function(path) - return ".../" .. vim.fn.fnamemodify(path, ":t") + return ".../" .. vim.fn.fnamemodify(path, ":t") end < @@ -1366,9 +1275,8 @@ Config: renderer *nvim-tree-config-renderer* • {symlink_destination}? (`boolean`, default: `true`) Appends an arrow followed by the target of the symlink. - • {decorators}? (`(string|nvim_tree.api.decorator.UserDecorator)[]`) - (default: - `{ "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }`) + • {decorators}? (`nvim_tree.config.renderer.decorator[]`, default: `{ "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }`) + List in order of additive precedence. • {highlight_git}? (`nvim_tree.config.renderer.highlight`) (default: `"none"`) • {highlight_opened_files}? (`nvim_tree.config.renderer.highlight`) @@ -1400,15 +1308,15 @@ Config: renderer *nvim-tree-config-renderer* ---@param hidden_stats nvim_tree.config.renderer.hidden_stats ---@return string? summary local my_hidden_display = function(hidden_stats) - local total_count = 0 - for reason, count in pairs(hidden_stats) do - total_count = total_count + count - end - - if total_count > 0 then - return "(" .. tostring(total_count) .. " hidden)" - end - return nil + local total_count = 0 + for reason, count in pairs(hidden_stats) do + total_count = total_count + count + end + + if total_count > 0 then + return "(" .. tostring(total_count) .. " hidden)" + end + return nil end < @@ -1423,7 +1331,11 @@ Config: renderer *nvim-tree-config-renderer* *nvim_tree.config.renderer.icons* Icons and separators - See |nvim-tree-icons-highlighting| for: {_placement} fields. + {_placement} *nvim_tree.config.renderer.icons.placement* + • `"before"`: before file/folder, after the file/folders icons + • `"after"`: after file/folder + • `"signcolumn"`: far left, requires |nvim_tree.config.view| {signcolumn}. + • `"right_align"`: far right Fields: ~ • {git_placement}? (`nvim_tree.config.renderer.icons.placement`) @@ -1854,11 +1766,11 @@ Config: actions *nvim-tree-config-actions* {open_win_config} is passed to |nvim_open_win()|, default: >lua { - col = 1, - row = 1, - relative = "cursor", - border = "shadow", - style = "minimal", + col = 1, + row = 1, + relative = "cursor", + border = "shadow", + style = "minimal", } < @@ -3200,4 +3112,374 @@ winid({opts}) *nvim_tree.api.tree.winid()* (`integer?`) |window-ID|, nil if tree is not visible. +============================================================================== +Class: Class *nvim-tree-class* + +nvim-tree uses the https://github.com/rxi/classic class framework adding safe +casts, instanceof mixin and conventional destructors. + +The key differences between classic and ordinary Lua classes: +• The constructor |nvim_tree.Class:new()| is not responsible for allocation: + `self` is available when the constructor is called. +• Instances are constructed via the `__call` meta method: `SomeClass(args)` + +Classes are conventionally named using camel case e.g. `MyClass` + +Classes are created by extending another class: >lua + + local Class = require("nvim-tree.classic") + + ---@class (exact) Fruit: nvim_tree.Class + ---@field ... + local Fruit = Class:extend() + + ---@class (exact) Apple: Fruit + ---@field ... + local Apple = Fruit:extend() +< + +Implementing a constructor |nvim_tree.Class:new()| is optional, however it +must call the `super` constructor: >lua + + ---@protected + ---@param args AppleArgs + function Apple:new(args) + + ---@type FruitArgs + local fruit_args = ... + + Apple.super.new(self, fruit_args) + --- +< + +Create an instance of a class using the `__call` meta method that will invoke +the constructor: >lua + + ---@type AppleArgs + local args = ... + + local an_apple = Apple(args) + -- above will call `Apple:new(args)` +< + +In order to strongly type instantiation, the following pattern is used to type +the meta method `__call` with arguments and return: >lua + + ---@class (exact) Fruit: nvim_tree.Class + ---@field ... + local Fruit = Class:extend() + + ---@class (exact) FruitArgs + ---@field ... + + ---@class Fruit + ---@overload fun(args: FruitArgs): Fruit + + ---@protected + ---@param args FruitArgs + function Fruit:new(args) +< + + +*nvim_tree.Class* + + Fields: ~ + • {super} (`nvim_tree.Class`) Parent class, `Class` for base + classes. + • {new} (`fun(self: nvim_tree.Class, ...: any)`) See + |nvim_tree.Class:new()|. + • {destroy} (`fun(self: nvim_tree.Class)`) See + |nvim_tree.Class:destroy()|. + • {extend} (`fun(self: nvim_tree.Class): [nvim_tree.Class]`) See + |nvim_tree.Class:extend()|. + • {implement} (`fun(self: nvim_tree.Class, mixin: nvim_tree.Class)`) + See |nvim_tree.Class:implement()|. + • {is} (`fun(self: nvim_tree.Class, class: T): boolean`) See + |nvim_tree.Class:is()|. + • {as} (`fun(self: nvim_tree.Class, class: T): T?`) See + |nvim_tree.Class:as()|. + • {nop} (`fun(self: nvim_tree.Class, ...: any)`) See + |nvim_tree.Class:nop()|. + + +Class:as({class}) *nvim_tree.Class:as()* + Type safe cast. + + If instance |nvim_tree.Class:is()|, cast to {class} and return it, + otherwise nil. + + Parameters: ~ + • {class} (`any`) `` + + Return: ~ + (`any?`) `` + +Class:destroy() *nvim_tree.Class:destroy()* + Conventional destructor, optional, must be called by the owner. + + Parent destructor must be invoked using the form `Parent.destroy(self)` + +Class:extend() *nvim_tree.Class:extend()* + Create a new class by extending another class. + + Base classes extend `Class` + + Return: ~ + (`[nvim_tree.Class]`) child class + +Class:implement({mixin}) *nvim_tree.Class:implement()* + Add the methods and fields of a mixin using the form + `SomeClass:implement(MixinClass)` + + If the mixin has fields, it must implement a constructor. + + Parameters: ~ + • {mixin} (`nvim_tree.Class`) + +Class:is({class}) *nvim_tree.Class:is()* + Instance of. + + Test whether an object is {class}, inherits {class} or implements mixin + {class}. + + Parameters: ~ + • {class} (`any`) `` + + Return: ~ + (`boolean`) + +Class:new({...}) *nvim_tree.Class:new()* + Constructor: `self` has been allocated and is available. + + Super constructor must be called using the form + `Child.super.new(self, parent_args)` + + Parameters: ~ + • {...} (`any`) constructor arguments + +Class:nop({...}) *nvim_tree.Class:nop()* + Utility method to bypass unused param warnings in abstract methods. + + Parameters: ~ + • {...} (`any`) + + +============================================================================== +Class: Decorator *nvim-tree-class-decorator* + +Highlighting and icons for nodes are provided by Decorators, see +|nvim-tree-icons-highlighting| for an overview. + +Decorators are rendered in |nvim_tree.config.renderer| {decorators} order of +additive precedence, with later decorators applying additively over earlier. + +You may provide your own in addition to the builtin decorators, see +|nvim-tree-class-decorator-example|. + +Decorators may: +• Add icons +• Set a highlight group name for the name or icons +• Override node icon + +To register your decorator: +• Create a class that extends |nvim_tree.api.Decorator| +• Register it by adding the class to |nvim_tree.config.renderer| {decorators} + +Your decorator will be constructed and executed each time the tree is +rendered. + +Your class must: +• |nvim_tree.Class:extend()| the interface |nvim_tree.api.Decorator| +• Provide a no-arguments constructor |nvim_tree.Class:new()| that sets the + mandatory fields: + • {enabled} + • {highlight_range} + • {icon_placement} +• Call |nvim_tree.api.Decorator:define_sign()| in your constructor when + {icon_placement} is `"signcolumn"` + +Your class may: +• Implement methods to provide decorations: + • |nvim_tree.api.Decorator:highlight_group()| + • |nvim_tree.api.Decorator:icon_node()| + • |nvim_tree.api.Decorator:icons()| + + +*nvim_tree.api.Decorator* + Extends: |nvim_tree.Class| + + Decorator interface + + Fields: ~ + • {enabled} (`boolean`) Enable this decorator. + • {highlight_range} (`nvim_tree.config.renderer.highlight`) What to + highlight: |nvim_tree.config.renderer.highlight| + • {icon_placement} (`"none"|nvim_tree.config.renderer.icons.placement`) + Where to place the icons: + |nvim_tree.config.renderer.icons.placement| + • {icon_node} (`fun(self: nvim_tree.api.Decorator, node: nvim_tree.api.Node): nvim_tree.api.highlighted_string?`) + See |nvim_tree.api.Decorator:icon_node()|. + • {icons} (`fun(self: nvim_tree.api.Decorator, node: nvim_tree.api.Node): nvim_tree.api.highlighted_string[]?`) + See |nvim_tree.api.Decorator:icons()|. + • {highlight_group} (`fun(self: nvim_tree.api.Decorator, node: nvim_tree.api.Node): string?`) + See |nvim_tree.api.Decorator:highlight_group()|. + • {define_sign} (`fun(self: nvim_tree.api.Decorator, icon: nvim_tree.api.highlighted_string?)`) + See |nvim_tree.api.Decorator:define_sign()|. + +*nvim_tree.api.highlighted_string* + Text or glyphs with optional highlight group names to apply to it. + + Fields: ~ + • {str} (`string`) One or many glyphs/characters. + • {hl} (`string[]`) Highlight group names to apply in order. Empty + table for no highlighting. + + +Decorator:define_sign({icon}) *nvim_tree.api.Decorator:define_sign()* + Defines a sign for an icon. This is mandatory and necessary only when + {icon_placement} is `"signcolumn"` + + This must be called during your constructor for all icons that you will + return from |nvim_tree.api.Decorator:icons()| + + Parameters: ~ + • {icon} (`nvim_tree.api.highlighted_string?`) does nothing if nil + + *nvim_tree.api.Decorator:highlight_group()* +Decorator:highlight_group({node}) + One highlight group that applies additively to the {node} name for + {highlight_range}. + + Abstract, optional to implement. + + Parameters: ~ + • {node} (`nvim_tree.api.Node`) + + Return: ~ + (`string?`) highlight group name `nil` when no highlighting to apply + to the node + +Decorator:icon_node({node}) *nvim_tree.api.Decorator:icon_node()* + Icon to override for the node. + + Abstract, optional to implement. + + Parameters: ~ + • {node} (`nvim_tree.api.Node`) + + Return: ~ + (`nvim_tree.api.highlighted_string?`) icon `nil` for no override + +Decorator:icons({node}) *nvim_tree.api.Decorator:icons()* + Icons to add to the node as per {icon_placement} + + Abstract, optional to implement. + + Parameters: ~ + • {node} (`nvim_tree.api.Node`) + + Return: ~ + (`nvim_tree.api.highlighted_string[]?`) icons `nil` or empty table for + no icons. Only the first glyph of {str} is used when {icon_placement} + is `"signcolumn"` + + +============================================================================== +Class: Decorator example *nvim-tree-class-decorator-example* + +A decorator class for nodes named "example", overriding all builtin decorators +except for Cut. +• Highlights node name with `IncSearch` +• Creates two icons `"1"` and `"2"` placed after the node name, highlighted + with `DiffAdd` and `DiffText` +• Replaces the node icon with `"N"`, highlighted with `Error ` + +Create a class file `~/.config/nvim/lua/my-decorator.lua` + +Require and register it during |nvim-tree-setup|: >lua + + local MyDecorator = require("my-decorator") + + require("nvim-tree").setup({ + renderer = { + decorators = { + "Git", + "Open", + "Hidden", + "Modified", + "Bookmark", + "Diagnostics", + "Copied", + MyDecorator, + "Cut", + }, + }, + }) +< + +Contents of `my-decorator.lua`: >lua + + ---@class (exact) MyDecorator: nvim_tree.api.Decorator + ---@field private my_icon1 nvim_tree.api.highlighted_string + ---@field private my_icon2 nvim_tree.api.highlighted_string + ---@field private my_icon_node nvim_tree.api.highlighted_string + ---@field private my_highlight_group string + local MyDecorator = require("nvim-tree.api").Decorator:extend() + + ---Mandatory constructor :new() will be called once per tree render, with no arguments. + function MyDecorator:new() + self.enabled = true + self.highlight_range = "name" + self.icon_placement = "after" + + -- create your icons and highlights once, applied to every node + self.my_icon1 = { str = "1", hl = { "DiffAdd" } } + self.my_icon2 = { str = "2", hl = { "DiffText" } } + self.my_icon_node = { str = "N", hl = { "Error" } } + self.my_highlight_group = "IncSearch" + + -- Define the icon signs only once + -- Only needed if you are using icon_placement = "signcolumn" + -- self:define_sign(self.my_icon1) + -- self:define_sign(self.my_icon2) + end + + ---Override node icon + ---@param node nvim_tree.api.Node + ---@return nvim_tree.api.highlighted_string? icon_node + function MyDecorator:icon_node(node) + if node.name == "example" then + return self.my_icon_node + else + return nil + end + end + + ---Return two icons for DecoratorIconPlacement "after" + ---@param node nvim_tree.api.Node + ---@return nvim_tree.api.highlighted_string[]? icons + function MyDecorator:icons(node) + if node.name == "example" then + return { self.my_icon1, self.my_icon2, } + else + return nil + end + end + + ---Exactly one highlight group for DecoratorHighlightRange "name" + ---@param node nvim_tree.api.Node + ---@return string? highlight_group + function MyDecorator:highlight_group(node) + if node.name == "example" then + return self.my_highlight_group + else + return nil + end + end + + return MyDecorator +< + + + vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl: diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 4d4dad7b1f3..7d3a79b46de 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -813,7 +813,7 @@ function M.setup(conf) vim.g.NvimTreeSetup = 1 vim.api.nvim_exec_autocmds("User", { pattern = "NvimTreeSetup" }) - require("nvim-tree.api.impl.post")(api) + require("nvim-tree.api.impl.post").hydrate(api) end vim.g.NvimTreeRequired = 1 diff --git a/lua/nvim-tree/_meta/api/decorator.lua b/lua/nvim-tree/_meta/api/decorator.lua new file mode 100644 index 00000000000..c4ef939765b --- /dev/null +++ b/lua/nvim-tree/_meta/api/decorator.lua @@ -0,0 +1,103 @@ +---@meta + +---@brief +---Highlighting and icons for nodes are provided by Decorators, see [nvim-tree-icons-highlighting] for an overview. +--- +---Decorators are rendered in [nvim_tree.config.renderer] {decorators} order of additive precedence, with later decorators applying additively over earlier. +--- +---You may provide your own in addition to the builtin decorators, see |nvim-tree-class-decorator-example|. +--- +---Decorators may: +---- Add icons +---- Set a highlight group name for the name or icons +---- Override node icon +--- +---To register your decorator: +---- Create a class that extends [nvim_tree.api.Decorator] +---- Register it by adding the class to [nvim_tree.config.renderer] {decorators} +--- +---Your decorator will be constructed and executed each time the tree is rendered. +--- +---Your class must: +---- [nvim_tree.Class:extend()] the interface [nvim_tree.api.Decorator] +---- Provide a no-arguments constructor [nvim_tree.Class:new()] that sets the mandatory fields: +--- - {enabled} +--- - {highlight_range} +--- - {icon_placement} +---- Call [nvim_tree.api.Decorator:define_sign()] in your constructor when {icon_placement} is `"signcolumn"` +--- +---Your class may: +---- Implement methods to provide decorations: +--- - [nvim_tree.api.Decorator:highlight_group()] +--- - [nvim_tree.api.Decorator:icon_node()] +--- - [nvim_tree.api.Decorator:icons()] + +local nvim_tree = { api = {} } + +local Class = require("nvim-tree.classic") + +--- +---Text or glyphs with optional highlight group names to apply to it. +--- +---@class nvim_tree.api.highlighted_string +--- +---One or many glyphs/characters. +---@field str string +--- +---Highlight group names to apply in order. Empty table for no highlighting. +---@field hl string[] + + +--- +---Decorator interface +--- +---@class nvim_tree.api.Decorator: nvim_tree.Class +--- +---Enable this decorator. +---@field enabled boolean +--- +---What to highlight: [nvim_tree.config.renderer.highlight] +---@field highlight_range nvim_tree.config.renderer.highlight +--- +---Where to place the icons: [nvim_tree.config.renderer.icons.placement] +---@field icon_placement "none"|nvim_tree.config.renderer.icons.placement +--- +local Decorator = Class:extend() +nvim_tree.api.Decorator = Decorator + +--- +---Icon to override for the node. +--- +---Abstract, optional to implement. +--- +---@param node nvim_tree.api.Node +---@return nvim_tree.api.highlighted_string? icon `nil` for no override +function Decorator:icon_node(node) end + +--- +---Icons to add to the node as per {icon_placement} +--- +---Abstract, optional to implement. +--- +---@param node nvim_tree.api.Node +---@return nvim_tree.api.highlighted_string[]? icons `nil` or empty table for no icons. Only the first glyph of {str} is used when {icon_placement} is `"signcolumn"` +function Decorator:icons(node) end + +--- +---One highlight group that applies additively to the {node} name for {highlight_range}. +--- +---Abstract, optional to implement. +--- +---@param node nvim_tree.api.Node +---@return string? highlight group name `nil` when no highlighting to apply to the node +function Decorator:highlight_group(node) end + +--- +---Defines a sign for an icon. This is mandatory and necessary only when {icon_placement} is `"signcolumn"` +--- +---This must be called during your constructor for all icons that you will return from [nvim_tree.api.Decorator:icons()] +--- +---@param icon nvim_tree.api.highlighted_string? does nothing if nil +function Decorator:define_sign(icon) end + +return nvim_tree.api.Decorator diff --git a/lua/nvim-tree/_meta/api/decorator_example.lua b/lua/nvim-tree/_meta/api/decorator_example.lua new file mode 100644 index 00000000000..32ccc4fd991 --- /dev/null +++ b/lua/nvim-tree/_meta/api/decorator_example.lua @@ -0,0 +1,96 @@ +---@meta +error("Cannot require a meta file") + +---@brief +--- +---A decorator class for nodes named "example", overriding all builtin decorators except for Cut. +---- Highlights node name with `IncSearch` +---- Creates two icons `"1"` and `"2"` placed after the node name, highlighted with `DiffAdd` and `DiffText` +---- Replaces the node icon with `"N"`, highlighted with `Error ` +--- +---Create a class file `~/.config/nvim/lua/my-decorator.lua` +--- +---Require and register it during |nvim-tree-setup|: +---```lua +--- +--- local MyDecorator = require("my-decorator") +--- +--- require("nvim-tree").setup({ +--- renderer = { +--- decorators = { +--- "Git", +--- "Open", +--- "Hidden", +--- "Modified", +--- "Bookmark", +--- "Diagnostics", +--- "Copied", +--- MyDecorator, +--- "Cut", +--- }, +--- }, +--- }) +---``` +---Contents of `my-decorator.lua`: +---```lua +--- +--- ---@class (exact) MyDecorator: nvim_tree.api.Decorator +--- ---@field private my_icon1 nvim_tree.api.highlighted_string +--- ---@field private my_icon2 nvim_tree.api.highlighted_string +--- ---@field private my_icon_node nvim_tree.api.highlighted_string +--- ---@field private my_highlight_group string +--- local MyDecorator = require("nvim-tree.api").Decorator:extend() +--- +--- ---Mandatory constructor :new() will be called once per tree render, with no arguments. +--- function MyDecorator:new() +--- self.enabled = true +--- self.highlight_range = "name" +--- self.icon_placement = "after" +--- +--- -- create your icons and highlights once, applied to every node +--- self.my_icon1 = { str = "1", hl = { "DiffAdd" } } +--- self.my_icon2 = { str = "2", hl = { "DiffText" } } +--- self.my_icon_node = { str = "N", hl = { "Error" } } +--- self.my_highlight_group = "IncSearch" +--- +--- -- Define the icon signs only once +--- -- Only needed if you are using icon_placement = "signcolumn" +--- -- self:define_sign(self.my_icon1) +--- -- self:define_sign(self.my_icon2) +--- end +--- +--- ---Override node icon +--- ---@param node nvim_tree.api.Node +--- ---@return nvim_tree.api.highlighted_string? icon_node +--- function MyDecorator:icon_node(node) +--- if node.name == "example" then +--- return self.my_icon_node +--- else +--- return nil +--- end +--- end +--- +--- ---Return two icons for DecoratorIconPlacement "after" +--- ---@param node nvim_tree.api.Node +--- ---@return nvim_tree.api.highlighted_string[]? icons +--- function MyDecorator:icons(node) +--- if node.name == "example" then +--- return { self.my_icon1, self.my_icon2, } +--- else +--- return nil +--- end +--- end +--- +--- ---Exactly one highlight group for DecoratorHighlightRange "name" +--- ---@param node nvim_tree.api.Node +--- ---@return string? highlight_group +--- function MyDecorator:highlight_group(node) +--- if node.name == "example" then +--- return self.my_highlight_group +--- else +--- return nil +--- end +--- end +--- +--- return MyDecorator +---``` diff --git a/lua/nvim-tree/_meta/api/deprecated.lua b/lua/nvim-tree/_meta/api/deprecated.lua index fdd4b88e85a..f9f37852225 100644 --- a/lua/nvim-tree/_meta/api/deprecated.lua +++ b/lua/nvim-tree/_meta/api/deprecated.lua @@ -30,4 +30,10 @@ nvim_tree.api.diagnostics = {} ---@deprecated use `nvim_tree.api.health.hi_test()` function nvim_tree.api.diagnostics.hi_test() end +nvim_tree.api.decorator = {} + +---@class nvim_tree.api.decorator.UserDecorator: nvim_tree.api.Decorator +---@deprecated use `nvim_tree.api.Decorator` +nvim_tree.api.decorator.UserDecorator = nvim_tree.api.Decorator + return nvim_tree.api diff --git a/lua/nvim-tree/_meta/api_decorator.lua b/lua/nvim-tree/_meta/api_decorator.lua deleted file mode 100644 index 4acca3a9acf..00000000000 --- a/lua/nvim-tree/_meta/api_decorator.lua +++ /dev/null @@ -1,59 +0,0 @@ ----@meta -error("Cannot require a meta file") - -local nvim_tree = { api = { decorator = {} } } - ----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 - ----A string for rendering, with optional highlight groups to apply to it ----@class (exact) nvim_tree.api.HighlightedString ----@field str string ----@field hl string[] - ----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 -nvim_tree.api.decorator.UserDecorator = {} - ----Create your decorator class ---- -function nvim_tree.api.decorator.UserDecorator:extend() end - ----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 diff --git a/lua/nvim-tree/_meta/classes.lua b/lua/nvim-tree/_meta/classes.lua index 7de002916c6..fc2c5021462 100644 --- a/lua/nvim-tree/_meta/classes.lua +++ b/lua/nvim-tree/_meta/classes.lua @@ -1,12 +1,6 @@ ---@meta error("Cannot require a meta file") - --- TODO #2688 --- These node subclasses are not ready for public exposure as they are: --- - not classic classes --- - only used in a few locations: api.tree.get_nodes and UserDecorator - --- ---File --- diff --git a/lua/nvim-tree/_meta/config/actions.lua b/lua/nvim-tree/_meta/config/actions.lua index 316ec3a47b1..012f4c364d9 100644 --- a/lua/nvim-tree/_meta/config/actions.lua +++ b/lua/nvim-tree/_meta/config/actions.lua @@ -60,13 +60,13 @@ error("Cannot require a meta file") --- ---{open_win_config} is passed to [nvim_open_win()], default: ---```lua ----{ ---- col = 1, ---- row = 1, ---- relative = "cursor", ---- border = "shadow", ---- style = "minimal", ----} +--- { +--- col = 1, +--- row = 1, +--- relative = "cursor", +--- border = "shadow", +--- style = "minimal", +--- } ---``` ---You shouldn't define {width} and {height} values here. They will be overridden to fit the file_popup content. ---@class nvim_tree.config.actions.file_popup diff --git a/lua/nvim-tree/_meta/config/default.lua b/lua/nvim-tree/_meta/config/default.lua index 1f1252f7483..4db71c02437 100644 --- a/lua/nvim-tree/_meta/config/default.lua +++ b/lua/nvim-tree/_meta/config/default.lua @@ -3,9 +3,8 @@ --- ---```lua --- -------@type nvim_tree.config ----local config = { ----default-config-injection-placeholder ----} +--- ---@type nvim_tree.config +--- local config = { +--- default-config-injection-placeholder +--- } ---``` ---- diff --git a/lua/nvim-tree/_meta/config/renderer.lua b/lua/nvim-tree/_meta/config/renderer.lua index e1ba26cbb91..4e7d419f101 100644 --- a/lua/nvim-tree/_meta/config/renderer.lua +++ b/lua/nvim-tree/_meta/config/renderer.lua @@ -5,18 +5,52 @@ error("Cannot require a meta file") ---Controls the appearance of the tree. --- ----See [nvim-tree-icons-highlighting] for {highlight_} and {decorators} fields. +---{highlight_} [nvim_tree.config.renderer.highlight]() +--- +---See [nvim-tree-icons-highlighting] +--- +---- `"none"`: no highlighting +---- `"icon"`: icon only +---- `"name"`: name only +---- `"all"`: icon and name +---@alias nvim_tree.config.renderer.highlight "none"|"icon"|"name"|"all" +--- +--- +--- +---{decorators} [nvim_tree.config.renderer.decorator]() +--- +---See [nvim-tree-icons-highlighting] +--- +---A builtin decorator name `string` or |nvim_tree.api.Decorator| class. +--- +---Builtin decorators in their default order: +---- `"Git"` +---- `"Open"` +---- `"Hidden"` +---- `"Modified"` +---- `"Bookmark"` +---- `"Diagnostics"` +---- `"Copied"` +---- `"Cut"` +--- +---Specify {decorators} is a list e.g. `{ "Git", MyDecorator, "Cut" }` +--- +---@alias nvim_tree.config.renderer.decorator nvim_tree.api.Decorator|"Git"|"Open"|"Hidden"|"Modified"|"Bookmark"|"Diagnostics"|"Copied"|"Cut" +--- +--- --- ---{root_folder_label} has 3 forms: ---- `string`: [filename-modifiers] format string, default `":~:s?$?/..?"` ---- `boolean`: `true` to disable ---- `fun(root_cwd: string): string`: return a literal string from root's absolute path e.g. ---```lua ----my_root_folder_label = function(path) ---- return ".../" .. vim.fn.fnamemodify(path, ":t") ----end +--- my_root_folder_label = function(path) +--- return ".../" .. vim.fn.fnamemodify(path, ":t") +--- end ---``` --- +--- +--- ---{hidden_display} [nvim_tree.config.renderer.hidden_display]() --- ---Summary of hidden nodes, below the last node in the directory, highlighted with `NvimTreeHiddenDisplay`. @@ -30,7 +64,7 @@ error("Cannot require a meta file") ---See [nvim_tree.config.renderer.hidden_stats] for details and example. ---@alias nvim_tree.config.renderer.hidden_display "none"|"simple"|"all"|(fun(hidden_stats: nvim_tree.config.renderer.hidden_stats): string?) --- ----@alias nvim_tree.config.renderer.highlight "none"|"icon"|"name"|"all" +--- --- ---@class nvim_tree.config.renderer --- @@ -61,8 +95,9 @@ error("Cannot require a meta file") ---(default: `true`) ---@field symlink_destination? boolean --- +---List in order of additive precedence. ---(default: `{ "Git", "Open", "Hidden", "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }`) ----@field decorators? (string|nvim_tree.api.decorator.UserDecorator)[] +---@field decorators? nvim_tree.config.renderer.decorator[] --- ---(default: `"none"`) ---@field highlight_git? nvim_tree.config.renderer.highlight @@ -131,10 +166,14 @@ error("Cannot require a meta file") ---Icons and separators --- ----See [nvim-tree-icons-highlighting] for: {_placement} fields. ---- +---{_placement} [nvim_tree.config.renderer.icons.placement]() +---- `"before"`: before file/folder, after the file/folders icons +---- `"after"`: after file/folder +---- `"signcolumn"`: far left, requires |nvim_tree.config.view| {signcolumn}. +---- `"right_align"`: far right ---@alias nvim_tree.config.renderer.icons.placement "before"|"after"|"signcolumn"|"right_align" --- +--- ---@class nvim_tree.config.renderer.icons --- ---(default: `before`) @@ -318,19 +357,19 @@ error("Cannot require a meta file") ---Passed to your [nvim_tree.config.renderer.hidden_display] function e.g. ---```lua --- -------@param hidden_stats nvim_tree.config.renderer.hidden_stats -------@return string? summary ----local my_hidden_display = function(hidden_stats) ---- local total_count = 0 ---- for reason, count in pairs(hidden_stats) do ---- total_count = total_count + count ---- end ---- ---- if total_count > 0 then ---- return "(" .. tostring(total_count) .. " hidden)" ---- end ---- return nil ----end +--- ---@param hidden_stats nvim_tree.config.renderer.hidden_stats +--- ---@return string? summary +--- local my_hidden_display = function(hidden_stats) +--- local total_count = 0 +--- for reason, count in pairs(hidden_stats) do +--- total_count = total_count + count +--- end +--- +--- if total_count > 0 then +--- return "(" .. tostring(total_count) .. " hidden)" +--- end +--- return nil +--- end ---``` --- ---@class nvim_tree.config.renderer.hidden_stats diff --git a/lua/nvim-tree/_meta/config/sort.lua b/lua/nvim-tree/_meta/config/sort.lua index 569fe56ba78..6c692dee73c 100644 --- a/lua/nvim-tree/_meta/config/sort.lua +++ b/lua/nvim-tree/_meta/config/sort.lua @@ -17,14 +17,14 @@ error("Cannot require a meta file") ---{sorter} may be a function that is passed a list of `nvim_tree.api.Node` to be sorted in place e.g. ---```lua --- -------Sort by name length -------@param nodes nvim_tree.api.Node[] -------@return nvim_tree.config.sort.Sorter? ----local sorter = function(nodes) ---- table.sort(nodes, function(a, b) ---- return #a.name < #b.name ---- end) ----end +--- ---Sort by name length +--- ---@param nodes nvim_tree.api.Node[] +--- ---@return nvim_tree.config.sort.Sorter? +--- local sorter = function(nodes) +--- table.sort(nodes, function(a, b) +--- return #a.name < #b.name +--- end) +--- end ---``` ---{sorter} may be a function that returns a [nvim_tree.config.sort.Sorter] --- diff --git a/lua/nvim-tree/_meta/config/view.lua b/lua/nvim-tree/_meta/config/view.lua index bc599885593..3d3a0404b9b 100644 --- a/lua/nvim-tree/_meta/config/view.lua +++ b/lua/nvim-tree/_meta/config/view.lua @@ -85,14 +85,14 @@ error("Cannot require a meta file") --- ---{open_win_config} is passed to [nvim_open_win()], default: ---```lua ----{ ---- relative = "editor", ---- border = "rounded", ---- width = 30, ---- height = 30, ---- row = 1, ---- col = 1, ----} +--- { +--- relative = "editor", +--- border = "rounded", +--- width = 30, +--- height = 30, +--- row = 1, +--- col = 1, +--- } ---``` ---@class nvim_tree.config.view.float --- diff --git a/lua/nvim-tree/actions/fs/clipboard.lua b/lua/nvim-tree/actions/fs/clipboard.lua index 3f3ed37c94d..494939d645b 100644 --- a/lua/nvim-tree/actions/fs/clipboard.lua +++ b/lua/nvim-tree/actions/fs/clipboard.lua @@ -15,7 +15,7 @@ local DirectoryNode = require("nvim-tree.node.directory") ---@alias ClipboardActionFn fun(source: string, dest: string): boolean, string? ----@class (exact) Clipboard: Class +---@class (exact) Clipboard: nvim_tree.Class ---@field private explorer Explorer ---@field private data ClipboardData ---@field private clipboard_name string diff --git a/lua/nvim-tree/api.lua b/lua/nvim-tree/api.lua index e88b19d1f0a..81250fe5fca 100644 --- a/lua/nvim-tree/api.lua +++ b/lua/nvim-tree/api.lua @@ -69,12 +69,9 @@ --- --- Load the (empty) meta definitions --- -local deprecated = require("nvim-tree._meta.api.deprecated") - +--- ---nvim-tree Public API +--- ---@class nvim_tree.api ---@nodoc local api = { @@ -89,17 +86,14 @@ local api = { node = require("nvim-tree._meta.api.node"), tree = require("nvim-tree._meta.api.tree"), - config = deprecated.config, ---@deprecated - diagnostics = deprecated.diagnostics, ---@deprecated - live_filter = deprecated.live_filter, ---@deprecated -} - - --- --- Map before-setup implementations, most throw an error notification "nvim-tree setup not called". --- -require("nvim-tree.api.impl.pre")(api) + Decorator = require("nvim-tree._meta.api.decorator"), + config = require("nvim-tree._meta.api.deprecated").config, ---@deprecated + decorator = require("nvim-tree._meta.api.deprecated").decorator, ---@deprecated + diagnostics = require("nvim-tree._meta.api.deprecated").diagnostics, ---@deprecated + live_filter = require("nvim-tree._meta.api.deprecated").live_filter, ---@deprecated +} +require("nvim-tree.api.impl.pre").hydrate(api) return api diff --git a/lua/nvim-tree/api/impl/legacy.lua b/lua/nvim-tree/api/impl/legacy.lua deleted file mode 100644 index 51924b4f365..00000000000 --- a/lua/nvim-tree/api/impl/legacy.lua +++ /dev/null @@ -1,25 +0,0 @@ ----Silently create new api entries pointing legacy functions to current ----@param api table not properly typed to prevent LSP from referencing implementations -return function(api) - api.config = api.config or {} - api.config.mappings = api.config.mappings or {} - api.config.mappings.get_keymap = api.map.keymap.current - api.config.mappings.get_keymap_default = api.map.keymap.default - api.config.mappings.default_on_attach = api.map.on_attach.default - - api.live_filter = api.live_filter or {} - api.live_filter.start = api.filter.live.start - api.live_filter.clear = api.filter.live.clear - - api.tree = api.tree or {} - api.tree.toggle_enable_filters = api.filter.toggle - api.tree.toggle_gitignore_filter = api.filter.git.ignored.toggle - api.tree.toggle_git_clean_filter = api.filter.git.clean.toggle - api.tree.toggle_no_buffer_filter = api.filter.no_buffer.toggle - api.tree.toggle_custom_filter = api.filter.custom.toggle - api.tree.toggle_hidden_filter = api.filter.dotfiles.toggle - api.tree.toggle_no_bookmark_filter = api.filter.no_bookmark.toggle - - api.diagnostics = api.diagnostics or {} - api.diagnostics.hi_test = api.health.hi_test -end diff --git a/lua/nvim-tree/api/impl/post.lua b/lua/nvim-tree/api/impl/post.lua index 2aa5a3caec3..11c4b5ede14 100644 --- a/lua/nvim-tree/api/impl/post.lua +++ b/lua/nvim-tree/api/impl/post.lua @@ -6,6 +6,8 @@ ---This is expensive as there are many cascading requires and is avoided ---until after setup has been called, so that the user may require API cheaply. +local legacy = require("nvim-tree.legacy") + local actions = require("nvim-tree.actions") local help = require("nvim-tree.help") local keymap = require("nvim-tree.keymap") @@ -16,6 +18,8 @@ local DirectoryNode = require("nvim-tree.node.directory") local FileLinkNode = require("nvim-tree.node.file-link") local RootNode = require("nvim-tree.node.root") +local M = {} + ---Invoke a method on the singleton explorer. ---Print error when setup not called. ---@param explorer_method string explorer method name @@ -133,9 +137,9 @@ local function open_or_expand_or_dir_up(mode, toggle_group) end end ----Hydrate all implementations barring those that were called during hydrate_pre +---Re-Hydrate api functions and classes post-setup ---@param api table not properly typed to prevent LSP from referencing implementations -local function hydrate_post(api) +function M.hydrate(api) api.tree.open = actions.tree.open.fn api.tree.focus = api.tree.open @@ -252,14 +256,9 @@ local function hydrate_post(api) api.marks.navigate.select = wrap_explorer_member("marks", "navigate_select") api.map.keymap.current = keymap.get_keymap -end ----Re-hydrate api ----@param api table not properly typed to prevent LSP from referencing implementations -return function(api) - -- All concrete implementations - hydrate_post(api) - - -- (Re)hydrate any legacy by mapping to function set above - require("nvim-tree.api.impl.legacy")(api) + -- (Re)hydrate any legacy by mapping to concrete set above + legacy.map_api(api) end + +return M diff --git a/lua/nvim-tree/api/impl/pre.lua b/lua/nvim-tree/api/impl/pre.lua index 7ad25ecb41f..489fb05649c 100644 --- a/lua/nvim-tree/api/impl/pre.lua +++ b/lua/nvim-tree/api/impl/pre.lua @@ -1,6 +1,7 @@ ---Hydrates meta api empty definition functions with a new function: --- - Default: error notification "nvim-tree setup not called". --- - Exceptions: concrete implementation for API that can be called before setup. +--Hydrates meta api empty definitions pre-setup: +-- - Pre-setup functions will be hydrated with their concrete implementation. +-- - Post-setup functions will notify error: "nvim-tree setup not called" +-- - All classes will be hydrated with their implementations. -- --Call it once when api is first required -- @@ -8,72 +9,53 @@ -- --Everything must be as lazily loaded as possible: the user must be able to require api cheaply. +local legacy = require("nvim-tree.legacy") + local commands = require("nvim-tree.commands") -- already required by plugin.lua local events = require("nvim-tree.events") -- needed for event registration pre-setup local keymap = require("nvim-tree.keymap") -- needed for default on attach local notify = require("nvim-tree.notify") -- already required by events and others -local UserDecorator = require("nvim-tree.renderer.decorator.user") +local Decorator = require("nvim-tree.renderer.decorator") + +local M = {} ----Walk the api, hydrating all functions with the error notification ----@param t table api root or sub-module +---Walk the api, hydrating all functions with the error notification. +---Do not hydrate classes: anything with a metatable. +---@param t table local function hydrate_error(t) for k, v in pairs(t) do if type(v) == "function" then t[k] = function() notify.error("nvim-tree setup not called") end - elseif type(v) == "table" then + elseif type(v) == "table" and not getmetatable(v) then hydrate_error(v) end end end ----Hydrate implementations that may be called pre setup +---Hydrate api functions and classes pre-setup ---@param api table not properly typed to prevent LSP from referencing implementations -local function hydrate_pre(api) - -- - -- Essential - -- - api.events.Event = events.Event - api.events.subscribe = events.subscribe +function M.hydrate(api) + -- default to the error message + hydrate_error(api) + -- eager functions + api.events.subscribe = events.subscribe api.map.on_attach.default = keymap.on_attach_default - - - -- - -- May be lazily requried on execution - -- - api.health.hi_test = function() require("nvim-tree.appearance.hi-test")() end - - - -- - -- Already required elsewhere - -- api.commands.get = commands.get - api.map.keymap.default = keymap.get_keymap_default + -- lazy functions + api.health.hi_test = function() require("nvim-tree.appearance.hi-test")() end - -- - -- TODO #3241 - -- - api.decorator = {} - ---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]] -end - ----Hydrate api ----@param api table not properly typed to prevent LSP from referencing implementations -return function(api) - -- Default: error - hydrate_error(api) - - -- Exceptions: may be called - hydrate_pre(api) + -- classes + api.Decorator = Decorator:extend() + api.events.Event = events.Event - -- Hydrate any legacy by mapping to function set above - require("nvim-tree.api.impl.legacy")(api) + -- Hydrate any legacy by mapping to concrete set above + legacy.map_api(api) end + +return M diff --git a/lua/nvim-tree/appearance/hi-test.lua b/lua/nvim-tree/appearance/hi-test.lua index 5223b8336dd..8aa7567ec7b 100644 --- a/lua/nvim-tree/appearance/hi-test.lua +++ b/lua/nvim-tree/appearance/hi-test.lua @@ -7,7 +7,8 @@ local SHORT_LEN = 50 local namespace_hi_test_id = vim.api.nvim_create_namespace("NvimTreeHiTest") ----@class (exact) HighlightDisplay: Class for :NvimTreeHiTest +---For :NvimTreeHiTest +---@class (exact) HighlightDisplay: nvim_tree.Class ---@field group string nvim-tree highlight group name ---@field links string link chain to a concretely defined group ---@field def string :hi concrete definition after following any links diff --git a/lua/nvim-tree/classic.lua b/lua/nvim-tree/classic.lua index 6e856bc90c0..f22d31f4172 100644 --- a/lua/nvim-tree/classic.lua +++ b/lua/nvim-tree/classic.lua @@ -9,18 +9,107 @@ -- https://github.com/rxi/classic -- ----@class (exact) Class ----@field super Class ----@field private implements table + +---@brief +--- +---nvim-tree uses the https://github.com/rxi/classic class framework adding safe casts, instanceof mixin and conventional destructors. +--- +---The key differences between classic and ordinary Lua classes: +---- The constructor [nvim_tree.Class:new()] is not responsible for allocation: `self` is available when the constructor is called. +---- Instances are constructed via the `__call` meta method: `SomeClass(args)` +--- +---Classes are conventionally named using camel case e.g. `MyClass` +--- +---Classes are created by extending another class: +---```lua +--- +--- local Class = require("nvim-tree.classic") +--- +--- ---@class (exact) Fruit: nvim_tree.Class +--- ---@field ... +--- local Fruit = Class:extend() +--- +--- ---@class (exact) Apple: Fruit +--- ---@field ... +--- local Apple = Fruit:extend() +---``` +--- +---Implementing a constructor [nvim_tree.Class:new()] is optional, however it must call the `super` constructor: +---```lua +--- +--- ---@protected +--- ---@param args AppleArgs +--- function Apple:new(args) +--- +--- ---@type FruitArgs +--- local fruit_args = ... +--- +--- Apple.super.new(self, fruit_args) +--- --- +---``` +--- +---Create an instance of a class using the `__call` meta method that will invoke the constructor: +---```lua +--- +--- ---@type AppleArgs +--- local args = ... +--- +--- local an_apple = Apple(args) +--- -- above will call `Apple:new(args)` +---``` +--- +---In order to strongly type instantiation, the following pattern is used to type the meta method `__call` with arguments and return: +---```lua +--- +--- ---@class (exact) Fruit: nvim_tree.Class +--- ---@field ... +--- local Fruit = Class:extend() +--- +--- ---@class (exact) FruitArgs +--- ---@field ... +--- +--- ---@class Fruit +--- ---@overload fun(args: FruitArgs): Fruit +--- +--- ---@protected +--- ---@param args FruitArgs +--- function Fruit:new(args) +---``` + +--- +---@class nvim_tree.Class +--- +---Parent class, `Class` for base classes. +---@field super nvim_tree.Class +--- +---mixin classes that are implemented. +---@field private implements table local Class = {} Class.__index = Class ---@diagnostic disable-line: inject-field ----Default constructor ----@protected +--- +---Constructor: `self` has been allocated and is available. +--- +---Super constructor must be called using the form `Child.super.new(self, parent_args)` +--- +---@param ... any constructor arguments function Class:new(...) --luacheck: ignore 212 end ----Extend a class, setting .super +--- +---Conventional destructor, optional, must be called by the owner. +--- +---Parent destructor must be invoked using the form `Parent.destroy(self)` +--- +function Class:destroy() +end + +--- +---Create a new class by extending another class. +--- +---Base classes extend `Class` +--- +---@return [nvim_tree.Class] child class function Class:extend() local cls = {} for k, v in pairs(self) do @@ -34,9 +123,12 @@ function Class:extend() return cls end ----Implement the functions of a mixin ----Add the mixin to .implements ----@param mixin Class +--- +---Add the methods and fields of a mixin using the form `SomeClass:implement(MixinClass)` +--- +---If the mixin has fields, it must implement a constructor. +--- +---@param mixin nvim_tree.Class function Class:implement(mixin) if not rawget(self, "implements") then -- set on the class itself instead of parents @@ -50,9 +142,13 @@ function Class:implement(mixin) end end ----Object is an instance of class or implements a mixin +--- +---Instance of. +--- +---Test whether an object is {class}, inherits {class} or implements mixin {class}. +--- ---@generic T ----@param class T +---@param class T `` ---@return boolean function Class:is(class) local mt = getmetatable(self) @@ -68,22 +164,32 @@ function Class:is(class) return false end ----Return object if :is otherwise nil +--- +---Type safe cast. +--- +---If instance [nvim_tree.Class:is()], cast to {class} and return it, otherwise nil. +--- ---@generic T ----@param class T ----@return T|nil +---@param class T `` +---@return T? `` function Class:as(class) return self:is(class) and self or nil end ----Constructor to create instance, call :new and return +--- +---Constructs an instance: calls [nvim_tree.Class:new()] and returns the new instance. +--- +---@param ... any constructor args +---@return nvim_tree.Class function Class:__call(...) local obj = setmetatable({}, self) obj:new(...) return obj end --- avoid unused param warnings in abstract methods +--- +---Utility method to bypass unused param warnings in abstract methods. +--- ---@param ... any function Class:nop(...) --luacheck: ignore 212 end diff --git a/lua/nvim-tree/explorer/filters.lua b/lua/nvim-tree/explorer/filters.lua index 43851954553..71be462e4c2 100644 --- a/lua/nvim-tree/explorer/filters.lua +++ b/lua/nvim-tree/explorer/filters.lua @@ -5,7 +5,7 @@ local Class = require("nvim-tree.classic") ---@alias FilterType "custom" | "dotfiles" | "git_ignored" | "git_clean" | "no_buffer" | "no_bookmark" ----@class (exact) Filters: Class +---@class (exact) Filters: nvim_tree.Class ---@field enabled boolean ---@field state table ---@field private explorer Explorer diff --git a/lua/nvim-tree/explorer/live-filter.lua b/lua/nvim-tree/explorer/live-filter.lua index c6d64e848d3..81e6da81657 100644 --- a/lua/nvim-tree/explorer/live-filter.lua +++ b/lua/nvim-tree/explorer/live-filter.lua @@ -5,7 +5,7 @@ local Class = require("nvim-tree.classic") local Iterator = require("nvim-tree.iterators.node-iterator") local DirectoryNode = require("nvim-tree.node.directory") ----@class (exact) LiveFilter: Class +---@class (exact) LiveFilter: nvim_tree.Class ---@field explorer Explorer ---@field prefix string ---@field always_show_folders boolean diff --git a/lua/nvim-tree/explorer/sorter.lua b/lua/nvim-tree/explorer/sorter.lua index 799cfa481b1..c0d5cb34cd4 100644 --- a/lua/nvim-tree/explorer/sorter.lua +++ b/lua/nvim-tree/explorer/sorter.lua @@ -6,7 +6,7 @@ local DirectoryNode = require("nvim-tree.node.directory") ---@alias SorterUser fun(nodes: Node[]): SorterType? ----@class (exact) Sorter: Class +---@class (exact) Sorter: nvim_tree.Class ---@field private explorer Explorer local Sorter = Class:extend() diff --git a/lua/nvim-tree/git/runner.lua b/lua/nvim-tree/git/runner.lua index 938d10fa0e0..3d41092631b 100644 --- a/lua/nvim-tree/git/runner.lua +++ b/lua/nvim-tree/git/runner.lua @@ -4,7 +4,7 @@ local notify = require("nvim-tree.notify") local Class = require("nvim-tree.classic") ----@class (exact) GitRunner: Class +---@class (exact) GitRunner: nvim_tree.Class ---@field private toplevel string absolute path ---@field private path string? absolute path ---@field private list_untracked boolean diff --git a/lua/nvim-tree/legacy.lua b/lua/nvim-tree/legacy.lua index 842700ba36b..47495e0e609 100644 --- a/lua/nvim-tree/legacy.lua +++ b/lua/nvim-tree/legacy.lua @@ -151,4 +151,32 @@ function M.migrate_legacy_options(opts) removed(opts) end +---Silently create new api entries pointing legacy functions to current +---@param api table not properly typed to prevent LSP from referencing implementations +function M.map_api(api) + api.config = api.config or {} + api.config.mappings = api.config.mappings or {} + api.config.mappings.get_keymap = api.map.keymap.current + api.config.mappings.get_keymap_default = api.map.keymap.default + api.config.mappings.default_on_attach = api.map.on_attach.default + + api.live_filter = api.live_filter or {} + api.live_filter.start = api.filter.live.start + api.live_filter.clear = api.filter.live.clear + + api.tree = api.tree or {} + api.tree.toggle_enable_filters = api.filter.toggle + api.tree.toggle_gitignore_filter = api.filter.git.ignored.toggle + api.tree.toggle_git_clean_filter = api.filter.git.clean.toggle + api.tree.toggle_no_buffer_filter = api.filter.no_buffer.toggle + api.tree.toggle_custom_filter = api.filter.custom.toggle + api.tree.toggle_hidden_filter = api.filter.dotfiles.toggle + api.tree.toggle_no_bookmark_filter = api.filter.no_bookmark.toggle + + api.diagnostics = api.diagnostics or {} + api.diagnostics.hi_test = api.health.hi_test + + api.decorator.UserDecorator = api.Decorator +end + return M diff --git a/lua/nvim-tree/marks/init.lua b/lua/nvim-tree/marks/init.lua index 7394b3044e0..abe67448908 100644 --- a/lua/nvim-tree/marks/init.lua +++ b/lua/nvim-tree/marks/init.lua @@ -58,7 +58,7 @@ local function load_bookmarks(opts) return {} end ----@class (exact) Marks: Class +---@class (exact) Marks: nvim_tree.Class ---@field private explorer Explorer ---@field private marks table by absolute path local Marks = Class:extend() diff --git a/lua/nvim-tree/node/directory-link.lua b/lua/nvim-tree/node/directory-link.lua index 6d503ad6d40..8ca9714bae7 100644 --- a/lua/nvim-tree/node/directory-link.lua +++ b/lua/nvim-tree/node/directory-link.lua @@ -38,7 +38,7 @@ function DirectoryLinkNode:update_git_status(parent_ignored, project) self.git_status = git_utils.git_status_dir(parent_ignored, project, self.link_to, self.absolute_path) end ----@return HighlightedString name +---@return nvim_tree.api.highlighted_string name function DirectoryLinkNode:highlighted_icon() if not self.explorer.opts.renderer.icons.show.folder then return self:highlighted_icon_empty() @@ -58,7 +58,7 @@ function DirectoryLinkNode:highlighted_icon() end ---Maybe override name with arrow ----@return HighlightedString name +---@return nvim_tree.api.highlighted_string name function DirectoryLinkNode:highlighted_name() local name = DirectoryNode.highlighted_name(self) diff --git a/lua/nvim-tree/node/directory.lua b/lua/nvim-tree/node/directory.lua index d53718085f9..8199da67e98 100644 --- a/lua/nvim-tree/node/directory.lua +++ b/lua/nvim-tree/node/directory.lua @@ -198,7 +198,7 @@ function DirectoryNode:expand_or_collapse(toggle_group) self.explorer.renderer:draw() end ----@return HighlightedString icon +---@return nvim_tree.api.highlighted_string icon function DirectoryNode:highlighted_icon() if not self.explorer.opts.renderer.icons.show.folder then return self:highlighted_icon_empty() @@ -243,7 +243,7 @@ function DirectoryNode:highlighted_icon() return { str = str, hl = { hl } } end ----@return HighlightedString icon +---@return nvim_tree.api.highlighted_string icon function DirectoryNode:highlighted_name() local str, hl diff --git a/lua/nvim-tree/node/file-link.lua b/lua/nvim-tree/node/file-link.lua index 6cb83e0343a..7bb2127b519 100644 --- a/lua/nvim-tree/node/file-link.lua +++ b/lua/nvim-tree/node/file-link.lua @@ -31,7 +31,7 @@ function FileLinkNode:update_git_status(parent_ignored, project) self.git_status = git_utils.git_status_file(parent_ignored, project, self.link_to, self.absolute_path) end ----@return HighlightedString icon +---@return nvim_tree.api.highlighted_string icon function FileLinkNode:highlighted_icon() if not self.explorer.opts.renderer.icons.show.file then return self:highlighted_icon_empty() @@ -46,7 +46,7 @@ function FileLinkNode:highlighted_icon() return { str = str, hl = { hl } } end ----@return HighlightedString name +---@return nvim_tree.api.highlighted_string name function FileLinkNode:highlighted_name() local str = self.name if self.explorer.opts.renderer.symlink_destination then diff --git a/lua/nvim-tree/node/file.lua b/lua/nvim-tree/node/file.lua index bba1621e21b..a0b012cb048 100644 --- a/lua/nvim-tree/node/file.lua +++ b/lua/nvim-tree/node/file.lua @@ -50,7 +50,7 @@ function FileNode:get_git_xy() return self.git_status.file and { self.git_status.file } end ----@return HighlightedString icon +---@return nvim_tree.api.highlighted_string icon function FileNode:highlighted_icon() if not self.explorer.opts.renderer.icons.show.file then return self:highlighted_icon_empty() @@ -79,7 +79,7 @@ function FileNode:highlighted_icon() return { str = str, hl = { hl } } end ----@return HighlightedString name +---@return nvim_tree.api.highlighted_string name function FileNode:highlighted_name() local hl if vim.tbl_contains(self.explorer.opts.renderer.special_files, self.absolute_path) or vim.tbl_contains(self.explorer.opts.renderer.special_files, self.name) then diff --git a/lua/nvim-tree/node/init.lua b/lua/nvim-tree/node/init.lua index 5aaf4fb094a..61fe6178959 100644 --- a/lua/nvim-tree/node/init.lua +++ b/lua/nvim-tree/node/init.lua @@ -1,7 +1,7 @@ local Class = require("nvim-tree.classic") ---Abstract Node class. ----@class (exact) Node: Class +---@class (exact) Node: nvim_tree.Class ---@field uid_node number vim.loop.hrtime() at construction time ---@field type "file" | "directory" | "link" uv.fs_stat.result.type ---@field explorer Explorer @@ -93,28 +93,28 @@ end ---Empty highlighted icon ---@protected ----@return HighlightedString icon +---@return nvim_tree.api.highlighted_string icon function Node:highlighted_icon_empty() return { str = "", hl = {} } end ---Highlighted icon for the node ---Empty for base Node ----@return HighlightedString icon +---@return nvim_tree.api.highlighted_string icon function Node:highlighted_icon() return self:highlighted_icon_empty() end ---Empty highlighted name ---@protected ----@return HighlightedString name +---@return nvim_tree.api.highlighted_string name function Node:highlighted_name_empty() return { str = "", hl = {} } end ---Highlighted name for the node ---Empty for base Node ----@return HighlightedString name +---@return nvim_tree.api.highlighted_string name function Node:highlighted_name() return self:highlighted_name_empty() end diff --git a/lua/nvim-tree/node/link.lua b/lua/nvim-tree/node/link.lua index c3bc164b912..a59e978862b 100644 --- a/lua/nvim-tree/node/link.lua +++ b/lua/nvim-tree/node/link.lua @@ -1,6 +1,6 @@ local Class = require("nvim-tree.classic") ----@class (exact) LinkNode: Class +---@class (exact) LinkNode: nvim_tree.Class ---@field link_to string ---@field fs_stat_target uv.fs_stat.result local LinkNode = Class:extend() diff --git a/lua/nvim-tree/renderer/builder.lua b/lua/nvim-tree/renderer/builder.lua index 819660e5306..be924ce5870 100644 --- a/lua/nvim-tree/renderer/builder.lua +++ b/lua/nvim-tree/renderer/builder.lua @@ -14,14 +14,13 @@ local GitDecorator = require("nvim-tree.renderer.decorator.git") local HiddenDecorator = require("nvim-tree.renderer.decorator.hidden") local ModifiedDecorator = require("nvim-tree.renderer.decorator.modified") local OpenDecorator = require("nvim-tree.renderer.decorator.opened") -local UserDecorator = require("nvim-tree.renderer.decorator.user") +local Decorator = require("nvim-tree.renderer.decorator") +local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") local pad = require("nvim-tree.renderer.components.padding") ----@alias HighlightedString nvim_tree.api.HighlightedString - -- Builtin Decorators ----@type table +---@type table local BUILTIN_DECORATORS = { Git = GitDecorator, Open = OpenDecorator, @@ -74,11 +73,11 @@ function Builder:new(args) -- instantiate all the builtin and user decorator instances local builtin, user for _, d in ipairs(self.explorer.opts.renderer.decorators) do - ---@type Decorator + ---@type BuiltinDecorator builtin = BUILTIN_DECORATORS[d] - ---@type UserDecorator - user = type(d) == "table" and type(d.as) == "function" and d:as(UserDecorator) + ---@type Decorator + user = type(d) == "table" and type(d.as) == "function" and d:as(Decorator) if builtin then table.insert(self.decorators, builtin({ explorer = self.explorer })) @@ -106,7 +105,7 @@ function Builder:insert_highlight(groups, start, end_) end ---@private ----@param highlighted_strings HighlightedString[] +---@param highlighted_strings nvim_tree.api.highlighted_string[] ---@return string function Builder:unwrap_highlighted_strings(highlighted_strings) if not highlighted_strings then @@ -126,12 +125,12 @@ function Builder:unwrap_highlighted_strings(highlighted_strings) end ---@private ----@param indent_markers HighlightedString[] ----@param arrows HighlightedString[]|nil ----@param icon HighlightedString ----@param name HighlightedString ----@param node table ----@return HighlightedString[] +---@param indent_markers nvim_tree.api.highlighted_string[] +---@param arrows? nvim_tree.api.highlighted_string[] +---@param icon nvim_tree.api.highlighted_string +---@param name nvim_tree.api.highlighted_string +---@param node Node +---@return nvim_tree.api.highlighted_string[] function Builder:format_line(indent_markers, arrows, icon, name, node) local added_len = 0 local function add_to_end(t1, t2) @@ -153,25 +152,40 @@ function Builder:format_line(indent_markers, arrows, icon, name, node) end end - -- use the api node for user decorators - local api_node = self.api_nodes and self.api_nodes[node.uid_node] --[[@as Node]] + local api_node = self.api_nodes and self.api_nodes[node.uid_node] + local b local line = { indent_markers, arrows } add_to_end(line, { icon }) for _, d in ipairs(self.decorators) do - add_to_end(line, d:icons_before(not d:is(UserDecorator) and node or api_node)) + b = d:as(BuiltinDecorator) + if b then + add_to_end(line, b:icons_before(node)) + elseif api_node then + add_to_end(line, d:icons_before(api_node)) + end end add_to_end(line, { name }) for _, d in ipairs(self.decorators) do - add_to_end(line, d:icons_after(not d:is(UserDecorator) and node or api_node)) + b = d:as(BuiltinDecorator) + if b then + add_to_end(line, b:icons_after(node)) + elseif api_node then + add_to_end(line, d:icons_after(api_node)) + end end local rights = {} for _, d in ipairs(self.decorators) do - add_to_end(rights, d:icons_right_align(not d:is(UserDecorator) and node or api_node)) + b = d:as(BuiltinDecorator) + if b then + add_to_end(line, b:icons_right_align(node)) + elseif api_node then + add_to_end(line, d:icons_right_align(api_node)) + end end if #rights > 0 then self.extmarks[self.index] = rights @@ -183,14 +197,20 @@ end ---@private ---@param node Node function Builder:build_signs(node) - -- use the api node for user decorators - local api_node = self.api_nodes and self.api_nodes[node.uid_node] --[[@as Node]] + local api_node = self.api_nodes and self.api_nodes[node.uid_node] -- first in priority order - local d, sign_name + local d, b, sign_name for i = #self.decorators, 1, -1 do d = self.decorators[i] - sign_name = d:sign_name(not d:is(UserDecorator) and node or api_node) + + b = d:as(BuiltinDecorator) + if b then + sign_name = b:sign_name(node) + elseif api_node then + sign_name = d:sign_name(api_node) + end + if sign_name then self.signs[self.index] = sign_name break @@ -231,11 +251,10 @@ end ---A highlight group is always calculated and upserted for the case of highlights changing. ---@private ---@param node Node ----@return HighlightedString icon ----@return HighlightedString name +---@return nvim_tree.api.highlighted_string icon +---@return nvim_tree.api.highlighted_string name function Builder:icon_name_decorated(node) - -- use the api node for user decorators - local api_node = self.api_nodes and self.api_nodes[node.uid_node] --[[@as Node]] + local api_node = self.api_nodes and self.api_nodes[node.uid_node] -- base case local icon = node:highlighted_icon() @@ -245,11 +264,17 @@ function Builder:icon_name_decorated(node) local icon_groups = {} local name_groups = {} local hl_icon, hl_name + local b for _, d in ipairs(self.decorators) do - -- maybe overridde icon - icon = d:icon_node((not d:is(UserDecorator) and node or api_node)) or icon - - hl_icon, hl_name = d:highlight_group_icon_name((not d:is(UserDecorator) and node or api_node)) + -- maybe override icon + b = d:as(BuiltinDecorator) + if b then + icon = b:icon_node(node) or icon + hl_icon, hl_name = b:highlight_group_icon_name(node) + elseif api_node then + icon = d:icon_node(api_node) or icon + hl_icon, hl_name = d:highlight_group_icon_name(api_node) + end table.insert(icon_groups, hl_icon) table.insert(name_groups, hl_name) diff --git a/lua/nvim-tree/renderer/components/padding.lua b/lua/nvim-tree/renderer/components/padding.lua index a33525cc437..be84ae0b9de 100644 --- a/lua/nvim-tree/renderer/components/padding.lua +++ b/lua/nvim-tree/renderer/components/padding.lua @@ -64,7 +64,7 @@ end ---@param node Node ---@param markers table ---@param early_stop integer? ----@return HighlightedString +---@return nvim_tree.api.highlighted_string function M.get_indent_markers(depth, idx, nodes_number, node, markers, early_stop) local str = "" @@ -83,7 +83,7 @@ function M.get_indent_markers(depth, idx, nodes_number, node, markers, early_sto end ---@param node Node ----@return HighlightedString[]|nil +---@return nvim_tree.api.highlighted_string[]? function M.get_arrows(node) if not M.config.icons.show.folder_arrow then return diff --git a/lua/nvim-tree/renderer/decorator/bookmarks.lua b/lua/nvim-tree/renderer/decorator/bookmarks.lua index c661748ef21..cc9da51e27b 100644 --- a/lua/nvim-tree/renderer/decorator/bookmarks.lua +++ b/lua/nvim-tree/renderer/decorator/bookmarks.lua @@ -1,17 +1,16 @@ -local Decorator = require("nvim-tree.renderer.decorator") +local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") ----@class (exact) BookmarkDecorator: Decorator ----@field private explorer Explorer ----@field private icon HighlightedString? -local BookmarkDecorator = Decorator:extend() +---@class (exact) BookmarkDecorator: BuiltinDecorator +---@field private icon nvim_tree.api.highlighted_string? +local BookmarkDecorator = BuiltinDecorator:extend() ---@class BookmarkDecorator ----@overload fun(args: DecoratorArgs): BookmarkDecorator +---@overload fun(args: BuiltinDecoratorArgs): BookmarkDecorator ---@protected ----@param args DecoratorArgs +---@param args BuiltinDecoratorArgs function BookmarkDecorator:new(args) - self.explorer = args.explorer + BookmarkDecorator.super.new(self, args) self.enabled = true self.highlight_range = self.explorer.opts.renderer.highlight_bookmarks or "none" @@ -28,7 +27,7 @@ end ---Bookmark icon: renderer.icons.show.bookmarks and node is marked ---@param node Node ----@return HighlightedString[]? icons +---@return nvim_tree.api.highlighted_string[]? icons function BookmarkDecorator:icons(node) if self.explorer.marks:get(node) then return { self.icon } diff --git a/lua/nvim-tree/renderer/decorator/builtin.lua b/lua/nvim-tree/renderer/decorator/builtin.lua new file mode 100644 index 00000000000..e1ff61300b7 --- /dev/null +++ b/lua/nvim-tree/renderer/decorator/builtin.lua @@ -0,0 +1,29 @@ +local Decorator = require("nvim-tree.renderer.decorator") + +---Abstract builtin decorator +---Overrides all methods to use a Node instead of nvim_tree.api.Node as we don't have generics. +--- +---@class (exact) BuiltinDecorator: Decorator +--- +---@field protected explorer Explorer +--- +---@field icon_node fun(self: BuiltinDecorator, node: Node): nvim_tree.api.highlighted_string? +---@field icons fun(self: BuiltinDecorator, node: Node): nvim_tree.api.highlighted_string? +---@field highlight_group fun(self: BuiltinDecorator, node: Node): string? +---@field highlight_group_icon_name fun(self: BuiltinDecorator, node: Node): string?, string? +---@field sign_name fun(self: BuiltinDecorator, node: Node): string? +---@field icons_before fun(self: BuiltinDecorator, node: Node): nvim_tree.api.highlighted_string[]? +---@field icons_after fun(self: BuiltinDecorator, node: Node): nvim_tree.api.highlighted_string[]? +---@field icons_right_align fun(self: BuiltinDecorator, node: Node): nvim_tree.api.highlighted_string[]? +local BuiltinDecorator = Decorator:extend() + +---@class (exact) BuiltinDecoratorArgs +---@field explorer Explorer + +---@protected +---@param args BuiltinDecoratorArgs +function BuiltinDecorator:new(args) + self.explorer = args.explorer +end + +return BuiltinDecorator diff --git a/lua/nvim-tree/renderer/decorator/copied.lua b/lua/nvim-tree/renderer/decorator/copied.lua index e930f14ee7f..581ce753dfc 100644 --- a/lua/nvim-tree/renderer/decorator/copied.lua +++ b/lua/nvim-tree/renderer/decorator/copied.lua @@ -1,16 +1,15 @@ -local Decorator = require("nvim-tree.renderer.decorator") +local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") ----@class (exact) CopiedDecorator: Decorator ----@field private explorer Explorer -local CopiedDecorator = Decorator:extend() +---@class (exact) CopiedDecorator: BuiltinDecorator +local CopiedDecorator = BuiltinDecorator:extend() ---@class CopiedDecorator ----@overload fun(args: DecoratorArgs): CopiedDecorator +---@overload fun(args: BuiltinDecoratorArgs): CopiedDecorator ---@protected ----@param args DecoratorArgs +---@param args BuiltinDecoratorArgs function CopiedDecorator:new(args) - self.explorer = args.explorer + CopiedDecorator.super.new(self, args) self.enabled = true self.highlight_range = self.explorer.opts.renderer.highlight_clipboard or "none" diff --git a/lua/nvim-tree/renderer/decorator/cut.lua b/lua/nvim-tree/renderer/decorator/cut.lua index 8a212da5d68..565e043165c 100644 --- a/lua/nvim-tree/renderer/decorator/cut.lua +++ b/lua/nvim-tree/renderer/decorator/cut.lua @@ -1,16 +1,15 @@ -local Decorator = require("nvim-tree.renderer.decorator") +local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") ----@class (exact) CutDecorator: Decorator ----@field private explorer Explorer -local CutDecorator = Decorator:extend() +---@class (exact) CutDecorator: BuiltinDecorator +local CutDecorator = BuiltinDecorator:extend() ---@class CutDecorator ----@overload fun(args: DecoratorArgs): CutDecorator +---@overload fun(args: BuiltinDecoratorArgs): CutDecorator ---@protected ----@param args DecoratorArgs +---@param args BuiltinDecoratorArgs function CutDecorator:new(args) - self.explorer = args.explorer + CutDecorator.super.new(self, args) self.enabled = true self.highlight_range = self.explorer.opts.renderer.highlight_clipboard or "none" diff --git a/lua/nvim-tree/renderer/decorator/diagnostics.lua b/lua/nvim-tree/renderer/decorator/diagnostics.lua index 56598ef9418..c859e767820 100644 --- a/lua/nvim-tree/renderer/decorator/diagnostics.lua +++ b/lua/nvim-tree/renderer/decorator/diagnostics.lua @@ -1,6 +1,6 @@ local diagnostics = require("nvim-tree.diagnostics") -local Decorator = require("nvim-tree.renderer.decorator") +local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") local DirectoryNode = require("nvim-tree.node.directory") -- highlight groups by severity @@ -30,18 +30,17 @@ local ICON_KEYS = { ["hint"] = vim.diagnostic.severity.HINT, } ----@class (exact) DiagnosticsDecorator: Decorator ----@field private explorer Explorer ----@field private diag_icons HighlightedString[]? -local DiagnosticsDecorator = Decorator:extend() +---@class (exact) DiagnosticsDecorator: BuiltinDecorator +---@field private diag_icons nvim_tree.api.highlighted_string[]? +local DiagnosticsDecorator = BuiltinDecorator:extend() ---@class DiagnosticsDecorator ----@overload fun(args: DecoratorArgs): DiagnosticsDecorator +---@overload fun(args: BuiltinDecoratorArgs): DiagnosticsDecorator ---@protected ----@param args DecoratorArgs +---@param args BuiltinDecoratorArgs function DiagnosticsDecorator:new(args) - self.explorer = args.explorer + DiagnosticsDecorator.super.new(self, args) self.enabled = true self.highlight_range = self.explorer.opts.renderer.highlight_diagnostics or "none" @@ -73,7 +72,7 @@ end ---Diagnostic icon: diagnostics.enable, renderer.icons.show.diagnostics and node has status ---@param node Node ----@return HighlightedString[]? icons +---@return nvim_tree.api.highlighted_string[]? icons function DiagnosticsDecorator:icons(node) if node and self.diag_icons then local diag_status = diagnostics.get_diag_status(node) diff --git a/lua/nvim-tree/renderer/decorator/git.lua b/lua/nvim-tree/renderer/decorator/git.lua index c117b16959d..8b473150500 100644 --- a/lua/nvim-tree/renderer/decorator/git.lua +++ b/lua/nvim-tree/renderer/decorator/git.lua @@ -1,9 +1,9 @@ local notify = require("nvim-tree.notify") -local Decorator = require("nvim-tree.renderer.decorator") +local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") local DirectoryNode = require("nvim-tree.node.directory") ----@class (exact) GitHighlightedString: nvim_tree.api.HighlightedString +---@class (exact) GitHighlightedString: nvim_tree.api.highlighted_string ---@field ord number decreasing priority ---@alias GitStatusStrings "deleted" | "ignored" | "renamed" | "staged" | "unmerged" | "unstaged" | "untracked" @@ -12,21 +12,20 @@ local DirectoryNode = require("nvim-tree.node.directory") ---@alias GitIconsByXY table porcelain status ---@alias GitGlyphsByStatus table from opts ----@class (exact) GitDecorator: Decorator ----@field private explorer Explorer +---@class (exact) GitDecorator: BuiltinDecorator ---@field private file_hl_by_xy table? ---@field private folder_hl_by_xy table? ---@field private icons_by_status GitIconsByStatus? ---@field private icons_by_xy GitIconsByXY? -local GitDecorator = Decorator:extend() +local GitDecorator = BuiltinDecorator:extend() ---@class GitDecorator ----@overload fun(args: DecoratorArgs): GitDecorator +---@overload fun(args: BuiltinDecoratorArgs): GitDecorator ---@protected ----@param args DecoratorArgs +---@param args BuiltinDecoratorArgs function GitDecorator:new(args) - self.explorer = args.explorer + GitDecorator.super.new(self, args) self.enabled = self.explorer.opts.git.enable self.highlight_range = self.explorer.opts.renderer.highlight_git or "none" @@ -142,7 +141,7 @@ end ---Git icons: git.enable, renderer.icons.show.git and node has status ---@param node Node ----@return HighlightedString[]? icons +---@return nvim_tree.api.highlighted_string[]? icons function GitDecorator:icons(node) if not self.icons_by_xy then return nil diff --git a/lua/nvim-tree/renderer/decorator/hidden.lua b/lua/nvim-tree/renderer/decorator/hidden.lua index 87168ceb82b..f25a7f35f8f 100644 --- a/lua/nvim-tree/renderer/decorator/hidden.lua +++ b/lua/nvim-tree/renderer/decorator/hidden.lua @@ -1,18 +1,17 @@ -local Decorator = require("nvim-tree.renderer.decorator") +local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") local DirectoryNode = require("nvim-tree.node.directory") ----@class (exact) HiddenDecorator: Decorator ----@field private explorer Explorer ----@field private icon HighlightedString? -local HiddenDecorator = Decorator:extend() +---@class (exact) HiddenDecorator: BuiltinDecorator +---@field private icon nvim_tree.api.highlighted_string? +local HiddenDecorator = BuiltinDecorator:extend() ---@class HiddenDecorator ----@overload fun(args: DecoratorArgs): HiddenDecorator +---@overload fun(args: BuiltinDecoratorArgs): HiddenDecorator ---@protected ----@param args DecoratorArgs +---@param args BuiltinDecoratorArgs function HiddenDecorator:new(args) - self.explorer = args.explorer + HiddenDecorator.super.new(self, args) self.enabled = true self.highlight_range = self.explorer.opts.renderer.highlight_hidden or "none" @@ -29,7 +28,7 @@ end ---Hidden icon: renderer.icons.show.hidden and node starts with `.` (dotfile). ---@param node Node ----@return HighlightedString[]? icons +---@return nvim_tree.api.highlighted_string[]? icons function HiddenDecorator:icons(node) if node:is_dotfile() then return { self.icon } diff --git a/lua/nvim-tree/renderer/decorator/init.lua b/lua/nvim-tree/renderer/decorator/init.lua index cc7ab0ad305..075156772ee 100644 --- a/lua/nvim-tree/renderer/decorator/init.lua +++ b/lua/nvim-tree/renderer/decorator/init.lua @@ -1,40 +1,13 @@ -local Class = require("nvim-tree.classic") - ----Abstract Decorator ----@class (exact) Decorator: Class ----@field protected enabled boolean ----@field protected highlight_range nvim_tree.api.decorator.HighlightRange ----@field protected icon_placement nvim_tree.api.decorator.IconPlacement -local Decorator = Class:extend() - ----@class (exact) DecoratorArgs ----@field explorer Explorer - ----Abstract icon override, optionally implemented ----@param node Node ----@return HighlightedString? icon_node -function Decorator:icon_node(node) - return self:nop(node) -end - ----Abstract icons, optionally implemented ----@protected ----@param node Node ----@return HighlightedString[]? icons -function Decorator:icons(node) - self:nop(node) -end +local DecoratorInterface = require("nvim-tree._meta.api.decorator") ----Abstract highlight group, optionally implemented ----@protected ----@param node Node ----@return string? highlight_group -function Decorator:highlight_group(node) - self:nop(node) -end +--- +---Abstract decorator +--- +---@class (exact) Decorator: nvim_tree.api.Decorator +local Decorator = DecoratorInterface:extend() ---Maybe highlight groups for icon and name ----@param node Node +---@param node nvim_tree.api.Node ---@return string? icon highlight group ---@return string? name highlight group function Decorator:highlight_group_icon_name(node) @@ -55,7 +28,7 @@ function Decorator:highlight_group_icon_name(node) end ---Maybe icon sign ----@param node Node +---@param node nvim_tree.api.Node ---@return string? name function Decorator:sign_name(node) if not self.enabled or self.icon_placement ~= "signcolumn" then @@ -69,8 +42,8 @@ function Decorator:sign_name(node) end ---Icons when "before" ----@param node Node ----@return HighlightedString[]? icons +---@param node nvim_tree.api.Node +---@return nvim_tree.api.highlighted_string[]? icons function Decorator:icons_before(node) if not self.enabled or self.icon_placement ~= "before" then return @@ -80,8 +53,8 @@ function Decorator:icons_before(node) end ---Icons when "after" ----@param node Node ----@return HighlightedString[]? icons +---@param node nvim_tree.api.Node +---@return nvim_tree.api.highlighted_string[]? icons function Decorator:icons_after(node) if not self.enabled or self.icon_placement ~= "after" then return @@ -91,8 +64,8 @@ function Decorator:icons_after(node) end ---Icons when "right_align" ----@param node Node ----@return HighlightedString[]? icons +---@param node nvim_tree.api.Node +---@return nvim_tree.api.highlighted_string[]? icons function Decorator:icons_right_align(node) if not self.enabled or self.icon_placement ~= "right_align" then return @@ -103,7 +76,7 @@ end ---Define a sign ---@protected ----@param icon HighlightedString? +---@param icon nvim_tree.api.highlighted_string? function Decorator:define_sign(icon) if icon and #icon.hl > 0 then local name = icon.hl[1] @@ -129,4 +102,5 @@ function Decorator:define_sign(icon) end end +---@type Decorator return Decorator diff --git a/lua/nvim-tree/renderer/decorator/modified.lua b/lua/nvim-tree/renderer/decorator/modified.lua index c182e300afc..5715a7c76f5 100644 --- a/lua/nvim-tree/renderer/decorator/modified.lua +++ b/lua/nvim-tree/renderer/decorator/modified.lua @@ -1,20 +1,19 @@ local buffers = require("nvim-tree.buffers") -local Decorator = require("nvim-tree.renderer.decorator") +local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") local DirectoryNode = require("nvim-tree.node.directory") ----@class (exact) ModifiedDecorator: Decorator ----@field private explorer Explorer ----@field private icon HighlightedString? -local ModifiedDecorator = Decorator:extend() +---@class (exact) ModifiedDecorator: BuiltinDecorator +---@field private icon nvim_tree.api.highlighted_string? +local ModifiedDecorator = BuiltinDecorator:extend() ---@class ModifiedDecorator ----@overload fun(args: DecoratorArgs): ModifiedDecorator +---@overload fun(args: BuiltinDecoratorArgs): ModifiedDecorator ---@protected ----@param args DecoratorArgs +---@param args BuiltinDecoratorArgs function ModifiedDecorator:new(args) - self.explorer = args.explorer + ModifiedDecorator.super.new(self, args) self.enabled = true self.highlight_range = self.explorer.opts.renderer.highlight_modified or "none" @@ -31,7 +30,7 @@ end ---Modified icon: modified.enable, renderer.icons.show.modified and node is modified ---@param node Node ----@return HighlightedString[]? icons +---@return nvim_tree.api.highlighted_string[]? icons function ModifiedDecorator:icons(node) if buffers.is_modified(node) then return { self.icon } diff --git a/lua/nvim-tree/renderer/decorator/opened.lua b/lua/nvim-tree/renderer/decorator/opened.lua index 240dce4948a..d9722c20013 100644 --- a/lua/nvim-tree/renderer/decorator/opened.lua +++ b/lua/nvim-tree/renderer/decorator/opened.lua @@ -1,19 +1,18 @@ local buffers = require("nvim-tree.buffers") -local Decorator = require("nvim-tree.renderer.decorator") +local BuiltinDecorator = require("nvim-tree.renderer.decorator.builtin") ----@class (exact) OpenDecorator: Decorator ----@field private explorer Explorer ----@field private icon HighlightedString|nil -local OpenDecorator = Decorator:extend() +---@class (exact) OpenDecorator: BuiltinDecorator +---@field private icon? nvim_tree.api.highlighted_string +local OpenDecorator = BuiltinDecorator:extend() ---@class OpenDecorator ----@overload fun(args: DecoratorArgs): OpenDecorator +---@overload fun(args: BuiltinDecoratorArgs): OpenDecorator ---@protected ----@param args DecoratorArgs +---@param args BuiltinDecoratorArgs function OpenDecorator:new(args) - self.explorer = args.explorer + OpenDecorator.super.new(self, args) self.enabled = true self.highlight_range = self.explorer.opts.renderer.highlight_opened_files or "none" diff --git a/lua/nvim-tree/renderer/decorator/user.lua b/lua/nvim-tree/renderer/decorator/user.lua deleted file mode 100644 index df55f543936..00000000000 --- a/lua/nvim-tree/renderer/decorator/user.lua +++ /dev/null @@ -1,7 +0,0 @@ -local Decorator = require("nvim-tree.renderer.decorator") - ----Exposed as nvim_tree.api.decorator.UserDecorator ----@class (exact) UserDecorator: Decorator -local UserDecorator = Decorator:extend() - -return UserDecorator diff --git a/lua/nvim-tree/renderer/init.lua b/lua/nvim-tree/renderer/init.lua index 30af27e81b9..e7b98e6cd6b 100644 --- a/lua/nvim-tree/renderer/init.lua +++ b/lua/nvim-tree/renderer/init.lua @@ -13,7 +13,7 @@ local namespace_virtual_lines_id = vim.api.nvim_create_namespace("NvimTreeVirtua ---@alias HighlightRangeArgs { higroup:string, start:integer[], finish:integer[] } named arguments for vim.hl.range ----@class (exact) Renderer: Class +---@class (exact) Renderer: nvim_tree.Class ---@field explorer Explorer local Renderer = Class:extend() diff --git a/lua/nvim-tree/watcher.lua b/lua/nvim-tree/watcher.lua index fbedc3b9e86..ecae249de4c 100644 --- a/lua/nvim-tree/watcher.lua +++ b/lua/nvim-tree/watcher.lua @@ -21,7 +21,7 @@ local M = { ---@type Event[] local events = {} ----@class (exact) Event: Class +---@class (exact) Event: nvim_tree.Class ---@field destroyed boolean ---@field private path string ---@field private fs_event uv.uv_fs_event_t? @@ -155,7 +155,7 @@ end ---@type Watcher[] local watchers = {} ----@class (exact) Watcher: Class +---@class (exact) Watcher: nvim_tree.Class ---@field data table user data ---@field destroyed boolean ---@field private path string diff --git a/scripts/vimdoc.sh b/scripts/vimdoc.sh index 398cc57562d..e49987f8866 100755 --- a/scripts/vimdoc.sh +++ b/scripts/vimdoc.sh @@ -58,6 +58,7 @@ cleanup() { # remove our config rm -fv "${DIR_NVIM_SRC}/src/gen/vimdoc_config.lua" + rm -fv "${DIR_NVIM_SRC}/runtime/lua/placeholder.lua" # remove generated help rm -fv "${DIR_NVIM_SRC}/runtime/doc/nvim-tree-lua.txt" @@ -85,6 +86,9 @@ if [ "${1}" = "doc" ]; then cp "${DIR_NVIM_SRC}/src/gen/gen_vimdoc.lua" "${DIR_NVIM_SRC}/src/gen/gen_vimdoc.lua.org" sed -i -E 's/spairs\(config\)/spairs\(require("gen.vimdoc_config")\)/g' "${DIR_NVIM_SRC}/src/gen/gen_vimdoc.lua" + # leave a generic placeholder to bridge between nvim.gen_vimdoc.Config + echo "---@brief placeholder" > "${DIR_NVIM_SRC}/runtime/lua/placeholder.lua" + # copy our config cp -v "scripts/vimdoc_config.lua" "${DIR_NVIM_SRC}/src/gen" fi diff --git a/scripts/vimdoc_config.lua b/scripts/vimdoc_config.lua index ec19468ad03..07d47eec2b8 100644 --- a/scripts/vimdoc_config.lua +++ b/scripts/vimdoc_config.lua @@ -8,55 +8,65 @@ ---@class (exact) Src ---@field helptag string must be globally unique ---@field section string arbitrary ----@field path string relative to root +---@field path string relative to cwd -local pre = "runtime/lua/nvim_tree/" +local base = "runtime/lua/nvim_tree/" +local placeholder = "runtime/lua/placeholder.lua" ---@type Src[] local srcs_config = { - { helptag = "nvim-tree-config", section = "Config", path = pre .. "_meta/config.lua", }, - - { helptag = "nvim-tree-config-sort", section = "Config: sort", path = pre .. "_meta/config/sort.lua", }, - { helptag = "nvim-tree-config-view", section = "Config: view", path = pre .. "_meta/config/view.lua", }, - { helptag = "nvim-tree-config-renderer", section = "Config: renderer", path = pre .. "_meta/config/renderer.lua", }, - { helptag = "nvim-tree-config-hijack-directories", section = "Config: hijack_directories", path = pre .. "_meta/config/hijack_directories.lua", }, - { helptag = "nvim-tree-config-update-focused-file", section = "Config: update_focused_file", path = pre .. "_meta/config/update_focused_file.lua", }, - { helptag = "nvim-tree-config-system-open", section = "Config: system_open", path = pre .. "_meta/config/system_open.lua", }, - { helptag = "nvim-tree-config-git", section = "Config: git", path = pre .. "_meta/config/git.lua", }, - { helptag = "nvim-tree-config-diagnostics", section = "Config: diagnostics", path = pre .. "_meta/config/diagnostics.lua", }, - { helptag = "nvim-tree-config-modified", section = "Config: modified", path = pre .. "_meta/config/modified.lua", }, - { helptag = "nvim-tree-config-filters", section = "Config: filters", path = pre .. "_meta/config/filters.lua", }, - { helptag = "nvim-tree-config-live-filter", section = "Config: live_filter", path = pre .. "_meta/config/live_filter.lua", }, - { helptag = "nvim-tree-config-filesystem-watchers", section = "Config: filesystem_watchers", path = pre .. "_meta/config/filesystem_watchers.lua", }, - { helptag = "nvim-tree-config-actions", section = "Config: actions", path = pre .. "_meta/config/actions.lua", }, - { helptag = "nvim-tree-config-trash", section = "Config: trash", path = pre .. "_meta/config/trash.lua", }, - { helptag = "nvim-tree-config-tab", section = "Config: tab", path = pre .. "_meta/config/tab.lua", }, - { helptag = "nvim-tree-config-notify", section = "Config: notify", path = pre .. "_meta/config/notify.lua", }, - { helptag = "nvim-tree-config-bookmarks", section = "Config: bookmarks", path = pre .. "_meta/config/bookmarks.lua", }, - { helptag = "nvim-tree-config-help", section = "Config: help", path = pre .. "_meta/config/help.lua", }, - { helptag = "nvim-tree-config-ui", section = "Config: ui", path = pre .. "_meta/config/ui.lua", }, - { helptag = "nvim-tree-config-experimental", section = "Config: experimental", path = pre .. "_meta/config/experimental.lua", }, - { helptag = "nvim-tree-config-log", section = "Config: log", path = pre .. "_meta/config/log.lua", }, - - { helptag = "nvim-tree-config-default", section = "Config: Default", path = pre .. "_meta/config/default.lua", }, - - { helptag = "nvim-tree-api", section = "placeholder for next Config", path = pre .. "api.lua", }, + { helptag = "nvim-tree-config", section = "Config", path = base .. "_meta/config.lua", }, + + { helptag = "nvim-tree-config-sort", section = "Config: sort", path = base .. "_meta/config/sort.lua", }, + { helptag = "nvim-tree-config-view", section = "Config: view", path = base .. "_meta/config/view.lua", }, + { helptag = "nvim-tree-config-renderer", section = "Config: renderer", path = base .. "_meta/config/renderer.lua", }, + { helptag = "nvim-tree-config-hijack-directories", section = "Config: hijack_directories", path = base .. "_meta/config/hijack_directories.lua", }, + { helptag = "nvim-tree-config-update-focused-file", section = "Config: update_focused_file", path = base .. "_meta/config/update_focused_file.lua", }, + { helptag = "nvim-tree-config-system-open", section = "Config: system_open", path = base .. "_meta/config/system_open.lua", }, + { helptag = "nvim-tree-config-git", section = "Config: git", path = base .. "_meta/config/git.lua", }, + { helptag = "nvim-tree-config-diagnostics", section = "Config: diagnostics", path = base .. "_meta/config/diagnostics.lua", }, + { helptag = "nvim-tree-config-modified", section = "Config: modified", path = base .. "_meta/config/modified.lua", }, + { helptag = "nvim-tree-config-filters", section = "Config: filters", path = base .. "_meta/config/filters.lua", }, + { helptag = "nvim-tree-config-live-filter", section = "Config: live_filter", path = base .. "_meta/config/live_filter.lua", }, + { helptag = "nvim-tree-config-filesystem-watchers", section = "Config: filesystem_watchers", path = base .. "_meta/config/filesystem_watchers.lua", }, + { helptag = "nvim-tree-config-actions", section = "Config: actions", path = base .. "_meta/config/actions.lua", }, + { helptag = "nvim-tree-config-trash", section = "Config: trash", path = base .. "_meta/config/trash.lua", }, + { helptag = "nvim-tree-config-tab", section = "Config: tab", path = base .. "_meta/config/tab.lua", }, + { helptag = "nvim-tree-config-notify", section = "Config: notify", path = base .. "_meta/config/notify.lua", }, + { helptag = "nvim-tree-config-bookmarks", section = "Config: bookmarks", path = base .. "_meta/config/bookmarks.lua", }, + { helptag = "nvim-tree-config-help", section = "Config: help", path = base .. "_meta/config/help.lua", }, + { helptag = "nvim-tree-config-ui", section = "Config: ui", path = base .. "_meta/config/ui.lua", }, + { helptag = "nvim-tree-config-experimental", section = "Config: experimental", path = base .. "_meta/config/experimental.lua", }, + { helptag = "nvim-tree-config-log", section = "Config: log", path = base .. "_meta/config/log.lua", }, + + { helptag = "nvim-tree-config-default", section = "Config: Default", path = base .. "_meta/config/default.lua", }, + + { helptag = "nvim-tree-api", section = "PLACEHOLDER", path = placeholder, }, } ---@type Src[] local srcs_api = { - { helptag = "nvim-tree-api", section = "API", path = pre .. "api.lua", }, - - { helptag = "nvim-tree-api-commands", section = "API: commands", path = pre .. "_meta/api/commands.lua", }, - { helptag = "nvim-tree-api-events", section = "API: events", path = pre .. "_meta/api/events.lua", }, - { helptag = "nvim-tree-api-filter", section = "API: filter", path = pre .. "_meta/api/filter.lua", }, - { helptag = "nvim-tree-api-fs", section = "API: fs", path = pre .. "_meta/api/fs.lua", }, - { helptag = "nvim-tree-api-git", section = "API: git", path = pre .. "_meta/api/git.lua", }, - { helptag = "nvim-tree-api-health", section = "API: health", path = pre .. "_meta/api/health.lua", }, - { helptag = "nvim-tree-api-map", section = "API: map", path = pre .. "_meta/api/map.lua", }, - { helptag = "nvim-tree-api-marks", section = "API: marks", path = pre .. "_meta/api/marks.lua", }, - { helptag = "nvim-tree-api-node", section = "API: node", path = pre .. "_meta/api/node.lua", }, - { helptag = "nvim-tree-api-tree", section = "API: tree", path = pre .. "_meta/api/tree.lua", }, + { helptag = "nvim-tree-api", section = "API", path = base .. "api.lua", }, + + { helptag = "nvim-tree-api-commands", section = "API: commands", path = base .. "_meta/api/commands.lua", }, + { helptag = "nvim-tree-api-events", section = "API: events", path = base .. "_meta/api/events.lua", }, + { helptag = "nvim-tree-api-filter", section = "API: filter", path = base .. "_meta/api/filter.lua", }, + { helptag = "nvim-tree-api-fs", section = "API: fs", path = base .. "_meta/api/fs.lua", }, + { helptag = "nvim-tree-api-git", section = "API: git", path = base .. "_meta/api/git.lua", }, + { helptag = "nvim-tree-api-health", section = "API: health", path = base .. "_meta/api/health.lua", }, + { helptag = "nvim-tree-api-map", section = "API: map", path = base .. "_meta/api/map.lua", }, + { helptag = "nvim-tree-api-marks", section = "API: marks", path = base .. "_meta/api/marks.lua", }, + { helptag = "nvim-tree-api-node", section = "API: node", path = base .. "_meta/api/node.lua", }, + { helptag = "nvim-tree-api-tree", section = "API: tree", path = base .. "_meta/api/tree.lua", }, + + { helptag = "nvim-tree-class", section = "PLACEHOLDER", path = placeholder, }, +} + +---@type Src[] +local srcs_class = { + { helptag = "nvim-tree-class", section = "Class: Class", path = base .. "classic.lua", }, + { helptag = "nvim-tree-class-decorator", section = "Class: Decorator", path = base .. "_meta/api/decorator.lua", }, + { helptag = "nvim-tree-class-decorator-example", section = "Class: Decorator example", path = base .. "_meta/api/decorator_example.lua", }, } ---Map paths to file names @@ -92,6 +102,22 @@ local function src_by_name(name, srcs) error(string.format("\n\nPath for lower, extension stripped file name='%s' not found in\nsrcs=%s\n", name, vim.inspect(srcs))) end +-- generator doesn't strip _meta +local function normalise_module(fun) + fun.module = fun.module and fun.module:gsub("._meta", "", 1) or nil +end + +---HACK +---Problem: +--- Generator generates fields for a class' methods. +--- This is a problem as method fields don't have a module and aren't transformed. +--- Method field fun only contains: classvar, desc, name and (function) type +---Solution: +--- Collect a map of "class:method" to modules when the real method passes through fn_xform +--- This works as the real method function is processed before the field method. +---@type table +local modules_by_method = {} + -- @type nvim.gen_vimdoc.Config[] return { -- Config @@ -110,23 +136,47 @@ return { section_fmt = function(name) return src_by_name(name, srcs_api).section end, helptag_fmt = function(name) return src_by_name(name, srcs_api).helptag end, - -- optional, no default xform to override fn_xform = function(fun) if (fun.module) then - -- generator doesn't strip meta - -- also cascades into fn_helptag_fmt - local module = fun.module:gsub("._meta", "", 1) + normalise_module(fun) - -- remove the API prefix from the left aligned function name - -- this will cascade into fn_helptag_fmt, which will apply the module prefix anyway - local name, replaced = fun.name:gsub("^" .. module .. "%.", "", 1) + -- remove the module prefix from the left aligned function name + -- default fn_helptag_fmt adds it back to the help tag + local replaced + fun.name, replaced = fun.name:gsub("^" .. fun.module .. "%.", "", 1) if (replaced ~= 1) then - error(string.format("\n\nfun.name='%s' does not start with _meta stripped module='%s'\nfun=%s", fun.name, module, vim.inspect(fun))) + error(string.format("\n\nfun.name='%s' does not start with module\nfun=%s", fun.name, vim.inspect(fun))) end + end + end, + }, + -- Classes + { + filename = "nvim-tree-lua.txt", + section_order = section_order(srcs_class), + files = files(srcs_class), + section_fmt = function(name) return src_by_name(name, srcs_class).section end, + helptag_fmt = function(name) return src_by_name(name, srcs_class).helptag end, + + fn_xform = function(fun) + if (fun.module) then + normalise_module(fun) - fun.module = module - fun.name = name + -- strip the class file from the module + fun.module = fun.module:gsub("%.[^%.]*$", "", 1) + + -- record the module for the method + modules_by_method[fun.classvar .. ":" .. fun.name] = fun.module end end, - } + + -- fn_helptag_fmt_common derived + -- module prepended to classes + -- module is fetched from modules_by_method when fun.module unavailable + fn_helptag_fmt = function(fun) + local fn_sfx = fun.table and "" or "()" + local module = fun.module or modules_by_method[fun.classvar .. ":" .. fun.name] + return string.format("%s.%s:%s%s", module, fun.classvar, fun.name, fn_sfx) + end, + }, }