vim.keymap.set("n", "tt", function() require("nvim-tree.api").tree.toggle({ find_file = true, focus = false }) end) ---@class nvim_tree.api.decorator.UserDecorator local Decorator = require("nvim-tree.api").Decorator local repo = require("git.repo") repo.on("refresh", function() require("nvim-tree.api").tree.reload() end) do local events = require("nvim-tree.api").events local function on_change(data) if not data then return end local seen = {} local function fire(path) if not path then return end local r = repo.find(path) if r and not seen[r] then seen[r] = true r:refresh() end end fire(data.fname) fire(data.folder_name) fire(data.old_name) fire(data.new_name) end events.subscribe(events.Event.FileCreated, on_change) events.subscribe(events.Event.FileRemoved, on_change) events.subscribe(events.Event.FolderCreated, on_change) events.subscribe(events.Event.FolderRemoved, on_change) events.subscribe(events.Event.NodeRenamed, on_change) end ---@class ow.GitDecorator: nvim_tree.api.Decorator local GitDecorator = Decorator:extend() function GitDecorator:new() self.enabled = true self.icon_placement = "after" self.highlight_range = "name" end ---@param node Node ---@return ow.Git.Status.Entry[]? local function entries_for(node) local r = repo.find(node.absolute_path) if not r then return end local rel = vim.fs.relpath(r.worktree, node.absolute_path) if not rel then return end if node.type == "directory" then local list = r.status:aggregate_at(rel) return #list > 0 and list or nil end return r.status.entries[rel] end ---@param node Node ---@return { str: string, hl: string[] }[]? function GitDecorator.icons(_, node) local list = entries_for(node) if not list then return end local out = {} for _, entry in ipairs(list) do if entry.kind ~= "ignored" then table.insert(out, { str = entry.char, hl = { entry.hl } }) end end return out end ---@param node Node ---@return string? function GitDecorator.highlight_group(_, node) local list = entries_for(node) if not list then return end local hl for _, entry in ipairs(list) do if entry.kind ~= "ignored" then return end hl = hl or entry.hl end return hl end local signs = require("lsp.diagnostic").signs require("nvim-tree").setup({ on_attach = function(bufnr) local function opts(desc) return { desc = "nvim-tree: " .. desc, buffer = bufnr, noremap = true, silent = true, nowait = true, } end local api = require("nvim-tree.api") api.map.on_attach.default(bufnr) vim.keymap.del("n", "D", { buffer = bufnr }) vim.keymap.del("n", "bt", { buffer = bufnr }) vim.keymap.set("n", "d", api.fs.trash, opts("Trash")) vim.keymap.set( "n", "bd", api.marks.bulk.trash, opts("Trash Bookmarked") ) vim.keymap.set("n", "", api.node.open.edit, opts("Open")) vim.keymap.set( "n", "", api.node.navigate.parent_close, opts("Close Directory") ) end, hijack_cursor = true, hijack_netrw = false, view = { width = 50, preserve_window_proportions = true, }, renderer = { full_name = true, root_folder_label = function(path) local label = vim.fn.fnamemodify(path, ":~") local r = require("git.repo").resolve(path) local git_head = r and r:head() if git_head then label = label .. ("  %s"):format(git_head) end return label end, special_files = {}, decorators = { GitDecorator, "Modified", "Bookmark", "Diagnostics", "Copied", "Cut", }, highlight_modified = "icon", highlight_bookmarks = "name", highlight_clipboard = "all", indent_markers = { enable = true, icons = { corner = "│", none = "│", }, }, icons = { diagnostics_placement = "signcolumn", bookmarks_placement = "after", symlink_arrow = " -> ", show = { file = false, folder = false, folder_arrow = false, bookmarks = false, }, glyphs = { modified = "*", }, }, }, update_focused_file = { enable = true, }, diagnostics = { enable = true, show_on_dirs = true, icons = { hint = signs.text[vim.diagnostic.severity.HINT], info = signs.text[vim.diagnostic.severity.INFO], warning = signs.text[vim.diagnostic.severity.WARN], error = signs.text[vim.diagnostic.severity.ERROR], }, }, modified = { enable = true, }, filters = { custom = { "^\\.git$" }, }, live_filter = { prefix = "Filter: ", always_show_folders = false, }, filesystem_watchers = { enable = true, }, actions = { use_system_clipboard = false, change_dir = { enable = false, }, expand_all = { exclude = { ".venv", "build" }, }, open_file = { window_picker = { enable = false, }, }, }, notify = { threshold = vim.log.levels.WARN, absolute_path = false, }, help = { sort_by = "desc", }, sync_root_with_cwd = true, git = { enable = false, }, }) local function clear_hl(hl) vim.cmd.highlight({ args = { "clear", hl } }) vim.cmd.highlight({ args = { "link", hl, "NONE" }, bang = true }) end clear_hl("NvimTreeExecFile") clear_hl("NvimTreeSpecialFile") clear_hl("NvimTreeSymlink") clear_hl("NvimTreeImageFile") vim.api.nvim_create_autocmd("QuitPre", { callback = function() local tree_wins = {} local floating_wins = {} local wins = vim.api.nvim_list_wins() for _, w in ipairs(wins) do local bufname = vim.api.nvim_buf_get_name(vim.api.nvim_win_get_buf(w)) if bufname:match("NvimTree_") ~= nil then table.insert(tree_wins, w) end if vim.api.nvim_win_get_config(w).relative ~= "" then table.insert(floating_wins, w) end end if 1 == #wins - #floating_wins - #tree_wins then -- Should quit, so we close all invalid windows. for _, w in ipairs(tree_wins) do vim.api.nvim_win_close(w, true) end end end, })