refactor(#2826): singleton View class, WIP

This commit is contained in:
Alexander Courtis 2025-04-20 13:54:37 +10:00
parent a3fe0c9007
commit 9d3d0d220f
15 changed files with 84 additions and 80 deletions

View File

@ -74,7 +74,7 @@ function M.change_root(path, bufnr)
end end
function M.tab_enter() function M.tab_enter()
if view.is_visible({ any_tabpage = true }) then if view.View:is_visible({ any_tabpage = true }) then
local bufname = vim.api.nvim_buf_get_name(0) local bufname = vim.api.nvim_buf_get_name(0)
local ft local ft
@ -99,7 +99,7 @@ function M.tab_enter()
end end
function M.open_on_directory() function M.open_on_directory()
local should_proceed = _config.hijack_directories.auto_open or view.is_visible() local should_proceed = _config.hijack_directories.auto_open or view.View:is_visible()
if not should_proceed then if not should_proceed then
return return
end end
@ -160,7 +160,7 @@ local function setup_autocommands(opts)
if opts.actions.open_file.eject then if opts.actions.open_file.eject then
view._prevent_buffer_override() view._prevent_buffer_override()
else else
view.abandon_current_window() view.View:abandon_current_window()
end end
end, end,
}) })
@ -687,7 +687,7 @@ end
function M.purge_all_state() function M.purge_all_state()
view.View:close_all_tabs() view.View:close_all_tabs()
view.abandon_all_windows() view.View:abandon_all_windows()
local explorer = core.get_explorer() local explorer = core.get_explorer()
if explorer then if explorer then
require("nvim-tree.git").purge_state() require("nvim-tree.git").purge_state()

View File

@ -14,7 +14,7 @@ local running = {}
---@param path string relative or absolute ---@param path string relative or absolute
function M.fn(path) function M.fn(path)
local explorer = core.get_explorer() local explorer = core.get_explorer()
if not explorer or not view.is_visible() then if not explorer or not view.View:is_visible() then
return return
end end
@ -84,9 +84,9 @@ function M.fn(path)
end) end)
:iterate() :iterate()
if found and view.is_visible() then if found and view.View:is_visible() then
explorer.renderer:draw() explorer.renderer:draw()
view.set_cursor({ line, 0 }) view.View:set_cursor({ line, 0 })
end end
running[path_real] = false running[path_real] = false

View File

@ -67,9 +67,9 @@ local function move(explorer, where, what, skip_gitignored)
end end
if nex then if nex then
view.set_cursor({ nex, 0 }) view.View:set_cursor({ nex, 0 })
elseif vim.o.wrapscan and first then elseif vim.o.wrapscan and first then
view.set_cursor({ first, 0 }) view.View:set_cursor({ first, 0 })
end end
end end
@ -189,13 +189,13 @@ local function move_prev_recursive(explorer, what, skip_gitignored)
-- 4.3) -- 4.3)
if node_init.name == ".." then -- root node if node_init.name == ".." then -- root node
view.set_cursor({ 1, 0 }) -- move to root node (position 1) view.View:set_cursor({ 1, 0 }) -- move to root node (position 1)
else else
local node_init_line = utils.find_node_line(node_init) local node_init_line = utils.find_node_line(node_init)
if node_init_line < 0 then if node_init_line < 0 then
return return
end end
view.set_cursor({ node_init_line, 0 }) view.View:set_cursor({ node_init_line, 0 })
end end
-- 4.4) -- 4.4)

View File

@ -25,7 +25,7 @@ function M.fn(should_close)
local parent = (node:get_parent_of_group() or node).parent local parent = (node:get_parent_of_group() or node).parent
if not parent or not parent.parent then if not parent or not parent.parent then
view.set_cursor({ 1, 0 }) view.View:set_cursor({ 1, 0 })
return return
end end
@ -33,7 +33,7 @@ function M.fn(should_close)
return n.absolute_path == parent.absolute_path return n.absolute_path == parent.absolute_path
end) end)
view.set_cursor({ line + 1, 0 }) view.View:set_cursor({ line + 1, 0 })
if should_close then if should_close then
parent.open = false parent.open = false
parent.explorer.renderer:draw() parent.explorer.renderer:draw()

View File

@ -373,7 +373,7 @@ local function is_already_loaded(filename)
end end
local function edit_in_current_buf(filename) local function edit_in_current_buf(filename)
require("nvim-tree.view").abandon_current_window() require("nvim-tree.view").View:abandon_current_window()
if M.relative_path then if M.relative_path then
filename = utils.path_relative(filename, vim.fn.getcwd()) filename = utils.path_relative(filename, vim.fn.getcwd())
end end
@ -419,7 +419,7 @@ function M.fn(mode, filename)
end end
if M.resize_window then if M.resize_window then
view.resize() view.View:resize()
end end
if mode == "preview" or mode == "preview_no_picker" then if mode == "preview" or mode == "preview_no_picker" then

View File

@ -41,7 +41,7 @@ function M.fn(opts)
return return
end end
if view.is_visible() then if view.View:is_visible() then
-- focus -- focus
if opts.focus then if opts.focus then
lib.set_target_win() lib.set_target_win()

View File

@ -23,7 +23,7 @@ function M.fn(opts)
opts.path = nil opts.path = nil
end end
if view.is_visible() then if view.View:is_visible() then
-- focus -- focus
lib.set_target_win() lib.set_target_win()
view.focus() view.focus()

View File

@ -8,7 +8,7 @@ function M.fn(opts)
if opts == nil then if opts == nil then
-- reset to config values -- reset to config values
view.View:configure_width() view.View:configure_width()
view.resize() view.View:resize()
return return
end end
@ -17,7 +17,7 @@ function M.fn(opts)
if width_cfg ~= nil then if width_cfg ~= nil then
view.View:configure_width(width_cfg) view.View:configure_width(width_cfg)
view.resize() view.View:resize()
return return
end end
@ -28,7 +28,7 @@ function M.fn(opts)
local absolute = options.absolute local absolute = options.absolute
if type(absolute) == "number" then if type(absolute) == "number" then
view.resize(absolute) view.View:resize(absolute)
return return
end end
@ -39,7 +39,7 @@ function M.fn(opts)
relative_size = "+" .. relative_size relative_size = "+" .. relative_size
end end
view.resize(relative_size) view.View:resize(relative_size)
return return
end end
end end

View File

@ -40,7 +40,7 @@ function M.fn(opts, no_focus, cwd, bang)
opts.path = nil opts.path = nil
end end
if view.is_visible() then if view.View:is_visible() then
-- close -- close
view.View:close() view.View:close()
else else

View File

@ -111,7 +111,7 @@ local CMDS = {
bar = true, bar = true,
}, },
command = function(c) command = function(c)
view.resize(c.args) view.View:resize(c.args)
end, end,
}, },
{ {

View File

@ -486,7 +486,7 @@ function Explorer:reload_explorer()
local projects = git.reload_all_projects() local projects = git.reload_all_projects()
self:refresh_nodes(projects) self:refresh_nodes(projects)
if view.is_visible() then if view.View:is_visible() then
self.renderer:draw() self.renderer:draw()
end end
event_running = false event_running = false

View File

@ -204,7 +204,7 @@ function LiveFilter:start_filtering()
self.explorer.renderer:draw() self.explorer.renderer:draw()
local row = require("nvim-tree.core").get_nodes_starting_line() - 1 local row = require("nvim-tree.core").get_nodes_starting_line() - 1
local col = #self.prefix > 0 and #self.prefix - 1 or 1 local col = #self.prefix > 0 and #self.prefix - 1 or 1
view.set_cursor({ row, col }) view.View:set_cursor({ row, col })
-- needs scheduling to let the cursor move before initializing the window -- needs scheduling to let the cursor move before initializing the window
vim.schedule(function() vim.schedule(function()
return create_overlay(self) return create_overlay(self)

View File

@ -111,17 +111,17 @@ function M.open(opts)
if should_hijack_current_buf() then if should_hijack_current_buf() then
view.View:close_this_tab_only() view.View:close_this_tab_only()
view.open_in_win() view.View:open_in_win()
if explorer then if explorer then
explorer.renderer:draw() explorer.renderer:draw()
end end
elseif opts.winid then elseif opts.winid then
view.open_in_win({ hijack_current_buf = false, resize = false, winid = opts.winid }) view.View:open_in_win({ hijack_current_buf = false, resize = false, winid = opts.winid })
if explorer then if explorer then
explorer.renderer:draw() explorer.renderer:draw()
end end
elseif opts.current_window then elseif opts.current_window then
view.open_in_win({ hijack_current_buf = false, resize = false }) view.View:open_in_win({ hijack_current_buf = false, resize = false })
if explorer then if explorer then
explorer.renderer:draw() explorer.renderer:draw()
end end

View File

@ -113,7 +113,7 @@ function Renderer:draw()
vim.api.nvim_win_set_cursor(view.get_winnr() or 0, cursor) vim.api.nvim_win_set_cursor(view.get_winnr() or 0, cursor)
end end
view.grow_from_content() view.View:grow_from_content()
log.profile_end(profile) log.profile_end(profile)

View File

@ -114,6 +114,7 @@ local tabinitial = {
winnr = nil, winnr = nil,
} }
-- TODO member
local BUFNR_PER_TAB = {} local BUFNR_PER_TAB = {}
---@type { name: string, value: any }[] ---@type { name: string, value: any }[]
@ -244,7 +245,7 @@ function View:open_window()
vim.api.nvim_open_win(0, true, self:open_win_config()) vim.api.nvim_open_win(0, true, self:open_win_config())
else else
vim.api.nvim_command("vsp") vim.api.nvim_command("vsp")
M.reposition_window() self:reposition_window()
end end
self:setup_tabpage(vim.api.nvim_get_current_tabpage()) self:setup_tabpage(vim.api.nvim_get_current_tabpage())
self:set_window_options_and_buffer() self:set_window_options_and_buffer()
@ -286,13 +287,13 @@ end
---@param tabnr integer ---@param tabnr integer
function View:save_tab_state(tabnr) function View:save_tab_state(tabnr)
local tabpage = tabnr or vim.api.nvim_get_current_tabpage() local tabpage = tabnr or vim.api.nvim_get_current_tabpage()
M.View.cursors[tabpage] = vim.api.nvim_win_get_cursor(M.get_winnr(tabpage) or 0) self.cursors[tabpage] = vim.api.nvim_win_get_cursor(M.get_winnr(tabpage) or 0)
end end
---@private ---@private
---@param tabpage integer ---@param tabpage integer
function View:close_internal(tabpage) function View:close_internal(tabpage)
if not M.is_visible({ tabpage = tabpage }) then if not self:is_visible({ tabpage = tabpage }) then
return return
end end
self:save_tab_state(tabpage) self:save_tab_state(tabpage)
@ -329,7 +330,7 @@ end
---@param tabpage integer|nil ---@param tabpage integer|nil
function View:close(tabpage) function View:close(tabpage)
if M.View.tab.sync.close then if self.tab.sync.close then
self:close_all_tabs() self:close_all_tabs()
elseif tabpage then elseif tabpage then
self:close_internal(tabpage) self:close_internal(tabpage)
@ -340,7 +341,7 @@ end
---@param options table|nil ---@param options table|nil
function View:open(options) function View:open(options)
if M.is_visible() then if self:is_visible() then
return return
end end
@ -348,7 +349,7 @@ function View:open(options)
self:create_buffer() self:create_buffer()
self:open_window() self:open_window()
M.resize() self:resize()
local opts = options or { focus_tree = true } local opts = options or { focus_tree = true }
if not opts.focus_tree then if not opts.focus_tree then
@ -359,11 +360,12 @@ function View:open(options)
log.profile_end(profile) log.profile_end(profile)
end end
local function grow() ---@private
function View:grow()
local starts_at = M.is_root_folder_visible(require("nvim-tree.core").get_cwd()) and 1 or 0 local starts_at = M.is_root_folder_visible(require("nvim-tree.core").get_cwd()) and 1 or 0
local lines = vim.api.nvim_buf_get_lines(M.get_bufnr(), starts_at, -1, false) local lines = vim.api.nvim_buf_get_lines(M.get_bufnr(), starts_at, -1, false)
-- number of columns of right-padding to indicate end of path -- number of columns of right-padding to indicate end of path
local padding = M.View:get_size(M.View.padding) local padding = self:get_size(self.padding)
-- account for sign/number columns etc. -- account for sign/number columns etc.
local wininfo = vim.fn.getwininfo(M.get_winnr()) local wininfo = vim.fn.getwininfo(M.get_winnr())
@ -371,14 +373,14 @@ local function grow()
padding = padding + wininfo[1].textoff padding = padding + wininfo[1].textoff
end end
local resizing_width = M.View.initial_width - padding local resizing_width = self.initial_width - padding
local max_width local max_width
-- maybe bound max -- maybe bound max
if M.View.max_width == -1 then if self.max_width == -1 then
max_width = -1 max_width = -1
else else
max_width = M.View:get_width(M.View.max_width) - padding max_width = self:get_width(self.max_width) - padding
end end
local ns_id = vim.api.nvim_get_namespaces()["NvimTreeExtmarks"] local ns_id = vim.api.nvim_get_namespaces()["NvimTreeExtmarks"]
@ -397,23 +399,23 @@ local function grow()
if resizing_width < count then if resizing_width < count then
resizing_width = count resizing_width = count
end end
if M.View.adaptive_size and max_width >= 0 and resizing_width >= max_width then if self.adaptive_size and max_width >= 0 and resizing_width >= max_width then
resizing_width = max_width resizing_width = max_width
break break
end end
end end
M.resize(resizing_width + padding) self:resize(resizing_width + padding)
end end
function M.grow_from_content() function View:grow_from_content()
if M.View.adaptive_size then if self.adaptive_size then
grow() self:grow()
end end
end end
---@param size string|number|nil ---@param size string|number|nil
function M.resize(size) function View:resize(size)
if M.View.float.enable and not M.View.adaptive_size then if self.float.enable and not self.adaptive_size then
-- if the floating windows's adaptive size is not desired, then the -- if the floating windows's adaptive size is not desired, then the
-- float size should be defined in view.float.open_win_config -- float size should be defined in view.float.open_win_config
return return
@ -425,7 +427,7 @@ function M.resize(size)
size = tonumber(size) size = tonumber(size)
if first_char == "+" or first_char == "-" then if first_char == "+" or first_char == "-" then
size = M.View.width + size size = self.width + size
end end
end end
@ -434,21 +436,21 @@ function M.resize(size)
end end
if size then if size then
M.View.width = size self.width = size
M.View.height = size self.height = size
end end
if not M.is_visible() then if not self:is_visible() then
return return
end end
local winnr = M.get_winnr() or 0 local winnr = M.get_winnr() or 0
local new_size = M.View:get_width() local new_size = self:get_width()
if new_size ~= vim.api.nvim_win_get_width(winnr) then if new_size ~= vim.api.nvim_win_get_width(winnr) then
vim.api.nvim_win_set_width(winnr, new_size) vim.api.nvim_win_set_width(winnr, new_size)
if not M.View.preserve_window_proportions then if not self.preserve_window_proportions then
vim.cmd(":wincmd =") vim.cmd(":wincmd =")
end end
end end
@ -456,65 +458,67 @@ function M.resize(size)
events._dispatch_on_tree_resize(new_size) events._dispatch_on_tree_resize(new_size)
end end
function M.reposition_window() ---@private
local move_to = move_tbl[M.View.side] function View:reposition_window()
local move_to = move_tbl[self.side]
vim.api.nvim_command("wincmd " .. move_to) vim.api.nvim_command("wincmd " .. move_to)
M.resize() self:resize()
end end
local function set_current_win() ---@private
function View:set_current_win()
local current_tab = vim.api.nvim_get_current_tabpage() local current_tab = vim.api.nvim_get_current_tabpage()
M.View.tabpages[current_tab].winnr = vim.api.nvim_get_current_win() self.tabpages[current_tab].winnr = vim.api.nvim_get_current_win()
end end
---Open the tree in the a window ---Open the tree in the a window
---@param opts OpenInWinOpts|nil ---@param opts OpenInWinOpts|nil
function M.open_in_win(opts) function View:open_in_win(opts)
opts = opts or { hijack_current_buf = true, resize = true } opts = opts or { hijack_current_buf = true, resize = true }
if opts.winid and vim.api.nvim_win_is_valid(opts.winid) then if opts.winid and vim.api.nvim_win_is_valid(opts.winid) then
vim.api.nvim_set_current_win(opts.winid) vim.api.nvim_set_current_win(opts.winid)
end end
M.View:create_buffer(opts.hijack_current_buf and vim.api.nvim_get_current_buf()) self:create_buffer(opts.hijack_current_buf and vim.api.nvim_get_current_buf())
M.View:setup_tabpage(vim.api.nvim_get_current_tabpage()) self:setup_tabpage(vim.api.nvim_get_current_tabpage())
set_current_win() self:set_current_win()
M.View:set_window_options_and_buffer() self:set_window_options_and_buffer()
if opts.resize then if opts.resize then
M.reposition_window() self:reposition_window()
M.resize() self:resize()
end end
events._dispatch_on_tree_open() events._dispatch_on_tree_open()
end end
function M.abandon_current_window() function View:abandon_current_window()
local tab = vim.api.nvim_get_current_tabpage() local tab = vim.api.nvim_get_current_tabpage()
BUFNR_PER_TAB[tab] = nil BUFNR_PER_TAB[tab] = nil
if M.View.tabpages[tab] then if self.tabpages[tab] then
M.View.tabpages[tab].winnr = nil self.tabpages[tab].winnr = nil
end end
end end
function M.abandon_all_windows() function View:abandon_all_windows()
for tab, _ in pairs(vim.api.nvim_list_tabpages()) do for tab, _ in pairs(vim.api.nvim_list_tabpages()) do
BUFNR_PER_TAB[tab] = nil BUFNR_PER_TAB[tab] = nil
if M.View.tabpages[tab] then if self.tabpages[tab] then
M.View.tabpages[tab].winnr = nil self.tabpages[tab].winnr = nil
end end
end end
end end
---@param opts table|nil ---@param opts table|nil
---@return boolean ---@return boolean
function M.is_visible(opts) function View:is_visible(opts)
if opts and opts.tabpage then if opts and opts.tabpage then
if M.View.tabpages[opts.tabpage] == nil then if self.tabpages[opts.tabpage] == nil then
return false return false
end end
local winnr = M.View.tabpages[opts.tabpage].winnr local winnr = self.tabpages[opts.tabpage].winnr
return winnr and vim.api.nvim_win_is_valid(winnr) return winnr and vim.api.nvim_win_is_valid(winnr)
end end
if opts and opts.any_tabpage then if opts and opts.any_tabpage then
for _, v in pairs(M.View.tabpages) do for _, v in pairs(self.tabpages) do
if v.winnr and vim.api.nvim_win_is_valid(v.winnr) then if v.winnr and vim.api.nvim_win_is_valid(v.winnr) then
return true return true
end end
@ -526,8 +530,8 @@ function M.is_visible(opts)
end end
---@param opts table|nil ---@param opts table|nil
function M.set_cursor(opts) function View:set_cursor(opts)
if M.is_visible() then if self:is_visible() then
pcall(vim.api.nvim_win_set_cursor, M.get_winnr(), opts) pcall(vim.api.nvim_win_set_cursor, M.get_winnr(), opts)
end end
end end
@ -541,7 +545,7 @@ function M.focus(winnr, open_if_closed)
M.close() M.close()
M.View:open() M.View:open()
wnr = M.get_winnr() wnr = M.get_winnr()
elseif open_if_closed and not M.is_visible() then elseif open_if_closed and not M.View:is_visible() then
M.View:open() M.View:open()
end end
@ -558,7 +562,7 @@ function M.winid(opts)
if tabpage == 0 then if tabpage == 0 then
tabpage = vim.api.nvim_get_current_tabpage() tabpage = vim.api.nvim_get_current_tabpage()
end end
if M.is_visible({ tabpage = tabpage }) then if M.View:is_visible({ tabpage = tabpage }) then
return M.get_winnr(tabpage) return M.get_winnr(tabpage)
else else
return nil return nil
@ -568,7 +572,7 @@ end
--- Restores the state of a NvimTree window if it was initialized before. --- Restores the state of a NvimTree window if it was initialized before.
function M.restore_tab_state() function M.restore_tab_state()
local tabpage = vim.api.nvim_get_current_tabpage() local tabpage = vim.api.nvim_get_current_tabpage()
M.set_cursor(M.View.cursors[tabpage]) M.View:set_cursor(M.View.cursors[tabpage])
end end
--- Returns the window number for nvim-tree within the tabpage specified --- Returns the window number for nvim-tree within the tabpage specified