diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index ffddba0b78b..8c97c5025a1 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -23,8 +23,8 @@ local M = { } --- Update the tree root to a directory or the directory containing ---- @param path string relative or absolute ---- @param bufnr number|nil +---@param path string relative or absolute +---@param bufnr number|nil function M.change_root(path, bufnr) -- skip if current file is in ignore_list if type(bufnr) == "number" then @@ -42,6 +42,10 @@ function M.change_root(path, bufnr) end local cwd = core.get_cwd() + if cwd == nil then + return + end + local vim_cwd = vim.fn.getcwd() -- test if in vim_cwd @@ -73,6 +77,7 @@ function M.change_root(path, bufnr) change_dir.fn(vim.fn.fnamemodify(path, ":p:h")) end +---@param cwd string|nil function M.open_replacing_current_buffer(cwd) if view.is_visible() then return @@ -153,10 +158,13 @@ function M.place_cursor_on_node() end end +---@return table function M.get_config() return M.config end +---@param disable_netrw boolean +---@param hijack_netrw boolean local function manage_netrw(disable_netrw, hijack_netrw) if hijack_netrw then vim.cmd "silent! autocmd! FileExplorer *" @@ -168,14 +176,18 @@ local function manage_netrw(disable_netrw, hijack_netrw) end end +---@param name string|nil function M.change_dir(name) - change_dir.fn(name) + if name then + change_dir.fn(name) + end if _config.update_focused_file.enable then find_file.fn() end end +---@param opts table local function setup_autocommands(opts) local augroup_id = vim.api.nvim_create_augroup("NvimTree", { clear = true }) local function create_nvim_tree_autocmd(name, custom_opts) @@ -671,9 +683,15 @@ local ACCEPTED_STRINGS = { }, } +---@param conf table|nil local function validate_options(conf) local msg + ---@param user any + ---@param def any + ---@param strs table + ---@param types table + ---@param prefix string local function validate(user, def, strs, types, prefix) -- if user's option is not a table there is nothing to do if type(user) ~= "table" then @@ -756,6 +774,7 @@ function M.purge_all_state() end end +---@param conf table|nil function M.setup(conf) if vim.fn.has "nvim-0.8" == 0 then notify.warn "nvim-tree.lua requires Neovim 0.8 or higher" diff --git a/lua/nvim-tree/actions/finders/search-node.lua b/lua/nvim-tree/actions/finders/search-node.lua index 23cb1c68543..10a97f4a9de 100644 --- a/lua/nvim-tree/actions/finders/search-node.lua +++ b/lua/nvim-tree/actions/finders/search-node.lua @@ -4,6 +4,9 @@ local find_file = require("nvim-tree.actions.finders.find-file").fn local M = {} +---@param search_dir string|nil +---@param input_path string +---@return string|nil local function search(search_dir, input_path) local realpaths_searched = {} @@ -11,6 +14,8 @@ local function search(search_dir, input_path) return end + ---@param dir string + ---@return string|nil local function iter(dir) local realpath, path, name, stat, handle, _ diff --git a/lua/nvim-tree/actions/fs/copy-paste.lua b/lua/nvim-tree/actions/fs/copy-paste.lua index 8953cd320a9..a342d8bee37 100644 --- a/lua/nvim-tree/actions/fs/copy-paste.lua +++ b/lua/nvim-tree/actions/fs/copy-paste.lua @@ -20,6 +20,10 @@ local clipboard = { copy = {}, } +---@param source string +---@param destination string +---@return boolean +---@return string|nil local function do_copy(source, destination) local source_stats, handle local success, errmsg @@ -81,6 +85,12 @@ local function do_copy(source, destination) return true end +---@param source string +---@param dest string +---@param action_type string +---@param action_fn fun(source: string, dest: string) +---@return boolean|nil -- success +---@return string|nil -- error message local function do_single_paste(source, dest, action_type, action_fn) local dest_stats local success, errmsg, errcode @@ -140,6 +150,8 @@ local function do_single_paste(source, dest, action_type, action_fn) end end +---@param node Node +---@param clip table local function toggle(node, clip) if node.name == ".." then return @@ -147,7 +159,8 @@ local function toggle(node, clip) local notify_node = notify.render_path(node.absolute_path) if utils.array_remove(clip, node) then - return notify.info(notify_node .. " removed from clipboard.") + notify.info(notify_node .. " removed from clipboard.") + return end table.insert(clip, node) @@ -161,22 +174,28 @@ function M.clear_clipboard() renderer.draw() end +---@param node Node function M.copy(node) utils.array_remove(clipboard.cut, node) toggle(node, clipboard.copy) renderer.draw() end +---@param node Node function M.cut(node) utils.array_remove(clipboard.copy, node) toggle(node, clipboard.cut) renderer.draw() end +---@param node Node +---@param action_type string +---@param action_fn fun(source: string, dest: string) local function do_paste(node, action_type, action_fn) node = lib.get_last_group_node(node) - if node.name == ".." then - node = core.get_explorer() + local explorer = core.get_explorer() + if node.name == ".." and explorer then + node = explorer end local clip = clipboard[action_type] if #clip == 0 then @@ -202,10 +221,14 @@ local function do_paste(node, action_type, action_fn) clipboard[action_type] = {} if not M.config.filesystem_watchers.enable then - return reloaders.reload_explorer() + reloaders.reload_explorer() end end +---@param source string +---@param destination string +---@return boolean +---@return string? local function do_cut(source, destination) log.line("copy_paste", "do_cut '%s' -> '%s'", source, destination) @@ -225,12 +248,13 @@ local function do_cut(source, destination) return true end +---@param node Node function M.paste(node) if clipboard.cut[1] ~= nil then - return do_paste(node, "cut", do_cut) + do_paste(node, "cut", do_cut) + else + do_paste(node, "copy", do_copy) end - - return do_paste(node, "copy", do_copy) end function M.print_clipboard() @@ -248,9 +272,10 @@ function M.print_clipboard() end end - return notify.info(table.concat(content, "\n") .. "\n") + notify.info(table.concat(content, "\n") .. "\n") end +---@param content string local function copy_to_clipboard(content) local clipboard_name if M.config.actions.use_system_clipboard == true then @@ -264,28 +289,36 @@ local function copy_to_clipboard(content) end vim.api.nvim_exec_autocmds("TextYankPost", {}) - return notify.info(string.format("Copied %s to %s clipboard!", content, clipboard_name)) + notify.info(string.format("Copied %s to %s clipboard!", content, clipboard_name)) end +---@param node Node function M.copy_filename(node) - return copy_to_clipboard(node.name) + copy_to_clipboard(node.name) end +---@param node Node function M.copy_path(node) local absolute_path = node.absolute_path - local relative_path = utils.path_relative(absolute_path, core.get_cwd()) + local cwd = core.get_cwd() + if cwd == nil then + return + end + + local relative_path = utils.path_relative(absolute_path, cwd) local content = node.nodes ~= nil and utils.path_add_trailing(relative_path) or relative_path - return copy_to_clipboard(content) + copy_to_clipboard(content) end +---@param node Node function M.copy_absolute_path(node) local absolute_path = node.absolute_path local content = node.nodes ~= nil and utils.path_add_trailing(absolute_path) or absolute_path - return copy_to_clipboard(content) + copy_to_clipboard(content) end ----Clipboard text highlight group and position when highlight_clipboard. ----@param node table +--- Clipboard text highlight group and position when highlight_clipboard. +---@param node Node ---@return HL_POSITION position none when clipboard empty ---@return string|nil group only when node present in clipboard function M.get_highlight(node) diff --git a/lua/nvim-tree/actions/fs/create-file.lua b/lua/nvim-tree/actions/fs/create-file.lua index 37ae4147b29..410e88eeb0a 100644 --- a/lua/nvim-tree/actions/fs/create-file.lua +++ b/lua/nvim-tree/actions/fs/create-file.lua @@ -8,6 +8,7 @@ local find_file = require("nvim-tree.actions.finders.find-file").fn local M = {} +---@param file string local function create_and_notify(file) events._dispatch_will_create_file(file) local ok, fd = pcall(vim.loop.fs_open, file, "w", 420) @@ -19,6 +20,8 @@ local function create_and_notify(file) events._dispatch_file_created(file) end +---@param iter function iterable +---@return integer local function get_num_nodes(iter) local i = 0 for _ in iter do @@ -27,6 +30,8 @@ local function get_num_nodes(iter) return i end +---@param node Node +---@return string local function get_containing_folder(node) if node.nodes ~= nil then return utils.path_add_trailing(node.absolute_path) @@ -35,11 +40,18 @@ local function get_containing_folder(node) return node.absolute_path:sub(0, -node_name_size - 1) end +---@param node Node|nil function M.fn(node) + local cwd = core.get_cwd() + if cwd == nil then + return + end + node = node and lib.get_last_group_node(node) if not node or node.name == ".." then node = { - absolute_path = core.get_cwd(), + absolute_path = cwd, + name = "", nodes = core.get_explorer().nodes, open = true, } diff --git a/lua/nvim-tree/actions/fs/remove-file.lua b/lua/nvim-tree/actions/fs/remove-file.lua index 4053a8424e5..3d55bff573b 100644 --- a/lua/nvim-tree/actions/fs/remove-file.lua +++ b/lua/nvim-tree/actions/fs/remove-file.lua @@ -8,6 +8,7 @@ local M = { config = {}, } +---@param windows integer[] local function close_windows(windows) -- Prevent from closing when the win count equals 1 or 2, -- where the win to remove could be the last opened. @@ -23,6 +24,7 @@ local function close_windows(windows) end end +---@param absolute_path string local function clear_buffer(absolute_path) local bufs = vim.fn.getbufinfo { bufloaded = 1, buflisted = 1 } for _, buf in pairs(bufs) do @@ -44,10 +46,13 @@ local function clear_buffer(absolute_path) end end +---@param cwd string +---@return boolean|nil local function remove_dir(cwd) local handle = vim.loop.fs_scandir(cwd) if type(handle) == "string" then - return notify.error(handle) + notify.error(handle) + return end while true do @@ -75,20 +80,22 @@ local function remove_dir(cwd) end --- Remove a node, notify errors, dispatch events ---- @param node table +---@param node Node function M.remove(node) local notify_node = notify.render_path(node.absolute_path) if node.nodes ~= nil and not node.link_to then local success = remove_dir(node.absolute_path) if not success then - return notify.error("Could not remove " .. notify_node) + notify.error("Could not remove " .. notify_node) + return end events._dispatch_folder_removed(node.absolute_path) else events._dispatch_will_remove_file(node.absolute_path) local success = vim.loop.fs_unlink(node.absolute_path) if not success then - return notify.error("Could not remove " .. notify_node) + notify.error("Could not remove " .. notify_node) + return end events._dispatch_file_removed(node.absolute_path) clear_buffer(node.absolute_path) @@ -96,6 +103,7 @@ function M.remove(node) notify.info(notify_node .. " was properly removed.") end +---@param node Node function M.fn(node) if node.name == ".." then return diff --git a/lua/nvim-tree/actions/fs/rename-file.lua b/lua/nvim-tree/actions/fs/rename-file.lua index 4c304d0419e..50f83a15650 100644 --- a/lua/nvim-tree/actions/fs/rename-file.lua +++ b/lua/nvim-tree/actions/fs/rename-file.lua @@ -20,6 +20,8 @@ local function err_fmt(from, to, reason) return string.format("Cannot rename %s -> %s: %s", from, to, reason) end +---@param node Node +---@param to string function M.rename(node, to) local notify_from = notify.render_path(node.absolute_path) local notify_to = notify.render_path(to) @@ -32,13 +34,16 @@ function M.rename(node, to) events._dispatch_will_rename_node(node.absolute_path, to) local success, err = vim.loop.fs_rename(node.absolute_path, to) if not success then - return notify.warn(err_fmt(notify_from, notify_to, err)) + notify.warn(err_fmt(notify_from, notify_to, err)) + return end notify.info(string.format("%s -> %s", notify_from, notify_to)) utils.rename_loaded_buffers(node.absolute_path, to) events._dispatch_node_renamed(node.absolute_path, to) end +---@param default_modifier string|nil +---@return fun(node: Node, modifier: string) function M.fn(default_modifier) default_modifier = default_modifier or ":t" @@ -47,13 +52,18 @@ function M.fn(default_modifier) node = lib.get_node_at_cursor() end + if node == nil then + return + end + if type(modifier) ~= "string" then modifier = default_modifier end -- support for only specific modifiers have been implemented if not ALLOWED_MODIFIERS[modifier] then - return notify.warn("Modifier " .. vim.inspect(modifier) .. " is not in allowed list : " .. table.concat(ALLOWED_MODIFIERS, ",")) + notify.warn("Modifier " .. vim.inspect(modifier) .. " is not in allowed list : " .. table.concat(ALLOWED_MODIFIERS, ",")) + return end node = lib.get_last_group_node(node) diff --git a/lua/nvim-tree/actions/fs/trash.lua b/lua/nvim-tree/actions/fs/trash.lua index 41bc8ba06c0..82449bd2745 100644 --- a/lua/nvim-tree/actions/fs/trash.lua +++ b/lua/nvim-tree/actions/fs/trash.lua @@ -8,6 +8,7 @@ local M = { local utils = require "nvim-tree.utils" local events = require "nvim-tree.events" +---@param absolute_path string local function clear_buffer(absolute_path) local bufs = vim.fn.getbufinfo { bufloaded = 1, buflisted = 1 } for _, buf in pairs(bufs) do @@ -24,6 +25,7 @@ local function clear_buffer(absolute_path) end end +---@param node Node function M.remove(node) local binary = M.config.trash.cmd:gsub(" .*$", "") if vim.fn.executable(binary) == 0 then @@ -76,6 +78,7 @@ function M.remove(node) end end +---@param node Node function M.fn(node) if node.name == ".." then return diff --git a/lua/nvim-tree/actions/moves/item.lua b/lua/nvim-tree/actions/moves/item.lua index 837fdd00177..15c1bc8396c 100644 --- a/lua/nvim-tree/actions/moves/item.lua +++ b/lua/nvim-tree/actions/moves/item.lua @@ -6,6 +6,9 @@ local explorer_node = require "nvim-tree.explorer.node" local M = {} +---@param where string +---@param what string +---@return fun() function M.fn(where, what) return function() local node_cur = lib.get_node_at_cursor() diff --git a/lua/nvim-tree/actions/moves/parent.lua b/lua/nvim-tree/actions/moves/parent.lua index 61bce43a75e..598483eb120 100644 --- a/lua/nvim-tree/actions/moves/parent.lua +++ b/lua/nvim-tree/actions/moves/parent.lua @@ -6,6 +6,8 @@ local lib = require "nvim-tree.lib" local M = {} +---@param should_close boolean|nil +---@return fun(node: Node): boolean|nil function M.fn(should_close) should_close = should_close or false diff --git a/lua/nvim-tree/actions/moves/sibling.lua b/lua/nvim-tree/actions/moves/sibling.lua index 6a051a881f1..16e95ba8f05 100644 --- a/lua/nvim-tree/actions/moves/sibling.lua +++ b/lua/nvim-tree/actions/moves/sibling.lua @@ -4,6 +4,8 @@ local Iterator = require "nvim-tree.iterators.node-iterator" local M = {} +---@param direction string +---@return fun(node: Node): nil function M.fn(direction) return function(node) if node.name == ".." or not direction then diff --git a/lua/nvim-tree/actions/node/file-popup.lua b/lua/nvim-tree/actions/node/file-popup.lua index 3bcc80128e0..1ce70fe2167 100644 --- a/lua/nvim-tree/actions/node/file-popup.lua +++ b/lua/nvim-tree/actions/node/file-popup.lua @@ -2,6 +2,8 @@ local utils = require "nvim-tree.utils" local M = {} +---@param node Node +---@return table local function get_formatted_lines(node) local stats = node.fs_stat local fpath = " fullpath: " .. node.absolute_path @@ -21,6 +23,7 @@ end local current_popup = nil +---@param node Node local function setup_window(node) local lines = get_formatted_lines(node) @@ -52,6 +55,7 @@ function M.close_popup() end end +---@param node Node function M.toggle_file_info(node) if node.name == ".." then return diff --git a/lua/nvim-tree/actions/node/open-file.lua b/lua/nvim-tree/actions/node/open-file.lua index 7d08a349962..afe167541e5 100644 --- a/lua/nvim-tree/actions/node/open-file.lua +++ b/lua/nvim-tree/actions/node/open-file.lua @@ -6,6 +6,8 @@ local view = require "nvim-tree.view" local M = {} +---Get single char from user input +---@return string local function get_user_input_char() local c = vim.fn.getchar() while type(c) ~= "number" do @@ -302,6 +304,8 @@ local function edit_in_current_buf(filename) vim.cmd("keepalt keepjumps edit " .. vim.fn.fnameescape(filename)) end +---@param mode string +---@param filename string function M.fn(mode, filename) if type(mode) ~= "string" then mode = "" diff --git a/lua/nvim-tree/actions/node/run-command.lua b/lua/nvim-tree/actions/node/run-command.lua index 453475f6d22..18bd8f8b0f2 100644 --- a/lua/nvim-tree/actions/node/run-command.lua +++ b/lua/nvim-tree/actions/node/run-command.lua @@ -6,14 +6,18 @@ local M = {} ---Retrieves the absolute path to the node. ---Safely handles the node representing the current directory ---(the topmost node in the nvim-tree window) +---@param node Node +---@return string local function get_node_path(node) - if node.name == ".." then - return utils.path_remove_trailing(core.get_cwd()) + local cwd = core.get_cwd() + if node.name == ".." and cwd then + return utils.path_remove_trailing(cwd) else return node.absolute_path end end +---@param node Node function M.run_file_command(node) local node_path = get_node_path(node) vim.api.nvim_input(": " .. node_path .. "") diff --git a/lua/nvim-tree/actions/node/system-open.lua b/lua/nvim-tree/actions/node/system-open.lua index 6c12d186ec1..fa3a9d846dd 100644 --- a/lua/nvim-tree/actions/node/system-open.lua +++ b/lua/nvim-tree/actions/node/system-open.lua @@ -3,6 +3,7 @@ local utils = require "nvim-tree.utils" local M = {} +---@param node Node function M.fn(node) if #M.config.system_open.cmd == 0 then require("nvim-tree.utils").notify.warn "Cannot open file with system application. Unrecognized platform." diff --git a/lua/nvim-tree/actions/reloaders/reloaders.lua b/lua/nvim-tree/actions/reloaders/reloaders.lua index 1292715cb47..14f4b0394ec 100644 --- a/lua/nvim-tree/actions/reloaders/reloaders.lua +++ b/lua/nvim-tree/actions/reloaders/reloaders.lua @@ -8,6 +8,9 @@ local Iterator = require "nvim-tree.iterators.node-iterator" local M = {} +---@param node Explorer|nil +---@param projects table +---@param unloaded_bufnr number|nil local function refresh_nodes(node, projects, unloaded_bufnr) Iterator.builder({ node }) :applier(function(n) @@ -22,7 +25,13 @@ local function refresh_nodes(node, projects, unloaded_bufnr) :iterate() end +---@param parent_node Node|nil +---@param projects table function M.reload_node_status(parent_node, projects) + if parent_node == nil then + return + end + local toplevel = git.get_toplevel(parent_node.absolute_path) local status = projects[toplevel] or {} for _, node in ipairs(parent_node.nodes) do diff --git a/lua/nvim-tree/actions/root/change-dir.lua b/lua/nvim-tree/actions/root/change-dir.lua index 0e667330b2b..954b2081ccf 100644 --- a/lua/nvim-tree/actions/root/change-dir.lua +++ b/lua/nvim-tree/actions/root/change-dir.lua @@ -6,9 +6,15 @@ local M = { current_tab = vim.api.nvim_get_current_tabpage(), } +---@param name string +---@return string|nil local function clean_input_cwd(name) name = vim.fn.fnameescape(name) - local root_parent_cwd = vim.fn.fnamemodify(utils.path_remove_trailing(core.get_cwd()), ":h") + local cwd = core.get_cwd() + if cwd == nil then + return + end + local root_parent_cwd = vim.fn.fnamemodify(utils.path_remove_trailing(cwd), ":h") if name == ".." and root_parent_cwd then return vim.fn.expand(root_parent_cwd) else @@ -16,17 +22,23 @@ local function clean_input_cwd(name) end end +---@param new_tabpage integer +---@return boolean local function is_window_event(new_tabpage) local is_event_scope_window = vim.v.event.scope == "window" or vim.v.event.changed_window return is_event_scope_window and new_tabpage == M.current_tab end +---@param foldername string +---@return boolean local function prevent_cwd_change(foldername) local is_same_cwd = foldername == core.get_cwd() local is_restricted_above = M.options.restrict_above_cwd and foldername < vim.fn.getcwd(-1, -1) return is_same_cwd or is_restricted_above end +---@param input_cwd string +---@param with_open boolean|nil function M.fn(input_cwd, with_open) if not core.get_explorer() then return @@ -38,7 +50,7 @@ function M.fn(input_cwd, with_open) end local foldername = clean_input_cwd(input_cwd) - if prevent_cwd_change(foldername) then + if foldername == nil or prevent_cwd_change(foldername) then return end @@ -46,14 +58,19 @@ function M.fn(input_cwd, with_open) M.force_dirchange(foldername, with_open) end +---@param global boolean +---@param path string local function cd(global, path) vim.cmd((global and "cd " or "lcd ") .. vim.fn.fnameescape(path)) end +---@return boolean local function should_change_dir() return M.options.enable and vim.tbl_isempty(vim.v.event) end +---@param f function +---@return fun(foldername: string, should_open_view: boolean|nil) local function add_profiling_to(f) return function(foldername, should_open_view) local profile = log.profile_start("change dir %s", foldername) diff --git a/lua/nvim-tree/actions/root/dir-up.lua b/lua/nvim-tree/actions/root/dir-up.lua index 439baa8cebc..ac963280b29 100644 --- a/lua/nvim-tree/actions/root/dir-up.lua +++ b/lua/nvim-tree/actions/root/dir-up.lua @@ -3,13 +3,19 @@ local core = require "nvim-tree.core" local M = {} +---@param node Node function M.fn(node) if not node or node.name == ".." then - return require("nvim-tree.actions.root.change-dir").fn ".." + require("nvim-tree.actions.root.change-dir").fn ".." else - local newdir = vim.fn.fnamemodify(utils.path_remove_trailing(core.get_cwd()), ":h") + local cwd = core.get_cwd() + if cwd == nil then + return + end + + local newdir = vim.fn.fnamemodify(utils.path_remove_trailing(cwd), ":h") require("nvim-tree.actions.root.change-dir").fn(newdir) - return require("nvim-tree.actions.finders.find-file").fn(node.absolute_path) + require("nvim-tree.actions.finders.find-file").fn(node.absolute_path) end end diff --git a/lua/nvim-tree/actions/tree-modifiers/collapse-all.lua b/lua/nvim-tree/actions/tree-modifiers/collapse-all.lua index d11cd78d5f8..c6add436f1e 100644 --- a/lua/nvim-tree/actions/tree-modifiers/collapse-all.lua +++ b/lua/nvim-tree/actions/tree-modifiers/collapse-all.lua @@ -6,6 +6,7 @@ local Iterator = require "nvim-tree.iterators.node-iterator" local M = {} +---@return fun(path: string): boolean local function buf_match() local buffer_paths = vim.tbl_map(function(buffer) return vim.api.nvim_buf_get_name(buffer) @@ -22,6 +23,7 @@ local function buf_match() end end +---@param keep_buffers boolean function M.fn(keep_buffers) local node = lib.get_node_at_cursor() local explorer = core.get_explorer() diff --git a/lua/nvim-tree/actions/tree-modifiers/expand-all.lua b/lua/nvim-tree/actions/tree-modifiers/expand-all.lua index 30ecd86dc0b..6af62e6ae49 100644 --- a/lua/nvim-tree/actions/tree-modifiers/expand-all.lua +++ b/lua/nvim-tree/actions/tree-modifiers/expand-all.lua @@ -6,6 +6,8 @@ local lib = require "nvim-tree.lib" local M = {} +---@param list string[] +---@return table local function to_lookup_table(list) local table = {} for _, element in ipairs(list) do @@ -15,6 +17,7 @@ local function to_lookup_table(list) return table end +---@param node Node local function expand(node) node = lib.get_last_group_node(node) node.open = true @@ -23,6 +26,9 @@ local function expand(node) end end +---@param expansion_count integer +---@param node Node +---@return boolean local function should_expand(expansion_count, node) local should_halt = expansion_count >= M.MAX_FOLDER_DISCOVERY local should_exclude = M.EXCLUDE[node.name] @@ -57,6 +63,7 @@ local function gen_iterator() end end +---@param base_node table function M.fn(base_node) local node = base_node.nodes and base_node or core.get_explorer() if gen_iterator()(node) then diff --git a/lua/nvim-tree/actions/tree/find-file.lua b/lua/nvim-tree/actions/tree/find-file.lua index 0514b26c914..3678276d654 100644 --- a/lua/nvim-tree/actions/tree/find-file.lua +++ b/lua/nvim-tree/actions/tree/find-file.lua @@ -6,7 +6,7 @@ local finders_find_file = require "nvim-tree.actions.finders.find-file" local M = {} --- Find file or buffer ---- @param opts ApiTreeFindFileOpts|nil|boolean legacy -> opts.buf +---@param opts ApiTreeFindFileOpts|nil|boolean legacy -> opts.buf function M.fn(opts) -- legacy arguments if type(opts) == "string" then diff --git a/lua/nvim-tree/api.lua b/lua/nvim-tree/api.lua index d2114fced7a..a57cbf4216c 100644 --- a/lua/nvim-tree/api.lua +++ b/lua/nvim-tree/api.lua @@ -30,6 +30,7 @@ local Api = { --- Do nothing when setup not called. --- f function to invoke +---@param f function local function wrap(f) return function(...) if vim.g.NvimTreeSetup == 1 then @@ -167,6 +168,8 @@ Api.fs.copy.absolute_path = wrap_node(require("nvim-tree.actions.fs.copy-paste") Api.fs.copy.filename = wrap_node(require("nvim-tree.actions.fs.copy-paste").copy_filename) Api.fs.copy.relative_path = wrap_node(require("nvim-tree.actions.fs.copy-paste").copy_path) +---@param mode string +---@param node table local function edit(mode, node) local path = node.absolute_path if node.link_to and not node.nodes then @@ -175,6 +178,8 @@ local function edit(mode, node) require("nvim-tree.actions.node.open-file").fn(mode, path) end +---@param mode string +---@return fun(node: table) local function open_or_expand_or_dir_up(mode) return function(node) if node.name == ".." then diff --git a/lua/nvim-tree/core.lua b/lua/nvim-tree/core.lua index 036411fa51e..9a27458275e 100644 --- a/lua/nvim-tree/core.lua +++ b/lua/nvim-tree/core.lua @@ -6,9 +6,11 @@ local log = require "nvim-tree.log" local M = {} +---@type Explorer|nil local TreeExplorer = nil local first_init_done = false +---@param foldername string function M.init(foldername) local profile = log.profile_start("core init %s", foldername) @@ -23,6 +25,7 @@ function M.init(foldername) log.profile_end(profile) end +---@return Explorer|nil function M.get_explorer() return TreeExplorer end @@ -31,10 +34,12 @@ function M.reset_explorer() TreeExplorer = nil end +---@return string|nil function M.get_cwd() return TreeExplorer and TreeExplorer.absolute_path end +---@return integer function M.get_nodes_starting_line() local offset = 1 if view.is_root_folder_visible(M.get_cwd()) then diff --git a/lua/nvim-tree/diagnostics.lua b/lua/nvim-tree/diagnostics.lua index c1d783a7f4a..93c689634a9 100644 --- a/lua/nvim-tree/diagnostics.lua +++ b/lua/nvim-tree/diagnostics.lua @@ -12,6 +12,7 @@ local severity_levels = { Hint = 4, } +---@return table local function from_nvim_lsp() local buffer_severity = {} @@ -36,10 +37,14 @@ local function from_nvim_lsp() return buffer_severity end +---@param severity integer +---@param config table +---@return boolean local function is_severity_in_range(severity, config) return config.max <= severity and severity <= config.min end +---@return table local function from_coc() if vim.g.coc_service_initialized ~= 1 then return {} diff --git a/lua/nvim-tree/events.lua b/lua/nvim-tree/events.lua index d2efe2d4668..4ab74932226 100644 --- a/lua/nvim-tree/events.lua +++ b/lua/nvim-tree/events.lua @@ -21,16 +21,22 @@ M.Event = { TreeRendered = "TreeRendered", } +---@param event_name string +---@return table local function get_handlers(event_name) return global_handlers[event_name] or {} end +---@param event_name string +---@param handler function function M.subscribe(event_name, handler) local handlers = get_handlers(event_name) table.insert(handlers, handler) global_handlers[event_name] = handlers end +---@param event_name string +---@param payload table|nil local function dispatch(event_name, payload) for _, handler in pairs(get_handlers(event_name)) do local success, error = pcall(handler, payload) diff --git a/lua/nvim-tree/explorer/explore.lua b/lua/nvim-tree/explorer/explore.lua index a8326599fa6..6a9185afb95 100644 --- a/lua/nvim-tree/explorer/explore.lua +++ b/lua/nvim-tree/explorer/explore.lua @@ -11,10 +11,17 @@ local Watcher = require "nvim-tree.watcher" local M = {} +---@param type_ string|nil +---@param cwd string +---@return any local function get_type_from(type_, cwd) return type_ or (vim.loop.fs_stat(cwd) or {}).type end +---@param handle uv.uv_fs_t +---@param cwd string +---@param node Node +---@param git_status table local function populate_children(handle, cwd, node, git_status) local node_ignored = explorer_node.is_git_ignored(node) local nodes_by_path = utils.bool_record(node.nodes, "absolute_path") @@ -53,6 +60,9 @@ local function populate_children(handle, cwd, node, git_status) end end +---@param node Node +---@param status table +---@return Node[]|nil function M.explore(node, status) local cwd = node.link_to or node.absolute_path local handle = vim.loop.fs_scandir(cwd) diff --git a/lua/nvim-tree/explorer/filters.lua b/lua/nvim-tree/explorer/filters.lua index 4e332c798ff..7c8d4723d78 100644 --- a/lua/nvim-tree/explorer/filters.lua +++ b/lua/nvim-tree/explorer/filters.lua @@ -5,6 +5,8 @@ local M = { exclude_list = {}, } +---@param path string +---@return boolean local function is_excluded(path) for _, node in ipairs(M.exclude_list) do if path:match(node) then @@ -61,10 +63,14 @@ local function buf(path, bufinfo, unloaded_bufnr) return true end +---@param path string +---@return boolean local function dotfile(path) return M.config.filter_dotfiles and utils.path_basename(path):sub(1, 1) == "." end +---@param path string +---@return boolean local function custom(path) if not M.config.filter_custom then return false diff --git a/lua/nvim-tree/explorer/init.lua b/lua/nvim-tree/explorer/init.lua index a47ac4d7423..3e98b00dc71 100644 --- a/lua/nvim-tree/explorer/init.lua +++ b/lua/nvim-tree/explorer/init.lua @@ -7,11 +7,20 @@ local M = {} M.explore = require("nvim-tree.explorer.explore").explore M.reload = require("nvim-tree.explorer.reload").reload +---@class Explorer +---@field absolute_path string +---@field nodes Node[] +---@field open boolean + local Explorer = {} Explorer.__index = Explorer +---@param cwd string|nil +---@return Explorer function Explorer.new(cwd) cwd = vim.loop.fs_realpath(cwd or vim.loop.cwd()) + + ---@class Explorer local explorer = setmetatable({ absolute_path = cwd, nodes = {}, @@ -22,12 +31,15 @@ function Explorer.new(cwd) return explorer end +---@private +---@param node Node function Explorer:_load(node) local cwd = node.link_to or node.absolute_path local git_status = git.load_project_status(cwd) M.explore(node, git_status) end +---@param node Node function Explorer:expand(node) self:_load(node) end diff --git a/lua/nvim-tree/explorer/node-builders.lua b/lua/nvim-tree/explorer/node-builders.lua index c96fe58057c..585270e5c37 100644 --- a/lua/nvim-tree/explorer/node-builders.lua +++ b/lua/nvim-tree/explorer/node-builders.lua @@ -3,6 +3,10 @@ local watch = require "nvim-tree.explorer.watch" local M = {} +---@param parent Node +---@param absolute_path string +---@param name string +---@return Node function M.folder(parent, absolute_path, name) local handle = vim.loop.fs_scandir(absolute_path) local has_children = handle and vim.loop.fs_scandir_next(handle) ~= nil @@ -25,8 +29,8 @@ function M.folder(parent, absolute_path, name) end --- path is an executable file or directory ---- @param absolute_path string ---- @return boolean +---@param absolute_path string +---@return boolean|nil function M.is_executable(absolute_path) if utils.is_windows or utils.is_wsl then --- executable detection on windows is buggy and not performant hence it is disabled @@ -36,6 +40,10 @@ function M.is_executable(absolute_path) end end +---@param parent Node +---@param absolute_path string +---@param name string +---@return Node function M.file(parent, absolute_path, name) local ext = string.match(name, ".?[^.]+%.(.*)") or "" @@ -55,6 +63,10 @@ end -- links (for instance libr2.so in /usr/lib) and thus even with a C program realpath fails -- when it has no real reason to. Maybe there is a reason, but errno is definitely wrong. -- So we need to check for link_to ~= nil when adding new links to the main tree +---@param parent Node +---@param absolute_path string +---@param name string +---@return Node function M.link(parent, absolute_path, name) --- I dont know if this is needed, because in my understanding, there isn't hard links in windows, but just to be sure i changed it. local link_to = vim.loop.fs_realpath(absolute_path) diff --git a/lua/nvim-tree/explorer/node.lua b/lua/nvim-tree/explorer/node.lua index 3a84e6e740c..6e58771e73b 100644 --- a/lua/nvim-tree/explorer/node.lua +++ b/lua/nvim-tree/explorer/node.lua @@ -1,14 +1,13 @@ local M = {} --- node.git_status structure: --- { --- file = string | nil, --- dir = { --- direct = { string } | nil, --- indirect = { string } | nil, --- } | nil, --- } - +---@class GitStatus +---@field file string|nil +---@field dir table|nil + +---@param parent_ignored boolean +---@param status table|nil +---@param absolute_path string +---@return GitStatus|nil local function get_dir_git_status(parent_ignored, status, absolute_path) if parent_ignored then return { file = "!!" } @@ -25,15 +24,24 @@ local function get_dir_git_status(parent_ignored, status, absolute_path) end end +---@param parent_ignored boolean +---@param status table +---@param absolute_path string +---@return GitStatus local function get_git_status(parent_ignored, status, absolute_path) local file_status = parent_ignored and "!!" or status.files and status.files[absolute_path] return { file = file_status } end +---@param node Node +---@return boolean function M.has_one_child_folder(node) - return #node.nodes == 1 and node.nodes[1].nodes and vim.loop.fs_access(node.nodes[1].absolute_path, "R") + return #node.nodes == 1 and node.nodes[1].nodes and vim.loop.fs_access(node.nodes[1].absolute_path, "R") or false end +---@param node Node +---@param parent_ignored boolean +---@param status table|nil function M.update_git_status(node, parent_ignored, status) local get_status if node.nodes then @@ -51,6 +59,8 @@ function M.update_git_status(node, parent_ignored, status) end end +---@param node Node +---@return GitStatus|nil function M.get_git_status(node) local git_status = node and node.git_status if not git_status then @@ -112,10 +122,13 @@ function M.get_git_status(node) end end +---@param node Node +---@return boolean function M.is_git_ignored(node) - return node and node.git_status and node.git_status.file == "!!" + return node and node.git_status ~= nil and node.git_status.file == "!!" end +---@param node Node function M.node_destroy(node) if not node then return diff --git a/lua/nvim-tree/explorer/reload.lua b/lua/nvim-tree/explorer/reload.lua index cd1aa458170..d921d033f97 100644 --- a/lua/nvim-tree/explorer/reload.lua +++ b/lua/nvim-tree/explorer/reload.lua @@ -12,6 +12,10 @@ local Watcher = require "nvim-tree.watcher" local M = {} +---@param nodes_by_path table +---@param node_ignored boolean +---@param status table +---@return fun(node: Node): table local function update_status(nodes_by_path, node_ignored, status) return function(node) if nodes_by_path[node.absolute_path] then @@ -21,6 +25,8 @@ local function update_status(nodes_by_path, node_ignored, status) end end +---@param path string +---@param callback fun(toplevel: string|nil, project: table|nil) local function reload_and_get_git_project(path, callback) local toplevel = git.get_toplevel(path) @@ -29,6 +35,9 @@ local function reload_and_get_git_project(path, callback) end) end +---@param node Node +---@param project table|nil +---@param root string|nil local function update_parent_statuses(node, project, root) while project and node do -- step up to the containing project @@ -58,6 +67,9 @@ local function update_parent_statuses(node, project, root) end end +---@param node Node +---@param git_status table +---@param unloaded_bufnr number|nil function M.reload(node, git_status, unloaded_bufnr) local cwd = node.link_to or node.absolute_path local handle = vim.loop.fs_scandir(cwd) @@ -143,7 +155,7 @@ function M.reload(node, git_status, unloaded_bufnr) return child_names[n.absolute_path] else explorer_node.node_destroy(n) - return nil + return false end end, node.nodes) ) @@ -165,7 +177,7 @@ function M.reload(node, git_status, unloaded_bufnr) end ---Refresh contents and git status for a single node ----@param node table +---@param node Node ---@param callback function function M.refresh_node(node, callback) if type(node) ~= "table" then diff --git a/lua/nvim-tree/explorer/sorters.lua b/lua/nvim-tree/explorer/sorters.lua index f2a259bc0bb..cb7400f512e 100644 --- a/lua/nvim-tree/explorer/sorters.lua +++ b/lua/nvim-tree/explorer/sorters.lua @@ -3,8 +3,8 @@ local M = {} local C = {} --- Predefined comparator, defaulting to name ---- @param sorter string as per options ---- @return function +---@param sorter string as per options +---@return function local function get_comparator(sorter) return C[sorter] or C.name end @@ -24,8 +24,8 @@ local function tbl_slice(t, first, last) end ---Evaluate `sort.folders_first` and `sort.files_first` ----@param a table node ----@param b table node +---@param a Node +---@param b Node ---@return boolean|nil local function folders_or_files_first(a, b) if not (M.config.sort.folders_first or M.config.sort.files_first) then @@ -41,6 +41,11 @@ local function folders_or_files_first(a, b) end end +---@param t table +---@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) local n1 = mid - first + 1 local n2 = last - mid @@ -74,6 +79,10 @@ local function merge(t, first, mid, last, comparator) end end +---@param t table +---@param first number +---@param last number +---@param comparator fun(a: Node, b: Node): boolean local function split_merge(t, first, last, comparator) if (last - first) < 1 then return @@ -137,6 +146,10 @@ function M.sort(t) end end +---@param a Node +---@param b Node +---@param ignorecase boolean|nil +---@return boolean local function node_comparator_name_ignorecase_or_not(a, b, ignorecase) if not (a and b) then return true diff --git a/lua/nvim-tree/explorer/watch.lua b/lua/nvim-tree/explorer/watch.lua index cbebe3b144b..79e3623ce9b 100644 --- a/lua/nvim-tree/explorer/watch.lua +++ b/lua/nvim-tree/explorer/watch.lua @@ -7,6 +7,8 @@ local M = { uid = 0, } +---@param path string +---@return boolean local function is_git(path) -- If $GIT_DIR is set, consider its value to be equivalent to '.git'. -- Expand $GIT_DIR (and `path`) to a full path (see :help filename-modifiers), since @@ -29,6 +31,8 @@ local IGNORED_PATHS = { "/dev", } +---@param path string +---@return boolean local function is_folder_ignored(path) for _, folder in ipairs(IGNORED_PATHS) do if vim.startswith(path, folder) then @@ -45,18 +49,14 @@ local function is_folder_ignored(path) return false end +---@param node Node +---@return Watcher|nil function M.create_watcher(node) if not M.config.filesystem_watchers.enable or type(node) ~= "table" then return nil end - local path - if node.type == "link" then - path = node.link_to - else - path = node.absolute_path - end - + local path = node.link_to or node.absolute_path if is_git(path) or is_folder_ignored(path) then return nil end diff --git a/lua/nvim-tree/git/init.lua b/lua/nvim-tree/git/init.lua index d2c180c9f58..0b2b20c8892 100644 --- a/lua/nvim-tree/git/init.lua +++ b/lua/nvim-tree/git/init.lua @@ -29,6 +29,10 @@ local WATCHED_FILES = { "index", -- staging area } +---@param toplevel string|nil +---@param path string|nil +---@param project table +---@param git_status table|nil local function reload_git_status(toplevel, path, project, git_status) if path then for p in pairs(project.files) do @@ -45,9 +49,9 @@ local function reload_git_status(toplevel, path, project, git_status) end --- Is this path in a known ignored directory? ---- @param path string ---- @param project table git status ---- @return boolean +---@param path string +---@param project table git status +---@return boolean local function path_ignored_in_project(path, project) if not path or not project then return false @@ -64,7 +68,7 @@ local function path_ignored_in_project(path, project) end --- Reload all projects ---- @return table projects maybe empty +---@return table projects maybe empty function M.reload() if not M.config.git.enable then return {} @@ -78,9 +82,9 @@ function M.reload() end --- Reload one project. Does nothing when no project or path is ignored ---- @param toplevel string|nil ---- @param path string|nil optional path to update only ---- @param callback function|nil +---@param toplevel string|nil +---@param path string|nil optional path to update only +---@param callback function|nil function M.reload_project(toplevel, path, callback) local project = M._projects_by_toplevel[toplevel] if not toplevel or not project or not M.config.git.enable then @@ -118,7 +122,8 @@ function M.reload_project(toplevel, path, callback) end --- Retrieve a known project ---- @return table|nil project +---@param toplevel string|nil +---@return table|nil project function M.get_project(toplevel) return M._projects_by_toplevel[toplevel] end @@ -128,8 +133,8 @@ end --- not part of a project --- not a directory --- path in git.disable_for_dirs ---- @param path string absolute ---- @return string|nil +---@param path string absolute +---@return string|nil function M.get_toplevel(path) if not M.config.git.enable then return nil @@ -207,8 +212,8 @@ end --- Load the project status for a path. Does nothing when no toplevel for path. --- Only fetches project status when unknown, otherwise returns existing. ---- @param path string absolute ---- @return table project maybe empty +---@param path string absolute +---@return table project maybe empty function M.load_project_status(path) if not M.config.git.enable then return {} @@ -252,12 +257,17 @@ function M.load_project_status(path) }) end - M._projects_by_toplevel[toplevel] = { - files = git_status, - dirs = git_utils.file_status_to_dir_status(git_status, toplevel), - watcher = watcher, - } - return M._projects_by_toplevel[toplevel] + if git_status then + M._projects_by_toplevel[toplevel] = { + files = git_status, + dirs = git_utils.file_status_to_dir_status(git_status, toplevel), + watcher = watcher, + } + return M._projects_by_toplevel[toplevel] + else + M._toplevels_by_path[path] = false + return {} + end end function M.purge_state() diff --git a/lua/nvim-tree/git/runner.lua b/lua/nvim-tree/git/runner.lua index dfcc31230cf..8e2635df8bb 100644 --- a/lua/nvim-tree/git/runner.lua +++ b/lua/nvim-tree/git/runner.lua @@ -2,13 +2,26 @@ local log = require "nvim-tree.log" local utils = require "nvim-tree.utils" local notify = require "nvim-tree.notify" +-- TODO add "${3rd}/luv/library" to "workspace.library" +---@class uv.uv_handle_t: table +---@class uv.uv_stream_t: uv.uv_handle_t +---@class uv.uv_pipe_t: uv.uv_stream_t + +---@class Runner local Runner = {} Runner.__index = Runner local timeouts = 0 local MAX_TIMEOUTS = 5 +---@private +---@param status string +---@param path string|nil function Runner:_parse_status_output(status, path) + if not path then + return + end + -- replacing slashes if on windows if vim.fn.has "win32" == 1 then path = path:gsub("/", "\\") @@ -18,6 +31,10 @@ function Runner:_parse_status_output(status, path) end end +---@private +---@param prev_output string +---@param incoming string +---@return string function Runner:_handle_incoming_data(prev_output, incoming) if incoming and utils.str_find(incoming, "\n") then local prev = prev_output .. incoming @@ -46,12 +63,15 @@ function Runner:_handle_incoming_data(prev_output, incoming) end for line in prev_output:gmatch "[^\n]*\n" do - self._parse_status_output(line) + self:_parse_status_output(line) end return "" end +---@param stdout_handle uv.uv_pipe_t +---@param stderr_handle uv.uv_pipe_t +---@return table function Runner:_getopts(stdout_handle, stderr_handle) local untracked = self.list_untracked and "-u" or nil local ignored = (self.list_untracked and self.list_ignored) and "--ignored=matching" or "--ignored=no" @@ -62,6 +82,7 @@ function Runner:_getopts(stdout_handle, stderr_handle) } end +---@param output string function Runner:_log_raw_output(output) if log.enabled "git" and output and type(output) == "string" then log.raw("git", "%s", output) @@ -69,12 +90,17 @@ function Runner:_log_raw_output(output) end end +---@param callback function|nil function Runner:_run_git_job(callback) local handle, pid local stdout = vim.loop.new_pipe(false) local stderr = vim.loop.new_pipe(false) local timer = vim.loop.new_timer() + if stdout == nil or stderr == nil or timer == nil then + return + end + local function on_finish(rc) self.rc = rc or 0 if timer:is_closing() or stdout:is_closing() or stderr:is_closing() or (handle and handle:is_closing()) then @@ -151,6 +177,7 @@ function Runner:_wait() end end +---@param opts table function Runner:_finalise(opts) if self.rc == -1 then log.line("git", "job timed out %s %s", opts.toplevel, opts.path) @@ -167,9 +194,9 @@ function Runner:_finalise(opts) end --- Runs a git process, which will be killed if it takes more than timeout which defaults to 400ms ---- @param opts table ---- @param callback function|nil executed passing return when complete ---- @return table|nil status by absolute path, nil if callback present +---@param opts table +---@param callback function|nil executed passing return when complete +---@return table|nil status by absolute path, nil if callback present function Runner.run(opts, callback) local self = setmetatable({ toplevel = opts.toplevel, diff --git a/lua/nvim-tree/git/utils.lua b/lua/nvim-tree/git/utils.lua index e088be6beae..d9f76bf8360 100644 --- a/lua/nvim-tree/git/utils.lua +++ b/lua/nvim-tree/git/utils.lua @@ -6,9 +6,9 @@ local M = { } --- Retrieve the git toplevel directory ---- @param cwd string path ---- @return string|nil toplevel absolute path ---- @return string|nil git_dir absolute path +---@param cwd string path +---@return string|nil toplevel absolute path +---@return string|nil git_dir absolute path function M.get_toplevel(cwd) local profile = log.profile_start("git toplevel git_dir %s", cwd) @@ -60,6 +60,8 @@ end local untracked = {} +---@param cwd string +---@return string|nil function M.should_show_untracked(cwd) if untracked[cwd] ~= nil then return untracked[cwd] @@ -79,12 +81,18 @@ function M.should_show_untracked(cwd) return untracked[cwd] end +---@param t table|nil +---@param k string +---@return table local function nil_insert(t, k) t = t or {} t[k] = true return t end +---@param status table +---@param cwd string|nil +---@return table function M.file_status_to_dir_status(status, cwd) local direct = {} for p, s in pairs(status) do diff --git a/lua/nvim-tree/help.lua b/lua/nvim-tree/help.lua index c7342be54d1..2f2c9d8c017 100644 --- a/lua/nvim-tree/help.lua +++ b/lua/nvim-tree/help.lua @@ -19,8 +19,8 @@ local M = { } --- Shorten and normalise a vim command lhs ---- @param lhs string ---- @return string +---@param lhs string +---@return string local function tidy_lhs(lhs) -- nvim_buf_get_keymap replaces leading "<" with "" e.g. "CTRL-v>" lhs = lhs:gsub("^", "<") @@ -43,15 +43,15 @@ end --- Remove prefix 'nvim-tree: ' --- Hardcoded to keep default_on_attach simple ---- @param desc string ---- @return string +---@param desc string +---@return string local function tidy_desc(desc) return desc and desc:gsub("^nvim%-tree: ", "") or "" end --- sort vim command lhs roughly as per :help index ---- @param a string ---- @param b string +---@param a string +---@param b string local function sort_lhs(a, b) -- mouse first if a:match(PAT_MOUSE) and not b:match(PAT_MOUSE) then @@ -79,9 +79,9 @@ local function sort_lhs(a, b) end --- Compute all lines for the buffer ---- @return table strings of text ---- @return table arrays of arguments 3-6 for nvim_buf_add_highlight() ---- @return number maximum length of text +---@return table strings of text +---@return table arrays of arguments 3-6 for nvim_buf_add_highlight() +---@return number maximum length of text local function compute() local head_lhs = "nvim-tree mappings" local head_rhs1 = "exit: q" diff --git a/lua/nvim-tree/iterators/node-iterator.lua b/lua/nvim-tree/iterators/node-iterator.lua index c1cf722fed8..8cd4abdeda6 100644 --- a/lua/nvim-tree/iterators/node-iterator.lua +++ b/lua/nvim-tree/iterators/node-iterator.lua @@ -1,6 +1,9 @@ +---@class NodeIterator local NodeIterator = {} NodeIterator.__index = NodeIterator +---@param nodes Node[] +---@return NodeIterator function NodeIterator.builder(nodes) return setmetatable({ nodes = nodes, @@ -15,6 +18,7 @@ function NodeIterator.builder(nodes) }, NodeIterator) end +---@return NodeIterator function NodeIterator:hidden() self._filter_hidden = function(_) return true @@ -22,21 +26,29 @@ function NodeIterator:hidden() return self end +---@param f fun(node: Node): boolean +---@return NodeIterator function NodeIterator:matcher(f) self._match = f return self end +---@param f fun(node: Node, i: number) +---@return NodeIterator function NodeIterator:applier(f) self._apply_fn_on_node = f return self end +---@param f fun(node: Node): any +---@return NodeIterator function NodeIterator:recursor(f) self._recurse_with = f return self end +---@return Node|nil +---@return number|nil function NodeIterator:iterate() local iteration_count = 0 local function iter(nodes) diff --git a/lua/nvim-tree/keymap.lua b/lua/nvim-tree/keymap.lua index 9a7189019bf..991b9b338f9 100644 --- a/lua/nvim-tree/keymap.lua +++ b/lua/nvim-tree/keymap.lua @@ -1,8 +1,8 @@ local M = {} --- Apply mappings to a scratch buffer and return buffer local mappings ---- @param fn function(bufnr) on_attach or default_on_attach ---- @return table as per vim.api.nvim_buf_get_keymap +---@param fn function(bufnr) on_attach or default_on_attach +---@return table as per vim.api.nvim_buf_get_keymap local function generate_keymap(fn) -- create an unlisted scratch buffer local scratch_bufnr = vim.api.nvim_create_buf(false, true) @@ -20,6 +20,7 @@ local function generate_keymap(fn) end -- stylua: ignore start +---@param bufnr integer function M.default_on_attach(bufnr) local api = require('nvim-tree.api') @@ -93,10 +94,12 @@ function M.default_on_attach(bufnr) end -- stylua: ignore end +---@return table function M.get_keymap() return generate_keymap(M.on_attach) end +---@return table function M.get_keymap_default() return generate_keymap(M.default_on_attach) end diff --git a/lua/nvim-tree/lib.lua b/lua/nvim-tree/lib.lua index 9f0a2c45748..8a383cbb4ce 100644 --- a/lua/nvim-tree/lib.lua +++ b/lua/nvim-tree/lib.lua @@ -13,6 +13,7 @@ local M = { target_winid = nil, } +---@return Node|nil function M.get_node_at_cursor() if not core.get_explorer() then return @@ -34,8 +35,8 @@ function M.get_node_at_cursor() end ---Create a sanitized partial copy of a node, populating children recursively. ----@param node table ----@return table|nil cloned node +---@param node Node|nil +---@return Node|nil cloned node local function clone_node(node) if not node then node = core.get_explorer() @@ -68,19 +69,25 @@ local function clone_node(node) end ---Api.tree.get_nodes +---@return Node[]|nil function M.get_nodes() return clone_node(core.get_explorer()) end -- If node is grouped, return the last node in the group. Otherwise, return the given node. +---@param node Node +---@return Node function M.get_last_group_node(node) - local next_node = node - while next_node.group_next do - next_node = next_node.group_next + while node and node.group_next do + node = node.group_next end - return next_node + + ---@diagnostic disable-next-line: return-type-mismatch -- it can't be nil + return node end +---@param node Node +---@return Node[] function M.get_all_nodes_in_group(node) local next_node = utils.get_parent_of_group(node) local nodes = {} @@ -91,6 +98,7 @@ function M.get_all_nodes_in_group(node) return nodes end +---@param node Node function M.expand_or_collapse(node) if node.has_children then node.has_children = false @@ -119,6 +127,7 @@ function M.set_target_win() M.target_winid = id end +---@param cwd string local function handle_buf_cwd(cwd) if M.respect_buf_cwd and cwd ~= core.get_cwd() then require("nvim-tree.actions.root.change-dir").fn(cwd) @@ -144,6 +153,11 @@ local function should_hijack_current_buf() return should_hijack_dir or should_hijack_unnamed end +---@param prompt_input string +---@param prompt_select string +---@param items_short string[] +---@param items_long string[] +---@param callback fun(item_short: string) function M.prompt(prompt_input, prompt_select, items_short, items_long, callback) local function format_item(short) for i, s in ipairs(items_short) do diff --git a/lua/nvim-tree/live-filter.lua b/lua/nvim-tree/live-filter.lua index 16eb159693c..f19ed5c01b5 100644 --- a/lua/nvim-tree/live-filter.lua +++ b/lua/nvim-tree/live-filter.lua @@ -10,8 +10,14 @@ local function redraw() require("nvim-tree.renderer").draw() end +---@param node_ Node|nil local function reset_filter(node_) node_ = node_ or require("nvim-tree.core").get_explorer() + + if node_ == nil then + return + end + Iterator.builder(node_.nodes) :hidden() :applier(function(node) @@ -47,12 +53,15 @@ local function remove_overlay() end end +---@param node Node +---@return boolean local function matches(node) local path = node.absolute_path local name = vim.fn.fnamemodify(path, ":t") return vim.regex(M.filter):match_str(name) ~= nil end +---@param node_ Node|nil function M.apply_filter(node_) if not M.filter or M.filter == "" then reset_filter(node_) @@ -105,6 +114,7 @@ local function configure_buffer_overlay() vim.api.nvim_buf_set_keymap(overlay_bufnr, "i", "", "stopinsert", {}) end +---@return integer local function calculate_overlay_win_width() local wininfo = vim.fn.getwininfo(view.get_winnr())[1] diff --git a/lua/nvim-tree/log.lua b/lua/nvim-tree/log.lua index 72dce2e9f0e..b32ef8969fa 100644 --- a/lua/nvim-tree/log.lua +++ b/lua/nvim-tree/log.lua @@ -4,9 +4,9 @@ local M = { } --- Write to log file ---- @param typ string as per log.types config ---- @param fmt string for string.format ---- @vararg any arguments for string.format +---@param typ string as per log.types config +---@param fmt string for string.format +---@param ... any arguments for string.format function M.raw(typ, fmt, ...) if not M.enabled(typ) then return @@ -27,9 +27,9 @@ end --- Write profile start to log file --- START is prefixed ---- @param fmt string for string.format ---- @vararg any arguments for string.format ---- @return Profile to pass to profile_end +---@param fmt string for string.format +---@param ... any arguments for string.format +---@return Profile to pass to profile_end function M.profile_start(fmt, ...) local profile = {} if M.enabled "profile" then @@ -42,7 +42,7 @@ end --- Write profile end to log file --- END is prefixed and duration in seconds is suffixed ---- @param profile Profile returned from profile_start +---@param profile Profile returned from profile_start function M.profile_end(profile) if M.enabled "profile" and type(profile) == "table" then local millis = profile.start and math.modf((vim.loop.hrtime() - profile.start) / 1000000) or -1 @@ -52,9 +52,9 @@ end --- Write to log file --- time and typ are prefixed and a trailing newline is added ---- @param typ string as per log.types config ---- @param fmt string for string.format ---- @vararg any arguments for string.format +---@param typ string as per log.types config +---@param fmt string for string.format +---@param ... any arguments for string.format function M.line(typ, fmt, ...) if M.enabled(typ) then M.raw(typ, string.format("[%s] [%s] %s\n", os.date "%Y-%m-%d %H:%M:%S", typ, (fmt or "???")), ...) @@ -63,17 +63,17 @@ end local inspect_opts = {} ---- @param opts table +---@param opts table function M.set_inspect_opts(opts) inspect_opts = opts end --- Write to log file the inspection of a node --- defaults to the node under cursor if none is provided ---- @param typ string as per log.types config ---- @param node table|nil node to be inspected ---- @param fmt string for string.format ---- @vararg any arguments for string.format +---@param typ string as per log.types config +---@param node table|nil node to be inspected +---@param fmt string for string.format +---@vararg any arguments for string.format function M.node(typ, node, fmt, ...) if M.enabled(typ) then node = node or require("nvim-tree.lib").get_node_at_cursor() @@ -82,8 +82,8 @@ function M.node(typ, node, fmt, ...) end --- Logging is enabled for typ or all ---- @param typ string as per log.types config ---- @return boolean +---@param typ string as per log.types config +---@return boolean function M.enabled(typ) return M.path ~= nil and (M.config.types[typ] or M.config.types.all) end diff --git a/lua/nvim-tree/marks/bulk-delete.lua b/lua/nvim-tree/marks/bulk-delete.lua index 7a9cb5a0597..3e27565d139 100644 --- a/lua/nvim-tree/marks/bulk-delete.lua +++ b/lua/nvim-tree/marks/bulk-delete.lua @@ -9,7 +9,7 @@ local M = { } --- Delete nodes; each removal will be optionally notified ---- @param nodes table +---@param nodes Node[] local function do_delete(nodes) for _, node in pairs(nodes) do remove_file.remove(node) diff --git a/lua/nvim-tree/marks/bulk-trash.lua b/lua/nvim-tree/marks/bulk-trash.lua index 532fb021fee..93c47d3eb96 100644 --- a/lua/nvim-tree/marks/bulk-trash.lua +++ b/lua/nvim-tree/marks/bulk-trash.lua @@ -9,7 +9,7 @@ local M = { } --- Delete nodes; each removal will be optionally notified ---- @param nodes table +---@param nodes Node[] local function do_trash(nodes) for _, node in pairs(nodes) do remove_file.remove(node) diff --git a/lua/nvim-tree/marks/init.lua b/lua/nvim-tree/marks/init.lua index 7b5773a6ca7..10804d5c21c 100644 --- a/lua/nvim-tree/marks/init.lua +++ b/lua/nvim-tree/marks/init.lua @@ -4,18 +4,24 @@ local NvimTreeMarks = {} local M = {} +---@class MinimalNode +---@field absolute_path string + +---@param node Node|MinimalNode local function add_mark(node) NvimTreeMarks[node.absolute_path] = node renderer.draw() end +---@param node Node|MinimalNode local function remove_mark(node) NvimTreeMarks[node.absolute_path] = nil renderer.draw() end +---@param node Node|MinimalNode function M.toggle_mark(node) if node.absolute_path == nil then return @@ -36,10 +42,13 @@ function M.clear_marks() renderer.draw() end +---@param node Node|MinimalNode +---@return table|nil function M.get_mark(node) return NvimTreeMarks[node.absolute_path] end +---@return table function M.get_marks() local list = {} for _, node in pairs(NvimTreeMarks) do diff --git a/lua/nvim-tree/marks/navigation.lua b/lua/nvim-tree/marks/navigation.lua index 8a20b211574..8ee3edbc966 100644 --- a/lua/nvim-tree/marks/navigation.lua +++ b/lua/nvim-tree/marks/navigation.lua @@ -5,6 +5,9 @@ local open_file = require "nvim-tree.actions.node.open-file" local utils = require "nvim-tree.utils" local lib = require "nvim-tree.lib" +---@param node table +---@param where string +---@return Node|nil local function get_nearest(node, where) local first, prev, next, last = nil, nil, nil, nil local found = false @@ -47,12 +50,16 @@ local function get_nearest(node, where) end end +---@param where string +---@param node table|nil +---@return Node|nil local function get(where, node) if node then return get_nearest(node, where) end end +---@param node table|nil local function open_or_focus(node) if node and not node.nodes and not utils.get_win_buf_from_path(node.absolute_path) then open_file.fn("edit", node.absolute_path) @@ -61,6 +68,8 @@ local function open_or_focus(node) end end +---@param where string +---@return function local function navigate_to(where) return function() local node = lib.get_node_at_cursor() diff --git a/lua/nvim-tree/modified.lua b/lua/nvim-tree/modified.lua index 51025e1b22f..8f77ef668fb 100644 --- a/lua/nvim-tree/modified.lua +++ b/lua/nvim-tree/modified.lua @@ -23,7 +23,7 @@ function M.reload() end end ----@param node table +---@param node Node ---@return boolean function M.is_modified(node) return M.config.enable diff --git a/lua/nvim-tree/node.lua b/lua/nvim-tree/node.lua new file mode 100644 index 00000000000..55ee1942dc4 --- /dev/null +++ b/lua/nvim-tree/node.lua @@ -0,0 +1,37 @@ +---@meta + +-- TODO add "${3rd}/luv/library" to "workspace.library" +---@class uv.uv_req_t: table +---@class uv.uv_fs_t: uv.uv_req_t + +---@class ParentNode +---@field name string + +---@class BaseNode +---@field absolute_path string +---@field executable boolean +---@field fs_stat uv.uv_fs_t +---@field git_status GitStatus|nil +---@field hidden boolean +---@field name string +---@field parent DirNode +---@field type string +---@field watcher function|nil + +---@class DirNode: BaseNode +---@field has_children boolean +---@field group_next Node|nil +---@field nodes Node[] +---@field open boolean + +---@class FileNode: BaseNode +---@field extension string + +---@class SymlinkDirNode: DirNode +---@field link_to string + +---@class SymlinkFileNode: FileNode +---@field link_to string + +---@alias SymlinkNode SymlinkDirNode|SymlinkFileNode +---@alias Node ParentNode|DirNode|FileNode|SymlinkNode|Explorer diff --git a/lua/nvim-tree/notify.lua b/lua/nvim-tree/notify.lua index 1a81b3c103b..03f7d6dedef 100644 --- a/lua/nvim-tree/notify.lua +++ b/lua/nvim-tree/notify.lua @@ -6,6 +6,7 @@ local config = { } local title_support +---@return boolean function M.supports_title() if title_support == nil then title_support = (package.loaded.notify and (vim.notify == require "notify" or vim.notify == require("notify").notify)) @@ -48,6 +49,8 @@ do end end +---@param path string +---@return string function M.render_path(path) if config.absolute_path then return path diff --git a/lua/nvim-tree/utils.lua b/lua/nvim-tree/utils.lua index 637117fca62..effdab46e2e 100644 --- a/lua/nvim-tree/utils.lua +++ b/lua/nvim-tree/utils.lua @@ -11,10 +11,15 @@ M.is_wsl = vim.fn.has "wsl" == 1 -- false for WSL M.is_windows = vim.fn.has "win32" == 1 or vim.fn.has "win32unix" == 1 +---@param haystack string +---@param needle string +---@return boolean function M.str_find(haystack, needle) return vim.fn.stridx(haystack, needle) ~= -1 end +---@param path string +---@return string|uv.uv_fs_t function M.read_file(path) local fd = vim.loop.fs_open(path, "r", 438) if not fd then @@ -30,15 +35,19 @@ function M.read_file(path) end local path_separator = package.config:sub(1, 1) +---@param paths string[] +---@return string function M.path_join(paths) return table.concat(vim.tbl_map(M.path_remove_trailing, paths), path_separator) end +---@param path string +---@return fun(): string function M.path_split(path) return path:gmatch("[^" .. path_separator .. "]+" .. path_separator .. "?") end ----Get the basename of the given path. +--- Get the basename of the given path. ---@param path string ---@return string function M.path_basename(path) @@ -50,11 +59,15 @@ function M.path_basename(path) return path:sub(i + 1, #path) end ----Get a path relative to another path. +--- Get a path relative to another path. ---@param path string ----@param relative_to string +---@param relative_to string|nil ---@return string function M.path_relative(path, relative_to) + if relative_to == nil then + return path + end + local _, r = path:find(M.path_add_trailing(relative_to), 1, true) local p = path if r then @@ -66,6 +79,8 @@ function M.path_relative(path, relative_to) return p end +---@param path string +---@return string function M.path_add_trailing(path) if path:sub(-1) == path_separator then return path @@ -74,6 +89,8 @@ function M.path_add_trailing(path) return path .. path_separator end +---@param path string +---@return string function M.path_remove_trailing(path) local p, _ = path:gsub(path_separator .. "$", "") return p @@ -81,10 +98,12 @@ end M.path_separator = path_separator --- get the node and index of the node from the tree that matches the predicate. --- The explored nodes are those displayed on the view. --- @param nodes list of node --- @param fn function(node): boolean +--- Get the node and index of the node from the tree that matches the predicate. +--- The explored nodes are those displayed on the view. +---@param nodes Node[] +---@param fn fun(node: Node): boolean +---@return table|nil +---@return number function M.find_node(nodes, fn) local node, i = Iterator.builder(nodes) :matcher(fn) @@ -99,6 +118,9 @@ end -- get the node in the tree state depending on the absolute path of the node -- (grouped or hidden too) +---@param path string +---@return Node|nil +---@return number|nil function M.get_node_from_path(path) local explorer = require("nvim-tree.core").get_explorer() @@ -127,7 +149,9 @@ function M.get_node_from_path(path) :iterate() end --- get the highest parent of grouped nodes +--- Get the highest parent of grouped nodes +---@param node_ Node +---@return table function M.get_parent_of_group(node_) local node = node_ while node.parent and node.parent.group_next do @@ -136,9 +160,9 @@ function M.get_parent_of_group(node_) return node end --- return visible nodes indexed by line --- @param nodes_all list of node --- @param line_start first index +--- Return visible nodes indexed by line +---@param nodes_all Node[] +---@param line_start number ---@return table function M.get_nodes_by_line(nodes_all, line_start) local nodes_by_line = {} @@ -192,15 +216,15 @@ function M.rename_loaded_buffers(old_path, new_path) end end ---- @param path string path to file or directory ---- @return boolean +---@param path string path to file or directory +---@return boolean function M.file_exists(path) local _, error = vim.loop.fs_stat(path) return error == nil end ---- @param path string ---- @return string +---@param path string +---@return string function M.canonical_path(path) if M.is_windows and path:match "^%a:" then return path:sub(1, 1):upper() .. path:sub(2) @@ -208,9 +232,9 @@ function M.canonical_path(path) return path end --- Escapes special characters in string if windows else returns unmodified string. --- @param path string --- @return path +--- Escapes special characters in string if windows else returns unmodified string. +---@param path string +---@return string|nil function M.escape_special_chars(path) if path == nil then return path @@ -218,10 +242,10 @@ function M.escape_special_chars(path) return M.is_windows and path:gsub("%(", "\\("):gsub("%)", "\\)") or path end --- Create empty sub-tables if not present --- @param tbl to create empty inside of --- @param path dot separated string of sub-tables --- @return table deepest sub-table +--- Create empty sub-tables if not present +---@param tbl table to create empty inside of +---@param path string dot separated string of sub-tables +---@return table deepest sub-table function M.table_create_missing(tbl, path) local t = tbl for s in string.gmatch(path, "([^%.]+)%.*") do @@ -236,13 +260,13 @@ end --- Move a value from src to dst if value is nil on dst. --- Remove value from src ---- @param src table to copy from ---- @param src_path string dot separated string of sub-tables ---- @param src_pos string value pos ---- @param dst table to copy to ---- @param dst_path string dot separated string of sub-tables, created when missing ---- @param dst_pos string value pos ---- @param remove boolean +---@param src table to copy from +---@param src_path string dot separated string of sub-tables +---@param src_pos string value pos +---@param dst table to copy to +---@param dst_path string dot separated string of sub-tables, created when missing +---@param dst_pos string value pos +---@param remove boolean function M.move_missing_val(src, src_path, src_pos, dst, dst_path, dst_pos, remove) local ok, err = pcall(vim.validate, { src = { src, "table" }, @@ -395,7 +419,7 @@ end ---Focus node passed as parameter if visible, otherwise focus first visible parent. ---If none of the parents is visible focus root. ---If node is nil do nothing. ----@param node table|nil node to focus +---@param node Node|nil node to focus function M.focus_node_or_parent(node) local explorer = require("nvim-tree.core").get_explorer() @@ -417,6 +441,9 @@ function M.focus_node_or_parent(node) end end +---@param path string +---@return integer|nil +---@return integer|nil function M.get_win_buf_from_path(path) for _, w in pairs(vim.api.nvim_tabpage_list_wins(0)) do local b = vim.api.nvim_win_get_buf(w) @@ -433,7 +460,9 @@ function M.clear_prompt() end end --- return a new table with values from array +--- Return a new table with values from array +---@param array table +---@return table function M.array_shallow_clone(array) local to = {} for _, v in ipairs(array) do @@ -443,9 +472,9 @@ function M.array_shallow_clone(array) end --- Remove and return item from array if present. ---- @param array table ---- @param item any ---- @return any|nil removed +---@param array table +---@param item any +---@return any|nil removed function M.array_remove(array, item) if not array then return nil @@ -458,20 +487,24 @@ function M.array_remove(array, item) end end +---@param array table +---@return table function M.array_remove_nils(array) return vim.tbl_filter(function(v) return v ~= nil end, array) end +---@param f fun(node: Node|nil) +---@return function function M.inject_node(f) return function() f(require("nvim-tree.lib").get_node_at_cursor()) end end ----Is the buffer named NvimTree_[0-9]+ a tree? filetype is "NvimTree" or not readable file. ----This is cheap, as the readable test should only ever be needed when resuming a vim session. +--- Is the buffer named NvimTree_[0-9]+ a tree? filetype is "NvimTree" or not readable file. +--- This is cheap, as the readable test should only ever be needed when resuming a vim session. ---@param bufnr number|nil may be 0 or nil for current ---@return boolean function M.is_nvim_tree_buf(bufnr) diff --git a/lua/nvim-tree/view.lua b/lua/nvim-tree/view.lua index c6dc4ef1e9f..81fe36e96c7 100644 --- a/lua/nvim-tree/view.lua +++ b/lua/nvim-tree/view.lua @@ -72,6 +72,8 @@ local BUFFER_OPTIONS = { buflisted = false, } +---@param bufnr integer +---@return boolean local function matches_bufnr(bufnr) for _, b in pairs(BUFNR_PER_TAB) do if b == bufnr then @@ -89,6 +91,7 @@ local function wipe_rogue_buffer() end end +---@param bufnr integer|boolean|nil local function create_buffer(bufnr) wipe_rogue_buffer() @@ -105,6 +108,8 @@ local function create_buffer(bufnr) events._dispatch_tree_attached_post(M.get_bufnr()) end +---@param size number|fun():number +---@return integer local function get_size(size) if type(size) == "number" then return size @@ -116,6 +121,7 @@ local function get_size(size) return math.floor(vim.o.columns * percent_as_decimal) end +---@param size number|function|nil local function get_width(size) size = size or M.View.width return get_size(size) @@ -127,6 +133,7 @@ local move_tbl = { } -- setup_tabpage sets up the initial state of a tab +---@param tabpage integer local function 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 }) @@ -142,6 +149,7 @@ local function set_window_options_and_buffer() vim.opt.eventignore = eventignore end +---@return table local function open_win_config() if type(M.View.float.open_win_config) == "function" then return M.View.float.open_win_config() @@ -161,10 +169,13 @@ local function open_window() set_window_options_and_buffer() end +---@param buf integer +---@return boolean local function is_buf_displayed(buf) return vim.api.nvim_buf_is_valid(buf) and vim.fn.buflisted(buf) == 1 end +---@return number|nil local function get_alt_or_next_buf() local alt_buf = vim.fn.bufnr "#" if is_buf_displayed(alt_buf) then @@ -190,11 +201,13 @@ local function switch_buf_if_last_buf() end -- save_tab_state saves any state that should be preserved across redraws. +---@param tabnr integer local function 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)) end +---@param tabpage integer local function close(tabpage) if not M.is_visible { tabpage = tabpage } then return @@ -236,6 +249,7 @@ function M.close() end end +---@param options table|nil function M.open(options) if M.is_visible() then return @@ -297,6 +311,7 @@ function M.grow_from_content() end end +---@param size string|number|nil function M.resize(size) if M.View.float.enable and not M.View.adaptive_size then -- if the floating windows's adaptive size is not desired, then the @@ -386,6 +401,7 @@ function M.abandon_all_windows() end end +---@param opts table|nil function M.is_visible(opts) if opts and opts.tabpage then if M.View.tabpages[opts.tabpage] == nil then @@ -407,12 +423,15 @@ function M.is_visible(opts) return M.get_winnr() ~= nil and vim.api.nvim_win_is_valid(M.get_winnr()) 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 +---@param winnr number|nil +---@param open_if_closed boolean|nil function M.focus(winnr, open_if_closed) local wnr = winnr or M.get_winnr() @@ -428,8 +447,8 @@ function M.focus(winnr, open_if_closed) 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 +---@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 @@ -465,6 +484,8 @@ function M.get_bufnr() return BUFNR_PER_TAB[vim.api.nvim_get_current_tabpage()] end +---@param bufnr number +---@return boolean function M.is_buf_valid(bufnr) return bufnr and vim.api.nvim_buf_is_valid(bufnr) and vim.api.nvim_buf_is_loaded(bufnr) end @@ -512,6 +533,8 @@ function M._prevent_buffer_override() end) end +---@param cwd string|nil +---@return boolean function M.is_root_folder_visible(cwd) return cwd ~= "/" and not M.View.hide_root_folder end diff --git a/lua/nvim-tree/watcher.lua b/lua/nvim-tree/watcher.lua index 1693aa0fb4e..92b3fbe4ae0 100644 --- a/lua/nvim-tree/watcher.lua +++ b/lua/nvim-tree/watcher.lua @@ -6,11 +6,13 @@ local M = { config = {}, } +---@class Event local Event = { _events = {}, } Event.__index = Event +---@class Watcher local Watcher = { _watchers = {}, } @@ -23,6 +25,8 @@ local FS_EVENT_FLAGS = { recursive = false, } +---@param path string +---@return Event|nil function Event:new(path) log.line("watcher", "Event:new '%s'", path) @@ -40,6 +44,7 @@ function Event:new(path) end end +---@return boolean function Event:start() log.line("watcher", "Event:start '%s'", self._path) @@ -84,10 +89,12 @@ function Event:start() return true end +---@param listener function function Event:add(listener) table.insert(self._listeners, listener) end +---@param listener function function Event:remove(listener) utils.array_remove(self._listeners, listener) if #self._listeners == 0 then @@ -95,6 +102,7 @@ function Event:remove(listener) end end +---@param message string|nil function Event:destroy(message) log.line("watcher", "Event:destroy '%s'", self._path) @@ -115,6 +123,11 @@ function Event:destroy(message) self.destroyed = true end +---@param path string +---@param files string[]|nil +---@param callback function +---@param data table +---@return Watcher|nil function Watcher:new(path, files, callback, data) log.line("watcher", "Watcher:new '%s' %s", path, vim.inspect(files)) @@ -160,7 +173,7 @@ end M.Watcher = Watcher --- Permanently disable watchers and purge all state following a catastrophic error. ---- @param msg string +---@param msg string function M.disable_watchers(msg) notify.warn(string.format("Disabling watchers: %s", msg)) M.config.filesystem_watchers.enable = false @@ -181,8 +194,8 @@ end --- Windows NT will present directories that cannot be enumerated. --- Detect these by attempting to start an event monitor. ---- @param path string ---- @return boolean +---@param path string +---@return boolean function M.is_fs_event_capable(path) if not utils.is_windows then return true