chore: add type annotations and resolve LSP warnings (#2555)

* chore: add type annotations to (almost) all functions

* stylua

* Add classes for symlink nodes

* Replace deprecated `@vararg`

* Move node classes to `node` module

* Fix `Symlink*` classes

* add vim and libuv runtime for luals, qualify libuv types

* add scripts/luals-check, not quite ready for CI

* additional nil checks for git/init.lua and git/runner.lua

* additional nil checks for nvim-tree.lua

* wrap vim.cmd-as-a-function calls inside functions

* vim.tbl_filter predicate returns booleans

* Revert "add scripts/luals-check, not quite ready for CI"

This reverts commit c70229cad9.

* Add `MinimalNode` class in `marks` module

* Fix various LSP warnings

* stylua

* Fix `Explorer` class, update related annotations and add necessary checks

* Add missing annotations to `live-filter`

* Add temporary aliases for `uv.*` types

* Resolve remaining LSP warnings

* Revert changes not related to internal types

* Minor adjustments

* Update doc comments style

* Minor adjustments (pt. 2)

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
This commit is contained in:
Azad
2023-12-09 01:34:35 +01:00
committed by GitHub
parent 7d1760f892
commit 13f967f8e7
51 changed files with 622 additions and 161 deletions

View File

@@ -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, _

View File

@@ -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)

View File

@@ -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,
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 = ""

View File

@@ -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 .. "<Home>")

View File

@@ -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."

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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