chore: migrate to classic (#2991)
* add classic, migrating nodes classes
* add mixins to classic
* typechecked optargs constructors for nodes
* typechecked optargs constructors for watcher and event
* luacheck
* typechecked optargs constructors for GitRunner
* typechecked optargs constructors for Sorter
* typechecked optargs constructors for decorators, WIP
* typechecked optargs constructors for decorators, WIP
* typechecked optargs constructors for decorators
* remove class
* replace enums with named maps
* Renderer and Builder use classic, tidy opts
* LiveFilter uses classic, tidy opts
* Filter uses classic, tidy opts
* add FilterTypes named map
* move toggles into filters
* Marks uses classic, tidy opts
* Sorter uses classic, tidy opts
* Clipboard uses classic, tidy opts
* use supers for node methods
* HighlightDisplay uses classic
* protected :new
* Watcher tidy
* Revert "use supers for node methods"
This reverts commit 9fc7a866ec.
* Watcher tidy
* format
* format
* Filters private methods
* format
* Sorter type safety
* Sorter type safety
* Sorter type safety
* Sorter type safety
* Sorter type safety
* Sorter type safety
* tidy Runner
* tidy hi-test name
This commit is contained in:
parent
610a1c189b
commit
3fc8de198c
@ -7,6 +7,7 @@ local notify = require("nvim-tree.notify")
|
||||
|
||||
local find_file = require("nvim-tree.actions.finders.find-file").fn
|
||||
|
||||
local Class = require("nvim-tree.classic")
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
|
||||
---@alias ClipboardAction "copy" | "cut"
|
||||
@ -14,35 +15,31 @@ local DirectoryNode = require("nvim-tree.node.directory")
|
||||
|
||||
---@alias ClipboardActionFn fun(source: string, dest: string): boolean, string?
|
||||
|
||||
---@class Clipboard to handle all actions.fs clipboard API
|
||||
---@field config table hydrated user opts.filters
|
||||
---@class (exact) Clipboard: Class
|
||||
---@field private explorer Explorer
|
||||
---@field private data ClipboardData
|
||||
---@field private clipboard_name string
|
||||
---@field private reg string
|
||||
local Clipboard = {}
|
||||
local Clipboard = Class:extend()
|
||||
|
||||
---@param opts table user options
|
||||
---@param explorer Explorer
|
||||
---@return Clipboard
|
||||
function Clipboard:new(opts, explorer)
|
||||
---@type Clipboard
|
||||
local o = {
|
||||
explorer = explorer,
|
||||
data = {
|
||||
copy = {},
|
||||
cut = {},
|
||||
},
|
||||
clipboard_name = opts.actions.use_system_clipboard and "system" or "neovim",
|
||||
reg = opts.actions.use_system_clipboard and "+" or "1",
|
||||
config = {
|
||||
filesystem_watchers = opts.filesystem_watchers,
|
||||
},
|
||||
---@class Clipboard
|
||||
---@overload fun(args: ClipboardArgs): Clipboard
|
||||
|
||||
---@class (exact) ClipboardArgs
|
||||
---@field explorer Explorer
|
||||
|
||||
---@protected
|
||||
---@param args ClipboardArgs
|
||||
function Clipboard:new(args)
|
||||
self.explorer = args.explorer
|
||||
|
||||
self.data = {
|
||||
copy = {},
|
||||
cut = {},
|
||||
}
|
||||
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
self.clipboard_name = self.explorer.opts.actions.use_system_clipboard and "system" or "neovim"
|
||||
self.reg = self.explorer.opts.actions.use_system_clipboard and "+" or "1"
|
||||
end
|
||||
|
||||
---@param source string
|
||||
@ -252,7 +249,7 @@ function Clipboard:do_paste(node, action, action_fn)
|
||||
end
|
||||
|
||||
self.data[action] = {}
|
||||
if not self.config.filesystem_watchers.enable then
|
||||
if not self.explorer.opts.filesystem_watchers.enable then
|
||||
self.explorer:reload_explorer()
|
||||
end
|
||||
end
|
||||
|
||||
@ -2,7 +2,6 @@ local M = {}
|
||||
|
||||
M.collapse_all = require("nvim-tree.actions.tree.modifiers.collapse-all")
|
||||
M.expand_all = require("nvim-tree.actions.tree.modifiers.expand-all")
|
||||
M.toggles = require("nvim-tree.actions.tree.modifiers.toggles")
|
||||
|
||||
function M.setup(opts)
|
||||
M.expand_all.setup(opts)
|
||||
|
||||
@ -1,73 +0,0 @@
|
||||
local utils = require("nvim-tree.utils")
|
||||
local core = require("nvim-tree.core")
|
||||
local M = {}
|
||||
|
||||
---@param explorer Explorer
|
||||
local function reload(explorer)
|
||||
local node = explorer:get_node_at_cursor()
|
||||
explorer:reload_explorer()
|
||||
if node then
|
||||
utils.focus_node_or_parent(node)
|
||||
end
|
||||
end
|
||||
|
||||
local function wrap_explorer(fn)
|
||||
return function(...)
|
||||
local explorer = core.get_explorer()
|
||||
if explorer then
|
||||
return fn(explorer, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param explorer Explorer
|
||||
local function custom(explorer)
|
||||
explorer.filters.config.filter_custom = not explorer.filters.config.filter_custom
|
||||
reload(explorer)
|
||||
end
|
||||
|
||||
---@param explorer Explorer
|
||||
local function git_ignored(explorer)
|
||||
explorer.filters.config.filter_git_ignored = not explorer.filters.config.filter_git_ignored
|
||||
reload(explorer)
|
||||
end
|
||||
|
||||
---@param explorer Explorer
|
||||
local function git_clean(explorer)
|
||||
explorer.filters.config.filter_git_clean = not explorer.filters.config.filter_git_clean
|
||||
reload(explorer)
|
||||
end
|
||||
|
||||
---@param explorer Explorer
|
||||
local function no_buffer(explorer)
|
||||
explorer.filters.config.filter_no_buffer = not explorer.filters.config.filter_no_buffer
|
||||
reload(explorer)
|
||||
end
|
||||
|
||||
---@param explorer Explorer
|
||||
local function no_bookmark(explorer)
|
||||
explorer.filters.config.filter_no_bookmark = not explorer.filters.config.filter_no_bookmark
|
||||
reload(explorer)
|
||||
end
|
||||
|
||||
---@param explorer Explorer
|
||||
local function dotfiles(explorer)
|
||||
explorer.filters.config.filter_dotfiles = not explorer.filters.config.filter_dotfiles
|
||||
reload(explorer)
|
||||
end
|
||||
|
||||
---@param explorer Explorer
|
||||
local function enable(explorer)
|
||||
explorer.filters.config.enable = not explorer.filters.config.enable
|
||||
reload(explorer)
|
||||
end
|
||||
|
||||
M.custom = wrap_explorer(custom)
|
||||
M.git_ignored = wrap_explorer(git_ignored)
|
||||
M.git_clean = wrap_explorer(git_clean)
|
||||
M.no_buffer = wrap_explorer(no_buffer)
|
||||
M.no_bookmark = wrap_explorer(no_bookmark)
|
||||
M.dotfiles = wrap_explorer(dotfiles)
|
||||
M.enable = wrap_explorer(enable)
|
||||
|
||||
return M
|
||||
@ -2,7 +2,7 @@ local core = require("nvim-tree.core")
|
||||
local view = require("nvim-tree.view")
|
||||
local utils = require("nvim-tree.utils")
|
||||
local actions = require("nvim-tree.actions")
|
||||
local appearance_diagnostics = require("nvim-tree.appearance.diagnostics")
|
||||
local appearance_hi_test = require("nvim-tree.appearance.hi-test")
|
||||
local events = require("nvim-tree.events")
|
||||
local help = require("nvim-tree.help")
|
||||
local keymap = require("nvim-tree.keymap")
|
||||
@ -89,6 +89,22 @@ local function wrap_node_or_nil(fn)
|
||||
end
|
||||
end
|
||||
|
||||
---Invoke a member's method on the singleton explorer.
|
||||
---Print error when setup not called.
|
||||
---@param explorer_member string explorer member name
|
||||
---@param member_method string method name to invoke on member
|
||||
---@param ... any passed to method
|
||||
---@return fun(...): any
|
||||
local function wrap_explorer_member_args(explorer_member, member_method, ...)
|
||||
local method_args = ...
|
||||
return wrap(function(...)
|
||||
local explorer = core.get_explorer()
|
||||
if explorer then
|
||||
return explorer[explorer_member][member_method](explorer[explorer_member], method_args, ...)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
---Invoke a member's method on the singleton explorer.
|
||||
---Print error when setup not called.
|
||||
---@param explorer_member string explorer member name
|
||||
@ -165,13 +181,13 @@ Api.tree.find_file = wrap(actions.tree.find_file.fn)
|
||||
Api.tree.search_node = wrap(actions.finders.search_node.fn)
|
||||
Api.tree.collapse_all = wrap(actions.tree.modifiers.collapse_all.fn)
|
||||
Api.tree.expand_all = wrap_node(actions.tree.modifiers.expand_all.fn)
|
||||
Api.tree.toggle_enable_filters = wrap(actions.tree.modifiers.toggles.enable)
|
||||
Api.tree.toggle_gitignore_filter = wrap(actions.tree.modifiers.toggles.git_ignored)
|
||||
Api.tree.toggle_git_clean_filter = wrap(actions.tree.modifiers.toggles.git_clean)
|
||||
Api.tree.toggle_no_buffer_filter = wrap(actions.tree.modifiers.toggles.no_buffer)
|
||||
Api.tree.toggle_custom_filter = wrap(actions.tree.modifiers.toggles.custom)
|
||||
Api.tree.toggle_hidden_filter = wrap(actions.tree.modifiers.toggles.dotfiles)
|
||||
Api.tree.toggle_no_bookmark_filter = wrap(actions.tree.modifiers.toggles.no_bookmark)
|
||||
Api.tree.toggle_enable_filters = wrap_explorer_member("filters", "toggle")
|
||||
Api.tree.toggle_gitignore_filter = wrap_explorer_member_args("filters", "toggle", "git_ignored")
|
||||
Api.tree.toggle_git_clean_filter = wrap_explorer_member_args("filters", "toggle", "git_clean")
|
||||
Api.tree.toggle_no_buffer_filter = wrap_explorer_member_args("filters", "toggle", "no_buffer")
|
||||
Api.tree.toggle_custom_filter = wrap_explorer_member_args("filters", "toggle", "custom")
|
||||
Api.tree.toggle_hidden_filter = wrap_explorer_member_args("filters", "toggle", "dotfiles")
|
||||
Api.tree.toggle_no_bookmark_filter = wrap_explorer_member_args("filters", "toggle", "no_bookmark")
|
||||
Api.tree.toggle_help = wrap(help.toggle)
|
||||
Api.tree.is_tree_buf = wrap(utils.is_nvim_tree_buf)
|
||||
|
||||
@ -289,7 +305,7 @@ 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.diagnostics.hi_test = wrap(appearance_diagnostics.hi_test)
|
||||
Api.diagnostics.hi_test = wrap(appearance_hi_test)
|
||||
|
||||
Api.commands.get = wrap(function()
|
||||
return require("nvim-tree.commands").get()
|
||||
|
||||
@ -1,45 +1,46 @@
|
||||
local appearance = require("nvim-tree.appearance")
|
||||
|
||||
local Class = require("nvim-tree.classic")
|
||||
|
||||
-- others with name and links less than this arbitrary value are short
|
||||
local SHORT_LEN = 50
|
||||
|
||||
local M = {}
|
||||
|
||||
---@class HighlightDisplay for :NvimTreeHiTest
|
||||
---@class (exact) HighlightDisplay: Class 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 = {}
|
||||
local HighlightDisplay = Class:extend()
|
||||
|
||||
---@param group string nvim-tree highlight group name
|
||||
---@return HighlightDisplay
|
||||
function HighlightDisplay:new(group)
|
||||
local o = {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
---@class HighlightDisplay
|
||||
---@overload fun(args: HighlightDisplayArgs): HighlightDisplay
|
||||
|
||||
o.group = group
|
||||
local concrete = o.group
|
||||
---@class (exact) HighlightDisplayArgs
|
||||
---@field group string nvim-tree highlight group name
|
||||
|
||||
---@protected
|
||||
---@param args HighlightDisplayArgs
|
||||
function HighlightDisplay:new(args)
|
||||
self.group = args.group
|
||||
|
||||
local concrete = self.group
|
||||
|
||||
-- maybe follow links
|
||||
local links = {}
|
||||
local link = vim.api.nvim_get_hl(0, { name = o.group }).link
|
||||
local link = vim.api.nvim_get_hl(0, { name = self.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, " ")
|
||||
self.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 *", "")
|
||||
self.def = res:gsub(".*xxx *", "")
|
||||
else
|
||||
o.def = ""
|
||||
self.def = ""
|
||||
end
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
---Render one group.
|
||||
@ -87,7 +88,7 @@ end
|
||||
|
||||
---Run a test similar to :so $VIMRUNTIME/syntax/hitest.vim
|
||||
---Display all nvim-tree and neovim highlight groups, their link chain and actual definition
|
||||
function M.hi_test()
|
||||
return function()
|
||||
-- create a buffer
|
||||
local bufnr = vim.api.nvim_create_buf(false, true)
|
||||
|
||||
@ -96,7 +97,7 @@ function M.hi_test()
|
||||
-- nvim-tree groups, ordered
|
||||
local displays = {}
|
||||
for _, highlight_group in ipairs(appearance.HIGHLIGHT_GROUPS) do
|
||||
local display = HighlightDisplay:new(highlight_group.group)
|
||||
local display = HighlightDisplay({ group = highlight_group.group })
|
||||
table.insert(displays, display)
|
||||
end
|
||||
l = render_displays("nvim-tree", displays, bufnr, l)
|
||||
@ -110,7 +111,7 @@ function M.hi_test()
|
||||
if ok then
|
||||
for group in string.gmatch(out, "(%w*)%s+xxx") do
|
||||
if group:find("NvimTree", 1, true) ~= 1 then
|
||||
local display = HighlightDisplay:new(group)
|
||||
local display = HighlightDisplay({ group = group })
|
||||
if #display.group + #display.links > SHORT_LEN then
|
||||
table.insert(displays_long, display)
|
||||
else
|
||||
@ -137,5 +138,3 @@ function M.hi_test()
|
||||
|
||||
vim.cmd.buffer(bufnr)
|
||||
end
|
||||
|
||||
return M
|
||||
@ -1,47 +0,0 @@
|
||||
---Generic class, useful for inheritence.
|
||||
---@class (exact) Class
|
||||
local Class = {}
|
||||
|
||||
---@generic T
|
||||
---@param self T
|
||||
---@param o T|nil
|
||||
---@return T
|
||||
function Class:new(o)
|
||||
o = o or {}
|
||||
|
||||
setmetatable(o, self)
|
||||
self.__index = self ---@diagnostic disable-line: inject-field
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
---Object is an instance of class
|
||||
---This will start with the lowest class and loop over all the superclasses.
|
||||
---@generic T
|
||||
---@param class T
|
||||
---@return boolean
|
||||
function Class:is(class)
|
||||
local mt = getmetatable(self)
|
||||
while mt do
|
||||
if mt == class then
|
||||
return true
|
||||
end
|
||||
mt = getmetatable(mt)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
---Return object if it is an instance of class, otherwise nil
|
||||
---@generic T
|
||||
---@param class T
|
||||
---@return T|nil
|
||||
function Class:as(class)
|
||||
return self:is(class) and self or nil
|
||||
end
|
||||
|
||||
-- avoid unused param warnings in abstract methods
|
||||
---@param ... any
|
||||
function Class:nop(...) --luacheck: ignore 212
|
||||
end
|
||||
|
||||
return Class
|
||||
91
lua/nvim-tree/classic.lua
Normal file
91
lua/nvim-tree/classic.lua
Normal file
@ -0,0 +1,91 @@
|
||||
--
|
||||
-- classic
|
||||
--
|
||||
-- Copyright (c) 2014, rxi
|
||||
--
|
||||
-- This module is free software; you can redistribute it and/or modify it under
|
||||
-- the terms of the MIT license. See LICENSE for details.
|
||||
--
|
||||
-- https://github.com/rxi/classic
|
||||
--
|
||||
|
||||
---@class (exact) Class
|
||||
---@field super Class
|
||||
---@field private implements table<Class, boolean>
|
||||
local Class = {}
|
||||
Class.__index = Class ---@diagnostic disable-line: inject-field
|
||||
|
||||
---Default constructor
|
||||
---@protected
|
||||
function Class:new(...) --luacheck: ignore 212
|
||||
end
|
||||
|
||||
---Extend a class, setting .super
|
||||
function Class:extend()
|
||||
local cls = {}
|
||||
for k, v in pairs(self) do
|
||||
if k:find("__") == 1 then
|
||||
cls[k] = v
|
||||
end
|
||||
end
|
||||
cls.__index = cls
|
||||
cls.super = self
|
||||
setmetatable(cls, self)
|
||||
return cls
|
||||
end
|
||||
|
||||
---Implement the functions of a mixin
|
||||
---Add the mixin to .implements
|
||||
---@param mixin Class
|
||||
function Class:implement(mixin)
|
||||
if not rawget(self, "implements") then
|
||||
-- set on the class itself instead of parents
|
||||
rawset(self, "implements", {})
|
||||
end
|
||||
self.implements[mixin] = true
|
||||
for k, v in pairs(mixin) do
|
||||
if self[k] == nil and type(v) == "function" then
|
||||
self[k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Object is an instance of class or implements a mixin
|
||||
---@generic T
|
||||
---@param class T
|
||||
---@return boolean
|
||||
function Class:is(class)
|
||||
local mt = getmetatable(self)
|
||||
while mt do
|
||||
if mt == class then
|
||||
return true
|
||||
end
|
||||
if mt.implements and mt.implements[class] then
|
||||
return true
|
||||
end
|
||||
mt = getmetatable(mt)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
---Return object if :is otherwise nil
|
||||
---@generic T
|
||||
---@param class T
|
||||
---@return T|nil
|
||||
function Class:as(class)
|
||||
return self:is(class) and self or nil
|
||||
end
|
||||
|
||||
---Constructor to create instance, call :new and return
|
||||
function Class:__call(...)
|
||||
local obj = setmetatable({}, self)
|
||||
obj:new(...)
|
||||
return obj
|
||||
end
|
||||
|
||||
-- avoid unused param warnings in abstract methods
|
||||
---@param ... any
|
||||
function Class:nop(...) --luacheck: ignore 212
|
||||
end
|
||||
|
||||
return Class
|
||||
@ -1,4 +1,5 @@
|
||||
local events = require("nvim-tree.events")
|
||||
local notify = require("nvim-tree.notify")
|
||||
local view = require("nvim-tree.view")
|
||||
local log = require("nvim-tree.log")
|
||||
|
||||
@ -15,7 +16,21 @@ function M.init(foldername)
|
||||
if TreeExplorer then
|
||||
TreeExplorer:destroy()
|
||||
end
|
||||
TreeExplorer = require("nvim-tree.explorer"):create(foldername)
|
||||
|
||||
local err, path
|
||||
|
||||
if foldername then
|
||||
path, err = vim.loop.fs_realpath(foldername)
|
||||
else
|
||||
path, err = vim.loop.cwd()
|
||||
end
|
||||
if path then
|
||||
TreeExplorer = require("nvim-tree.explorer")({ path = path })
|
||||
else
|
||||
notify.error(err)
|
||||
TreeExplorer = nil
|
||||
end
|
||||
|
||||
if not first_init_done then
|
||||
events._dispatch_ready()
|
||||
first_init_done = true
|
||||
|
||||
@ -1,32 +1,5 @@
|
||||
local M = {}
|
||||
|
||||
---Must be synced with uv.fs_stat.result as it is compared with it
|
||||
---@enum (key) NODE_TYPE
|
||||
M.NODE_TYPE = {
|
||||
directory = 1,
|
||||
file = 2,
|
||||
link = 4,
|
||||
}
|
||||
|
||||
---Setup options for "highlight_*"
|
||||
---@enum HL_POSITION
|
||||
M.HL_POSITION = {
|
||||
none = 0,
|
||||
icon = 1,
|
||||
name = 2,
|
||||
all = 4,
|
||||
}
|
||||
|
||||
---Setup options for "*_placement"
|
||||
---@enum ICON_PLACEMENT
|
||||
M.ICON_PLACEMENT = {
|
||||
none = 0,
|
||||
signcolumn = 1,
|
||||
before = 2,
|
||||
after = 3,
|
||||
right_align = 4,
|
||||
}
|
||||
|
||||
---Reason for filter in filter.lua
|
||||
---@enum FILTER_REASON
|
||||
M.FILTER_REASON = {
|
||||
|
||||
@ -1,52 +1,59 @@
|
||||
local utils = require("nvim-tree.utils")
|
||||
local FILTER_REASON = require("nvim-tree.enum").FILTER_REASON
|
||||
|
||||
---@class Filters to handle all opts.filters and related API
|
||||
---@field config table hydrated user opts.filters
|
||||
local Class = require("nvim-tree.classic")
|
||||
|
||||
---@alias FilterType "custom" | "dotfiles" | "git_ignored" | "git_clean" | "no_buffer" | "no_bookmark"
|
||||
|
||||
---@class (exact) Filters: Class
|
||||
---@field enabled boolean
|
||||
---@field state table<FilterType, boolean>
|
||||
---@field private explorer Explorer
|
||||
---@field private exclude_list string[] filters.exclude
|
||||
---@field private ignore_list string[] filters.custom string table
|
||||
---@field private ignore_list table<string, boolean> filters.custom string table
|
||||
---@field private custom_function (fun(absolute_path: string): boolean)|nil filters.custom function
|
||||
local Filters = {}
|
||||
local Filters = Class:extend()
|
||||
|
||||
---@param opts table user options
|
||||
---@param explorer Explorer
|
||||
---@return Filters
|
||||
function Filters:new(opts, explorer)
|
||||
local o = {
|
||||
explorer = explorer,
|
||||
ignore_list = {},
|
||||
exclude_list = opts.filters.exclude,
|
||||
custom_function = nil,
|
||||
config = {
|
||||
enable = opts.filters.enable,
|
||||
filter_custom = true,
|
||||
filter_dotfiles = opts.filters.dotfiles,
|
||||
filter_git_ignored = opts.filters.git_ignored,
|
||||
filter_git_clean = opts.filters.git_clean,
|
||||
filter_no_buffer = opts.filters.no_buffer,
|
||||
filter_no_bookmark = opts.filters.no_bookmark,
|
||||
},
|
||||
---@class Filters
|
||||
---@overload fun(args: FiltersArgs): Filters
|
||||
|
||||
---@class (exact) FiltersArgs
|
||||
---@field explorer Explorer
|
||||
|
||||
---@protected
|
||||
---@param args FiltersArgs
|
||||
function Filters:new(args)
|
||||
self.explorer = args.explorer
|
||||
self.ignore_list = {}
|
||||
self.exclude_list = self.explorer.opts.filters.exclude
|
||||
self.custom_function = nil
|
||||
|
||||
self.enabled = self.explorer.opts.filters.enable
|
||||
self.state = {
|
||||
custom = true,
|
||||
dotfiles = self.explorer.opts.filters.dotfiles,
|
||||
git_ignored = self.explorer.opts.filters.git_ignored,
|
||||
git_clean = self.explorer.opts.filters.git_clean,
|
||||
no_buffer = self.explorer.opts.filters.no_buffer,
|
||||
no_bookmark = self.explorer.opts.filters.no_bookmark,
|
||||
}
|
||||
|
||||
local custom_filter = opts.filters.custom
|
||||
local custom_filter = self.explorer.opts.filters.custom
|
||||
if type(custom_filter) == "function" then
|
||||
o.custom_function = custom_filter
|
||||
self.custom_function = custom_filter
|
||||
else
|
||||
if custom_filter and #custom_filter > 0 then
|
||||
for _, filter_name in pairs(custom_filter) do
|
||||
o.ignore_list[filter_name] = true
|
||||
self.ignore_list[filter_name] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param path string
|
||||
---@return boolean
|
||||
local function is_excluded(self, path)
|
||||
function Filters:is_excluded(path)
|
||||
for _, node in ipairs(self.exclude_list) do
|
||||
if path:match(node) then
|
||||
return true
|
||||
@ -56,10 +63,11 @@ local function is_excluded(self, path)
|
||||
end
|
||||
|
||||
---Check if the given path is git clean/ignored
|
||||
---@private
|
||||
---@param path string Absolute path
|
||||
---@param project GitProject from prepare
|
||||
---@return boolean
|
||||
local function git(self, path, project)
|
||||
function Filters:git(path, project)
|
||||
if type(project) ~= "table" or type(project.files) ~= "table" or type(project.dirs) ~= "table" then
|
||||
return false
|
||||
end
|
||||
@ -70,12 +78,12 @@ local function git(self, path, project)
|
||||
xy = xy or project.dirs.indirect[path] and project.dirs.indirect[path][1]
|
||||
|
||||
-- filter ignored; overrides clean as they are effectively dirty
|
||||
if self.config.filter_git_ignored and xy == "!!" then
|
||||
if self.state.git_ignored and xy == "!!" then
|
||||
return true
|
||||
end
|
||||
|
||||
-- filter clean
|
||||
if self.config.filter_git_clean and not xy then
|
||||
if self.state.git_clean and not xy then
|
||||
return true
|
||||
end
|
||||
|
||||
@ -83,11 +91,12 @@ local function git(self, path, project)
|
||||
end
|
||||
|
||||
---Check if the given path has no listed buffer
|
||||
---@private
|
||||
---@param path string Absolute path
|
||||
---@param bufinfo table vim.fn.getbufinfo { buflisted = 1 }
|
||||
---@return boolean
|
||||
local function buf(self, path, bufinfo)
|
||||
if not self.config.filter_no_buffer or type(bufinfo) ~= "table" then
|
||||
function Filters:buf(path, bufinfo)
|
||||
if not self.state.no_buffer or type(bufinfo) ~= "table" then
|
||||
return false
|
||||
end
|
||||
|
||||
@ -101,19 +110,21 @@ local function buf(self, path, bufinfo)
|
||||
return true
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param path string
|
||||
---@return boolean
|
||||
local function dotfile(self, path)
|
||||
return self.config.filter_dotfiles and utils.path_basename(path):sub(1, 1) == "."
|
||||
function Filters:dotfile(path)
|
||||
return self.state.dotfiles and utils.path_basename(path):sub(1, 1) == "."
|
||||
end
|
||||
|
||||
---Bookmark is present
|
||||
---@private
|
||||
---@param path string
|
||||
---@param path_type string|nil filetype of path
|
||||
---@param bookmarks table<string, string|nil> path, filetype table of bookmarked files
|
||||
---@return boolean
|
||||
local function bookmark(self, path, path_type, bookmarks)
|
||||
if not self.config.filter_no_bookmark then
|
||||
function Filters:bookmark(path, path_type, bookmarks)
|
||||
if not self.state.no_bookmark then
|
||||
return false
|
||||
end
|
||||
-- if bookmark is empty, we should see a empty filetree
|
||||
@ -145,10 +156,11 @@ local function bookmark(self, path, path_type, bookmarks)
|
||||
return true
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param path string
|
||||
---@return boolean
|
||||
local function custom(self, path)
|
||||
if not self.config.filter_custom then
|
||||
function Filters:custom(path)
|
||||
if not self.state.custom then
|
||||
return false
|
||||
end
|
||||
|
||||
@ -190,7 +202,7 @@ function Filters:prepare(project)
|
||||
bookmarks = {},
|
||||
}
|
||||
|
||||
if self.config.filter_no_buffer then
|
||||
if self.state.no_buffer then
|
||||
status.bufinfo = vim.fn.getbufinfo({ buflisted = 1 })
|
||||
end
|
||||
|
||||
@ -210,20 +222,20 @@ end
|
||||
---@param status table from prepare
|
||||
---@return boolean
|
||||
function Filters:should_filter(path, fs_stat, status)
|
||||
if not self.config.enable then
|
||||
if not self.enabled then
|
||||
return false
|
||||
end
|
||||
|
||||
-- exclusions override all filters
|
||||
if is_excluded(self, path) then
|
||||
if self:is_excluded(path) then
|
||||
return false
|
||||
end
|
||||
|
||||
return git(self, path, status.project)
|
||||
or buf(self, path, status.bufinfo)
|
||||
or dotfile(self, path)
|
||||
or custom(self, path)
|
||||
or bookmark(self, path, fs_stat and fs_stat.type, status.bookmarks)
|
||||
return self:git(path, status.project)
|
||||
or self:buf(path, status.bufinfo)
|
||||
or self:dotfile(path)
|
||||
or self:custom(path)
|
||||
or self:bookmark(path, fs_stat and fs_stat.type, status.bookmarks)
|
||||
end
|
||||
|
||||
--- Check if the given path should be filtered, and provide the reason why it was
|
||||
@ -232,27 +244,44 @@ end
|
||||
---@param status table from prepare
|
||||
---@return FILTER_REASON
|
||||
function Filters:should_filter_as_reason(path, fs_stat, status)
|
||||
if not self.config.enable then
|
||||
if not self.enabled then
|
||||
return FILTER_REASON.none
|
||||
end
|
||||
|
||||
if is_excluded(self, path) then
|
||||
if self:is_excluded(path) then
|
||||
return FILTER_REASON.none
|
||||
end
|
||||
|
||||
if git(self, path, status.project) then
|
||||
if self:git(path, status.project) then
|
||||
return FILTER_REASON.git
|
||||
elseif buf(self, path, status.bufinfo) then
|
||||
elseif self:buf(path, status.bufinfo) then
|
||||
return FILTER_REASON.buf
|
||||
elseif dotfile(self, path) then
|
||||
elseif self:dotfile(path) then
|
||||
return FILTER_REASON.dotfile
|
||||
elseif custom(self, path) then
|
||||
elseif self:custom(path) then
|
||||
return FILTER_REASON.custom
|
||||
elseif bookmark(self, path, fs_stat and fs_stat.type, status.bookmarks) then
|
||||
elseif self:bookmark(path, fs_stat and fs_stat.type, status.bookmarks) then
|
||||
return FILTER_REASON.bookmark
|
||||
else
|
||||
return FILTER_REASON.none
|
||||
end
|
||||
end
|
||||
|
||||
---Toggle a type and refresh
|
||||
---@private
|
||||
---@param type FilterType? nil to disable all
|
||||
function Filters:toggle(type)
|
||||
if not type or self.state[type] == nil then
|
||||
self.enabled = not self.enabled
|
||||
else
|
||||
self.state[type] = not self.state[type]
|
||||
end
|
||||
|
||||
local node = self.explorer:get_node_at_cursor()
|
||||
self.explorer:reload_explorer()
|
||||
if node then
|
||||
utils.focus_node_or_parent(node)
|
||||
end
|
||||
end
|
||||
|
||||
return Filters
|
||||
|
||||
@ -3,7 +3,6 @@ local buffers = require("nvim-tree.buffers")
|
||||
local core = require("nvim-tree.core")
|
||||
local git = require("nvim-tree.git")
|
||||
local log = require("nvim-tree.log")
|
||||
local notify = require("nvim-tree.notify")
|
||||
local utils = require("nvim-tree.utils")
|
||||
local view = require("nvim-tree.view")
|
||||
local node_factory = require("nvim-tree.node.factory")
|
||||
@ -18,7 +17,7 @@ local NodeIterator = require("nvim-tree.iterators.node-iterator")
|
||||
local Filters = require("nvim-tree.explorer.filters")
|
||||
local Marks = require("nvim-tree.marks")
|
||||
local LiveFilter = require("nvim-tree.explorer.live-filter")
|
||||
local Sorters = require("nvim-tree.explorer.sorters")
|
||||
local Sorter = require("nvim-tree.explorer.sorter")
|
||||
local Clipboard = require("nvim-tree.actions.fs.clipboard")
|
||||
local Renderer = require("nvim-tree.renderer")
|
||||
|
||||
@ -36,51 +35,39 @@ local config
|
||||
---@field sorters Sorter
|
||||
---@field marks Marks
|
||||
---@field clipboard Clipboard
|
||||
local Explorer = RootNode:new()
|
||||
local Explorer = RootNode:extend()
|
||||
|
||||
---Static factory method
|
||||
---@param path string?
|
||||
---@return Explorer?
|
||||
function Explorer:create(path)
|
||||
local err
|
||||
---@class Explorer
|
||||
---@overload fun(args: ExplorerArgs): Explorer
|
||||
|
||||
if path then
|
||||
path, err = vim.loop.fs_realpath(path)
|
||||
else
|
||||
path, err = vim.loop.cwd()
|
||||
end
|
||||
if not path then
|
||||
notify.error(err)
|
||||
return nil
|
||||
end
|
||||
---@class (exact) ExplorerArgs
|
||||
---@field path string
|
||||
|
||||
---@type Explorer
|
||||
local explorer_placeholder = nil
|
||||
---@protected
|
||||
---@param args ExplorerArgs
|
||||
function Explorer:new(args)
|
||||
Explorer.super.new(self, {
|
||||
explorer = self,
|
||||
absolute_path = args.path,
|
||||
name = "..",
|
||||
})
|
||||
|
||||
local o = RootNode:create(explorer_placeholder, path, "..", nil)
|
||||
self.uid_explorer = vim.loop.hrtime()
|
||||
self.augroup_id = vim.api.nvim_create_augroup("NvimTree_Explorer_" .. self.uid_explorer, {})
|
||||
|
||||
o = self:new(o)
|
||||
self.open = true
|
||||
self.opts = config
|
||||
|
||||
o.explorer = o
|
||||
self.sorters = Sorter({ explorer = self })
|
||||
self.renderer = Renderer({ explorer = self })
|
||||
self.filters = Filters({ explorer = self })
|
||||
self.live_filter = LiveFilter({ explorer = self })
|
||||
self.marks = Marks({ explorer = self })
|
||||
self.clipboard = Clipboard({ explorer = self })
|
||||
|
||||
o.uid_explorer = vim.loop.hrtime()
|
||||
o.augroup_id = vim.api.nvim_create_augroup("NvimTree_Explorer_" .. o.uid_explorer, {})
|
||||
self:create_autocmds()
|
||||
|
||||
o.open = true
|
||||
o.opts = config
|
||||
|
||||
o.sorters = Sorters:create(config)
|
||||
o.renderer = Renderer:new(config, o)
|
||||
o.filters = Filters:new(config, o)
|
||||
o.live_filter = LiveFilter:new(config, o)
|
||||
o.marks = Marks:new(config, o)
|
||||
o.clipboard = Clipboard:new(config, o)
|
||||
|
||||
o:create_autocmds()
|
||||
|
||||
o:_load(o)
|
||||
|
||||
return o
|
||||
self:_load(self)
|
||||
end
|
||||
|
||||
function Explorer:destroy()
|
||||
@ -114,7 +101,7 @@ function Explorer:create_autocmds()
|
||||
vim.api.nvim_create_autocmd("BufReadPost", {
|
||||
group = self.augroup_id,
|
||||
callback = function(data)
|
||||
if (self.filters.config.filter_no_buffer or self.opts.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == "" then
|
||||
if (self.filters.state.no_buffer or self.opts.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == "" then
|
||||
utils.debounce("Buf:filter_buffer_" .. self.uid_explorer, self.opts.view.debounce_delay, function()
|
||||
self:reload_explorer()
|
||||
end)
|
||||
@ -126,7 +113,7 @@ function Explorer:create_autocmds()
|
||||
vim.api.nvim_create_autocmd("BufUnload", {
|
||||
group = self.augroup_id,
|
||||
callback = function(data)
|
||||
if (self.filters.config.filter_no_buffer or self.opts.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == "" then
|
||||
if (self.filters.state.no_buffer or self.opts.highlight_opened_files ~= "none") and vim.bo[data.buf].buftype == "" then
|
||||
utils.debounce("Buf:filter_buffer_" .. self.uid_explorer, self.opts.view.debounce_delay, function()
|
||||
self:reload_explorer()
|
||||
end)
|
||||
@ -213,10 +200,10 @@ function Explorer:reload(node, project)
|
||||
|
||||
-- To reset we must 'zero' everything that we use
|
||||
node.hidden_stats = vim.tbl_deep_extend("force", node.hidden_stats or {}, {
|
||||
git = 0,
|
||||
buf = 0,
|
||||
dotfile = 0,
|
||||
custom = 0,
|
||||
git = 0,
|
||||
buf = 0,
|
||||
dotfile = 0,
|
||||
custom = 0,
|
||||
bookmark = 0,
|
||||
})
|
||||
|
||||
@ -246,7 +233,13 @@ function Explorer:reload(node, project)
|
||||
end
|
||||
|
||||
if not nodes_by_path[abs] then
|
||||
local new_child = node_factory.create_node(self, node, abs, stat, name)
|
||||
local new_child = node_factory.create({
|
||||
explorer = self,
|
||||
parent = node,
|
||||
absolute_path = abs,
|
||||
name = name,
|
||||
fs_stat = stat
|
||||
})
|
||||
if new_child then
|
||||
table.insert(node.nodes, new_child)
|
||||
nodes_by_path[abs] = new_child
|
||||
@ -362,10 +355,10 @@ function Explorer:populate_children(handle, cwd, node, project, parent)
|
||||
local filter_status = parent.filters:prepare(project)
|
||||
|
||||
node.hidden_stats = vim.tbl_deep_extend("force", node.hidden_stats or {}, {
|
||||
git = 0,
|
||||
buf = 0,
|
||||
dotfile = 0,
|
||||
custom = 0,
|
||||
git = 0,
|
||||
buf = 0,
|
||||
dotfile = 0,
|
||||
custom = 0,
|
||||
bookmark = 0,
|
||||
})
|
||||
|
||||
@ -384,7 +377,13 @@ function Explorer:populate_children(handle, cwd, node, project, parent)
|
||||
local stat = vim.loop.fs_lstat(abs)
|
||||
local filter_reason = parent.filters:should_filter_as_reason(abs, stat, filter_status)
|
||||
if filter_reason == FILTER_REASON.none and not nodes_by_path[abs] then
|
||||
local child = node_factory.create_node(self, node, abs, stat, name)
|
||||
local child = node_factory.create({
|
||||
explorer = self,
|
||||
parent = node,
|
||||
absolute_path = abs,
|
||||
name = name,
|
||||
fs_stat = stat
|
||||
})
|
||||
if child then
|
||||
table.insert(node.nodes, child)
|
||||
nodes_by_path[child.absolute_path] = true
|
||||
|
||||
@ -1,29 +1,30 @@
|
||||
local view = require("nvim-tree.view")
|
||||
local utils = require("nvim-tree.utils")
|
||||
|
||||
local Class = require("nvim-tree.classic")
|
||||
local Iterator = require("nvim-tree.iterators.node-iterator")
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
|
||||
---@class LiveFilter
|
||||
---@class (exact) LiveFilter: Class
|
||||
---@field explorer Explorer
|
||||
---@field prefix string
|
||||
---@field always_show_folders boolean
|
||||
---@field filter string
|
||||
local LiveFilter = {}
|
||||
local LiveFilter = Class:extend()
|
||||
|
||||
---@param opts table
|
||||
---@param explorer Explorer
|
||||
---@return LiveFilter
|
||||
function LiveFilter:new(opts, explorer)
|
||||
local o = {
|
||||
explorer = explorer,
|
||||
prefix = opts.live_filter.prefix,
|
||||
always_show_folders = opts.live_filter.always_show_folders,
|
||||
filter = nil,
|
||||
}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
---@class LiveFilter
|
||||
---@overload fun(args: LiveFilterArgs): LiveFilter
|
||||
|
||||
---@class (exact) LiveFilterArgs
|
||||
---@field explorer Explorer
|
||||
|
||||
---@protected
|
||||
---@param args LiveFilterArgs
|
||||
function LiveFilter:new(args)
|
||||
self.explorer = args.explorer
|
||||
self.prefix = self.explorer.opts.live_filter.prefix
|
||||
self.always_show_folders = self.explorer.opts.live_filter.always_show_folders
|
||||
self.filter = nil
|
||||
end
|
||||
|
||||
---@param node_ Node?
|
||||
@ -81,7 +82,7 @@ end
|
||||
---@param node Node
|
||||
---@return boolean
|
||||
local function matches(self, node)
|
||||
if not self.explorer.filters.config.enable then
|
||||
if not self.explorer.filters.enabled then
|
||||
return true
|
||||
end
|
||||
|
||||
@ -168,21 +169,21 @@ local function create_overlay(self)
|
||||
if view.View.float.enable then
|
||||
-- don't close nvim-tree float when focus is changed to filter window
|
||||
vim.api.nvim_clear_autocmds({
|
||||
event = "WinLeave",
|
||||
event = "WinLeave",
|
||||
pattern = "NvimTree_*",
|
||||
group = vim.api.nvim_create_augroup("NvimTree", { clear = false }),
|
||||
group = vim.api.nvim_create_augroup("NvimTree", { clear = false }),
|
||||
})
|
||||
end
|
||||
|
||||
configure_buffer_overlay(self)
|
||||
overlay_winnr = vim.api.nvim_open_win(overlay_bufnr, true, {
|
||||
col = 1,
|
||||
row = 0,
|
||||
col = 1,
|
||||
row = 0,
|
||||
relative = "cursor",
|
||||
width = calculate_overlay_win_width(self),
|
||||
height = 1,
|
||||
border = "none",
|
||||
style = "minimal",
|
||||
width = calculate_overlay_win_width(self),
|
||||
height = 1,
|
||||
border = "none",
|
||||
style = "minimal",
|
||||
})
|
||||
|
||||
if vim.fn.has("nvim-0.10") == 1 then
|
||||
|
||||
@ -1,43 +1,25 @@
|
||||
local Class = require("nvim-tree.class")
|
||||
local Class = require("nvim-tree.classic")
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
|
||||
local C = {}
|
||||
---@alias SorterType "name" | "case_sensitive" | "modification_time" | "extension" | "suffix" | "filetype"
|
||||
---@alias SorterComparator fun(self: Sorter, a: Node, b: Node): boolean?
|
||||
|
||||
---@class (exact) SorterCfg
|
||||
---@field sorter string|fun(nodes: Node[])
|
||||
---@field folders_first boolean
|
||||
---@field files_first boolean
|
||||
---@alias SorterUser fun(nodes: Node[]): SorterType?
|
||||
|
||||
---@class (exact) Sorter: Class
|
||||
---@field cfg SorterCfg
|
||||
---@field user fun(nodes: Node[])?
|
||||
---@field pre string?
|
||||
local Sorter = Class:new()
|
||||
---@field private explorer Explorer
|
||||
local Sorter = Class:extend()
|
||||
|
||||
---@param opts table user options
|
||||
---@return Sorter
|
||||
function Sorter:create(opts)
|
||||
---@type Sorter
|
||||
local o = {
|
||||
cfg = vim.deepcopy(opts.sort),
|
||||
}
|
||||
o = self:new(o)
|
||||
---@class Sorter
|
||||
---@overload fun(args: SorterArgs): Sorter
|
||||
|
||||
if type(o.cfg.sorter) == "function" then
|
||||
o.user = o.cfg.sorter --[[@as fun(nodes: Node[])]]
|
||||
elseif type(o.cfg.sorter) == "string" then
|
||||
o.pre = o.cfg.sorter --[[@as string]]
|
||||
end
|
||||
return o
|
||||
end
|
||||
---@class (exact) SorterArgs
|
||||
---@field explorer Explorer
|
||||
|
||||
--- Predefined comparator, defaulting to name
|
||||
---@param sorter string as per options
|
||||
---@return fun(a: Node, b: Node): boolean
|
||||
function Sorter:get_comparator(sorter)
|
||||
return function(a, b)
|
||||
return (C[sorter] or C.name)(a, b, self.cfg)
|
||||
end
|
||||
---@protected
|
||||
---@param args SorterArgs
|
||||
function Sorter:new(args)
|
||||
self.explorer = args.explorer
|
||||
end
|
||||
|
||||
---Create a shallow copy of a portion of a list.
|
||||
@ -54,31 +36,32 @@ local function tbl_slice(t, first, last)
|
||||
return slice
|
||||
end
|
||||
|
||||
---Evaluate `sort.folders_first` and `sort.files_first`
|
||||
---@param a Node
|
||||
---@param b Node
|
||||
---@param cfg SorterCfg
|
||||
---@return boolean|nil
|
||||
local function folders_or_files_first(a, b, cfg)
|
||||
if not (cfg.folders_first or cfg.files_first) then
|
||||
return
|
||||
---Evaluate folders_first and sort.files_first returning nil when no order is necessary
|
||||
---@private
|
||||
---@type SorterComparator
|
||||
function Sorter:folders_or_files_first(a, b)
|
||||
if not (self.explorer.opts.sort.folders_first or self.explorer.opts.sort.files_first) then
|
||||
return nil
|
||||
end
|
||||
|
||||
if not a:is(DirectoryNode) and b:is(DirectoryNode) then
|
||||
-- file <> folder
|
||||
return cfg.files_first
|
||||
return self.explorer.opts.sort.files_first
|
||||
elseif a:is(DirectoryNode) and not b:is(DirectoryNode) then
|
||||
-- folder <> file
|
||||
return not cfg.files_first
|
||||
return not self.explorer.opts.sort.files_first
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
---@param t table
|
||||
---@private
|
||||
---@param t Node[]
|
||||
---@param first number
|
||||
---@param mid number
|
||||
---@param last number
|
||||
---@param comparator fun(a: Node, b: Node): boolean
|
||||
local function merge(t, first, mid, last, comparator)
|
||||
---@param comparator SorterComparator
|
||||
function Sorter:merge(t, first, mid, last, comparator)
|
||||
local n1 = mid - first + 1
|
||||
local n2 = last - mid
|
||||
local ls = tbl_slice(t, first, mid)
|
||||
@ -88,7 +71,7 @@ local function merge(t, first, mid, last, comparator)
|
||||
local k = first
|
||||
|
||||
while i <= n1 and j <= n2 do
|
||||
if comparator(ls[i], rs[j]) then
|
||||
if comparator(self, ls[i], rs[j]) then
|
||||
t[k] = ls[i]
|
||||
i = i + 1
|
||||
else
|
||||
@ -111,45 +94,49 @@ local function merge(t, first, mid, last, comparator)
|
||||
end
|
||||
end
|
||||
|
||||
---@param t table
|
||||
---@private
|
||||
---@param t Node[]
|
||||
---@param first number
|
||||
---@param last number
|
||||
---@param comparator fun(a: Node, b: Node): boolean
|
||||
local function split_merge(t, first, last, comparator)
|
||||
---@param comparator SorterComparator
|
||||
function Sorter:split_merge(t, first, last, comparator)
|
||||
if (last - first) < 1 then
|
||||
return
|
||||
end
|
||||
|
||||
local mid = math.floor((first + last) / 2)
|
||||
|
||||
split_merge(t, first, mid, comparator)
|
||||
split_merge(t, mid + 1, last, comparator)
|
||||
merge(t, first, mid, last, comparator)
|
||||
self:split_merge(t, first, mid, comparator)
|
||||
self:split_merge(t, mid + 1, last, comparator)
|
||||
self:merge(t, first, mid, last, comparator)
|
||||
end
|
||||
|
||||
---Perform a merge sort using sorter option.
|
||||
---@param t Node[]
|
||||
function Sorter:sort(t)
|
||||
if self.user then
|
||||
if self[self.explorer.opts.sort.sorter] then
|
||||
self:split_merge(t, 1, #t, self[self.explorer.opts.sort.sorter])
|
||||
elseif type(self.explorer.opts.sort.sorter) == "function" then
|
||||
local t_user = {}
|
||||
local origin_index = {}
|
||||
|
||||
for _, n in ipairs(t) do
|
||||
table.insert(t_user, {
|
||||
absolute_path = n.absolute_path,
|
||||
executable = n.executable,
|
||||
extension = n.extension,
|
||||
filetype = vim.filetype.match({ filename = n.name }),
|
||||
link_to = n.link_to,
|
||||
name = n.name,
|
||||
type = n.type,
|
||||
executable = n.executable,
|
||||
extension = n.extension,
|
||||
filetype = vim.filetype.match({ filename = n.name }),
|
||||
link_to = n.link_to,
|
||||
name = n.name,
|
||||
type = n.type,
|
||||
})
|
||||
table.insert(origin_index, n)
|
||||
end
|
||||
|
||||
local predefined = self.user(t_user)
|
||||
if predefined then
|
||||
split_merge(t, 1, #t, self:get_comparator(predefined))
|
||||
-- user may return a SorterType
|
||||
local ret = self.explorer.opts.sort.sorter(t_user)
|
||||
if self[ret] then
|
||||
self:split_merge(t, 1, #t, self[ret])
|
||||
return
|
||||
end
|
||||
|
||||
@ -162,7 +149,7 @@ function Sorter:sort(t)
|
||||
end
|
||||
|
||||
-- if missing value found, then using origin_index
|
||||
local mini_comparator = function(a, b)
|
||||
local mini_comparator = function(_, a, b)
|
||||
local a_index = user_index[a.absolute_path] or origin_index[a.absolute_path]
|
||||
local b_index = user_index[b.absolute_path] or origin_index[b.absolute_path]
|
||||
|
||||
@ -172,48 +159,52 @@ function Sorter:sort(t)
|
||||
return (a_index or 0) <= (b_index or 0)
|
||||
end
|
||||
|
||||
split_merge(t, 1, #t, mini_comparator) -- sort by user order
|
||||
elseif self.pre then
|
||||
split_merge(t, 1, #t, self:get_comparator(self.pre))
|
||||
self:split_merge(t, 1, #t, mini_comparator) -- sort by user order
|
||||
end
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param a Node
|
||||
---@param b Node
|
||||
---@param ignorecase boolean|nil
|
||||
---@param cfg SorterCfg
|
||||
---@param ignore_case boolean
|
||||
---@return boolean
|
||||
local function node_comparator_name_ignorecase_or_not(a, b, ignorecase, cfg)
|
||||
function Sorter:name_case(a, b, ignore_case)
|
||||
if not (a and b) then
|
||||
return true
|
||||
end
|
||||
|
||||
local early_return = folders_or_files_first(a, b, cfg)
|
||||
local early_return = self:folders_or_files_first(a, b)
|
||||
if early_return ~= nil then
|
||||
return early_return
|
||||
end
|
||||
|
||||
if ignorecase then
|
||||
if ignore_case then
|
||||
return a.name:lower() <= b.name:lower()
|
||||
else
|
||||
return a.name <= b.name
|
||||
end
|
||||
end
|
||||
|
||||
function C.case_sensitive(a, b, cfg)
|
||||
return node_comparator_name_ignorecase_or_not(a, b, false, cfg)
|
||||
---@private
|
||||
---@type SorterComparator
|
||||
function Sorter:case_sensitive(a, b)
|
||||
return self:name_case(a, b, false)
|
||||
end
|
||||
|
||||
function C.name(a, b, cfg)
|
||||
return node_comparator_name_ignorecase_or_not(a, b, true, cfg)
|
||||
---@private
|
||||
---@type SorterComparator
|
||||
function Sorter:name(a, b)
|
||||
return self:name_case(a, b, true)
|
||||
end
|
||||
|
||||
function C.modification_time(a, b, cfg)
|
||||
---@private
|
||||
---@type SorterComparator
|
||||
function Sorter:modification_time(a, b)
|
||||
if not (a and b) then
|
||||
return true
|
||||
end
|
||||
|
||||
local early_return = folders_or_files_first(a, b, cfg)
|
||||
local early_return = self:folders_or_files_first(a, b)
|
||||
if early_return ~= nil then
|
||||
return early_return
|
||||
end
|
||||
@ -232,17 +223,19 @@ function C.modification_time(a, b, cfg)
|
||||
return last_modified_b <= last_modified_a
|
||||
end
|
||||
|
||||
function C.suffix(a, b, cfg)
|
||||
---@private
|
||||
---@type SorterComparator
|
||||
function Sorter:suffix(a, b)
|
||||
if not (a and b) then
|
||||
return true
|
||||
end
|
||||
|
||||
-- directories go first
|
||||
local early_return = folders_or_files_first(a, b, cfg)
|
||||
local early_return = self:folders_or_files_first(a, b)
|
||||
if early_return ~= nil then
|
||||
return early_return
|
||||
elseif a.nodes and b.nodes then
|
||||
return C.name(a, b, cfg)
|
||||
return self:name(a, b)
|
||||
end
|
||||
|
||||
-- dotfiles go second
|
||||
@ -251,7 +244,7 @@ function C.suffix(a, b, cfg)
|
||||
elseif a.name:sub(1, 1) ~= "." and b.name:sub(1, 1) == "." then
|
||||
return false
|
||||
elseif a.name:sub(1, 1) == "." and b.name:sub(1, 1) == "." then
|
||||
return C.name(a, b, cfg)
|
||||
return self:name(a, b)
|
||||
end
|
||||
|
||||
-- unsuffixed go third
|
||||
@ -263,7 +256,7 @@ function C.suffix(a, b, cfg)
|
||||
elseif a_suffix_ndx and not b_suffix_ndx then
|
||||
return false
|
||||
elseif not (a_suffix_ndx and b_suffix_ndx) then
|
||||
return C.name(a, b, cfg)
|
||||
return self:name(a, b)
|
||||
end
|
||||
|
||||
-- finally, compare by suffixes
|
||||
@ -275,18 +268,20 @@ function C.suffix(a, b, cfg)
|
||||
elseif not a_suffix and b_suffix then
|
||||
return false
|
||||
elseif a_suffix:lower() == b_suffix:lower() then
|
||||
return C.name(a, b, cfg)
|
||||
return self:name(a, b)
|
||||
end
|
||||
|
||||
return a_suffix:lower() < b_suffix:lower()
|
||||
end
|
||||
|
||||
function C.extension(a, b, cfg)
|
||||
---@private
|
||||
---@type SorterComparator
|
||||
function Sorter:extension(a, b)
|
||||
if not (a and b) then
|
||||
return true
|
||||
end
|
||||
|
||||
local early_return = folders_or_files_first(a, b, cfg)
|
||||
local early_return = self:folders_or_files_first(a, b)
|
||||
if early_return ~= nil then
|
||||
return early_return
|
||||
end
|
||||
@ -300,18 +295,20 @@ function C.extension(a, b, cfg)
|
||||
local a_ext = (a.extension or ""):lower()
|
||||
local b_ext = (b.extension or ""):lower()
|
||||
if a_ext == b_ext then
|
||||
return C.name(a, b, cfg)
|
||||
return self:name(a, b)
|
||||
end
|
||||
|
||||
return a_ext < b_ext
|
||||
end
|
||||
|
||||
function C.filetype(a, b, cfg)
|
||||
---@private
|
||||
---@type SorterComparator
|
||||
function Sorter:filetype(a, b)
|
||||
local a_ft = vim.filetype.match({ filename = a.name })
|
||||
local b_ft = vim.filetype.match({ filename = b.name })
|
||||
|
||||
-- directories first
|
||||
local early_return = folders_or_files_first(a, b, cfg)
|
||||
local early_return = self:folders_or_files_first(a, b)
|
||||
if early_return ~= nil then
|
||||
return early_return
|
||||
end
|
||||
@ -325,7 +322,7 @@ function C.filetype(a, b, cfg)
|
||||
|
||||
-- same filetype or both nil, sort by name
|
||||
if a_ft == b_ft then
|
||||
return C.name(a, b, cfg)
|
||||
return self:name(a, b)
|
||||
end
|
||||
|
||||
return a_ft < b_ft
|
||||
@ -83,8 +83,12 @@ function M.create_watcher(node)
|
||||
end
|
||||
|
||||
M.uid = M.uid + 1
|
||||
return Watcher:create(path, nil, callback, {
|
||||
context = "explorer:watch:" .. path .. ":" .. M.uid,
|
||||
return Watcher:create({
|
||||
path = path,
|
||||
callback = callback,
|
||||
data = {
|
||||
context = "explorer:watch:" .. path .. ":" .. M.uid
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
@ -128,25 +128,25 @@ function M.reload_project(toplevel, path, callback)
|
||||
return
|
||||
end
|
||||
|
||||
---@type GitRunnerOpts
|
||||
local runner_opts = {
|
||||
toplevel = toplevel,
|
||||
path = path,
|
||||
---@type GitRunnerArgs
|
||||
local args = {
|
||||
toplevel = toplevel,
|
||||
path = path,
|
||||
list_untracked = git_utils.should_show_untracked(toplevel),
|
||||
list_ignored = true,
|
||||
timeout = M.config.git.timeout,
|
||||
list_ignored = true,
|
||||
timeout = M.config.git.timeout,
|
||||
}
|
||||
|
||||
if callback then
|
||||
---@param path_xy GitPathXY
|
||||
runner_opts.callback = function(path_xy)
|
||||
args.callback = function(path_xy)
|
||||
reload_git_project(toplevel, path, project, path_xy)
|
||||
callback()
|
||||
end
|
||||
GitRunner:run(runner_opts)
|
||||
GitRunner:run(args)
|
||||
else
|
||||
-- TODO #1974 use callback once async/await is available
|
||||
reload_git_project(toplevel, path, project, GitRunner:run(runner_opts))
|
||||
reload_git_project(toplevel, path, project, GitRunner:run(args))
|
||||
end
|
||||
end
|
||||
|
||||
@ -276,10 +276,10 @@ function M.load_project(path)
|
||||
end
|
||||
|
||||
local path_xys = GitRunner:run({
|
||||
toplevel = toplevel,
|
||||
toplevel = toplevel,
|
||||
list_untracked = git_utils.should_show_untracked(toplevel),
|
||||
list_ignored = true,
|
||||
timeout = M.config.git.timeout,
|
||||
list_ignored = true,
|
||||
timeout = M.config.git.timeout,
|
||||
})
|
||||
|
||||
local watcher = nil
|
||||
@ -298,15 +298,20 @@ function M.load_project(path)
|
||||
end
|
||||
|
||||
local git_dir = vim.env.GIT_DIR or M._git_dirs_by_toplevel[toplevel] or utils.path_join({ toplevel, ".git" })
|
||||
watcher = Watcher:create(git_dir, WATCHED_FILES, callback, {
|
||||
toplevel = toplevel,
|
||||
watcher = Watcher:create({
|
||||
path = git_dir,
|
||||
files = WATCHED_FILES,
|
||||
callback = callback,
|
||||
data = {
|
||||
toplevel = toplevel,
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
if path_xys then
|
||||
M._projects_by_toplevel[toplevel] = {
|
||||
files = path_xys,
|
||||
dirs = git_utils.project_files_to_project_dirs(path_xys, toplevel),
|
||||
files = path_xys,
|
||||
dirs = git_utils.project_files_to_project_dirs(path_xys, toplevel),
|
||||
watcher = watcher,
|
||||
}
|
||||
return M._projects_by_toplevel[toplevel]
|
||||
|
||||
@ -2,9 +2,23 @@ local log = require("nvim-tree.log")
|
||||
local utils = require("nvim-tree.utils")
|
||||
local notify = require("nvim-tree.notify")
|
||||
|
||||
local Class = require("nvim-tree.class")
|
||||
local Class = require("nvim-tree.classic")
|
||||
|
||||
---@class (exact) GitRunnerOpts
|
||||
---@class (exact) GitRunner: Class
|
||||
---@field private toplevel string absolute path
|
||||
---@field private path string? absolute path
|
||||
---@field private list_untracked boolean
|
||||
---@field private list_ignored boolean
|
||||
---@field private timeout integer
|
||||
---@field private callback fun(path_xy: GitPathXY)?
|
||||
---@field private path_xy GitPathXY
|
||||
---@field private rc integer? -- -1 indicates timeout
|
||||
local GitRunner = Class:extend()
|
||||
|
||||
---@class GitRunner
|
||||
---@overload fun(args: GitRunnerArgs): GitRunner
|
||||
|
||||
---@class (exact) GitRunnerArgs
|
||||
---@field toplevel string absolute path
|
||||
---@field path string? absolute path
|
||||
---@field list_untracked boolean
|
||||
@ -12,15 +26,23 @@ local Class = require("nvim-tree.class")
|
||||
---@field timeout integer
|
||||
---@field callback fun(path_xy: GitPathXY)?
|
||||
|
||||
---@class (exact) GitRunner: Class
|
||||
---@field private opts GitRunnerOpts
|
||||
---@field private path_xy GitPathXY
|
||||
---@field private rc integer? -- -1 indicates timeout
|
||||
local GitRunner = Class:new()
|
||||
|
||||
local timeouts = 0
|
||||
local MAX_TIMEOUTS = 5
|
||||
|
||||
---@protected
|
||||
---@param args GitRunnerArgs
|
||||
function GitRunner:new(args)
|
||||
self.toplevel = args.toplevel
|
||||
self.path = args.path
|
||||
self.list_untracked = args.list_untracked
|
||||
self.list_ignored = args.list_ignored
|
||||
self.timeout = args.timeout
|
||||
self.callback = args.callback
|
||||
|
||||
self.path_xy = {}
|
||||
self.rc = nil
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param status string
|
||||
---@param path string|nil
|
||||
@ -34,7 +56,7 @@ function GitRunner:parse_status_output(status, path)
|
||||
path = path:gsub("/", "\\")
|
||||
end
|
||||
if #status > 0 and #path > 0 then
|
||||
self.path_xy[utils.path_remove_trailing(utils.path_join({ self.opts.toplevel, path }))] = status
|
||||
self.path_xy[utils.path_remove_trailing(utils.path_join({ self.toplevel, path }))] = status
|
||||
end
|
||||
end
|
||||
|
||||
@ -81,11 +103,11 @@ end
|
||||
---@param stderr_handle uv.uv_pipe_t
|
||||
---@return uv.spawn.options
|
||||
function GitRunner:get_spawn_options(stdout_handle, stderr_handle)
|
||||
local untracked = self.opts.list_untracked and "-u" or nil
|
||||
local ignored = (self.opts.list_untracked and self.opts.list_ignored) and "--ignored=matching" or "--ignored=no"
|
||||
local untracked = self.list_untracked and "-u" or nil
|
||||
local ignored = (self.list_untracked and self.list_ignored) and "--ignored=matching" or "--ignored=no"
|
||||
return {
|
||||
args = { "--no-optional-locks", "status", "--porcelain=v1", "-z", ignored, untracked, self.opts.path },
|
||||
cwd = self.opts.toplevel,
|
||||
args = { "--no-optional-locks", "status", "--porcelain=v1", "-z", ignored, untracked, self.path },
|
||||
cwd = self.toplevel,
|
||||
stdio = { nil, stdout_handle, stderr_handle },
|
||||
}
|
||||
end
|
||||
@ -139,7 +161,7 @@ function GitRunner:run_git_job(callback)
|
||||
end
|
||||
|
||||
local spawn_options = self:get_spawn_options(stdout, stderr)
|
||||
log.line("git", "running job with timeout %dms", self.opts.timeout)
|
||||
log.line("git", "running job with timeout %dms", self.timeout)
|
||||
log.line("git", "git %s", table.concat(utils.array_remove_nils(spawn_options.args), " "))
|
||||
|
||||
handle, pid = vim.loop.spawn(
|
||||
@ -151,7 +173,7 @@ function GitRunner:run_git_job(callback)
|
||||
)
|
||||
|
||||
timer:start(
|
||||
self.opts.timeout,
|
||||
self.timeout,
|
||||
0,
|
||||
vim.schedule_wrap(function()
|
||||
on_finish(-1)
|
||||
@ -191,17 +213,17 @@ end
|
||||
---@private
|
||||
function GitRunner:finalise()
|
||||
if self.rc == -1 then
|
||||
log.line("git", "job timed out %s %s", self.opts.toplevel, self.opts.path)
|
||||
log.line("git", "job timed out %s %s", self.toplevel, self.path)
|
||||
timeouts = timeouts + 1
|
||||
if timeouts == MAX_TIMEOUTS then
|
||||
notify.warn(string.format("%d git jobs have timed out after git.timeout %dms, disabling git integration.", timeouts,
|
||||
self.opts.timeout))
|
||||
self.timeout))
|
||||
require("nvim-tree.git").disable_git_integration()
|
||||
end
|
||||
elseif self.rc ~= 0 then
|
||||
log.line("git", "job fail rc %d %s %s", self.rc, self.opts.toplevel, self.opts.path)
|
||||
log.line("git", "job fail rc %d %s %s", self.rc, self.toplevel, self.path)
|
||||
else
|
||||
log.line("git", "job success %s %s", self.opts.toplevel, self.opts.path)
|
||||
log.line("git", "job success %s %s", self.toplevel, self.path)
|
||||
end
|
||||
end
|
||||
|
||||
@ -209,17 +231,17 @@ end
|
||||
---@private
|
||||
---@return GitPathXY?
|
||||
function GitRunner:execute()
|
||||
local async = self.opts.callback ~= nil
|
||||
local profile = log.profile_start("git %s job %s %s", async and "async" or "sync", self.opts.toplevel, self.opts.path)
|
||||
local async = self.callback ~= nil
|
||||
local profile = log.profile_start("git %s job %s %s", async and "async" or "sync", self.toplevel, self.path)
|
||||
|
||||
if async and self.opts.callback then
|
||||
if async and self.callback then
|
||||
-- async, always call back
|
||||
self:run_git_job(function()
|
||||
log.profile_end(profile)
|
||||
|
||||
self:finalise()
|
||||
|
||||
self.opts.callback(self.path_xy)
|
||||
self.callback(self.path_xy)
|
||||
end)
|
||||
else
|
||||
-- sync, maybe call back
|
||||
@ -230,8 +252,8 @@ function GitRunner:execute()
|
||||
|
||||
self:finalise()
|
||||
|
||||
if self.opts.callback then
|
||||
self.opts.callback(self.path_xy)
|
||||
if self.callback then
|
||||
self.callback(self.path_xy)
|
||||
else
|
||||
return self.path_xy
|
||||
end
|
||||
@ -240,15 +262,10 @@ end
|
||||
|
||||
---Static method to run a git process, which will be killed if it takes more than timeout
|
||||
---Return nil when callback present
|
||||
---@param opts GitRunnerOpts
|
||||
---@param args GitRunnerArgs
|
||||
---@return GitPathXY?
|
||||
function GitRunner:run(opts)
|
||||
---@type GitRunner
|
||||
local runner = {
|
||||
opts = opts,
|
||||
path_xy = {},
|
||||
}
|
||||
runner = GitRunner:new(runner)
|
||||
function GitRunner:run(args)
|
||||
local runner = GitRunner(args)
|
||||
|
||||
return runner:execute()
|
||||
end
|
||||
|
||||
@ -172,8 +172,8 @@ function M.git_status_dir(parent_ignored, project, path, path_fallback)
|
||||
elseif project then
|
||||
ns = {
|
||||
file = project.files and (project.files[path] or project.files[path_fallback]),
|
||||
dir = project.dirs and {
|
||||
direct = project.dirs.direct and project.dirs.direct[path],
|
||||
dir = project.dirs and {
|
||||
direct = project.dirs.direct and project.dirs.direct[path],
|
||||
indirect = project.dirs.indirect and project.dirs.indirect[path],
|
||||
},
|
||||
}
|
||||
|
||||
@ -8,37 +8,33 @@ local rename_file = require("nvim-tree.actions.fs.rename-file")
|
||||
local trash = require("nvim-tree.actions.fs.trash")
|
||||
local utils = require("nvim-tree.utils")
|
||||
|
||||
local Class = require("nvim-tree.classic")
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
|
||||
---@class Marks
|
||||
---@field config table hydrated user opts.filters
|
||||
---@class (exact) Marks: Class
|
||||
---@field private explorer Explorer
|
||||
---@field private marks table<string, Node> by absolute path
|
||||
local Marks = {}
|
||||
local Marks = Class:extend()
|
||||
|
||||
---@return Marks
|
||||
---@param opts table user options
|
||||
---@param explorer Explorer
|
||||
function Marks:new(opts, explorer)
|
||||
local o = {
|
||||
explorer = explorer,
|
||||
config = {
|
||||
ui = opts.ui,
|
||||
filesystem_watchers = opts.filesystem_watchers,
|
||||
},
|
||||
marks = {},
|
||||
}
|
||||
---@class Marks
|
||||
---@overload fun(args: MarksArgs): Marks
|
||||
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
---@class (exact) MarksArgs
|
||||
---@field explorer Explorer
|
||||
|
||||
---@protected
|
||||
---@param args MarksArgs
|
||||
function Marks:new(args)
|
||||
self.explorer = args.explorer
|
||||
|
||||
self.marks = {}
|
||||
end
|
||||
|
||||
---Clear all marks and reload if watchers disabled
|
||||
---@private
|
||||
function Marks:clear_reload()
|
||||
self:clear()
|
||||
if not self.config.filesystem_watchers.enable then
|
||||
if not self.explorer.opts.filesystem_watchers.enable then
|
||||
self.explorer:reload_explorer()
|
||||
end
|
||||
end
|
||||
@ -100,7 +96,7 @@ function Marks:bulk_delete()
|
||||
self:clear_reload()
|
||||
end
|
||||
|
||||
if self.config.ui.confirm.remove then
|
||||
if self.explorer.opts.ui.confirm.remove then
|
||||
local prompt_select = "Remove bookmarked ?"
|
||||
local prompt_input = prompt_select .. " y/N: "
|
||||
lib.prompt(prompt_input, prompt_select, { "", "y" }, { "No", "Yes" }, "nvimtree_bulk_delete", function(item_short)
|
||||
@ -129,7 +125,7 @@ function Marks:bulk_trash()
|
||||
self:clear_reload()
|
||||
end
|
||||
|
||||
if self.config.ui.confirm.trash then
|
||||
if self.explorer.opts.ui.confirm.trash then
|
||||
local prompt_select = "Trash bookmarked ?"
|
||||
local prompt_input = prompt_select .. " y/N: "
|
||||
lib.prompt(prompt_input, prompt_select, { "", "y" }, { "No", "Yes" }, "nvimtree_bulk_trash", function(item_short)
|
||||
|
||||
@ -2,35 +2,29 @@ local git_utils = require("nvim-tree.git.utils")
|
||||
local utils = require("nvim-tree.utils")
|
||||
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
local LinkNode = require("nvim-tree.node.link")
|
||||
|
||||
---@class (exact) DirectoryLinkNode: DirectoryNode
|
||||
---@field link_to string absolute path
|
||||
---@field private fs_stat_target uv.fs_stat.result
|
||||
local DirectoryLinkNode = DirectoryNode:new()
|
||||
---@class (exact) DirectoryLinkNode: DirectoryNode, LinkNode
|
||||
local DirectoryLinkNode = DirectoryNode:extend()
|
||||
DirectoryLinkNode:implement(LinkNode)
|
||||
|
||||
---Static factory method
|
||||
---@param explorer Explorer
|
||||
---@param parent DirectoryNode
|
||||
---@param absolute_path string
|
||||
---@param link_to string
|
||||
---@param name string
|
||||
---@param fs_stat uv.fs_stat.result?
|
||||
---@param fs_stat_target uv.fs_stat.result
|
||||
---@return DirectoryLinkNode? nil on vim.loop.fs_realpath failure
|
||||
function DirectoryLinkNode:create(explorer, parent, absolute_path, link_to, name, fs_stat, fs_stat_target)
|
||||
-- create DirectoryNode with the target path for the watcher
|
||||
local o = DirectoryNode:create(explorer, parent, link_to, name, fs_stat)
|
||||
---@class DirectoryLinkNode
|
||||
---@overload fun(args: LinkNodeArgs): DirectoryLinkNode
|
||||
|
||||
o = self:new(o)
|
||||
---@protected
|
||||
---@param args LinkNodeArgs
|
||||
function DirectoryLinkNode:new(args)
|
||||
LinkNode.new(self, args)
|
||||
|
||||
-- create DirectoryNode with watcher on link_to
|
||||
local absolute_path = args.absolute_path
|
||||
args.absolute_path = args.link_to
|
||||
DirectoryLinkNode.super.new(self, args)
|
||||
|
||||
self.type = "link"
|
||||
|
||||
-- reset absolute path to the link itself
|
||||
o.absolute_path = absolute_path
|
||||
|
||||
o.type = "link"
|
||||
o.link_to = link_to
|
||||
o.fs_stat_target = fs_stat_target
|
||||
|
||||
return o
|
||||
self.absolute_path = absolute_path
|
||||
end
|
||||
|
||||
function DirectoryLinkNode:destroy()
|
||||
@ -54,10 +48,10 @@ function DirectoryLinkNode:highlighted_icon()
|
||||
|
||||
if self.open then
|
||||
str = self.explorer.opts.renderer.icons.glyphs.folder.symlink_open
|
||||
hl = "NvimTreeOpenedFolderIcon"
|
||||
hl = "NvimTreeOpenedFolderIcon"
|
||||
else
|
||||
str = self.explorer.opts.renderer.icons.glyphs.folder.symlink
|
||||
hl = "NvimTreeClosedFolderIcon"
|
||||
hl = "NvimTreeClosedFolderIcon"
|
||||
end
|
||||
|
||||
return { str = str, hl = { hl } }
|
||||
@ -70,8 +64,9 @@ function DirectoryLinkNode:highlighted_name()
|
||||
|
||||
if self.explorer.opts.renderer.symlink_destination then
|
||||
local link_to = utils.path_relative(self.link_to, self.explorer.absolute_path)
|
||||
name.str = string.format("%s%s%s", name.str, self.explorer.opts.renderer.icons.symlink_arrow, link_to)
|
||||
name.hl = { "NvimTreeSymlinkFolderName" }
|
||||
|
||||
name.str = string.format("%s%s%s", name.str, self.explorer.opts.renderer.icons.symlink_arrow, link_to)
|
||||
name.hl = { "NvimTreeSymlinkFolderName" }
|
||||
end
|
||||
|
||||
return name
|
||||
@ -82,7 +77,6 @@ end
|
||||
function DirectoryLinkNode:clone()
|
||||
local clone = DirectoryNode.clone(self) --[[@as DirectoryLinkNode]]
|
||||
|
||||
clone.type = self.type
|
||||
clone.link_to = self.link_to
|
||||
clone.fs_stat_target = self.fs_stat_target
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
local git_utils = require("nvim-tree.git.utils")
|
||||
local icons = require("nvim-tree.renderer.components.devicons")
|
||||
local notify = require("nvim-tree.notify")
|
||||
|
||||
local Node = require("nvim-tree.node")
|
||||
|
||||
---@class (exact) DirectoryNode: Node
|
||||
@ -10,45 +11,28 @@ local Node = require("nvim-tree.node")
|
||||
---@field open boolean
|
||||
---@field hidden_stats table? -- Each field of this table is a key for source and value for count
|
||||
---@field private watcher Watcher?
|
||||
local DirectoryNode = Node:new()
|
||||
local DirectoryNode = Node:extend()
|
||||
|
||||
---Static factory method
|
||||
---@param explorer Explorer
|
||||
---@param parent DirectoryNode?
|
||||
---@param absolute_path string
|
||||
---@param name string
|
||||
---@param fs_stat uv.fs_stat.result|nil
|
||||
---@return DirectoryNode
|
||||
function DirectoryNode:create(explorer, parent, absolute_path, name, fs_stat)
|
||||
local handle = vim.loop.fs_scandir(absolute_path)
|
||||
---@class DirectoryNode
|
||||
---@overload fun(args: NodeArgs): DirectoryNode
|
||||
|
||||
---@protected
|
||||
---@param args NodeArgs
|
||||
function DirectoryNode:new(args)
|
||||
DirectoryNode.super.new(self, args)
|
||||
|
||||
local handle = vim.loop.fs_scandir(args.absolute_path)
|
||||
local has_children = handle and vim.loop.fs_scandir_next(handle) ~= nil or false
|
||||
|
||||
---@type DirectoryNode
|
||||
local o = {
|
||||
type = "directory",
|
||||
explorer = explorer,
|
||||
absolute_path = absolute_path,
|
||||
executable = false,
|
||||
fs_stat = fs_stat,
|
||||
git_status = nil,
|
||||
hidden = false,
|
||||
name = name,
|
||||
parent = parent,
|
||||
watcher = nil,
|
||||
diag_status = nil,
|
||||
is_dot = false,
|
||||
self.type = "directory"
|
||||
|
||||
has_children = has_children,
|
||||
group_next = nil,
|
||||
nodes = {},
|
||||
open = false,
|
||||
hidden_stats = nil,
|
||||
}
|
||||
o = self:new(o)
|
||||
self.has_children = has_children
|
||||
self.group_next = nil
|
||||
self.nodes = {}
|
||||
self.open = false
|
||||
self.hidden_stats = nil
|
||||
|
||||
o.watcher = require("nvim-tree.explorer.watch").create_watcher(o)
|
||||
|
||||
return o
|
||||
self.watcher = require("nvim-tree.explorer.watch").create_watcher(self)
|
||||
end
|
||||
|
||||
function DirectoryNode:destroy()
|
||||
@ -289,12 +273,12 @@ end
|
||||
---Create a sanitized partial copy of a node, populating children recursively.
|
||||
---@return DirectoryNode cloned
|
||||
function DirectoryNode:clone()
|
||||
local clone = Node.clone(self) --[[@as DirectoryNode]]
|
||||
local clone = Node.clone(self) --[[@as DirectoryNode]]
|
||||
|
||||
clone.has_children = self.has_children
|
||||
clone.group_next = nil
|
||||
clone.nodes = {}
|
||||
clone.open = self.open
|
||||
clone.group_next = nil
|
||||
clone.nodes = {}
|
||||
clone.open = self.open
|
||||
clone.hidden_stats = nil
|
||||
|
||||
for _, child in ipairs(self.nodes) do
|
||||
|
||||
@ -7,38 +7,38 @@ local Watcher = require("nvim-tree.watcher")
|
||||
local M = {}
|
||||
|
||||
---Factory function to create the appropriate Node
|
||||
---@param explorer Explorer
|
||||
---@param parent DirectoryNode
|
||||
---@param absolute_path string
|
||||
---@param stat uv.fs_stat.result? -- on nil stat return nil Node
|
||||
---@param name string
|
||||
---nil on invalid stat or invalid link target stat
|
||||
---@param args NodeArgs
|
||||
---@return Node?
|
||||
function M.create_node(explorer, parent, absolute_path, stat, name)
|
||||
if not stat then
|
||||
function M.create(args)
|
||||
if not args.fs_stat then
|
||||
return nil
|
||||
end
|
||||
|
||||
if stat.type == "directory" then
|
||||
if args.fs_stat.type == "directory" then
|
||||
-- directory must be readable and enumerable
|
||||
if vim.loop.fs_access(absolute_path, "R") and Watcher.is_fs_event_capable(absolute_path) then
|
||||
return DirectoryNode:create(explorer, parent, absolute_path, name, stat)
|
||||
if vim.loop.fs_access(args.absolute_path, "R") and Watcher.is_fs_event_capable(args.absolute_path) then
|
||||
return DirectoryNode(args)
|
||||
end
|
||||
elseif stat.type == "file" then
|
||||
-- any file
|
||||
return FileNode:create(explorer, parent, absolute_path, name, stat)
|
||||
elseif stat.type == "link" then
|
||||
elseif args.fs_stat.type == "file" then
|
||||
return FileNode(args)
|
||||
elseif args.fs_stat.type == "link" then
|
||||
-- link target path and stat must resolve
|
||||
local link_to = vim.loop.fs_realpath(absolute_path)
|
||||
local link_to = vim.loop.fs_realpath(args.absolute_path)
|
||||
local link_to_stat = link_to and vim.loop.fs_stat(link_to)
|
||||
if not link_to or not link_to_stat then
|
||||
return
|
||||
end
|
||||
|
||||
---@cast args LinkNodeArgs
|
||||
args.link_to = link_to
|
||||
args.fs_stat_target = link_to_stat
|
||||
|
||||
-- choose directory or file
|
||||
if link_to_stat.type == "directory" then
|
||||
return DirectoryLinkNode:create(explorer, parent, absolute_path, link_to, name, stat, link_to_stat)
|
||||
return DirectoryLinkNode(args)
|
||||
else
|
||||
return FileLinkNode:create(explorer, parent, absolute_path, link_to, name, stat, link_to_stat)
|
||||
return FileLinkNode(args)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -2,31 +2,22 @@ local git_utils = require("nvim-tree.git.utils")
|
||||
local utils = require("nvim-tree.utils")
|
||||
|
||||
local FileNode = require("nvim-tree.node.file")
|
||||
local LinkNode = require("nvim-tree.node.link")
|
||||
|
||||
---@class (exact) FileLinkNode: FileNode
|
||||
---@field link_to string absolute path
|
||||
---@field private fs_stat_target uv.fs_stat.result
|
||||
local FileLinkNode = FileNode:new()
|
||||
---@class (exact) FileLinkNode: FileNode, LinkNode
|
||||
local FileLinkNode = FileNode:extend()
|
||||
FileLinkNode:implement(LinkNode)
|
||||
|
||||
---Static factory method
|
||||
---@param explorer Explorer
|
||||
---@param parent DirectoryNode
|
||||
---@param absolute_path string
|
||||
---@param link_to string
|
||||
---@param name string
|
||||
---@param fs_stat uv.fs_stat.result?
|
||||
---@param fs_stat_target uv.fs_stat.result
|
||||
---@return FileLinkNode? nil on vim.loop.fs_realpath failure
|
||||
function FileLinkNode:create(explorer, parent, absolute_path, link_to, name, fs_stat, fs_stat_target)
|
||||
local o = FileNode:create(explorer, parent, absolute_path, name, fs_stat)
|
||||
---@class FileLinkNode
|
||||
---@overload fun(args: LinkNodeArgs): FileLinkNode
|
||||
|
||||
o = self:new(o)
|
||||
---@protected
|
||||
---@param args LinkNodeArgs
|
||||
function FileLinkNode:new(args)
|
||||
LinkNode.new(self, args)
|
||||
FileLinkNode.super.new(self, args)
|
||||
|
||||
o.type = "link"
|
||||
o.link_to = link_to
|
||||
o.fs_stat_target = fs_stat_target
|
||||
|
||||
return o
|
||||
self.type = "link"
|
||||
end
|
||||
|
||||
function FileLinkNode:destroy()
|
||||
@ -71,7 +62,6 @@ end
|
||||
function FileLinkNode:clone()
|
||||
local clone = FileNode.clone(self) --[[@as FileLinkNode]]
|
||||
|
||||
clone.type = self.type
|
||||
clone.link_to = self.link_to
|
||||
clone.fs_stat_target = self.fs_stat_target
|
||||
|
||||
|
||||
@ -15,35 +15,19 @@ local PICTURE_MAP = {
|
||||
|
||||
---@class (exact) FileNode: Node
|
||||
---@field extension string
|
||||
local FileNode = Node:new()
|
||||
local FileNode = Node:extend()
|
||||
|
||||
---Static factory method
|
||||
---@param explorer Explorer
|
||||
---@param parent DirectoryNode
|
||||
---@param absolute_path string
|
||||
---@param name string
|
||||
---@param fs_stat uv.fs_stat.result?
|
||||
---@return FileNode
|
||||
function FileNode:create(explorer, parent, absolute_path, name, fs_stat)
|
||||
---@type FileNode
|
||||
local o = {
|
||||
type = "file",
|
||||
explorer = explorer,
|
||||
absolute_path = absolute_path,
|
||||
executable = utils.is_executable(absolute_path),
|
||||
fs_stat = fs_stat,
|
||||
git_status = nil,
|
||||
hidden = false,
|
||||
name = name,
|
||||
parent = parent,
|
||||
diag_status = nil,
|
||||
is_dot = false,
|
||||
---@class FileNode
|
||||
---@overload fun(args: NodeArgs): FileNode
|
||||
|
||||
extension = string.match(name, ".?[^.]+%.(.*)") or "",
|
||||
}
|
||||
o = self:new(o)
|
||||
---@protected
|
||||
---@param args NodeArgs
|
||||
function FileNode:new(args)
|
||||
FileNode.super.new(self, args)
|
||||
|
||||
return o
|
||||
self.type = "file"
|
||||
self.extension = string.match(args.name, ".?[^.]+%.(.*)") or ""
|
||||
self.executable = utils.is_executable(args.absolute_path)
|
||||
end
|
||||
|
||||
function FileNode:destroy()
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
local Class = require("nvim-tree.class")
|
||||
local Class = require("nvim-tree.classic")
|
||||
|
||||
---Abstract Node class.
|
||||
---Uses the abstract factory pattern to instantiate child instances.
|
||||
---@class (exact) Node: Class
|
||||
---@field type NODE_TYPE
|
||||
---@field type "file" | "directory" | "link" uv.fs_stat.result.type
|
||||
---@field explorer Explorer
|
||||
---@field absolute_path string
|
||||
---@field executable boolean
|
||||
@ -14,7 +13,29 @@ local Class = require("nvim-tree.class")
|
||||
---@field parent DirectoryNode?
|
||||
---@field diag_status DiagStatus?
|
||||
---@field private is_dot boolean cached is_dotfile
|
||||
local Node = Class:new()
|
||||
local Node = Class:extend()
|
||||
|
||||
---@class (exact) NodeArgs
|
||||
---@field explorer Explorer
|
||||
---@field parent DirectoryNode?
|
||||
---@field absolute_path string
|
||||
---@field name string
|
||||
---@field fs_stat uv.fs_stat.result?
|
||||
|
||||
---@protected
|
||||
---@param args NodeArgs
|
||||
function Node:new(args)
|
||||
self.explorer = args.explorer
|
||||
self.absolute_path = args.absolute_path
|
||||
self.executable = false
|
||||
self.fs_stat = args.fs_stat
|
||||
self.git_status = nil
|
||||
self.hidden = false
|
||||
self.name = args.name
|
||||
self.parent = args.parent
|
||||
self.diag_status = nil
|
||||
self.is_dot = false
|
||||
end
|
||||
|
||||
function Node:destroy()
|
||||
end
|
||||
@ -104,17 +125,17 @@ function Node:clone()
|
||||
|
||||
---@type Node
|
||||
local clone = {
|
||||
type = self.type,
|
||||
explorer = explorer_placeholder,
|
||||
type = self.type,
|
||||
explorer = explorer_placeholder,
|
||||
absolute_path = self.absolute_path,
|
||||
executable = self.executable,
|
||||
fs_stat = self.fs_stat,
|
||||
git_status = self.git_status,
|
||||
hidden = self.hidden,
|
||||
name = self.name,
|
||||
parent = nil,
|
||||
diag_status = nil,
|
||||
is_dot = self.is_dot,
|
||||
executable = self.executable,
|
||||
fs_stat = self.fs_stat,
|
||||
git_status = self.git_status,
|
||||
hidden = self.hidden,
|
||||
name = self.name,
|
||||
parent = nil,
|
||||
diag_status = nil,
|
||||
is_dot = self.is_dot,
|
||||
}
|
||||
|
||||
return clone
|
||||
|
||||
19
lua/nvim-tree/node/link.lua
Normal file
19
lua/nvim-tree/node/link.lua
Normal file
@ -0,0 +1,19 @@
|
||||
local Class = require("nvim-tree.classic")
|
||||
|
||||
---@class (exact) LinkNode: Class
|
||||
---@field link_to string
|
||||
---@field protected fs_stat_target uv.fs_stat.result
|
||||
local LinkNode = Class:extend()
|
||||
|
||||
---@class (exact) LinkNodeArgs: NodeArgs
|
||||
---@field link_to string
|
||||
---@field fs_stat_target uv.fs_stat.result
|
||||
|
||||
---@protected
|
||||
---@param args LinkNodeArgs
|
||||
function LinkNode:new(args)
|
||||
self.link_to = args.link_to
|
||||
self.fs_stat_target = args.fs_stat_target
|
||||
end
|
||||
|
||||
return LinkNode
|
||||
@ -1,20 +1,15 @@
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
|
||||
---@class (exact) RootNode: DirectoryNode
|
||||
local RootNode = DirectoryNode:new()
|
||||
local RootNode = DirectoryNode:extend()
|
||||
|
||||
---Static factory method
|
||||
---@param explorer Explorer
|
||||
---@param absolute_path string
|
||||
---@param name string
|
||||
---@param fs_stat uv.fs_stat.result|nil
|
||||
---@return RootNode
|
||||
function RootNode:create(explorer, absolute_path, name, fs_stat)
|
||||
local o = DirectoryNode:create(explorer, nil, absolute_path, name, fs_stat)
|
||||
---@class RootNode
|
||||
---@overload fun(args: NodeArgs): RootNode
|
||||
|
||||
o = self:new(o)
|
||||
|
||||
return o
|
||||
---@protected
|
||||
---@param args NodeArgs
|
||||
function RootNode:new(args)
|
||||
RootNode.super.new(self, args)
|
||||
end
|
||||
|
||||
---Root is never a dotfile
|
||||
|
||||
@ -2,6 +2,7 @@ local notify = require("nvim-tree.notify")
|
||||
local utils = require("nvim-tree.utils")
|
||||
local view = require("nvim-tree.view")
|
||||
|
||||
local Class = require("nvim-tree.classic")
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
|
||||
local DecoratorBookmarks = require("nvim-tree.renderer.decorator.bookmarks")
|
||||
@ -26,57 +27,51 @@ local pad = require("nvim-tree.renderer.components.padding")
|
||||
---@field col_end number
|
||||
|
||||
---@class (exact) Builder
|
||||
---@field private __index? table
|
||||
---@field lines string[] includes icons etc.
|
||||
---@field hl_args AddHighlightArgs[] line highlights
|
||||
---@field signs string[] line signs
|
||||
---@field extmarks table[] extra marks for right icon placement
|
||||
---@field virtual_lines table[] virtual lines for hidden count display
|
||||
---@field private explorer Explorer
|
||||
---@field private opts table
|
||||
---@field private index number
|
||||
---@field private depth number
|
||||
---@field private combined_groups table<string, boolean> combined group names
|
||||
---@field private markers boolean[] indent markers
|
||||
---@field private decorators Decorator[]
|
||||
---@field private hidden_display fun(node: Node): string|nil
|
||||
local Builder = {}
|
||||
local Builder = Class:extend()
|
||||
|
||||
---@param opts table user options
|
||||
---@param explorer Explorer
|
||||
---@return Builder
|
||||
function Builder:new(opts, explorer)
|
||||
---@type Builder
|
||||
local o = {
|
||||
opts = opts,
|
||||
explorer = explorer,
|
||||
index = 0,
|
||||
depth = 0,
|
||||
hl_args = {},
|
||||
combined_groups = {},
|
||||
lines = {},
|
||||
markers = {},
|
||||
signs = {},
|
||||
extmarks = {},
|
||||
virtual_lines = {},
|
||||
decorators = {
|
||||
-- priority order
|
||||
DecoratorCut:create(opts, explorer),
|
||||
DecoratorCopied:create(opts, explorer),
|
||||
DecoratorDiagnostics:create(opts, explorer),
|
||||
DecoratorBookmarks:create(opts, explorer),
|
||||
DecoratorModified:create(opts, explorer),
|
||||
DecoratorHidden:create(opts, explorer),
|
||||
DecoratorOpened:create(opts, explorer),
|
||||
DecoratorGit:create(opts, explorer),
|
||||
},
|
||||
hidden_display = Builder:setup_hidden_display_function(opts),
|
||||
---@class Builder
|
||||
---@overload fun(args: BuilderArgs): Builder
|
||||
|
||||
---@class (exact) BuilderArgs
|
||||
---@field explorer Explorer
|
||||
|
||||
---@protected
|
||||
---@param args BuilderArgs
|
||||
function Builder:new(args)
|
||||
self.explorer = args.explorer
|
||||
self.index = 0
|
||||
self.depth = 0
|
||||
self.hl_args = {}
|
||||
self.combined_groups = {}
|
||||
self.lines = {}
|
||||
self.markers = {}
|
||||
self.signs = {}
|
||||
self.extmarks = {}
|
||||
self.virtual_lines = {}
|
||||
self.decorators = {
|
||||
-- priority order
|
||||
DecoratorCut({ explorer = args.explorer }),
|
||||
DecoratorCopied({ explorer = args.explorer }),
|
||||
DecoratorDiagnostics({ explorer = args.explorer }),
|
||||
DecoratorBookmarks({ explorer = args.explorer }),
|
||||
DecoratorModified({ explorer = args.explorer }),
|
||||
DecoratorHidden({ explorer = args.explorer }),
|
||||
DecoratorOpened({ explorer = args.explorer }),
|
||||
DecoratorGit({ explorer = args.explorer })
|
||||
}
|
||||
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
|
||||
return o
|
||||
self.hidden_display = Builder:setup_hidden_display_function(self.explorer.opts)
|
||||
end
|
||||
|
||||
---Insert ranged highlight groups into self.highlights
|
||||
@ -123,7 +118,7 @@ function Builder:format_line(indent_markers, arrows, icon, name, node)
|
||||
end
|
||||
for _, v in ipairs(t2) do
|
||||
if added_len > 0 then
|
||||
table.insert(t1, { str = self.opts.renderer.icons.padding })
|
||||
table.insert(t1, { str = self.explorer.opts.renderer.icons.padding })
|
||||
end
|
||||
table.insert(t1, v)
|
||||
end
|
||||
@ -284,7 +279,7 @@ function Builder:add_hidden_count_string(node, idx, num_children)
|
||||
local hidden_count_string = self.hidden_display(node.hidden_stats)
|
||||
if hidden_count_string and hidden_count_string ~= "" then
|
||||
local indent_markers = pad.get_indent_markers(self.depth, idx or 0, num_children or 0, node, self.markers, 1)
|
||||
local indent_width = self.opts.renderer.indent_width
|
||||
local indent_width = self.explorer.opts.renderer.indent_width
|
||||
|
||||
local indent_padding = string.rep(" ", indent_width)
|
||||
local indent_string = indent_padding .. indent_markers.str
|
||||
@ -354,16 +349,16 @@ end
|
||||
---@private
|
||||
function Builder:build_header()
|
||||
if view.is_root_folder_visible(self.explorer.absolute_path) then
|
||||
local root_name = self:format_root_name(self.opts.renderer.root_folder_label)
|
||||
local root_name = self:format_root_name(self.explorer.opts.renderer.root_folder_label)
|
||||
table.insert(self.lines, root_name)
|
||||
self:insert_highlight({ "NvimTreeRootFolder" }, 0, string.len(root_name))
|
||||
self.index = 1
|
||||
end
|
||||
|
||||
if self.explorer.live_filter.filter then
|
||||
local filter_line = string.format("%s/%s/", self.opts.live_filter.prefix, self.explorer.live_filter.filter)
|
||||
local filter_line = string.format("%s/%s/", self.explorer.opts.live_filter.prefix, self.explorer.live_filter.filter)
|
||||
table.insert(self.lines, filter_line)
|
||||
local prefix_length = string.len(self.opts.live_filter.prefix)
|
||||
local prefix_length = string.len(self.explorer.opts.live_filter.prefix)
|
||||
self:insert_highlight({ "NvimTreeLiveFilterPrefix" }, 0, prefix_length)
|
||||
self:insert_highlight({ "NvimTreeLiveFilterValue" }, prefix_length, string.len(filter_line))
|
||||
self.index = self.index + 1
|
||||
@ -413,11 +408,11 @@ function Builder:setup_hidden_display_function(opts)
|
||||
-- In case of missing field such as live_filter we zero it, otherwise keep field as is
|
||||
hidden_stats = vim.tbl_deep_extend("force", {
|
||||
live_filter = 0,
|
||||
git = 0,
|
||||
buf = 0,
|
||||
dotfile = 0,
|
||||
custom = 0,
|
||||
bookmark = 0,
|
||||
git = 0,
|
||||
buf = 0,
|
||||
dotfile = 0,
|
||||
custom = 0,
|
||||
bookmark = 0,
|
||||
}, hidden_stats or {})
|
||||
|
||||
local ok, result = pcall(hidden_display, hidden_stats)
|
||||
|
||||
@ -1,95 +0,0 @@
|
||||
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
|
||||
local diagnostics = require("nvim-tree.diagnostics")
|
||||
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
|
||||
local M = {
|
||||
-- highlight strings for the icons
|
||||
HS_ICON = {},
|
||||
|
||||
-- highlight groups for HL
|
||||
HG_FILE = {},
|
||||
HG_FOLDER = {},
|
||||
|
||||
-- position for HL
|
||||
HL_POS = HL_POSITION.none,
|
||||
}
|
||||
|
||||
---Diagnostics highlight group and position when highlight_diagnostics.
|
||||
---@param node Node
|
||||
---@return HL_POSITION position none when no status
|
||||
---@return string|nil group only when status
|
||||
function M.get_highlight(node)
|
||||
if not node or M.HL_POS == HL_POSITION.none then
|
||||
return HL_POSITION.none, nil
|
||||
end
|
||||
|
||||
local group
|
||||
local diag_status = diagnostics.get_diag_status(node)
|
||||
if node:is(DirectoryNode) then
|
||||
group = M.HS_FOLDER[diag_status and diag_status.value]
|
||||
else
|
||||
group = M.HS_FILE[diag_status and diag_status.value]
|
||||
end
|
||||
|
||||
if group then
|
||||
return M.HL_POS, group
|
||||
else
|
||||
return HL_POSITION.none, nil
|
||||
end
|
||||
end
|
||||
|
||||
---diagnostics icon if there is a status
|
||||
---@param node Node
|
||||
---@return HighlightedString|nil modified icon
|
||||
function M.get_icon(node)
|
||||
if node and M.config.diagnostics.enable and M.config.renderer.icons.show.diagnostics then
|
||||
local diag_status = diagnostics.get_diag_status(node)
|
||||
return M.ICON[diag_status and diag_status.value]
|
||||
end
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
M.config = {
|
||||
diagnostics = opts.diagnostics,
|
||||
renderer = opts.renderer,
|
||||
}
|
||||
|
||||
if opts.diagnostics.enable and opts.renderer.highlight_diagnostics then
|
||||
M.HL_POS = HL_POSITION[opts.renderer.highlight_diagnostics]
|
||||
end
|
||||
|
||||
M.HG_FILE[vim.diagnostic.severity.ERROR] = "NvimTreeDiagnosticErrorFileHL"
|
||||
M.HG_FILE[vim.diagnostic.severity.WARN] = "NvimTreeDiagnosticWarningFileHL"
|
||||
M.HG_FILE[vim.diagnostic.severity.INFO] = "NvimTreeDiagnosticInfoFileHL"
|
||||
M.HG_FILE[vim.diagnostic.severity.HINT] = "NvimTreeDiagnosticHintFileHL"
|
||||
|
||||
M.HG_FOLDER[vim.diagnostic.severity.ERROR] = "NvimTreeDiagnosticErrorFolderHL"
|
||||
M.HG_FOLDER[vim.diagnostic.severity.WARN] = "NvimTreeDiagnosticWarningFolderHL"
|
||||
M.HG_FOLDER[vim.diagnostic.severity.INFO] = "NvimTreeDiagnosticInfoFolderHL"
|
||||
M.HG_FOLDER[vim.diagnostic.severity.HINT] = "NvimTreeDiagnosticHintFolderHL"
|
||||
|
||||
M.HS_ICON[vim.diagnostic.severity.ERROR] = {
|
||||
str = M.config.diagnostics.icons.error,
|
||||
hl = { "NvimTreeDiagnosticErrorIcon" },
|
||||
}
|
||||
|
||||
M.HS_ICON[vim.diagnostic.severity.WARN] = {
|
||||
str = M.config.diagnostics.icons.warning,
|
||||
hl = { "NvimTreeDiagnosticWarningIcon" },
|
||||
}
|
||||
M.HS_ICON[vim.diagnostic.severity.INFO] = {
|
||||
str = M.config.diagnostics.icons.info,
|
||||
hl = { "NvimTreeDiagnosticInfoIcon" },
|
||||
}
|
||||
M.HS_ICON[vim.diagnostic.severity.HINT] = {
|
||||
str = M.config.diagnostics.icons.hint,
|
||||
hl = { "NvimTreeDiagnosticHintIcon" },
|
||||
}
|
||||
|
||||
for _, i in ipairs(M.HS_ICON) do
|
||||
vim.fn.sign_define(i.hl[1], { text = i.str, texthl = i.hl[1] })
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
@ -57,13 +57,13 @@ local function show()
|
||||
end
|
||||
|
||||
M.popup_win = vim.api.nvim_open_win(vim.api.nvim_create_buf(false, false), false, {
|
||||
relative = "win",
|
||||
row = 0,
|
||||
bufpos = { vim.api.nvim_win_get_cursor(0)[1] - 1, 0 },
|
||||
width = math.min(text_width, vim.o.columns - 2),
|
||||
height = 1,
|
||||
relative = "win",
|
||||
row = 0,
|
||||
bufpos = { vim.api.nvim_win_get_cursor(0)[1] - 1, 0 },
|
||||
width = math.min(text_width, vim.o.columns - 2),
|
||||
height = 1,
|
||||
noautocmd = true,
|
||||
style = "minimal",
|
||||
style = "minimal",
|
||||
})
|
||||
|
||||
local ns_id = vim.api.nvim_get_namespaces()["NvimTreeHighlights"]
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
local M = {}
|
||||
|
||||
M.diagnostics = require("nvim-tree.renderer.components.diagnostics")
|
||||
M.full_name = require("nvim-tree.renderer.components.full-name")
|
||||
M.devicons = require("nvim-tree.renderer.components.devicons")
|
||||
M.padding = require("nvim-tree.renderer.components.padding")
|
||||
|
||||
function M.setup(opts)
|
||||
M.diagnostics.setup(opts)
|
||||
M.full_name.setup(opts)
|
||||
M.devicons.setup(opts)
|
||||
M.padding.setup(opts)
|
||||
|
||||
@ -1,35 +1,29 @@
|
||||
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
|
||||
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
|
||||
|
||||
local Decorator = require("nvim-tree.renderer.decorator")
|
||||
|
||||
---@class (exact) DecoratorBookmarks: Decorator
|
||||
---@field icon HighlightedString?
|
||||
local DecoratorBookmarks = Decorator:new()
|
||||
local DecoratorBookmarks = Decorator:extend()
|
||||
|
||||
---Static factory method
|
||||
---@param opts table
|
||||
---@param explorer Explorer
|
||||
---@return DecoratorBookmarks
|
||||
function DecoratorBookmarks:create(opts, explorer)
|
||||
---@type DecoratorBookmarks
|
||||
local o = {
|
||||
explorer = explorer,
|
||||
enabled = true,
|
||||
hl_pos = HL_POSITION[opts.renderer.highlight_bookmarks] or HL_POSITION.none,
|
||||
icon_placement = ICON_PLACEMENT[opts.renderer.icons.bookmarks_placement] or ICON_PLACEMENT.none,
|
||||
}
|
||||
o = self:new(o)
|
||||
---@class DecoratorBookmarks
|
||||
---@overload fun(explorer: DecoratorArgs): DecoratorBookmarks
|
||||
|
||||
if opts.renderer.icons.show.bookmarks then
|
||||
o.icon = {
|
||||
str = opts.renderer.icons.glyphs.bookmark,
|
||||
---@protected
|
||||
---@param args DecoratorArgs
|
||||
function DecoratorBookmarks:new(args)
|
||||
Decorator.new(self, {
|
||||
explorer = args.explorer,
|
||||
enabled = true,
|
||||
hl_pos = args.explorer.opts.renderer.highlight_bookmarks or "none",
|
||||
icon_placement = args.explorer.opts.renderer.icons.bookmarks_placement or "none",
|
||||
})
|
||||
|
||||
if self.explorer.opts.renderer.icons.show.bookmarks then
|
||||
self.icon = {
|
||||
str = self.explorer.opts.renderer.icons.glyphs.bookmark,
|
||||
hl = { "NvimTreeBookmarkIcon" },
|
||||
}
|
||||
o:define_sign(o.icon)
|
||||
self:define_sign(self.icon)
|
||||
end
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
---Bookmark icon: renderer.icons.show.bookmarks and node is marked
|
||||
@ -45,7 +39,7 @@ end
|
||||
---@param node Node
|
||||
---@return string|nil group
|
||||
function DecoratorBookmarks:calculate_highlight(node)
|
||||
if self.hl_pos ~= HL_POSITION.none and self.explorer.marks:get(node) then
|
||||
if self.range ~= "none" and self.explorer.marks:get(node) then
|
||||
return "NvimTreeBookmarkHL"
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,34 +1,27 @@
|
||||
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
|
||||
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
|
||||
|
||||
local Decorator = require("nvim-tree.renderer.decorator")
|
||||
|
||||
---@class (exact) DecoratorCopied: Decorator
|
||||
---@field icon HighlightedString?
|
||||
local DecoratorCopied = Decorator:new()
|
||||
local DecoratorCopied = Decorator:extend()
|
||||
|
||||
---Static factory method
|
||||
---@param opts table
|
||||
---@param explorer Explorer
|
||||
---@return DecoratorCopied
|
||||
function DecoratorCopied:create(opts, explorer)
|
||||
---@type DecoratorCopied
|
||||
local o = {
|
||||
explorer = explorer,
|
||||
enabled = true,
|
||||
hl_pos = HL_POSITION[opts.renderer.highlight_clipboard] or HL_POSITION.none,
|
||||
icon_placement = ICON_PLACEMENT.none,
|
||||
}
|
||||
o = self:new(o)
|
||||
---@class DecoratorCopied
|
||||
---@overload fun(explorer: DecoratorArgs): DecoratorCopied
|
||||
|
||||
return o
|
||||
---@protected
|
||||
---@param args DecoratorArgs
|
||||
function DecoratorCopied:new(args)
|
||||
Decorator.new(self, {
|
||||
explorer = args.explorer,
|
||||
enabled = true,
|
||||
hl_pos = args.explorer.opts.renderer.highlight_clipboard or "none",
|
||||
icon_placement = "none",
|
||||
})
|
||||
end
|
||||
|
||||
---Copied highlight: renderer.highlight_clipboard and node is copied
|
||||
---@param node Node
|
||||
---@return string|nil group
|
||||
function DecoratorCopied:calculate_highlight(node)
|
||||
if self.hl_pos ~= HL_POSITION.none and self.explorer.clipboard:is_copied(node) then
|
||||
if self.range ~= "none" and self.explorer.clipboard:is_copied(node) then
|
||||
return "NvimTreeCopiedHL"
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,33 +1,27 @@
|
||||
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
|
||||
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
|
||||
|
||||
local Decorator = require("nvim-tree.renderer.decorator")
|
||||
|
||||
---@class (exact) DecoratorCut: Decorator
|
||||
local DecoratorCut = Decorator:new()
|
||||
local DecoratorCut = Decorator:extend()
|
||||
|
||||
---Static factory method
|
||||
---@param opts table
|
||||
---@param explorer Explorer
|
||||
---@return DecoratorCut
|
||||
function DecoratorCut:create(opts, explorer)
|
||||
---@type DecoratorCut
|
||||
local o = {
|
||||
explorer = explorer,
|
||||
enabled = true,
|
||||
hl_pos = HL_POSITION[opts.renderer.highlight_clipboard] or HL_POSITION.none,
|
||||
icon_placement = ICON_PLACEMENT.none,
|
||||
}
|
||||
o = self:new(o)
|
||||
---@class DecoratorCut
|
||||
---@overload fun(explorer: DecoratorArgs): DecoratorCut
|
||||
|
||||
return o
|
||||
---@protected
|
||||
---@param args DecoratorArgs
|
||||
function DecoratorCut:new(args)
|
||||
Decorator.new(self, {
|
||||
explorer = args.explorer,
|
||||
enabled = true,
|
||||
hl_pos = args.explorer.opts.renderer.highlight_clipboard or "none",
|
||||
icon_placement = "none",
|
||||
})
|
||||
end
|
||||
|
||||
---Cut highlight: renderer.highlight_clipboard and node is cut
|
||||
---@param node Node
|
||||
---@return string|nil group
|
||||
function DecoratorCut:calculate_highlight(node)
|
||||
if self.hl_pos ~= HL_POSITION.none and self.explorer.clipboard:is_cut(node) then
|
||||
if self.range ~= "none" and self.explorer.clipboard:is_cut(node) then
|
||||
return "NvimTreeCutHL"
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
local diagnostics = require("nvim-tree.diagnostics")
|
||||
|
||||
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
|
||||
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
|
||||
|
||||
local Decorator = require("nvim-tree.renderer.decorator")
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
|
||||
@ -35,38 +32,35 @@ local ICON_KEYS = {
|
||||
|
||||
---@class (exact) DecoratorDiagnostics: Decorator
|
||||
---@field icons HighlightedString[]?
|
||||
local DecoratorDiagnostics = Decorator:new()
|
||||
local DecoratorDiagnostics = Decorator:extend()
|
||||
|
||||
---Static factory method
|
||||
---@param opts table
|
||||
---@param explorer Explorer
|
||||
---@return DecoratorDiagnostics
|
||||
function DecoratorDiagnostics:create(opts, explorer)
|
||||
---@type DecoratorDiagnostics
|
||||
local o = {
|
||||
explorer = explorer,
|
||||
enabled = opts.diagnostics.enable,
|
||||
hl_pos = HL_POSITION[opts.renderer.highlight_diagnostics] or HL_POSITION.none,
|
||||
icon_placement = ICON_PLACEMENT[opts.renderer.icons.diagnostics_placement] or ICON_PLACEMENT.none,
|
||||
}
|
||||
o = self:new(o)
|
||||
---@class DecoratorDiagnostics
|
||||
---@overload fun(explorer: DecoratorArgs): DecoratorDiagnostics
|
||||
|
||||
if not o.enabled then
|
||||
return o
|
||||
---@protected
|
||||
---@param args DecoratorArgs
|
||||
function DecoratorDiagnostics:new(args)
|
||||
Decorator.new(self, {
|
||||
explorer = args.explorer,
|
||||
enabled = true,
|
||||
hl_pos = args.explorer.opts.renderer.highlight_diagnostics or "none",
|
||||
icon_placement = args.explorer.opts.renderer.icons.diagnostics_placement or "none",
|
||||
})
|
||||
|
||||
if not self.enabled then
|
||||
return
|
||||
end
|
||||
|
||||
if opts.renderer.icons.show.diagnostics then
|
||||
o.icons = {}
|
||||
if self.explorer.opts.renderer.icons.show.diagnostics then
|
||||
self.icons = {}
|
||||
for name, sev in pairs(ICON_KEYS) do
|
||||
o.icons[sev] = {
|
||||
str = opts.diagnostics.icons[name],
|
||||
self.icons[sev] = {
|
||||
str = self.explorer.opts.diagnostics.icons[name],
|
||||
hl = { HG_ICON[sev] },
|
||||
}
|
||||
o:define_sign(o.icons[sev])
|
||||
self:define_sign(self.icons[sev])
|
||||
end
|
||||
end
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
---Diagnostic icon: diagnostics.enable, renderer.icons.show.diagnostics and node has status
|
||||
@ -87,7 +81,7 @@ end
|
||||
---@param node Node
|
||||
---@return string|nil group
|
||||
function DecoratorDiagnostics:calculate_highlight(node)
|
||||
if not node or not self.enabled or self.hl_pos == HL_POSITION.none then
|
||||
if not node or not self.enabled or self.range == "none" then
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
local notify = require("nvim-tree.notify")
|
||||
|
||||
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
|
||||
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
|
||||
|
||||
local Decorator = require("nvim-tree.renderer.decorator")
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
|
||||
@ -20,52 +17,49 @@ local DirectoryNode = require("nvim-tree.node.directory")
|
||||
---@field folder_hl_by_xy table<GitXY, string>?
|
||||
---@field icons_by_status GitIconsByStatus?
|
||||
---@field icons_by_xy GitIconsByXY?
|
||||
local DecoratorGit = Decorator:new()
|
||||
local DecoratorGit = Decorator:extend()
|
||||
|
||||
---Static factory method
|
||||
---@param opts table
|
||||
---@param explorer Explorer
|
||||
---@return DecoratorGit
|
||||
function DecoratorGit:create(opts, explorer)
|
||||
---@type DecoratorGit
|
||||
local o = {
|
||||
explorer = explorer,
|
||||
enabled = opts.git.enable,
|
||||
hl_pos = HL_POSITION[opts.renderer.highlight_git] or HL_POSITION.none,
|
||||
icon_placement = ICON_PLACEMENT[opts.renderer.icons.git_placement] or ICON_PLACEMENT.none,
|
||||
}
|
||||
o = self:new(o)
|
||||
---@class DecoratorGit
|
||||
---@overload fun(explorer: DecoratorArgs): DecoratorGit
|
||||
|
||||
if not o.enabled then
|
||||
return o
|
||||
---@protected
|
||||
---@param args DecoratorArgs
|
||||
function DecoratorGit:new(args)
|
||||
Decorator.new(self, {
|
||||
explorer = args.explorer,
|
||||
enabled = args.explorer.opts.git.enable,
|
||||
hl_pos = args.explorer.opts.renderer.highlight_git or "none",
|
||||
icon_placement = args.explorer.opts.renderer.icons.git_placement or "none",
|
||||
})
|
||||
|
||||
if not self.enabled then
|
||||
return
|
||||
end
|
||||
|
||||
if o.hl_pos ~= HL_POSITION.none then
|
||||
o:build_file_folder_hl_by_xy()
|
||||
if self.range ~= "none" then
|
||||
self:build_file_folder_hl_by_xy()
|
||||
end
|
||||
|
||||
if opts.renderer.icons.show.git then
|
||||
o:build_icons_by_status(opts.renderer.icons.glyphs.git)
|
||||
o:build_icons_by_xy(o.icons_by_status)
|
||||
if self.explorer.opts.renderer.icons.show.git then
|
||||
self:build_icons_by_status(self.explorer.opts.renderer.icons.glyphs.git)
|
||||
self:build_icons_by_xy(self.icons_by_status)
|
||||
|
||||
for _, icon in pairs(o.icons_by_status) do
|
||||
for _, icon in pairs(self.icons_by_status) do
|
||||
self:define_sign(icon)
|
||||
end
|
||||
end
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
---@param glyphs GitGlyphsByStatus
|
||||
function DecoratorGit:build_icons_by_status(glyphs)
|
||||
self.icons_by_status = {}
|
||||
self.icons_by_status.staged = { str = glyphs.staged, hl = { "NvimTreeGitStagedIcon" }, ord = 1 }
|
||||
self.icons_by_status.unstaged = { str = glyphs.unstaged, hl = { "NvimTreeGitDirtyIcon" }, ord = 2 }
|
||||
self.icons_by_status.renamed = { str = glyphs.renamed, hl = { "NvimTreeGitRenamedIcon" }, ord = 3 }
|
||||
self.icons_by_status.deleted = { str = glyphs.deleted, hl = { "NvimTreeGitDeletedIcon" }, ord = 4 }
|
||||
self.icons_by_status.unmerged = { str = glyphs.unmerged, hl = { "NvimTreeGitMergeIcon" }, ord = 5 }
|
||||
self.icons_by_status = {}
|
||||
self.icons_by_status.staged = { str = glyphs.staged, hl = { "NvimTreeGitStagedIcon" }, ord = 1 }
|
||||
self.icons_by_status.unstaged = { str = glyphs.unstaged, hl = { "NvimTreeGitDirtyIcon" }, ord = 2 }
|
||||
self.icons_by_status.renamed = { str = glyphs.renamed, hl = { "NvimTreeGitRenamedIcon" }, ord = 3 }
|
||||
self.icons_by_status.deleted = { str = glyphs.deleted, hl = { "NvimTreeGitDeletedIcon" }, ord = 4 }
|
||||
self.icons_by_status.unmerged = { str = glyphs.unmerged, hl = { "NvimTreeGitMergeIcon" }, ord = 5 }
|
||||
self.icons_by_status.untracked = { str = glyphs.untracked, hl = { "NvimTreeGitNewIcon" }, ord = 6 }
|
||||
self.icons_by_status.ignored = { str = glyphs.ignored, hl = { "NvimTreeGitIgnoredIcon" }, ord = 7 }
|
||||
self.icons_by_status.ignored = { str = glyphs.ignored, hl = { "NvimTreeGitIgnoredIcon" }, ord = 7 }
|
||||
end
|
||||
|
||||
---@param icons GitIconsByXY
|
||||
@ -102,7 +96,7 @@ function DecoratorGit:build_icons_by_xy(icons)
|
||||
["DD"] = { icons.deleted },
|
||||
["DU"] = { icons.deleted, icons.unmerged },
|
||||
["!!"] = { icons.ignored },
|
||||
dirty = { icons.unstaged },
|
||||
dirty = { icons.unstaged },
|
||||
}
|
||||
end
|
||||
|
||||
@ -121,7 +115,7 @@ function DecoratorGit:build_file_folder_hl_by_xy()
|
||||
[" T"] = "NvimTreeGitFileDirtyHL",
|
||||
["MM"] = "NvimTreeGitFileDirtyHL",
|
||||
["AM"] = "NvimTreeGitFileDirtyHL",
|
||||
dirty = "NvimTreeGitFileDirtyHL",
|
||||
dirty = "NvimTreeGitFileDirtyHL",
|
||||
["A "] = "NvimTreeGitFileStagedHL",
|
||||
["??"] = "NvimTreeGitFileNewHL",
|
||||
["AU"] = "NvimTreeGitFileMergeHL",
|
||||
@ -165,7 +159,7 @@ function DecoratorGit:calculate_icons(node)
|
||||
for _, s in pairs(git_xy) do
|
||||
local icons = self.icons_by_xy[s]
|
||||
if not icons then
|
||||
if self.hl_pos == HL_POSITION.none then
|
||||
if self.range == "none" then
|
||||
notify.warn(string.format("Unrecognized git state '%s'", git_xy))
|
||||
end
|
||||
return nil
|
||||
@ -197,7 +191,7 @@ end
|
||||
---@param node Node
|
||||
---@return string|nil name
|
||||
function DecoratorGit:sign_name(node)
|
||||
if self.icon_placement ~= ICON_PLACEMENT.signcolumn then
|
||||
if self.icon_placement ~= "signcolumn" then
|
||||
return
|
||||
end
|
||||
|
||||
@ -211,7 +205,7 @@ end
|
||||
---@param node Node
|
||||
---@return string|nil group
|
||||
function DecoratorGit:calculate_highlight(node)
|
||||
if not node or not self.enabled or self.hl_pos == HL_POSITION.none then
|
||||
if not node or not self.enabled or self.range == "none" then
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
@ -1,36 +1,30 @@
|
||||
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
|
||||
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
|
||||
|
||||
local Decorator = require("nvim-tree.renderer.decorator")
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
|
||||
---@class (exact) DecoratorHidden: Decorator
|
||||
---@field icon HighlightedString?
|
||||
local DecoratorHidden = Decorator:new()
|
||||
local DecoratorHidden = Decorator:extend()
|
||||
|
||||
---Static factory method
|
||||
---@param opts table
|
||||
---@param explorer Explorer
|
||||
---@return DecoratorHidden
|
||||
function DecoratorHidden:create(opts, explorer)
|
||||
---@type DecoratorHidden
|
||||
local o = {
|
||||
explorer = explorer,
|
||||
enabled = true,
|
||||
hl_pos = HL_POSITION[opts.renderer.highlight_hidden] or HL_POSITION.none,
|
||||
icon_placement = ICON_PLACEMENT[opts.renderer.icons.hidden_placement] or ICON_PLACEMENT.none,
|
||||
}
|
||||
o = self:new(o)
|
||||
---@class DecoratorHidden
|
||||
---@overload fun(explorer: DecoratorArgs): DecoratorHidden
|
||||
|
||||
if opts.renderer.icons.show.hidden then
|
||||
o.icon = {
|
||||
str = opts.renderer.icons.glyphs.hidden,
|
||||
---@protected
|
||||
---@param args DecoratorArgs
|
||||
function DecoratorHidden:new(args)
|
||||
Decorator.new(self, {
|
||||
explorer = args.explorer,
|
||||
enabled = true,
|
||||
hl_pos = args.explorer.opts.renderer.highlight_hidden or "none",
|
||||
icon_placement = args.explorer.opts.renderer.icons.hidden_placement or "none",
|
||||
})
|
||||
|
||||
if self.explorer.opts.renderer.icons.show.hidden then
|
||||
self.icon = {
|
||||
str = self.explorer.opts.renderer.icons.glyphs.hidden,
|
||||
hl = { "NvimTreeHiddenIcon" },
|
||||
}
|
||||
o:define_sign(o.icon)
|
||||
self:define_sign(self.icon)
|
||||
end
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
---Hidden icon: renderer.icons.show.hidden and node starts with `.` (dotfile).
|
||||
@ -46,7 +40,7 @@ end
|
||||
---@param node Node
|
||||
---@return string|nil group
|
||||
function DecoratorHidden:calculate_highlight(node)
|
||||
if not self.enabled or self.hl_pos == HL_POSITION.none or not node:is_dotfile() then
|
||||
if not self.enabled or self.range == "none" or not node:is_dotfile() then
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
@ -1,16 +1,33 @@
|
||||
local Class = require("nvim-tree.class")
|
||||
local Class = require("nvim-tree.classic")
|
||||
|
||||
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
|
||||
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
|
||||
---@alias DecoratorRange "none" | "icon" | "name" | "all"
|
||||
---@alias DecoratorIconPlacement "none" | "before" | "after" | "signcolumn" | "right_align"
|
||||
|
||||
---Abstract Decorator
|
||||
---Uses the factory pattern to instantiate child instances.
|
||||
---@class (exact) Decorator: Class
|
||||
---@field protected explorer Explorer
|
||||
---@field protected enabled boolean
|
||||
---@field protected hl_pos HL_POSITION
|
||||
---@field protected icon_placement ICON_PLACEMENT
|
||||
local Decorator = Class:new()
|
||||
---@field protected range DecoratorRange
|
||||
---@field protected icon_placement DecoratorIconPlacement
|
||||
local Decorator = Class:extend()
|
||||
|
||||
---@class (exact) DecoratorArgs
|
||||
---@field explorer Explorer
|
||||
|
||||
---@class (exact) AbstractDecoratorArgs: DecoratorArgs
|
||||
---@field enabled boolean
|
||||
---@field hl_pos DecoratorRange
|
||||
---@field icon_placement DecoratorIconPlacement
|
||||
|
||||
---@protected
|
||||
---@param args AbstractDecoratorArgs
|
||||
function Decorator:new(args)
|
||||
self.explorer = args.explorer
|
||||
self.enabled = args.enabled
|
||||
self.range = args.hl_pos
|
||||
self.icon_placement = args.icon_placement
|
||||
end
|
||||
|
||||
---Maybe highlight groups
|
||||
---@param node Node
|
||||
@ -19,13 +36,13 @@ local Decorator = Class:new()
|
||||
function Decorator:groups_icon_name(node)
|
||||
local icon_hl, name_hl
|
||||
|
||||
if self.enabled and self.hl_pos ~= HL_POSITION.none then
|
||||
if self.enabled and self.range ~= "none" then
|
||||
local hl = self:calculate_highlight(node)
|
||||
|
||||
if self.hl_pos == HL_POSITION.all or self.hl_pos == HL_POSITION.icon then
|
||||
if self.range == "all" or self.range == "icon" then
|
||||
icon_hl = hl
|
||||
end
|
||||
if self.hl_pos == HL_POSITION.all or self.hl_pos == HL_POSITION.name then
|
||||
if self.range == "all" or self.range == "name" then
|
||||
name_hl = hl
|
||||
end
|
||||
end
|
||||
@ -37,7 +54,7 @@ end
|
||||
---@param node Node
|
||||
---@return string|nil name
|
||||
function Decorator:sign_name(node)
|
||||
if not self.enabled or self.icon_placement ~= ICON_PLACEMENT.signcolumn then
|
||||
if not self.enabled or self.icon_placement ~= "signcolumn" then
|
||||
return
|
||||
end
|
||||
|
||||
@ -47,33 +64,33 @@ function Decorator:sign_name(node)
|
||||
end
|
||||
end
|
||||
|
||||
---Icons when ICON_PLACEMENT.before
|
||||
---Icons when "before"
|
||||
---@param node Node
|
||||
---@return HighlightedString[]|nil icons
|
||||
function Decorator:icons_before(node)
|
||||
if not self.enabled or self.icon_placement ~= ICON_PLACEMENT.before then
|
||||
if not self.enabled or self.icon_placement ~= "before" then
|
||||
return
|
||||
end
|
||||
|
||||
return self:calculate_icons(node)
|
||||
end
|
||||
|
||||
---Icons when ICON_PLACEMENT.after
|
||||
---Icons when "after"
|
||||
---@param node Node
|
||||
---@return HighlightedString[]|nil icons
|
||||
function Decorator:icons_after(node)
|
||||
if not self.enabled or self.icon_placement ~= ICON_PLACEMENT.after then
|
||||
if not self.enabled or self.icon_placement ~= "after" then
|
||||
return
|
||||
end
|
||||
|
||||
return self:calculate_icons(node)
|
||||
end
|
||||
|
||||
---Icons when ICON_PLACEMENT.right_align
|
||||
---Icons when "right_align"
|
||||
---@param node Node
|
||||
---@return HighlightedString[]|nil icons
|
||||
function Decorator:icons_right_align(node)
|
||||
if not self.enabled or self.icon_placement ~= ICON_PLACEMENT.right_align then
|
||||
if not self.enabled or self.icon_placement ~= "right_align" then
|
||||
return
|
||||
end
|
||||
|
||||
@ -109,7 +126,7 @@ function Decorator:define_sign(icon)
|
||||
|
||||
-- don't use sign if not defined
|
||||
if #icon.str < 1 then
|
||||
self.icon_placement = ICON_PLACEMENT.none
|
||||
self.icon_placement = "none"
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
@ -1,42 +1,36 @@
|
||||
local buffers = require("nvim-tree.buffers")
|
||||
|
||||
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
|
||||
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
|
||||
|
||||
local Decorator = require("nvim-tree.renderer.decorator")
|
||||
local DirectoryNode = require("nvim-tree.node.directory")
|
||||
|
||||
---@class (exact) DecoratorModified: Decorator
|
||||
---@field icon HighlightedString|nil
|
||||
local DecoratorModified = Decorator:new()
|
||||
---@field icon HighlightedString?
|
||||
local DecoratorModified = Decorator:extend()
|
||||
|
||||
---Static factory method
|
||||
---@param opts table
|
||||
---@param explorer Explorer
|
||||
---@return DecoratorModified
|
||||
function DecoratorModified:create(opts, explorer)
|
||||
---@type DecoratorModified
|
||||
local o = {
|
||||
explorer = explorer,
|
||||
enabled = opts.modified.enable,
|
||||
hl_pos = HL_POSITION[opts.renderer.highlight_modified] or HL_POSITION.none,
|
||||
icon_placement = ICON_PLACEMENT[opts.renderer.icons.modified_placement] or ICON_PLACEMENT.none,
|
||||
}
|
||||
o = self:new(o)
|
||||
---@class DecoratorModified
|
||||
---@overload fun(explorer: DecoratorArgs): DecoratorModified
|
||||
|
||||
if not o.enabled then
|
||||
return o
|
||||
---@protected
|
||||
---@param args DecoratorArgs
|
||||
function DecoratorModified:new(args)
|
||||
Decorator.new(self, {
|
||||
explorer = args.explorer,
|
||||
enabled = true,
|
||||
hl_pos = args.explorer.opts.renderer.highlight_modified or "none",
|
||||
icon_placement = args.explorer.opts.renderer.icons.modified_placement or "none",
|
||||
})
|
||||
|
||||
if not self.enabled then
|
||||
return
|
||||
end
|
||||
|
||||
if opts.renderer.icons.show.modified then
|
||||
o.icon = {
|
||||
str = opts.renderer.icons.glyphs.modified,
|
||||
if self.explorer.opts.renderer.icons.show.modified then
|
||||
self.icon = {
|
||||
str = self.explorer.opts.renderer.icons.glyphs.modified,
|
||||
hl = { "NvimTreeModifiedIcon" },
|
||||
}
|
||||
o:define_sign(o.icon)
|
||||
self:define_sign(self.icon)
|
||||
end
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
---Modified icon: modified.enable, renderer.icons.show.modified and node is modified
|
||||
@ -52,7 +46,7 @@ end
|
||||
---@param node Node
|
||||
---@return string|nil group
|
||||
function DecoratorModified:calculate_highlight(node)
|
||||
if not self.enabled or self.hl_pos == HL_POSITION.none or not buffers.is_modified(node) then
|
||||
if not self.enabled or self.range == "none" or not buffers.is_modified(node) then
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
@ -1,36 +1,30 @@
|
||||
local buffers = require("nvim-tree.buffers")
|
||||
|
||||
local HL_POSITION = require("nvim-tree.enum").HL_POSITION
|
||||
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
|
||||
|
||||
local Decorator = require("nvim-tree.renderer.decorator")
|
||||
|
||||
---@class (exact) DecoratorOpened: Decorator
|
||||
---@field icon HighlightedString|nil
|
||||
local DecoratorOpened = Decorator:new()
|
||||
local DecoratorOpened = Decorator:extend()
|
||||
|
||||
---Static factory method
|
||||
---@param opts table
|
||||
---@param explorer Explorer
|
||||
---@return DecoratorOpened
|
||||
function DecoratorOpened:create(opts, explorer)
|
||||
---@type DecoratorOpened
|
||||
local o = {
|
||||
explorer = explorer,
|
||||
enabled = true,
|
||||
hl_pos = HL_POSITION[opts.renderer.highlight_opened_files] or HL_POSITION.none,
|
||||
icon_placement = ICON_PLACEMENT.none,
|
||||
}
|
||||
o = self:new(o)
|
||||
---@class DecoratorOpened
|
||||
---@overload fun(explorer: DecoratorArgs): DecoratorOpened
|
||||
|
||||
return o
|
||||
---@protected
|
||||
---@param args DecoratorArgs
|
||||
function DecoratorOpened:new(args)
|
||||
Decorator.new(self, {
|
||||
explorer = args.explorer,
|
||||
enabled = true,
|
||||
hl_pos = args.explorer.opts.renderer.highlight_opened_files or "none",
|
||||
icon_placement = "none",
|
||||
})
|
||||
end
|
||||
|
||||
---Opened highlight: renderer.highlight_opened_files and node has an open buffer
|
||||
---@param node Node
|
||||
---@return string|nil group
|
||||
function DecoratorOpened:calculate_highlight(node)
|
||||
if self.hl_pos ~= HL_POSITION.none and buffers.is_opened(node) then
|
||||
if self.range ~= "none" and buffers.is_opened(node) then
|
||||
return "NvimTreeOpenedHL"
|
||||
end
|
||||
end
|
||||
|
||||
@ -2,6 +2,7 @@ local log = require("nvim-tree.log")
|
||||
local view = require("nvim-tree.view")
|
||||
local events = require("nvim-tree.events")
|
||||
|
||||
local Class = require("nvim-tree.classic")
|
||||
local Builder = require("nvim-tree.renderer.builder")
|
||||
|
||||
local SIGN_GROUP = "NvimTreeRendererSigns"
|
||||
@ -10,26 +11,20 @@ local namespace_highlights_id = vim.api.nvim_create_namespace("NvimTreeHighlight
|
||||
local namespace_extmarks_id = vim.api.nvim_create_namespace("NvimTreeExtmarks")
|
||||
local namespace_virtual_lines_id = vim.api.nvim_create_namespace("NvimTreeVirtualLines")
|
||||
|
||||
---@class (exact) Renderer
|
||||
---@field private __index? table
|
||||
---@field private opts table user options
|
||||
---@field private explorer Explorer
|
||||
local Renderer = {}
|
||||
---@class (exact) Renderer: Class
|
||||
---@field explorer Explorer
|
||||
local Renderer = Class:extend()
|
||||
|
||||
---@param opts table user options
|
||||
---@param explorer Explorer
|
||||
---@return Renderer
|
||||
function Renderer:new(opts, explorer)
|
||||
---@type Renderer
|
||||
local o = {
|
||||
opts = opts,
|
||||
explorer = explorer,
|
||||
}
|
||||
---@class Renderer
|
||||
---@overload fun(args: RendererArgs): Renderer
|
||||
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
---@class (exact) RendererArgs
|
||||
---@field explorer Explorer
|
||||
|
||||
return o
|
||||
---@protected
|
||||
---@param args RendererArgs
|
||||
function Renderer:new(args)
|
||||
self.explorer = args.explorer
|
||||
end
|
||||
|
||||
---@private
|
||||
@ -64,9 +59,9 @@ function Renderer:_draw(bufnr, lines, hl_args, signs, extmarks, virtual_lines)
|
||||
for i, extname in pairs(extmarks) do
|
||||
for _, mark in ipairs(extname) do
|
||||
vim.api.nvim_buf_set_extmark(bufnr, namespace_extmarks_id, i, -1, {
|
||||
virt_text = { { mark.str, mark.hl } },
|
||||
virt_text = { { mark.str, mark.hl } },
|
||||
virt_text_pos = "right_align",
|
||||
hl_mode = "combine",
|
||||
hl_mode = "combine",
|
||||
})
|
||||
end
|
||||
end
|
||||
@ -74,8 +69,8 @@ function Renderer:_draw(bufnr, lines, hl_args, signs, extmarks, virtual_lines)
|
||||
vim.api.nvim_buf_clear_namespace(bufnr, namespace_virtual_lines_id, 0, -1)
|
||||
for line_nr, vlines in pairs(virtual_lines) do
|
||||
vim.api.nvim_buf_set_extmark(bufnr, namespace_virtual_lines_id, line_nr, 0, {
|
||||
virt_lines = vlines,
|
||||
virt_lines_above = false,
|
||||
virt_lines = vlines,
|
||||
virt_lines_above = false,
|
||||
virt_lines_leftcol = true,
|
||||
})
|
||||
end
|
||||
@ -106,7 +101,7 @@ function Renderer:draw()
|
||||
|
||||
local cursor = vim.api.nvim_win_get_cursor(view.get_winnr() or 0)
|
||||
|
||||
local builder = Builder:new(self.opts, self.explorer):build()
|
||||
local builder = Builder(self.explorer):build()
|
||||
|
||||
self:_draw(bufnr, builder.lines, builder.hl_args, builder.signs, builder.extmarks, builder.virtual_lines)
|
||||
|
||||
|
||||
@ -15,31 +15,31 @@ local DEFAULT_MAX_WIDTH = -1
|
||||
local DEFAULT_PADDING = 1
|
||||
|
||||
M.View = {
|
||||
adaptive_size = false,
|
||||
adaptive_size = false,
|
||||
centralize_selection = false,
|
||||
tabpages = {},
|
||||
cursors = {},
|
||||
hide_root_folder = false,
|
||||
live_filter = {
|
||||
tabpages = {},
|
||||
cursors = {},
|
||||
hide_root_folder = false,
|
||||
live_filter = {
|
||||
prev_focused_node = nil,
|
||||
},
|
||||
winopts = {
|
||||
winopts = {
|
||||
relativenumber = false,
|
||||
number = false,
|
||||
list = false,
|
||||
foldenable = false,
|
||||
winfixwidth = true,
|
||||
winfixheight = true,
|
||||
spell = false,
|
||||
signcolumn = "yes",
|
||||
foldmethod = "manual",
|
||||
foldcolumn = "0",
|
||||
cursorcolumn = false,
|
||||
cursorline = true,
|
||||
cursorlineopt = "both",
|
||||
colorcolumn = "0",
|
||||
wrap = false,
|
||||
winhl = table.concat({
|
||||
number = false,
|
||||
list = false,
|
||||
foldenable = false,
|
||||
winfixwidth = true,
|
||||
winfixheight = true,
|
||||
spell = false,
|
||||
signcolumn = "yes",
|
||||
foldmethod = "manual",
|
||||
foldcolumn = "0",
|
||||
cursorcolumn = false,
|
||||
cursorline = true,
|
||||
cursorlineopt = "both",
|
||||
colorcolumn = "0",
|
||||
wrap = false,
|
||||
winhl = table.concat({
|
||||
"EndOfBuffer:NvimTreeEndOfBuffer",
|
||||
"CursorLine:NvimTreeCursorLine",
|
||||
"CursorLineNr:NvimTreeCursorLineNr",
|
||||
@ -152,7 +152,6 @@ local function set_window_options_and_buffer()
|
||||
pcall(vim.api.nvim_command, "buffer " .. M.get_bufnr())
|
||||
|
||||
if vim.fn.has("nvim-0.10") == 1 then
|
||||
|
||||
local eventignore = vim.api.nvim_get_option_value("eventignore", {})
|
||||
vim.api.nvim_set_option_value("eventignore", "all", {})
|
||||
|
||||
@ -161,9 +160,7 @@ local function set_window_options_and_buffer()
|
||||
end
|
||||
|
||||
vim.api.nvim_set_option_value("eventignore", eventignore, {})
|
||||
|
||||
else
|
||||
|
||||
local eventignore = vim.api.nvim_get_option("eventignore") ---@diagnostic disable-line: deprecated
|
||||
vim.api.nvim_set_option("eventignore", "all") ---@diagnostic disable-line: deprecated
|
||||
|
||||
@ -172,7 +169,6 @@ local function set_window_options_and_buffer()
|
||||
end
|
||||
|
||||
vim.api.nvim_set_option("eventignore", eventignore) ---@diagnostic disable-line: deprecated
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ local notify = require("nvim-tree.notify")
|
||||
local log = require("nvim-tree.log")
|
||||
local utils = require("nvim-tree.utils")
|
||||
|
||||
local Class = require("nvim-tree.class")
|
||||
local Class = require("nvim-tree.classic")
|
||||
|
||||
local FS_EVENT_FLAGS = {
|
||||
-- inotify or equivalent will be used; fallback to stat has not yet been implemented
|
||||
@ -15,36 +15,45 @@ local M = {
|
||||
config = {},
|
||||
}
|
||||
|
||||
---Registry of all events
|
||||
---@type Event[]
|
||||
local events = {}
|
||||
|
||||
---@class (exact) Event: Class
|
||||
---@field destroyed boolean
|
||||
---@field private path string
|
||||
---@field private fs_event uv.uv_fs_event_t?
|
||||
---@field private listeners function[]
|
||||
local Event = Class:new()
|
||||
local Event = Class:extend()
|
||||
|
||||
---Registry of all events
|
||||
---@type Event[]
|
||||
local events = {}
|
||||
---@class Event
|
||||
---@overload fun(args: EventArgs): Event
|
||||
|
||||
---@class (exact) EventArgs
|
||||
---@field path string
|
||||
|
||||
---@protected
|
||||
---@param args EventArgs
|
||||
function Event:new(args)
|
||||
self.destroyed = false
|
||||
self.path = args.path
|
||||
self.fs_event = nil
|
||||
self.listeners = {}
|
||||
end
|
||||
|
||||
---Static factory method
|
||||
---Creates and starts an Event
|
||||
---@param path string
|
||||
---@return Event|nil
|
||||
function Event:create(path)
|
||||
log.line("watcher", "Event:create '%s'", path)
|
||||
---nil on failure to start
|
||||
---@param args EventArgs
|
||||
---@return Event?
|
||||
function Event:create(args)
|
||||
log.line("watcher", "Event:create '%s'", args.path)
|
||||
|
||||
---@type Event
|
||||
local o = {
|
||||
destroyed = false,
|
||||
path = path,
|
||||
fs_event = nil,
|
||||
listeners = {},
|
||||
}
|
||||
o = self:new(o)
|
||||
local event = Event(args)
|
||||
|
||||
if o:start() then
|
||||
events[path] = o
|
||||
return o
|
||||
if event:start() then
|
||||
events[event.path] = event
|
||||
return event
|
||||
else
|
||||
return nil
|
||||
end
|
||||
@ -128,8 +137,10 @@ function Event:destroy(message)
|
||||
events[self.path] = nil
|
||||
end
|
||||
|
||||
---Static factory method
|
||||
---Creates and starts a Watcher
|
||||
---Registry of all watchers
|
||||
---@type Watcher[]
|
||||
local watchers = {}
|
||||
|
||||
---@class (exact) Watcher: Class
|
||||
---@field data table user data
|
||||
---@field destroyed boolean
|
||||
@ -138,43 +149,50 @@ end
|
||||
---@field private files string[]?
|
||||
---@field private listener fun(filename: string)?
|
||||
---@field private event Event
|
||||
local Watcher = Class:new()
|
||||
local Watcher = Class:extend()
|
||||
|
||||
---Registry of all watchers
|
||||
---@type Watcher[]
|
||||
local watchers = {}
|
||||
---@class Watcher
|
||||
---@overload fun(args: WatcherArgs): Watcher
|
||||
|
||||
---@class (exact) WatcherArgs
|
||||
---@field path string
|
||||
---@field files string[]|nil
|
||||
---@field callback fun(watcher: Watcher)
|
||||
---@field data table? user data
|
||||
|
||||
---@protected
|
||||
---@param args WatcherArgs
|
||||
function Watcher:new(args)
|
||||
self.data = args.data
|
||||
self.destroyed = false
|
||||
self.path = args.path
|
||||
self.callback = args.callback
|
||||
self.files = args.files
|
||||
self.listener = nil
|
||||
end
|
||||
|
||||
---Static factory method
|
||||
---@param path string
|
||||
---@param files string[]|nil
|
||||
---@param callback fun(watcher: Watcher)
|
||||
---@param data table user data
|
||||
---Creates and starts a Watcher
|
||||
---nil on failure to create Event
|
||||
---@param args WatcherArgs
|
||||
---@return Watcher|nil
|
||||
function Watcher:create(path, files, callback, data)
|
||||
log.line("watcher", "Watcher:create '%s' %s", path, vim.inspect(files))
|
||||
function Watcher:create(args)
|
||||
log.line("watcher", "Watcher:create '%s' %s", args.path, vim.inspect(args.files))
|
||||
|
||||
local event = events[path] or Event:create(path)
|
||||
local event = events[args.path] or Event:create({ path = args.path })
|
||||
if not event then
|
||||
return nil
|
||||
end
|
||||
|
||||
---@type Watcher
|
||||
local o = {
|
||||
data = data,
|
||||
destroyed = false,
|
||||
path = path,
|
||||
callback = callback,
|
||||
files = files,
|
||||
listener = nil,
|
||||
event = event,
|
||||
}
|
||||
o = self:new(o)
|
||||
local watcher = Watcher(args)
|
||||
|
||||
o:start()
|
||||
watcher.event = event
|
||||
|
||||
table.insert(watchers, o)
|
||||
watcher:start()
|
||||
|
||||
return o
|
||||
table.insert(watchers, watcher)
|
||||
|
||||
return watcher
|
||||
end
|
||||
|
||||
function Watcher:start()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user