diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 80317e15..45417db2 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -1,4 +1,5 @@ local log = require("nvim-tree.log") +local view = require("nvim-tree.view") local utils = require("nvim-tree.utils") local actions = require("nvim-tree.actions") local core = require("nvim-tree.core") @@ -73,8 +74,7 @@ function M.change_root(path, bufnr) end function M.tab_enter() - local explorer = core.get_explorer() - if explorer and explorer.window:is_visible({ any_tabpage = true }) then + if view.is_visible({ any_tabpage = true }) then local bufname = vim.api.nvim_buf_get_name(0) local ft @@ -89,15 +89,17 @@ function M.tab_enter() return end end - explorer.window:open({ focus_tree = false }) - explorer.renderer:draw() + local explorer = core.get_explorer() + if explorer then + explorer.window:open({ focus_tree = false }) + explorer.renderer:draw() + end end end function M.open_on_directory() - local explorer = core.get_explorer() - local should_proceed = _config.hijack_directories.auto_open or explorer and explorer.window:is_visible() + local should_proceed = _config.hijack_directories.auto_open or view.is_visible() if not should_proceed then return end @@ -668,7 +670,9 @@ function M.purge_all_state() local explorer = core.get_explorer() if explorer then explorer.window:close_all_tabs() - explorer.window:abandon_all_windows() + end + view.abandon_all_windows() + if explorer then require("nvim-tree.git").purge_state() explorer:destroy() core.reset_explorer() diff --git a/lua/nvim-tree/actions/finders/find-file.lua b/lua/nvim-tree/actions/finders/find-file.lua index aa8274e2..55e2f23d 100644 --- a/lua/nvim-tree/actions/finders/find-file.lua +++ b/lua/nvim-tree/actions/finders/find-file.lua @@ -1,4 +1,5 @@ local log = require("nvim-tree.log") +local view = require("nvim-tree.view") local utils = require("nvim-tree.utils") local core = require("nvim-tree.core") @@ -13,7 +14,7 @@ local running = {} ---@param path string relative or absolute function M.fn(path) local explorer = core.get_explorer() - if not explorer or not explorer.window:is_visible() then + if not explorer or not view.is_visible() then return end @@ -83,9 +84,9 @@ function M.fn(path) end) :iterate() - if found and explorer.window:is_visible() then + if found and view.is_visible() then explorer.renderer:draw() - explorer.window:set_cursor({ line, 0 }) + view.set_cursor({ line, 0 }) end running[path_real] = false diff --git a/lua/nvim-tree/actions/moves/item.lua b/lua/nvim-tree/actions/moves/item.lua index 90d6616b..8aacaae3 100644 --- a/lua/nvim-tree/actions/moves/item.lua +++ b/lua/nvim-tree/actions/moves/item.lua @@ -1,4 +1,5 @@ local utils = require("nvim-tree.utils") +local view = require("nvim-tree.view") local core = require("nvim-tree.core") local diagnostics = require("nvim-tree.diagnostics") @@ -66,9 +67,9 @@ local function move(explorer, where, what, skip_gitignored) end if nex then - explorer.window:set_cursor({ nex, 0 }) + view.set_cursor({ nex, 0 }) elseif vim.o.wrapscan and first then - explorer.window:set_cursor({ first, 0 }) + view.set_cursor({ first, 0 }) end end @@ -188,13 +189,13 @@ local function move_prev_recursive(explorer, what, skip_gitignored) -- 4.3) if node_init.name == ".." then -- root node - explorer.window:set_cursor({ 1, 0 }) -- move to root node (position 1) + view.set_cursor({ 1, 0 }) -- move to root node (position 1) else local node_init_line = utils.find_node_line(node_init) if node_init_line < 0 then return end - explorer.window:set_cursor({ node_init_line, 0 }) + view.set_cursor({ node_init_line, 0 }) end -- 4.4) diff --git a/lua/nvim-tree/actions/moves/parent.lua b/lua/nvim-tree/actions/moves/parent.lua index 438a9abe..32ca8398 100644 --- a/lua/nvim-tree/actions/moves/parent.lua +++ b/lua/nvim-tree/actions/moves/parent.lua @@ -1,3 +1,4 @@ +local view = require("nvim-tree.view") local utils = require("nvim-tree.utils") local DirectoryNode = require("nvim-tree.node.directory") @@ -24,7 +25,7 @@ function M.fn(should_close) local parent = (node:get_parent_of_group() or node).parent if not parent or not parent.parent then - node.explorer.window:set_cursor({ 1, 0 }) + view.set_cursor({ 1, 0 }) return end @@ -32,7 +33,7 @@ function M.fn(should_close) return n.absolute_path == parent.absolute_path end) - node.explorer.window:set_cursor({ line + 1, 0 }) + view.set_cursor({ line + 1, 0 }) if should_close then parent.open = false parent.explorer.renderer:draw() diff --git a/lua/nvim-tree/actions/node/open-file.lua b/lua/nvim-tree/actions/node/open-file.lua index ddc78a8b..fe9f2380 100644 --- a/lua/nvim-tree/actions/node/open-file.lua +++ b/lua/nvim-tree/actions/node/open-file.lua @@ -3,6 +3,7 @@ local lib = require("nvim-tree.lib") local notify = require("nvim-tree.notify") local utils = require("nvim-tree.utils") local core = require("nvim-tree.core") +local view = require("nvim-tree.view") local M = {} @@ -19,10 +20,9 @@ end ---Get all windows in the current tabpage that aren't NvimTree. ---@return table with valid win_ids local function usable_win_ids() - local explorer = core.get_explorer() local tabpage = vim.api.nvim_get_current_tabpage() local win_ids = vim.api.nvim_tabpage_list_wins(tabpage) - local tree_winid = explorer and explorer.window:get_winnr(tabpage) + local tree_winid = view.get_winnr(tabpage) return vim.tbl_filter(function(id) local bufid = vim.api.nvim_win_get_buf(id) @@ -386,12 +386,7 @@ local function is_already_loaded(filename) end local function edit_in_current_buf(filename) - local explorer = core.get_explorer() - - if explorer then - explorer.window:abandon_current_window() - end - + require("nvim-tree.view").abandon_current_window() if M.relative_path then filename = utils.path_relative(filename, vim.fn.getcwd()) end diff --git a/lua/nvim-tree/actions/tree/find-file.lua b/lua/nvim-tree/actions/tree/find-file.lua index 3e2faabb..1c5c4256 100644 --- a/lua/nvim-tree/actions/tree/find-file.lua +++ b/lua/nvim-tree/actions/tree/find-file.lua @@ -1,5 +1,6 @@ local core = require("nvim-tree.core") local lib = require("nvim-tree.lib") +local view = require("nvim-tree.view") local finders_find_file = require("nvim-tree.actions.finders.find-file") local M = {} @@ -41,7 +42,7 @@ function M.fn(opts) end local explorer = core.get_explorer() - if explorer and explorer.window:is_visible() then + if explorer and view.is_visible() then -- focus if opts.focus then lib.set_target_win() diff --git a/lua/nvim-tree/actions/tree/open.lua b/lua/nvim-tree/actions/tree/open.lua index 31592741..8ea7e1fa 100644 --- a/lua/nvim-tree/actions/tree/open.lua +++ b/lua/nvim-tree/actions/tree/open.lua @@ -1,5 +1,6 @@ local core = require("nvim-tree.core") local lib = require("nvim-tree.lib") +local view = require("nvim-tree.view") local finders_find_file = require("nvim-tree.actions.finders.find-file") local M = {} @@ -25,7 +26,7 @@ function M.fn(opts) local explorer = core.get_explorer() - if explorer and explorer.window:is_visible() then + if explorer and view.is_visible() then -- focus lib.set_target_win() explorer.window:focus() diff --git a/lua/nvim-tree/actions/tree/toggle.lua b/lua/nvim-tree/actions/tree/toggle.lua index 79691dcb..60313951 100644 --- a/lua/nvim-tree/actions/tree/toggle.lua +++ b/lua/nvim-tree/actions/tree/toggle.lua @@ -1,5 +1,6 @@ local core = require("nvim-tree.core") local lib = require("nvim-tree.lib") +local view = require("nvim-tree.view") local finders_find_file = require("nvim-tree.actions.finders.find-file") local M = {} @@ -42,7 +43,7 @@ function M.fn(opts, no_focus, cwd, bang) opts.path = nil end - if explorer and explorer.window:is_visible() then + if explorer and view.is_visible() then -- close explorer.window:close() else diff --git a/lua/nvim-tree/api.lua b/lua/nvim-tree/api.lua index e204c048..b64ccf02 100644 --- a/lua/nvim-tree/api.lua +++ b/lua/nvim-tree/api.lua @@ -1,4 +1,5 @@ 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_hi_test = require("nvim-tree.appearance.hi-test") @@ -140,9 +141,9 @@ Api.tree.focus = Api.tree.open ---@field focus boolean|nil default true Api.tree.toggle = wrap(actions.tree.toggle.fn) -Api.tree.close = wrap_explorer_member("view", "close") -Api.tree.close_in_this_tab = wrap_explorer_member("view", "close_this_tab_only") -Api.tree.close_in_all_tabs = wrap_explorer_member("view", "close_all_tabs") +Api.tree.close = wrap_explorer_member("window", "close") +Api.tree.close_in_this_tab = wrap_explorer_member("window", "close_this_tab_only") +Api.tree.close_in_all_tabs = wrap_explorer_member("window", "close_all_tabs") Api.tree.reload = wrap_explorer("reload_explorer") ---@class ApiTreeResizeOpts @@ -201,12 +202,12 @@ Api.tree.is_tree_buf = wrap(utils.is_nvim_tree_buf) ---@field tabpage number|nil ---@field any_tabpage boolean|nil default false -Api.tree.is_visible = wrap_explorer_member("view", "is_visible") +Api.tree.is_visible = wrap(view.is_visible) ---@class ApiTreeWinIdOpts ---@field tabpage number|nil default nil -Api.tree.winid = wrap_explorer_member("view", "winid") +Api.tree.winid = wrap(view.winid) Api.fs.create = wrap_node_or_nil(actions.fs.create_file.fn) Api.fs.remove = wrap_node(actions.fs.remove_file.fn) diff --git a/lua/nvim-tree/diagnostics.lua b/lua/nvim-tree/diagnostics.lua index 97910184..76810d4a 100644 --- a/lua/nvim-tree/diagnostics.lua +++ b/lua/nvim-tree/diagnostics.lua @@ -1,5 +1,6 @@ local core = require("nvim-tree.core") local utils = require("nvim-tree.utils") +local view = require("nvim-tree.view") local log = require("nvim-tree.log") local DirectoryNode = require("nvim-tree.node.directory") @@ -181,15 +182,10 @@ function M.update_coc() end log.profile_end(profile) - local explorer = core.get_explorer() - - local bufnr - if explorer then - bufnr = explorer.window:get_bufnr() - end - + local bufnr = view.get_bufnr() local should_draw = bufnr and vim.api.nvim_buf_is_valid(bufnr) and vim.api.nvim_buf_is_loaded(bufnr) if should_draw then + local explorer = core.get_explorer() if explorer then explorer.renderer:draw() end diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index 6c1457fa..7b8a494d 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -4,6 +4,7 @@ local core = require("nvim-tree.core") local git = require("nvim-tree.git") local log = require("nvim-tree.log") local utils = require("nvim-tree.utils") +local view = require("nvim-tree.view") local node_factory = require("nvim-tree.node.factory") local DirectoryNode = require("nvim-tree.node.directory") @@ -176,7 +177,7 @@ function Explorer:create_autocmds() if self.opts.actions.open_file.eject then self.window:prevent_buffer_override() else - self.window:abandon_current_window() + view.abandon_current_window() end end, }) @@ -526,7 +527,7 @@ function Explorer:reload_explorer() local projects = git.reload_all_projects() self:refresh_nodes(projects) - if self.window:is_visible() then + if view.is_visible() then self.renderer:draw() end event_running = false @@ -548,7 +549,7 @@ end ---nil on no explorer or invalid view win ---@return integer[]|nil function Explorer:get_cursor_position() - local winnr = self.window:get_winnr() + local winnr = view.get_winnr() if not winnr or not vim.api.nvim_win_is_valid(winnr) then return end diff --git a/lua/nvim-tree/explorer/live-filter.lua b/lua/nvim-tree/explorer/live-filter.lua index e239471b..54552f85 100644 --- a/lua/nvim-tree/explorer/live-filter.lua +++ b/lua/nvim-tree/explorer/live-filter.lua @@ -1,3 +1,4 @@ +local view = require("nvim-tree.view") local utils = require("nvim-tree.utils") local Class = require("nvim-tree.classic") @@ -209,7 +210,7 @@ function LiveFilter:start_filtering() self.explorer.renderer:draw() local row = require("nvim-tree.core").get_nodes_starting_line() - 1 local col = #self.prefix > 0 and #self.prefix - 1 or 1 - self.explorer.window:set_cursor({ row, col }) + view.set_cursor({ row, col }) -- needs scheduling to let the cursor move before initializing the window vim.schedule(function() return create_overlay(self) diff --git a/lua/nvim-tree/explorer/window.lua b/lua/nvim-tree/explorer/window.lua index 7633d56c..e6685fc8 100644 --- a/lua/nvim-tree/explorer/window.lua +++ b/lua/nvim-tree/explorer/window.lua @@ -3,6 +3,7 @@ local events = require("nvim-tree.events") local utils = require("nvim-tree.utils") local log = require("nvim-tree.log") local notify = require("nvim-tree.notify") +local view = require("nvim-tree.view") local Class = require("nvim-tree.classic") @@ -11,18 +12,10 @@ local Class = require("nvim-tree.classic") ---@field resize boolean|nil default true ---@field winid number|nil 0 or nil for current -local M = {} - local DEFAULT_MIN_WIDTH = 30 local DEFAULT_MAX_WIDTH = -1 local DEFAULT_PADDING = 1 --- TODO global, rework for multiinstance explorer --- M.View retained for simpler change history -M.View = { - tabpages = {} -} - ---@class (exact) Window: Class ---@field live_filter table ---@field side string @@ -30,7 +23,6 @@ M.View = { ---@field private explorer Explorer ---@field private adaptive_size boolean ---@field private centralize_selection boolean ----@field private cursors table as per vim.api.nvim_win_get_cursor ---@field private hide_root_folder boolean ---@field private winopts table ---@field private height integer @@ -55,7 +47,6 @@ function Window:new(args) self.explorer = args.explorer self.adaptive_size = false self.centralize_selection = self.explorer.opts.view.centralize_selection - self.cursors = {} self.float = self.explorer.opts.view.float self.height = self.explorer.opts.view.height self.hide_root_folder = self.explorer.opts.renderer.root_folder_label == false @@ -90,18 +81,6 @@ function Window:destroy() self.explorer:log_destroy("Window") end --- The initial state of a tab -local tabinitial = { - -- The position of the cursor { line, column } - cursor = { 0, 0 }, - -- The NvimTree window number - winnr = nil, -} - --- TODO global, rework for multiinstance explorer ----@type table -local BUFNR_PER_TAB = {} - ---@type { name: string, value: any }[] local BUFFER_OPTIONS = { { name = "bufhidden", value = "wipe" }, @@ -112,44 +91,23 @@ local BUFFER_OPTIONS = { { name = "swapfile", value = false }, } ----@private ----@param bufnr integer ----@return boolean -function Window:matches_bufnr(bufnr) - for _, b in pairs(BUFNR_PER_TAB) do - if b == bufnr then - return true - end - end - return false -end - ----@private -function Window:wipe_rogue_buffer() - for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do - if not self:matches_bufnr(bufnr) and utils.is_nvim_tree_buf(bufnr) then - pcall(vim.api.nvim_buf_delete, bufnr, { force = true }) - end - end -end - ---@private ---@param bufnr integer|false|nil function Window:create_buffer(bufnr) - self:wipe_rogue_buffer() + view.wipe_rogue_buffer() - local tab = vim.api.nvim_get_current_tabpage() - BUFNR_PER_TAB[tab] = bufnr or vim.api.nvim_create_buf(false, false) - vim.api.nvim_buf_set_name(self:get_bufnr(), "NvimTree_" .. tab) + local tab = view.create_buffer(bufnr) - bufnr = self:get_bufnr() + vim.api.nvim_buf_set_name(view.get_bufnr(), "NvimTree_" .. tab) + + bufnr = view.get_bufnr() for _, option in ipairs(BUFFER_OPTIONS) do vim.api.nvim_set_option_value(option.name, option.value, { buf = bufnr }) end - require("nvim-tree.keymap").on_attach(self:get_bufnr()) + require("nvim-tree.keymap").on_attach(view.get_bufnr()) - events._dispatch_tree_attached_post(self:get_bufnr()) + events._dispatch_tree_attached_post(view.get_bufnr()) end ---@private @@ -166,6 +124,7 @@ function Window:get_size(size) return math.floor(vim.o.columns * percent_as_decimal) end +---@private ---@param size (fun():integer)|integer|nil ---@return integer function Window:get_width(size) @@ -176,22 +135,9 @@ function Window:get_width(size) end end -local move_tbl = { - left = "H", - right = "L", -} - --- setup_tabpage sets up the initial state of a tab ----@private ----@param tabpage integer -function Window:setup_tabpage(tabpage) - local winnr = vim.api.nvim_get_current_win() - M.View.tabpages[tabpage] = vim.tbl_extend("force", M.View.tabpages[tabpage] or tabinitial, { winnr = winnr }) -end - ---@private function Window:set_window_options_and_buffer() - pcall(vim.api.nvim_command, "buffer " .. self:get_bufnr()) + pcall(vim.api.nvim_command, "buffer " .. view.get_bufnr()) if vim.fn.has("nvim-0.10") == 1 then local eventignore = vim.api.nvim_get_option_value("eventignore", {}) @@ -234,7 +180,7 @@ function Window:open_window() vim.api.nvim_command("vsp") self:reposition_window() end - self:setup_tabpage(vim.api.nvim_get_current_tabpage()) + view.setup_tabpage(vim.api.nvim_get_current_tabpage()) self:set_window_options_and_buffer() end @@ -269,23 +215,14 @@ local function switch_buf_if_last_buf() end end ----save_tab_state saves any state that should be preserved across redraws. ----@private ----@param tabnr integer -function Window:save_tab_state(tabnr) - local tabpage = tabnr or vim.api.nvim_get_current_tabpage() - self.cursors[tabpage] = vim.api.nvim_win_get_cursor(self:get_winnr(tabpage) or 0) -end - ----@private ---@param tabpage integer -function Window:close_internal(tabpage) - if not self:is_visible({ tabpage = tabpage }) then +local function close(tabpage) + if not view.is_visible({ tabpage = tabpage }) then return end - self:save_tab_state(tabpage) + view.save_tab_state(tabpage) switch_buf_if_last_buf() - local tree_win = self:get_winnr(tabpage) + local tree_win = view.get_winnr(tabpage) local current_win = vim.api.nvim_get_current_win() for _, win in pairs(vim.api.nvim_tabpage_list_wins(tabpage)) do if vim.api.nvim_win_get_config(win).relative == "" then @@ -306,13 +243,13 @@ function Window:close_internal(tabpage) end function Window:close_this_tab_only() - self:close_internal(vim.api.nvim_get_current_tabpage()) + close(vim.api.nvim_get_current_tabpage()) end function Window:close_all_tabs() - for tabpage, _ in pairs(M.View.tabpages) do - self:close_internal(tabpage) - end + view.all_tabs_callback(function(t) + close(t) + end) end ---@param tabpage integer|nil @@ -320,7 +257,7 @@ function Window:close(tabpage) if self.explorer.opts.tab.sync.close then self:close_all_tabs() elseif tabpage then - self:close_internal(tabpage) + close(tabpage) else self:close_this_tab_only() end @@ -328,7 +265,7 @@ end ---@param options table|nil function Window:open(options) - if self:is_visible() then + if view.is_visible() then return end @@ -351,12 +288,12 @@ end ---@private function Window:grow() local starts_at = self:is_root_folder_visible(require("nvim-tree.core").get_cwd()) and 1 or 0 - local lines = vim.api.nvim_buf_get_lines(self:get_bufnr(), starts_at, -1, false) + local lines = vim.api.nvim_buf_get_lines(view.get_bufnr(), starts_at, -1, false) -- number of columns of right-padding to indicate end of path local padding = self:get_size(self.padding) -- account for sign/number columns etc. - local wininfo = vim.fn.getwininfo(self:get_winnr()) + local wininfo = vim.fn.getwininfo(view.get_winnr()) if type(wininfo) == "table" and type(wininfo[1]) == "table" then padding = padding + wininfo[1].textoff end @@ -375,7 +312,7 @@ function Window:grow() for line_nr, l in pairs(lines) do local count = vim.fn.strchars(l) -- also add space for right-aligned icons - local extmarks = vim.api.nvim_buf_get_extmarks(self:get_bufnr(), ns_id, { line_nr, 0 }, { line_nr, -1 }, { details = true }) + local extmarks = vim.api.nvim_buf_get_extmarks(view.get_bufnr(), ns_id, { line_nr, 0 }, { line_nr, -1 }, { details = true }) count = count + utils.extmarks_length(extmarks) if resizing_width < count then resizing_width = count @@ -421,11 +358,11 @@ function Window:resize(size) self.height = size end - if not self:is_visible() then + if not view.is_visible() then return end - local winnr = self:get_winnr() or 0 + local winnr = view.get_winnr() or 0 local new_size = self:get_width() @@ -441,17 +378,10 @@ end ---@private function Window:reposition_window() - local move_to = move_tbl[self.side] - vim.api.nvim_command("wincmd " .. move_to) + vim.api.nvim_command("wincmd " .. (self.side == "left" and "H" or "L")) self:resize() end ----@private -function Window:set_current_win() - local current_tab = vim.api.nvim_get_current_tabpage() - M.View.tabpages[current_tab].winnr = vim.api.nvim_get_current_win() -end - ---Open the tree in the a window ---@param opts OpenInWinOpts|nil function Window:open_in_win(opts) @@ -461,8 +391,8 @@ function Window:open_in_win(opts) vim.api.nvim_set_current_win(opts.winid) end self:create_buffer(opts.hijack_current_buf and vim.api.nvim_get_current_buf()) - self:setup_tabpage(vim.api.nvim_get_current_tabpage()) - self:set_current_win() + view.setup_tabpage(vim.api.nvim_get_current_tabpage()) + view.set_current_win() self:set_window_options_and_buffer() if opts.resize then self:reposition_window() @@ -471,63 +401,16 @@ function Window:open_in_win(opts) events._dispatch_on_tree_open() end -function Window:abandon_current_window() - local tab = vim.api.nvim_get_current_tabpage() - BUFNR_PER_TAB[tab] = nil - if M.View.tabpages[tab] then - M.View.tabpages[tab].winnr = nil - end -end - -function Window:abandon_all_windows() - for tab, _ in pairs(vim.api.nvim_list_tabpages()) do - BUFNR_PER_TAB[tab] = nil - if M.View.tabpages[tab] then - M.View.tabpages[tab].winnr = nil - end - end -end - ----@param opts table|nil ----@return boolean -function Window:is_visible(opts) - if opts and opts.tabpage then - if M.View.tabpages[opts.tabpage] == nil then - return false - end - local winnr = M.View.tabpages[opts.tabpage].winnr - return winnr and vim.api.nvim_win_is_valid(winnr) - end - - if opts and opts.any_tabpage then - for _, v in pairs(M.View.tabpages) do - if v.winnr and vim.api.nvim_win_is_valid(v.winnr) then - return true - end - end - return false - end - - return self:get_winnr() ~= nil and vim.api.nvim_win_is_valid(self:get_winnr() or 0) -end - ----@param opts table|nil -function Window:set_cursor(opts) - if self:is_visible() then - pcall(vim.api.nvim_win_set_cursor, self:get_winnr(), opts) - end -end - ---@param winnr number|nil ---@param open_if_closed boolean|nil function Window:focus(winnr, open_if_closed) - local wnr = winnr or self:get_winnr() + local wnr = winnr or view.get_winnr() if vim.api.nvim_win_get_tabpage(wnr or 0) ~= vim.api.nvim_win_get_tabpage(0) then self:close() self:open() - wnr = self:get_winnr() - elseif open_if_closed and not self:is_visible() then + wnr = view.get_winnr() + elseif open_if_closed and not view.is_visible() then self:open() end @@ -536,47 +419,9 @@ function Window:focus(winnr, open_if_closed) end end ---- Retrieve the winid of the open tree. ----@param opts ApiTreeWinIdOpts|nil ----@return number|nil winid unlike get_winnr(), this returns nil if the nvim-tree window is not visible -function Window:winid(opts) - local tabpage = opts and opts.tabpage - if tabpage == 0 then - tabpage = vim.api.nvim_get_current_tabpage() - end - if self:is_visible({ tabpage = tabpage }) then - return self:get_winnr(tabpage) - else - return nil - end -end - ---- Restores the state of a NvimTree window if it was initialized before. -function Window:restore_tab_state() - local tabpage = vim.api.nvim_get_current_tabpage() - self:set_cursor(self.cursors[tabpage]) -end - ---- Returns the window number for nvim-tree within the tabpage specified ----@param tabpage number|nil (optional) the number of the chosen tabpage. Defaults to current tabpage. ----@return number|nil -function Window:get_winnr(tabpage) - tabpage = tabpage or vim.api.nvim_get_current_tabpage() - local tabinfo = M.View.tabpages[tabpage] - if tabinfo and tabinfo.winnr and vim.api.nvim_win_is_valid(tabinfo.winnr) then - return tabinfo.winnr - end -end - ---- Returns the current nvim tree bufnr ----@return number -function Window:get_bufnr() - return BUFNR_PER_TAB[vim.api.nvim_get_current_tabpage()] -end - function Window:prevent_buffer_override() - local view_winnr = self:get_winnr() - local view_bufnr = self:get_bufnr() + local view_winnr = view.get_winnr() + local view_bufnr = view.get_bufnr() -- need to schedule to let the new buffer populate the window -- because this event needs to be run on bufWipeout. @@ -588,12 +433,7 @@ function Window:prevent_buffer_override() local bufname = vim.api.nvim_buf_get_name(curbuf) if not bufname:match("NvimTree") then - for i, tabpage in ipairs(M.View.tabpages) do - if tabpage.winnr == view_winnr then - M.View.tabpages[i] = nil - break - end - end + view.clear_tabpage(view_winnr) end if curwin ~= view_winnr or bufname == "" or curbuf == view_bufnr then return @@ -605,10 +445,7 @@ function Window:prevent_buffer_override() vim.cmd("setlocal nowinfixheight") self:open({ focus_tree = false }) - local explorer = require("nvim-tree.core").get_explorer() - if explorer then - explorer.renderer:draw() - end + self.explorer.renderer:draw() pcall(vim.api.nvim_win_close, curwin, { force = true }) @@ -630,9 +467,9 @@ end -- used on ColorScheme event function Window:reset_winhl() - local winnr = self:get_winnr() + local winnr = view.get_winnr() if winnr and vim.api.nvim_win_is_valid(winnr) then - vim.wo[self:get_winnr()].winhl = appearance.WIN_HL + vim.wo[view.get_winnr()].winhl = appearance.WIN_HL end end diff --git a/lua/nvim-tree/lib.lua b/lua/nvim-tree/lib.lua index b390ec55..9eba16ab 100644 --- a/lua/nvim-tree/lib.lua +++ b/lua/nvim-tree/lib.lua @@ -1,3 +1,4 @@ +local view = require("nvim-tree.view") local core = require("nvim-tree.core") local notify = require("nvim-tree.notify") @@ -11,11 +12,9 @@ local M = { } function M.set_target_win() - local explorer = core.get_explorer() - local id = vim.api.nvim_get_current_win() - - if explorer and id == explorer.window:get_winnr() then + local tree_id = view.get_winnr() + if tree_id and id == tree_id then M.target_winid = 0 return end @@ -134,10 +133,7 @@ function M.open(opts) else open_view_and_draw() end - - if explorer then - explorer.window:restore_tab_state() - end + view.restore_tab_state() end function M.setup(opts) diff --git a/lua/nvim-tree/renderer/init.lua b/lua/nvim-tree/renderer/init.lua index e90e2d1a..f5f9cc06 100644 --- a/lua/nvim-tree/renderer/init.lua +++ b/lua/nvim-tree/renderer/init.lua @@ -1,4 +1,5 @@ local log = require("nvim-tree.log") +local view = require("nvim-tree.view") local events = require("nvim-tree.events") local Class = require("nvim-tree.classic") @@ -101,28 +102,28 @@ function Renderer:render_hl(bufnr, hl_range_args) end function Renderer:draw() - local bufnr = self.explorer.window:get_bufnr() + local bufnr = view.get_bufnr() if not bufnr or not vim.api.nvim_buf_is_loaded(bufnr) then return end local profile = log.profile_start("draw") - local cursor = vim.api.nvim_win_get_cursor(self.explorer.window:get_winnr() or 0) + local cursor = vim.api.nvim_win_get_cursor(view.get_winnr() or 0) local builder = Builder(self.explorer):build() self:_draw(bufnr, builder.lines, builder.hl_range_args, builder.signs, builder.extmarks, builder.virtual_lines) if cursor and #builder.lines >= cursor[1] then - vim.api.nvim_win_set_cursor(self.explorer.window:get_winnr() or 0, cursor) + vim.api.nvim_win_set_cursor(view.get_winnr() or 0, cursor) end self.explorer.window:grow_from_content() log.profile_end(profile) - events._dispatch_on_tree_rendered(bufnr, self.explorer.window:get_winnr()) + events._dispatch_on_tree_rendered(bufnr, view.get_winnr()) end return Renderer diff --git a/lua/nvim-tree/utils.lua b/lua/nvim-tree/utils.lua index 87063a45..6c61e528 100644 --- a/lua/nvim-tree/utils.lua +++ b/lua/nvim-tree/utils.lua @@ -543,10 +543,7 @@ function M.focus_file(path) local _, i = M.find_node(require("nvim-tree.core").get_explorer().nodes, function(node) return node.absolute_path == path end) - local explorer = require("nvim-tree.core").get_explorer() - if explorer then - explorer.window:set_cursor({ i + 1, 1 }) - end + require("nvim-tree.view").set_cursor({ i + 1, 1 }) end ---Focus node passed as parameter if visible, otherwise focus first visible parent. @@ -566,7 +563,7 @@ function M.focus_node_or_parent(node) end) if found_node or node.parent == nil then - explorer.window:set_cursor({ i + 1, 1 }) + require("nvim-tree.view").set_cursor({ i + 1, 1 }) break end diff --git a/lua/nvim-tree/view.lua b/lua/nvim-tree/view.lua new file mode 100644 index 00000000..1514ce69 --- /dev/null +++ b/lua/nvim-tree/view.lua @@ -0,0 +1,186 @@ +local utils = require("nvim-tree.utils") + +local M = {} + +M.View = { + tabpages = {}, + cursors = {}, +} + +-- The initial state of a tab +local tabinitial = { + -- The position of the cursor { line, column } + cursor = { 0, 0 }, + -- The NvimTree window number + winnr = nil, +} + +local BUFNR_PER_TAB = {} + +---@param bufnr integer +---@return boolean +local function matches_bufnr(bufnr) + for _, b in pairs(BUFNR_PER_TAB) do + if b == bufnr then + return true + end + end + return false +end + +function M.wipe_rogue_buffer() + for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do + if not matches_bufnr(bufnr) and utils.is_nvim_tree_buf(bufnr) then + pcall(vim.api.nvim_buf_delete, bufnr, { force = true }) + end + end +end + +---@param bufnr integer|boolean|nil +---@return integer tab +function M.create_buffer(bufnr) + local tab = vim.api.nvim_get_current_tabpage() + BUFNR_PER_TAB[tab] = bufnr or vim.api.nvim_create_buf(false, false) + return tab +end + +-- setup_tabpage sets up the initial state of a tab +---@param tabpage integer +function M.setup_tabpage(tabpage) + local winnr = vim.api.nvim_get_current_win() + M.View.tabpages[tabpage] = vim.tbl_extend("force", M.View.tabpages[tabpage] or tabinitial, { winnr = winnr }) +end + +-- save_tab_state saves any state that should be preserved across redraws. +---@param tabnr integer +function M.save_tab_state(tabnr) + 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) +end + +---@param fn fun(tabpage: integer) +function M.all_tabs_callback(fn) + for tabpage, _ in pairs(M.View.tabpages) do + fn(tabpage) + end +end + +function M.set_current_win() + local current_tab = vim.api.nvim_get_current_tabpage() + M.View.tabpages[current_tab].winnr = vim.api.nvim_get_current_win() +end + +function M.abandon_current_window() + local tab = vim.api.nvim_get_current_tabpage() + BUFNR_PER_TAB[tab] = nil + if M.View.tabpages[tab] then + M.View.tabpages[tab].winnr = nil + end +end + +function M.abandon_all_windows() + for tab, _ in pairs(vim.api.nvim_list_tabpages()) do + BUFNR_PER_TAB[tab] = nil + if M.View.tabpages[tab] then + M.View.tabpages[tab].winnr = nil + end + end +end + +---@param opts table|nil +---@return boolean +function M.is_visible(opts) + if opts and opts.tabpage then + if M.View.tabpages[opts.tabpage] == nil then + return false + end + local winnr = M.View.tabpages[opts.tabpage].winnr + return winnr and vim.api.nvim_win_is_valid(winnr) + end + + if opts and opts.any_tabpage then + for _, v in pairs(M.View.tabpages) do + if v.winnr and vim.api.nvim_win_is_valid(v.winnr) then + return true + end + end + return false + end + + return M.get_winnr() ~= nil and vim.api.nvim_win_is_valid(M.get_winnr() or 0) +end + +---@param opts table|nil +function M.set_cursor(opts) + if M.is_visible() then + pcall(vim.api.nvim_win_set_cursor, M.get_winnr(), opts) + end +end + +--- Retrieve the winid of the open tree. +---@param opts ApiTreeWinIdOpts|nil +---@return number|nil winid unlike get_winnr(), this returns nil if the nvim-tree window is not visible +function M.winid(opts) + local tabpage = opts and opts.tabpage + if tabpage == 0 then + tabpage = vim.api.nvim_get_current_tabpage() + end + if M.is_visible({ tabpage = tabpage }) then + return M.get_winnr(tabpage) + else + return nil + end +end + +--- Restores the state of a NvimTree window if it was initialized before. +function M.restore_tab_state() + local tabpage = vim.api.nvim_get_current_tabpage() + M.set_cursor(M.View.cursors[tabpage]) +end + +--- Returns the window number for nvim-tree within the tabpage specified +---@param tabpage number|nil (optional) the number of the chosen tabpage. Defaults to current tabpage. +---@return number|nil +function M.get_winnr(tabpage) + tabpage = tabpage or vim.api.nvim_get_current_tabpage() + local tabinfo = M.View.tabpages[tabpage] + if tabinfo and tabinfo.winnr and vim.api.nvim_win_is_valid(tabinfo.winnr) then + return tabinfo.winnr + end +end + +--- Returns the current nvim tree bufnr +---@return number +function M.get_bufnr() + return BUFNR_PER_TAB[vim.api.nvim_get_current_tabpage()] +end + +---@param winnr number|nil +function M.clear_tabpage(winnr) + for i, tabpage in ipairs(M.View.tabpages) do + if tabpage.winnr == winnr then + M.View.tabpages[i] = nil + break + end + end +end + +function M.setup(opts) + local options = opts.view or {} + M.View.centralize_selection = options.centralize_selection + M.View.side = (options.side == "right") and "right" or "left" + M.View.height = options.height + M.View.hide_root_folder = opts.renderer.root_folder_label == false + M.View.tab = opts.tab + M.View.preserve_window_proportions = options.preserve_window_proportions + M.View.winopts.cursorline = options.cursorline + M.View.winopts.number = options.number + M.View.winopts.relativenumber = options.relativenumber + M.View.winopts.signcolumn = options.signcolumn + M.View.float = options.float + M.on_attach = opts.on_attach + + M.config = options +end + +return M