feat(view): add filters.git_clean, filters.no_buffer (#1784)
* feat(view): add filters.git_clean * feat(view): add filters.git_clean * feat(view): add filters.no_buffer * feat(view): filters.no_buffer misses unloaded, handles buffer in/out * feat(view): filters.no_buffer matches directories specifically * feat(view): filters.no_buffer clarify targets * feat: add placeholder filters.diagnostics_ok, refactor filters * feat(view): remove placeholder filters.diagnostics_ok
This commit is contained in:
committed by
GitHub
parent
e49fa4e529
commit
c5dc80c36b
@@ -12,9 +12,10 @@ local function get_type_from(type_, cwd)
|
||||
return type_ or (vim.loop.fs_stat(cwd) or {}).type
|
||||
end
|
||||
|
||||
local function populate_children(handle, cwd, node, status)
|
||||
local function populate_children(handle, cwd, node, git_status)
|
||||
local node_ignored = node.git_status == "!!"
|
||||
local nodes_by_path = utils.bool_record(node.nodes, "absolute_path")
|
||||
local filter_status = filters.prepare(git_status)
|
||||
while true do
|
||||
local name, t = vim.loop.fs_scandir_next(handle)
|
||||
if not name then
|
||||
@@ -23,11 +24,7 @@ local function populate_children(handle, cwd, node, status)
|
||||
|
||||
local abs = utils.path_join { cwd, name }
|
||||
t = get_type_from(t, abs)
|
||||
if
|
||||
not filters.should_ignore(abs)
|
||||
and not filters.should_ignore_git(abs, status.files)
|
||||
and not nodes_by_path[abs]
|
||||
then
|
||||
if not filters.should_filter(abs, filter_status) and not nodes_by_path[abs] then
|
||||
local child = nil
|
||||
if t == "directory" and vim.loop.fs_access(abs, "R") then
|
||||
child = builders.folder(node, abs, name)
|
||||
@@ -42,7 +39,7 @@ local function populate_children(handle, cwd, node, status)
|
||||
if child then
|
||||
table.insert(node.nodes, child)
|
||||
nodes_by_path[child.absolute_path] = true
|
||||
common.update_git_status(child, node_ignored, status)
|
||||
common.update_git_status(child, node_ignored, git_status)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,26 +14,63 @@ local function is_excluded(path)
|
||||
return false
|
||||
end
|
||||
|
||||
---Check if the given path should be ignored.
|
||||
---Check if the given path is git clean/ignored
|
||||
---@param path string Absolute path
|
||||
---@param git_status table from prepare
|
||||
---@return boolean
|
||||
function M.should_ignore(path)
|
||||
local basename = utils.path_basename(path)
|
||||
|
||||
if is_excluded(path) then
|
||||
local function git(path, git_status)
|
||||
if type(git_status) ~= "table" or type(git_status.files) ~= "table" or type(git_status.dirs) ~= "table" then
|
||||
return false
|
||||
end
|
||||
|
||||
if M.config.filter_dotfiles then
|
||||
if basename:sub(1, 1) == "." then
|
||||
return true
|
||||
-- default status to clean
|
||||
local status = git_status.files[path] or git_status.dirs[path] or " "
|
||||
|
||||
-- filter ignored; overrides clean as they are effectively dirty
|
||||
if M.config.filter_git_ignored and status == "!!" then
|
||||
return true
|
||||
end
|
||||
|
||||
-- filter clean
|
||||
if M.config.filter_git_clean and status == " " then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
---Check if the given path has no listed buffer
|
||||
---@param path string Absolute path
|
||||
---@param bufinfo table vim.fn.getbufinfo { buflisted = 1 }
|
||||
---@param unloaded_bufnr number optional bufnr recently unloaded via BufUnload event
|
||||
---@return boolean
|
||||
local function buf(path, bufinfo, unloaded_bufnr)
|
||||
if not M.config.filter_no_buffer or type(bufinfo) ~= "table" then
|
||||
return false
|
||||
end
|
||||
|
||||
-- filter files with no open buffer and directories containing no open buffers
|
||||
for _, b in ipairs(bufinfo) do
|
||||
if b.name == path or b.name:find(path .. "/", 1, true) and b.bufnr ~= unloaded_bufnr then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function dotfile(path)
|
||||
return M.config.filter_dotfiles and utils.path_basename(path):sub(1, 1) == "."
|
||||
end
|
||||
|
||||
local function custom(path)
|
||||
if not M.config.filter_custom then
|
||||
return false
|
||||
end
|
||||
|
||||
local basename = utils.path_basename(path)
|
||||
|
||||
-- filter custom regexes
|
||||
local relpath = utils.path_relative(path, vim.loop.cwd())
|
||||
for pat, _ in pairs(M.ignore_list) do
|
||||
if vim.fn.match(relpath, pat) ~= -1 or vim.fn.match(basename, pat) ~= -1 then
|
||||
@@ -51,10 +88,41 @@ function M.should_ignore(path)
|
||||
return false
|
||||
end
|
||||
|
||||
function M.should_ignore_git(path, status)
|
||||
return M.config.filter_git_ignored
|
||||
and (M.config.filter_git_ignored and status and status[path] == "!!")
|
||||
and not is_excluded(path)
|
||||
---Prepare arguments for should_filter. This is done prior to should_filter for efficiency reasons.
|
||||
---@param git_status table results of git.load_project_status(...)
|
||||
---@param unloaded_bufnr number optional bufnr recently unloaded via BufUnload event
|
||||
---@return table
|
||||
--- git_status: reference
|
||||
--- unloaded_bufnr: copy
|
||||
--- bufinfo: empty unless no_buffer set: vim.fn.getbufinfo { buflisted = 1 }
|
||||
function M.prepare(git_status, unloaded_bufnr)
|
||||
local status = {
|
||||
git_status = git_status or {},
|
||||
unloaded_bufnr = unloaded_bufnr,
|
||||
bufinfo = {},
|
||||
}
|
||||
|
||||
if M.config.filter_no_buffer then
|
||||
status.bufinfo = vim.fn.getbufinfo { buflisted = 1 }
|
||||
end
|
||||
|
||||
return status
|
||||
end
|
||||
|
||||
---Check if the given path should be filtered.
|
||||
---@param path string Absolute path
|
||||
---@param status table from prepare
|
||||
---@return boolean
|
||||
function M.should_filter(path, status)
|
||||
-- exclusions override all filters
|
||||
if is_excluded(path) then
|
||||
return false
|
||||
end
|
||||
|
||||
return git(path, status.git_status)
|
||||
or buf(path, status.bufinfo, status.unloaded_bufnr)
|
||||
or dotfile(path)
|
||||
or custom(path)
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
@@ -62,6 +130,8 @@ function M.setup(opts)
|
||||
filter_custom = true,
|
||||
filter_dotfiles = opts.filters.dotfiles,
|
||||
filter_git_ignored = opts.git.ignore,
|
||||
filter_git_clean = opts.filters.git_clean,
|
||||
filter_no_buffer = opts.filters.no_buffer,
|
||||
}
|
||||
|
||||
M.ignore_list = {}
|
||||
|
||||
@@ -34,7 +34,7 @@ local function update_parent_statuses(node, project, root)
|
||||
end
|
||||
end
|
||||
|
||||
function M.reload(node, status)
|
||||
function M.reload(node, git_status, unloaded_bufnr)
|
||||
local cwd = node.link_to or node.absolute_path
|
||||
local handle = vim.loop.fs_scandir(cwd)
|
||||
if type(handle) == "string" then
|
||||
@@ -44,6 +44,8 @@ function M.reload(node, status)
|
||||
|
||||
local ps = log.profile_start("reload %s", node.absolute_path)
|
||||
|
||||
local filter_status = filters.prepare(git_status, unloaded_bufnr)
|
||||
|
||||
if node.group_next then
|
||||
node.nodes = { node.group_next }
|
||||
node.group_next = nil
|
||||
@@ -71,7 +73,7 @@ function M.reload(node, status)
|
||||
|
||||
local abs = utils.path_join { cwd, name }
|
||||
t = t or (fs_stat_cached(abs) or {}).type
|
||||
if not filters.should_ignore(abs) and not filters.should_ignore_git(abs, status.files) then
|
||||
if not filters.should_filter(abs, filter_status) then
|
||||
child_names[abs] = true
|
||||
|
||||
-- Recreate node if type changes.
|
||||
@@ -112,7 +114,7 @@ function M.reload(node, status)
|
||||
end
|
||||
|
||||
node.nodes = vim.tbl_map(
|
||||
update_status(nodes_by_path, node_ignored, status),
|
||||
update_status(nodes_by_path, node_ignored, git_status),
|
||||
vim.tbl_filter(function(n)
|
||||
if child_names[n.absolute_path] then
|
||||
return child_names[n.absolute_path]
|
||||
@@ -127,7 +129,7 @@ function M.reload(node, status)
|
||||
local child_folder_only = common.has_one_child_folder(node) and node.nodes[1]
|
||||
if M.config.group_empty and not is_root and child_folder_only then
|
||||
node.group_next = child_folder_only
|
||||
local ns = M.reload(child_folder_only, status)
|
||||
local ns = M.reload(child_folder_only, git_status)
|
||||
node.nodes = ns or {}
|
||||
log.profile_end(ps, "reload %s", node.absolute_path)
|
||||
return ns
|
||||
|
||||
Reference in New Issue
Block a user