refactor(#2830): multi instance nvim-tree.marks (#2838)

refactor(#2380): multi instance nvim-tree.marks
This commit is contained in:
Alexander Courtis 2024-07-21 16:12:42 +10:00 committed by GitHub
parent 48a9290757
commit 4e396b2624
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 135 additions and 66 deletions

View file

@ -1,4 +1,5 @@
local lib = require "nvim-tree.lib" local lib = require "nvim-tree.lib"
local core = require "nvim-tree.core"
local view = require "nvim-tree.view" local view = require "nvim-tree.view"
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local actions = require "nvim-tree.actions" local actions = require "nvim-tree.actions"
@ -6,7 +7,6 @@ local appearance_diagnostics = require "nvim-tree.appearance.diagnostics"
local events = require "nvim-tree.events" local events = require "nvim-tree.events"
local help = require "nvim-tree.help" local help = require "nvim-tree.help"
local live_filter = require "nvim-tree.live-filter" local live_filter = require "nvim-tree.live-filter"
local marks = require "nvim-tree.marks"
local marks_navigation = require "nvim-tree.marks.navigation" local marks_navigation = require "nvim-tree.marks.navigation"
local marks_bulk_delete = require "nvim-tree.marks.bulk-delete" local marks_bulk_delete = require "nvim-tree.marks.bulk-delete"
local marks_bulk_trash = require "nvim-tree.marks.bulk-trash" local marks_bulk_trash = require "nvim-tree.marks.bulk-trash"
@ -43,9 +43,10 @@ local Api = {
diagnostics = {}, diagnostics = {},
} }
--- Do nothing when setup not called. --- Print error when setup not called.
--- f function to invoke --- f function to invoke
---@param f function ---@param f function
---@return fun(...) : any
local function wrap(f) local function wrap(f)
return function(...) return function(...)
if vim.g.NvimTreeSetup == 1 then if vim.g.NvimTreeSetup == 1 then
@ -56,13 +57,13 @@ local function wrap(f)
end end
end end
---Inject the node as the first argument if absent. ---Inject the node as the first argument if present otherwise do nothing.
---@param fn function function to invoke ---@param fn function function to invoke
local function wrap_node(fn) local function wrap_node(fn)
return function(node, ...) return function(node, ...)
node = node or lib.get_node_at_cursor() node = node or lib.get_node_at_cursor()
if node then if node then
fn(node, ...) return fn(node, ...)
end end
end end
end end
@ -72,10 +73,36 @@ end
local function wrap_node_or_nil(fn) local function wrap_node_or_nil(fn)
return function(node, ...) return function(node, ...)
node = node or lib.get_node_at_cursor() node = node or lib.get_node_at_cursor()
fn(node, ...) return fn(node, ...)
end end
end end
---Inject the explorer as the first argument if present otherwise do nothing.
---@param fn function function to invoke
---@return fun(...) : any
local function wrap_explorer(fn)
return function(...)
local explorer = core.get_explorer()
if explorer then
return fn(explorer, ...)
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
---@param member_method string method name to invoke on member
---@return fun(...) : any
local function wrap_explorer_member(explorer_member, member_method)
return wrap(function(...)
local explorer = core.get_explorer()
if explorer then
return explorer[explorer_member][member_method](explorer[explorer_member], ...)
end
end)
end
---@class ApiTreeOpenOpts ---@class ApiTreeOpenOpts
---@field path string|nil path ---@field path string|nil path
---@field current_window boolean|nil default false ---@field current_window boolean|nil default false
@ -241,13 +268,13 @@ Api.events.Event = events.Event
Api.live_filter.start = wrap(live_filter.start_filtering) Api.live_filter.start = wrap(live_filter.start_filtering)
Api.live_filter.clear = wrap(live_filter.clear_filter) Api.live_filter.clear = wrap(live_filter.clear_filter)
Api.marks.get = wrap_node(marks.get_mark) Api.marks.get = wrap_node(wrap_explorer_member("marks", "get_mark"))
Api.marks.list = wrap(marks.get_marks) Api.marks.list = wrap_explorer_member("marks", "get_marks")
Api.marks.toggle = wrap_node(marks.toggle_mark) Api.marks.toggle = wrap_node(wrap_explorer_member("marks", "toggle_mark"))
Api.marks.clear = wrap(marks.clear_marks) Api.marks.clear = wrap_explorer_member("marks", "clear_marks")
Api.marks.bulk.delete = wrap(marks_bulk_delete.bulk_delete) Api.marks.bulk.delete = wrap_explorer(marks_bulk_delete.bulk_delete)
Api.marks.bulk.trash = wrap(marks_bulk_trash.bulk_trash) Api.marks.bulk.trash = wrap_explorer(marks_bulk_trash.bulk_trash)
Api.marks.bulk.move = wrap(marks_bulk_move.bulk_move) Api.marks.bulk.move = wrap_explorer(marks_bulk_move.bulk_move)
Api.marks.navigate.next = wrap(marks_navigation.next) Api.marks.navigate.next = wrap(marks_navigation.next)
Api.marks.navigate.prev = wrap(marks_navigation.prev) Api.marks.navigate.prev = wrap(marks_navigation.prev)
Api.marks.navigate.select = wrap(marks_navigation.select) Api.marks.navigate.select = wrap(marks_navigation.select)

View file

@ -1,5 +1,4 @@
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local marks = require "nvim-tree.marks"
local M = { local M = {
ignore_list = {}, ignore_list = {},
@ -155,8 +154,11 @@ function M.prepare(git_status)
status.bufinfo = vim.fn.getbufinfo { buflisted = 1 } status.bufinfo = vim.fn.getbufinfo { buflisted = 1 }
end end
for _, node in pairs(marks.get_marks()) do local explorer = require("nvim-tree.core").get_explorer()
status.bookmarks[node.absolute_path] = node.type if explorer then
for _, node in pairs(explorer.marks:get_marks()) do
status.bookmarks[node.absolute_path] = node.type
end
end end
return status return status

View file

@ -2,6 +2,7 @@ local git = require "nvim-tree.git"
local notify = require "nvim-tree.notify" local notify = require "nvim-tree.notify"
local watch = require "nvim-tree.explorer.watch" local watch = require "nvim-tree.explorer.watch"
local explorer_node = require "nvim-tree.explorer.node" local explorer_node = require "nvim-tree.explorer.node"
local Marks = require "nvim-tree.marks"
local M = {} local M = {}
@ -12,6 +13,7 @@ M.reload = require("nvim-tree.explorer.reload").reload
---@field absolute_path string ---@field absolute_path string
---@field nodes Node[] ---@field nodes Node[]
---@field open boolean ---@field open boolean
---@field marks Marks
local Explorer = {} local Explorer = {}
Explorer.__index = Explorer Explorer.__index = Explorer
@ -36,6 +38,7 @@ function Explorer.new(path)
absolute_path = path, absolute_path = path,
nodes = {}, nodes = {},
open = true, open = true,
marks = Marks:new(),
}, Explorer) }, Explorer)
explorer.watcher = watch.create_watcher(explorer) explorer.watcher = watch.create_watcher(explorer)
explorer:_load(explorer) explorer:_load(explorer)

View file

@ -1,4 +1,3 @@
local marks = require "nvim-tree.marks"
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local remove_file = require "nvim-tree.actions.fs.remove-file" local remove_file = require "nvim-tree.actions.fs.remove-file"
local notify = require "nvim-tree.notify" local notify = require "nvim-tree.notify"
@ -10,12 +9,13 @@ local M = {
--- Delete nodes; each removal will be optionally notified --- Delete nodes; each removal will be optionally notified
---@param nodes Node[] ---@param nodes Node[]
local function do_delete(nodes) ---@param marks Marks
local function do_delete(marks, nodes)
for _, node in pairs(nodes) do for _, node in pairs(nodes) do
remove_file.remove(node) remove_file.remove(node)
end end
marks.clear_marks() marks:clear_marks()
if not M.config.filesystem_watchers.enable then if not M.config.filesystem_watchers.enable then
require("nvim-tree.actions.reloaders").reload_explorer() require("nvim-tree.actions.reloaders").reload_explorer()
@ -23,8 +23,15 @@ local function do_delete(nodes)
end end
--- Delete marked nodes, optionally prompting --- Delete marked nodes, optionally prompting
function M.bulk_delete() ---@param explorer Explorer
local nodes = marks.get_marks() function M.bulk_delete(explorer)
if not explorer then
return
end
local marks = explorer.marks
local nodes = marks:get_marks()
if not nodes or #nodes == 0 then if not nodes or #nodes == 0 then
notify.warn "No bookmarksed to delete." notify.warn "No bookmarksed to delete."
return return
@ -36,11 +43,11 @@ function M.bulk_delete()
lib.prompt(prompt_input, prompt_select, { "", "y" }, { "No", "Yes" }, "nvimtree_bulk_delete", function(item_short) lib.prompt(prompt_input, prompt_select, { "", "y" }, { "No", "Yes" }, "nvimtree_bulk_delete", function(item_short)
utils.clear_prompt() utils.clear_prompt()
if item_short == "y" then if item_short == "y" then
do_delete(nodes) do_delete(marks, nodes)
end end
end) end)
else else
do_delete(nodes) do_delete(marks, nodes)
end end
end end

View file

@ -1,4 +1,3 @@
local marks = require "nvim-tree.marks"
local core = require "nvim-tree.core" local core = require "nvim-tree.core"
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local rename_file = require "nvim-tree.actions.fs.rename-file" local rename_file = require "nvim-tree.actions.fs.rename-file"
@ -9,8 +8,14 @@ local M = {
config = {}, config = {},
} }
function M.bulk_move() ---@param explorer Explorer
if #marks.get_marks() == 0 then function M.bulk_move(explorer)
if not explorer then
return
end
local marks = explorer.marks
if #marks:get_marks() == 0 then
notify.warn "No bookmarks to move." notify.warn "No bookmarks to move."
return return
end end
@ -40,14 +45,14 @@ function M.bulk_move()
return return
end end
local nodes = marks.get_marks() local nodes = marks:get_marks()
for _, node in pairs(nodes) do for _, node in pairs(nodes) do
local head = vim.fn.fnamemodify(node.absolute_path, ":t") local head = vim.fn.fnamemodify(node.absolute_path, ":t")
local to = utils.path_join { location, head } local to = utils.path_join { location, head }
rename_file.rename(node, to) rename_file.rename(node, to)
end end
marks.clear_marks() marks:clear_marks()
if not M.config.filesystem_watchers.enable then if not M.config.filesystem_watchers.enable then
require("nvim-tree.actions.reloaders").reload_explorer() require("nvim-tree.actions.reloaders").reload_explorer()

View file

@ -1,4 +1,3 @@
local marks = require "nvim-tree.marks"
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local remove_file = require "nvim-tree.actions.fs.trash" local remove_file = require "nvim-tree.actions.fs.trash"
local notify = require "nvim-tree.notify" local notify = require "nvim-tree.notify"
@ -14,12 +13,17 @@ local function do_trash(nodes)
for _, node in pairs(nodes) do for _, node in pairs(nodes) do
remove_file.remove(node) remove_file.remove(node)
end end
marks.clear_marks()
end end
function M.bulk_trash() ---@param explorer Explorer
local nodes = marks.get_marks() function M.bulk_trash(explorer)
if not explorer then
return
end
local marks = explorer.marks
local nodes = marks:get_marks()
if not nodes or #nodes == 0 then if not nodes or #nodes == 0 then
notify.warn "No bookmarks to trash." notify.warn "No bookmarks to trash."
return return
@ -32,10 +36,12 @@ function M.bulk_trash()
utils.clear_prompt() utils.clear_prompt()
if item_short == "y" then if item_short == "y" then
do_trash(nodes) do_trash(nodes)
marks:clear_marks()
end end
end) end)
else else
do_trash(nodes) do_trash(nodes)
marks:clear_marks()
end end
end end

View file

@ -1,63 +1,73 @@
local renderer = {} -- circular dependency local renderer = {} -- circular dependency
local NvimTreeMarks = {} ---@class Marks
---@field private marks Node[]
local Marks = {}
local M = {} ---@return Marks
function Marks:new()
local o = {}
setmetatable(o, self)
self.__index = self
---@class MinimalNode o.marks = {}
---@field absolute_path string
---@param node Node|MinimalNode return o
local function add_mark(node) end
NvimTreeMarks[node.absolute_path] = node
---@private
---@param node Node
function Marks:add_mark(node)
self.marks[node.absolute_path] = node
renderer.draw() renderer.draw()
end end
---@param node Node|MinimalNode ---@private
local function remove_mark(node) ---@param node Node
NvimTreeMarks[node.absolute_path] = nil function Marks:remove_mark(node)
self.marks[node.absolute_path] = nil
renderer.draw() renderer.draw()
end end
---@param node Node|MinimalNode ---@param node Node
function M.toggle_mark(node) function Marks:toggle_mark(node)
if node.absolute_path == nil then if node.absolute_path == nil then
return return
end end
if M.get_mark(node) then if self:get_mark(node) then
remove_mark(node) self:remove_mark(node)
else else
add_mark(node) self:add_mark(node)
end end
renderer.draw() renderer.draw()
end end
function M.clear_marks() function Marks:clear_marks()
NvimTreeMarks = {} self.marks = {}
renderer.draw() renderer.draw()
end end
---@param node Node|MinimalNode ---@param node Node
---@return table|nil ---@return Node|nil
function M.get_mark(node) function Marks:get_mark(node)
return node and NvimTreeMarks[node.absolute_path] return node and self.marks[node.absolute_path]
end end
---@return table ---@return Node[]
function M.get_marks() function Marks:get_marks()
local list = {} local list = {}
for _, node in pairs(NvimTreeMarks) do for _, node in pairs(self.marks) do
table.insert(list, node) table.insert(list, node)
end end
return list return list
end end
function M.setup(opts) function Marks.setup(opts)
renderer = require "nvim-tree.renderer" renderer = require "nvim-tree.renderer"
require("nvim-tree.marks.bulk-delete").setup(opts) require("nvim-tree.marks.bulk-delete").setup(opts)
@ -65,4 +75,4 @@ function M.setup(opts)
require("nvim-tree.marks.bulk-move").setup(opts) require("nvim-tree.marks.bulk-move").setup(opts)
end end
return M return Marks

View file

@ -1,6 +1,5 @@
local Iterator = require "nvim-tree.iterators.node-iterator" local Iterator = require "nvim-tree.iterators.node-iterator"
local core = require "nvim-tree.core" local core = require "nvim-tree.core"
local Marks = require "nvim-tree.marks"
local open_file = require "nvim-tree.actions.node.open-file" local open_file = require "nvim-tree.actions.node.open-file"
local utils = require "nvim-tree.utils" local utils = require "nvim-tree.utils"
local lib = require "nvim-tree.lib" local lib = require "nvim-tree.lib"
@ -9,10 +8,15 @@ local lib = require "nvim-tree.lib"
---@param where string ---@param where string
---@return Node|nil ---@return Node|nil
local function get_nearest(node, where) local function get_nearest(node, where)
local explorer = core.get_explorer()
if not explorer then
return
end
local first, prev, next, last = nil, nil, nil, nil local first, prev, next, last = nil, nil, nil, nil
local found = false local found = false
Iterator.builder(core.get_explorer().nodes) Iterator.builder(explorer.nodes)
:recursor(function(n) :recursor(function(n)
return n.open and n.nodes return n.open and n.nodes
end) end)
@ -22,7 +26,7 @@ local function get_nearest(node, where)
return return
end end
if not Marks.get_mark(n) then if not explorer.marks:get_mark(n) then
return return
end end
@ -84,9 +88,14 @@ M.next = navigate_to "next"
M.prev = navigate_to "prev" M.prev = navigate_to "prev"
function M.select() function M.select()
local explorer = core.get_explorer()
if not explorer then
return
end
local list = vim.tbl_map(function(n) local list = vim.tbl_map(function(n)
return n.absolute_path return n.absolute_path
end, Marks.get_marks()) end, explorer.marks:get_marks())
vim.ui.select(list, { vim.ui.select(list, {
prompt = "Select a file to open or a folder to focus", prompt = "Select a file to open or a folder to focus",
@ -94,7 +103,7 @@ function M.select()
if not choice or choice == "" then if not choice or choice == "" then
return return
end end
local node = Marks.get_mark { absolute_path = choice } local node = explorer.marks:get_mark { absolute_path = choice }
open_or_focus(node) open_or_focus(node)
end) end)
end end

View file

@ -1,4 +1,4 @@
local marks = require "nvim-tree.marks" local core = require "nvim-tree.core"
local HL_POSITION = require("nvim-tree.enum").HL_POSITION local HL_POSITION = require("nvim-tree.enum").HL_POSITION
local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT local ICON_PLACEMENT = require("nvim-tree.enum").ICON_PLACEMENT
@ -34,7 +34,7 @@ end
---@param node Node ---@param node Node
---@return HighlightedString[]|nil icons ---@return HighlightedString[]|nil icons
function DecoratorBookmarks:calculate_icons(node) function DecoratorBookmarks:calculate_icons(node)
if marks.get_mark(node) then if core.get_explorer() and core.get_explorer().marks:get_mark(node) then
return { self.icon } return { self.icon }
end end
end end
@ -43,7 +43,7 @@ end
---@param node Node ---@param node Node
---@return string|nil group ---@return string|nil group
function DecoratorBookmarks:calculate_highlight(node) function DecoratorBookmarks:calculate_highlight(node)
if self.hl_pos ~= HL_POSITION.none and marks.get_mark(node) then if self.hl_pos ~= HL_POSITION.none and core.get_explorer() and core.get_explorer().marks:get_mark(node) then
return "NvimTreeBookmarkHL" return "NvimTreeBookmarkHL"
end end
end end