diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 32696f10999..a3628c2f276 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -10,6 +10,7 @@ CONTENTS *nvim-tree* 2.1 Quickstart: Setup |nvim-tree-quickstart-setup| 2.2 Quickstart: Help |nvim-tree-quickstart-help| 2.3 Quickstart: Custom Mappings |nvim-tree-quickstart-custom-mappings| + 2.4 Quickstart: Highlight |nvim-tree-quickstart-highlight| 3. Commands |nvim-tree-commands| 4. Setup |nvim-tree-setup| 5. Opts |nvim-tree-opts| @@ -43,6 +44,7 @@ CONTENTS *nvim-tree* 6.7 API Marks |nvim-tree-api.marks| 6.8 API Config |nvim-tree-api.config| 6.9 API Commands |nvim-tree-api.commands| + 6.10 API Appearance |nvim-tree-api.appearance| 7. Mappings |nvim-tree-mappings| 7.1 Mappings: Default |nvim-tree-mappings-default| 8. Highlight |nvim-tree-highlight| @@ -229,6 +231,16 @@ via |nvim-tree.on_attach| e.g. > --- } < +============================================================================== + 2.4 QUICKSTART: HIGHLIGHT *nvim-tree-quickstart-highlight* + +Run |:NvimTreeHiTest| to show all the highlights that nvim-tree uses. + +They can be customised before or after setup is called and will be immediately +applied at runtime. + +See |nvim-tree-highlight| for details. + ============================================================================== 3. COMMANDS *nvim-tree-commands* @@ -323,6 +335,14 @@ via |nvim-tree.on_attach| e.g. > Calls: `api.tree.collapse_all(true)` +*:NvimTreeHiTest* + + Show nvim-tree highlight groups similar to `:so $VIMRUNTIME/syntax/hitest.vim` + + See |nvim-tree-api.appearance.hi_test()| + + Calls: `api.appearance.hi_test()` + ============================================================================== 4. SETUP *nvim-tree-setup* @@ -2070,7 +2090,7 @@ config.mappings.get_keymap_default() (table) as per |nvim_buf_get_keymap()| ============================================================================== - 6.8 API COMMANDS *nvim-tree-api.commands* + 6.9 API COMMANDS *nvim-tree-api.commands* commands.get() *nvim-tree-api.commands.get()* Retrieve all commands, see |nvim-tree-commands| @@ -2081,6 +2101,15 @@ commands.get() *nvim-tree-api.commands.get()* • {command} (function) • {opts} (table) +============================================================================== + 6.10 APPEARANCE *nvim-tree-api.appearance* + +appearance.hi_test() *nvim-tree-api.appearance.hi_test()* + Open a new buffer displaying all nvim-tree highlight groups, their link + chain and concrete definition. + + Similar to `:so $VIMRUNTIME/syntax/hitest.vim` as per |:highlight| + ============================================================================== 7. MAPPINGS *nvim-tree-mappings* @@ -2245,7 +2274,9 @@ Example |:highlight| > It is recommended to enable 'termguicolors' for the more pleasant 24-bit colours. -To view the active highlight groups run `:so $VIMRUNTIME/syntax/hitest.vim` +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-opts-renderer| precedence. diff --git a/lua/nvim-tree/api.lua b/lua/nvim-tree/api.lua index 3c85071e899..d70eb27d7d5 100644 --- a/lua/nvim-tree/api.lua +++ b/lua/nvim-tree/api.lua @@ -2,6 +2,7 @@ local lib = require "nvim-tree.lib" local view = require "nvim-tree.view" local utils = require "nvim-tree.utils" local actions = require "nvim-tree.actions" +local appearance = require "nvim-tree.appearance" local events = require "nvim-tree.events" local help = require "nvim-tree.help" local live_filter = require "nvim-tree.live-filter" @@ -38,6 +39,7 @@ local Api = { config = { mappings = {}, }, + appearance = {}, commands = {}, } @@ -244,6 +246,8 @@ Api.config.mappings.get_keymap = wrap(keymap.get_keymap) Api.config.mappings.get_keymap_default = wrap(keymap.get_keymap_default) Api.config.mappings.default_on_attach = keymap.default_on_attach +Api.appearance.hi_test = wrap(appearance.hi_test) + Api.commands.get = wrap(function() return require("nvim-tree.commands").get() end) diff --git a/lua/nvim-tree/appearance.lua b/lua/nvim-tree/appearance.lua index fd50f93ac6c..a68624311b6 100644 --- a/lua/nvim-tree/appearance.lua +++ b/lua/nvim-tree/appearance.lua @@ -1,123 +1,122 @@ local M = {} --- directly defined groups, please keep these to an absolute minimum -local DEFAULT_DEFS = { - - NvimTreeFolderIcon = "guifg=#8094b4 ctermfg=Blue", - NvimTreeWindowPicker = "guifg=#ededed guibg=#4493c8 gui=bold ctermfg=White ctermbg=Cyan", -} - --- nvim-tree default highlight group links, please attempt to keep in order with help -local DEFAULT_LINKS = { +-- All highlight groups: linked or directly defined. +-- Please add new groups to help and preserve order. +-- Please avoid directly defined groups to preserve accessibility for TUI. +local HIGHLIGHT_GROUPS = { -- Standard - NvimTreeNormal = "Normal", - NvimTreeNormalFloat = "NormalFloat", - NvimTreeNormalNC = "NvimTreeNormal", + { group = "NvimTreeNormal", link = "Normal" }, + { group = "NvimTreeNormalFloat", link = "NormalFloat" }, + { group = "NvimTreeNormalNC", link = "NvimTreeNormal" }, - NvimTreeLineNr = "LineNr", - NvimTreeWinSeparator = "WinSeparator", - NvimTreeEndOfBuffer = "EndOfBuffer", - NvimTreePopup = "Normal", - NvimTreeSignColumn = "NvimTreeNormal", + { group = "NvimTreeLineNr", link = "LineNr" }, + { group = "NvimTreeWinSeparator", link = "WinSeparator" }, + { group = "NvimTreeEndOfBuffer", link = "EndOfBuffer" }, + { group = "NvimTreePopup", link = "Normal" }, + { group = "NvimTreeSignColumn", link = "NvimTreeNormal" }, - NvimTreeCursorColumn = "CursorColumn", - NvimTreeCursorLine = "CursorLine", - NvimTreeCursorLineNr = "CursorLineNr", + { group = "NvimTreeCursorColumn", link = "CursorColumn" }, + { group = "NvimTreeCursorLine", link = "CursorLine" }, + { group = "NvimTreeCursorLineNr", link = "CursorLineNr" }, - NvimTreeStatusLine = "StatusLine", - NvimTreeStatusLineNC = "StatusLineNC", + { group = "NvimTreeStatusLine", link = "StatusLine" }, + { group = "NvimTreeStatusLineNC", link = "StatusLineNC" }, -- File Text - NvimTreeExecFile = "SpellCap", - NvimTreeImageFile = "SpellCap", - NvimTreeSpecialFile = "SpellCap", - NvimTreeSymlink = "SpellCap", + { group = "NvimTreeExecFile", link = "SpellCap" }, + { group = "NvimTreeImageFile", link = "SpellCap" }, + { group = "NvimTreeSpecialFile", link = "SpellCap" }, + { group = "NvimTreeSymlink", link = "SpellCap" }, -- Folder Text - NvimTreeRootFolder = "Title", - NvimTreeFolderName = "Directory", - NvimTreeEmptyFolderName = "Directory", - NvimTreeOpenedFolderName = "Directory", - NvimTreeSymlinkFolderName = "Directory", + { group = "NvimTreeRootFolder", link = "Title" }, + { group = "NvimTreeFolderName", link = "Directory" }, + { group = "NvimTreeEmptyFolderName", link = "Directory" }, + { group = "NvimTreeOpenedFolderName", link = "Directory" }, + { group = "NvimTreeSymlinkFolderName", link = "Directory" }, -- File Icons - NvimTreeFileIcon = "NvimTreeNormal", - NvimTreeSymlinkIcon = "NvimTreeNormal", + { group = "NvimTreeFileIcon", link = "NvimTreeNormal" }, + { group = "NvimTreeSymlinkIcon", link = "NvimTreeNormal" }, -- Folder Icons - NvimTreeOpenedFolderIcon = "NvimTreeFolderIcon", - NvimTreeClosedFolderIcon = "NvimTreeFolderIcon", - NvimTreeFolderArrowClosed = "NvimTreeIndentMarker", - NvimTreeFolderArrowOpen = "NvimTreeIndentMarker", + { group = "NvimTreeFolderIcon", def = "guifg=#8094b4 ctermfg=Blue" }, + { group = "NvimTreeOpenedFolderIcon", link = "NvimTreeFolderIcon" }, + { group = "NvimTreeClosedFolderIcon", link = "NvimTreeFolderIcon" }, + { group = "NvimTreeFolderArrowClosed", link = "NvimTreeIndentMarker" }, + { group = "NvimTreeFolderArrowOpen", link = "NvimTreeIndentMarker" }, -- Indent - NvimTreeIndentMarker = "NvimTreeFolderIcon", + { group = "NvimTreeIndentMarker", link = "NvimTreeFolderIcon" }, + + -- Picker + { group = "NvimTreeWindowPicker", def = "guifg=#ededed guibg=#4493c8 gui=bold ctermfg=White ctermbg=Cyan" }, -- LiveFilter - NvimTreeLiveFilterPrefix = "PreProc", - NvimTreeLiveFilterValue = "ModeMsg", + { group = "NvimTreeLiveFilterPrefix", link = "PreProc" }, + { group = "NvimTreeLiveFilterValue", link = "ModeMsg" }, -- Clipboard - NvimTreeCutHL = "SpellBad", - NvimTreeCopiedHL = "SpellRare", + { group = "NvimTreeCutHL", link = "SpellBad" }, + { group = "NvimTreeCopiedHL", link = "SpellRare" }, -- Bookmark - NvimTreeBookmarkIcon = "NvimTreeFolderIcon", - NvimTreeBookmarkHL = "SpellLocal", + { group = "NvimTreeBookmarkIcon", link = "NvimTreeFolderIcon" }, + { group = "NvimTreeBookmarkHL", link = "SpellLocal" }, -- Modified - NvimTreeModifiedIcon = "Type", - NvimTreeModifiedFileHL = "NvimTreeModifiedIcon", - NvimTreeModifiedFolderHL = "NvimTreeModifiedFileHL", + { group = "NvimTreeModifiedIcon", link = "Type" }, + { group = "NvimTreeModifiedFileHL", link = "NvimTreeModifiedIcon" }, + { group = "NvimTreeModifiedFolderHL", link = "NvimTreeModifiedFileHL" }, -- Opened - NvimTreeOpenedHL = "Special", + { group = "NvimTreeOpenedHL", link = "Special" }, -- Git Icon - NvimTreeGitDeletedIcon = "Statement", - NvimTreeGitDirtyIcon = "Statement", - NvimTreeGitIgnoredIcon = "Comment", - NvimTreeGitMergeIcon = "Constant", - NvimTreeGitNewIcon = "PreProc", - NvimTreeGitRenamedIcon = "PreProc", - NvimTreeGitStagedIcon = "Constant", + { group = "NvimTreeGitDeletedIcon", link = "Statement" }, + { group = "NvimTreeGitDirtyIcon", link = "Statement" }, + { group = "NvimTreeGitIgnoredIcon", link = "Comment" }, + { group = "NvimTreeGitMergeIcon", link = "Constant" }, + { group = "NvimTreeGitNewIcon", link = "PreProc" }, + { group = "NvimTreeGitRenamedIcon", link = "PreProc" }, + { group = "NvimTreeGitStagedIcon", link = "Constant" }, -- Git File Highlight - NvimTreeGitFileDeletedHL = "NvimTreeGitDeletedIcon", - NvimTreeGitFileDirtyHL = "NvimTreeGitDirtyIcon", - NvimTreeGitFileIgnoredHL = "NvimTreeGitIgnoredIcon", - NvimTreeGitFileMergeHL = "NvimTreeGitMergeIcon", - NvimTreeGitFileNewHL = "NvimTreeGitNewIcon", - NvimTreeGitFileRenamedHL = "NvimTreeGitRenamedIcon", - NvimTreeGitFileStagedHL = "NvimTreeGitStagedIcon", + { group = "NvimTreeGitFileDeletedHL", link = "NvimTreeGitDeletedIcon" }, + { group = "NvimTreeGitFileDirtyHL", link = "NvimTreeGitDirtyIcon" }, + { group = "NvimTreeGitFileIgnoredHL", link = "NvimTreeGitIgnoredIcon" }, + { group = "NvimTreeGitFileMergeHL", link = "NvimTreeGitMergeIcon" }, + { group = "NvimTreeGitFileNewHL", link = "NvimTreeGitNewIcon" }, + { group = "NvimTreeGitFileRenamedHL", link = "NvimTreeGitRenamedIcon" }, + { group = "NvimTreeGitFileStagedHL", link = "NvimTreeGitStagedIcon" }, -- Git Folder Highlight - NvimTreeGitFolderDeletedHL = "NvimTreeGitFileDeletedHL", - NvimTreeGitFolderDirtyHL = "NvimTreeGitFileDirtyHL", - NvimTreeGitFolderIgnoredHL = "NvimTreeGitFileIgnoredHL", - NvimTreeGitFolderMergeHL = "NvimTreeGitFileMergeHL", - NvimTreeGitFolderNewHL = "NvimTreeGitFileNewHL", - NvimTreeGitFolderRenamedHL = "NvimTreeGitFileRenamedHL", - NvimTreeGitFolderStagedHL = "NvimTreeGitFileStagedHL", + { group = "NvimTreeGitFolderDeletedHL", link = "NvimTreeGitFileDeletedHL" }, + { group = "NvimTreeGitFolderDirtyHL", link = "NvimTreeGitFileDirtyHL" }, + { group = "NvimTreeGitFolderIgnoredHL", link = "NvimTreeGitFileIgnoredHL" }, + { group = "NvimTreeGitFolderMergeHL", link = "NvimTreeGitFileMergeHL" }, + { group = "NvimTreeGitFolderNewHL", link = "NvimTreeGitFileNewHL" }, + { group = "NvimTreeGitFolderRenamedHL", link = "NvimTreeGitFileRenamedHL" }, + { group = "NvimTreeGitFolderStagedHL", link = "NvimTreeGitFileStagedHL" }, -- Diagnostics Icon - NvimTreeDiagnosticErrorIcon = "DiagnosticError", - NvimTreeDiagnosticWarnIcon = "DiagnosticWarn", - NvimTreeDiagnosticInfoIcon = "DiagnosticInfo", - NvimTreeDiagnosticHintIcon = "DiagnosticHint", + { group = "NvimTreeDiagnosticErrorIcon", link = "DiagnosticError" }, + { group = "NvimTreeDiagnosticWarnIcon", link = "DiagnosticWarn" }, + { group = "NvimTreeDiagnosticInfoIcon", link = "DiagnosticInfo" }, + { group = "NvimTreeDiagnosticHintIcon", link = "DiagnosticHint" }, -- Diagnostics File Highlight - NvimTreeDiagnosticErrorFileHL = "DiagnosticUnderlineError", - NvimTreeDiagnosticWarnFileHL = "DiagnosticUnderlineWarn", - NvimTreeDiagnosticInfoFileHL = "DiagnosticUnderlineInfo", - NvimTreeDiagnosticHintFileHL = "DiagnosticUnderlineHint", + { group = "NvimTreeDiagnosticErrorFileHL", link = "DiagnosticUnderlineError" }, + { group = "NvimTreeDiagnosticWarnFileHL", link = "DiagnosticUnderlineWarn" }, + { group = "NvimTreeDiagnosticInfoFileHL", link = "DiagnosticUnderlineInfo" }, + { group = "NvimTreeDiagnosticHintFileHL", link = "DiagnosticUnderlineHint" }, -- Diagnostics Folder Highlight - NvimTreeDiagnosticErrorFolderHL = "NvimTreeDiagnosticErrorFileHL", - NvimTreeDiagnosticWarnFolderHL = "NvimTreeDiagnosticWarnFileHL", - NvimTreeDiagnosticInfoFolderHL = "NvimTreeDiagnosticInfoFileHL", - NvimTreeDiagnosticHintFolderHL = "NvimTreeDiagnosticHintFileHL", + { group = "NvimTreeDiagnosticErrorFolderHL", link = "NvimTreeDiagnosticErrorFileHL" }, + { group = "NvimTreeDiagnosticWarnFolderHL", link = "NvimTreeDiagnosticWarnFileHL" }, + { group = "NvimTreeDiagnosticInfoFolderHL", link = "NvimTreeDiagnosticInfoFileHL" }, + { group = "NvimTreeDiagnosticHintFolderHL", link = "NvimTreeDiagnosticHintFileHL" }, } -- nvim-tree highlight groups to legacy @@ -168,10 +167,87 @@ local LEGACY_LINKS = { NvimTreeDiagnosticHintFolderHL = "NvimTreeLspDiagnosticsHintFolderText", } +---@class HighlightDisplay for :NvimTreeHiTest +---@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 +local HighlightDisplay = {} + +---@param group string nvim-tree highlight group +---@return HighlightDisplay +function HighlightDisplay:new(group) + local o = {} + setmetatable(o, self) + self.__index = self + + o.group = group + local concrete = o.group + + -- maybe follow links + local links = {} + local link = vim.api.nvim_get_hl(0, { name = o.group }).link + while link do + table.insert(links, link) + concrete = link + link = vim.api.nvim_get_hl(0, { name = link }).link + end + o.links = table.concat(links, " ") + + -- concrete definition + local ok, res = pcall(vim.api.nvim_cmd, { cmd = "highlight", args = { concrete } }, { output = true }) + if ok and type(res) == "string" then + o.def = res:gsub(".*xxx *", "") + else + o.def = "" + end + + return o +end + +function HighlightDisplay:render(bufnr, fmt, l) + local text = string.format(fmt, self.group, self.links, self.def) + + vim.api.nvim_buf_set_lines(bufnr, l, -1, true, { text }) + vim.api.nvim_buf_add_highlight(bufnr, -1, self.group, l, 0, #self.group) +end + +---Run a test similar to :so $VIMRUNTIME/syntax/hitest.vim +---Display all nvim-tree highlight groups, their link chain and actual definition +function M.hi_test() + local displays = {} + local max_group_len = 0 + local max_links_len = 0 + + -- build all highlight groups, name only + for _, highlight_group in ipairs(HIGHLIGHT_GROUPS) do + local display = HighlightDisplay:new(highlight_group.group) + table.insert(displays, display) + max_group_len = math.max(max_group_len, #display.group) + max_links_len = math.max(max_links_len, #display.links) + end + + -- create a buffer + local bufnr = vim.api.nvim_create_buf(false, true) + + -- render and highlight + local l = 0 + local fmt = string.format("%%-%d.%ds %%-%d.%ds %%s", max_group_len, max_group_len, max_links_len, max_links_len) + for _, display in ipairs(displays) do + display:render(bufnr, fmt, l) + l = l + 1 + end + + -- finalise and focus the buffer + vim.api.nvim_buf_set_option(bufnr, "modifiable", false) + vim.cmd.buffer(bufnr) +end + function M.setup() -- non-linked - for k, d in pairs(DEFAULT_DEFS) do - vim.api.nvim_command("hi def " .. k .. " " .. d) + for _, g in ipairs(HIGHLIGHT_GROUPS) do + if g.def then + vim.api.nvim_command("hi def " .. g.group .. " " .. g.def) + end end -- hard link override when legacy only is present @@ -191,8 +267,10 @@ function M.setup() end -- default links - for from, to in pairs(DEFAULT_LINKS) do - vim.api.nvim_command("hi def link " .. from .. " " .. to) + for _, g in ipairs(HIGHLIGHT_GROUPS) do + if g.link then + vim.api.nvim_command("hi def link " .. g.group .. " " .. g.link) + end end end diff --git a/lua/nvim-tree/commands.lua b/lua/nvim-tree/commands.lua index dc0d899a364..7dbaabe9585 100644 --- a/lua/nvim-tree/commands.lua +++ b/lua/nvim-tree/commands.lua @@ -134,6 +134,13 @@ local CMDS = { api.tree.collapse_all(true) end, }, + { + name = "NvimTreeHiTest", + opts = { + desc = "nvim-tree: highlight test", + }, + command = api.appearance.hi_test, + }, } function M.get()