Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: bookmark filter shows marked directory children #2719

Merged
merged 10 commits into from
Mar 30, 2024
3 changes: 2 additions & 1 deletion lua/nvim-tree/actions/finders/search-node.lua
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,13 @@ local function search(search_dir, input_path)
while name do
path = dir .. "/" .. name

---@type uv.fs_stat.result|nil
stat, _ = vim.loop.fs_stat(path)
if not stat then
break
end

if not filters.should_filter(path, filter_status) then
if not filters.should_filter(path, stat, filter_status) then
if string.find(path, "/" .. input_path .. "$") then
return path
end
Expand Down
8 changes: 8 additions & 0 deletions lua/nvim-tree/actions/node/file-popup.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ local M = {}
---@return table
local function get_formatted_lines(node)
local stats = node.fs_stat
if stats == nil then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many thanks!

return {
"",
" Can't retrieve file information",
"",
}
end

local fpath = " fullpath: " .. node.absolute_path
local created_at = " created: " .. os.date("%x %X", stats.birthtime.sec)
local modified_at = " modified: " .. os.date("%x %X", stats.mtime.sec)
Expand Down
20 changes: 7 additions & 13 deletions lua/nvim-tree/explorer/explore.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,6 @@ 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
Expand All @@ -33,18 +26,19 @@ local function populate_children(handle, cwd, node, git_status)
end

local abs = utils.path_join { cwd, name }

local profile = log.profile_start("explore populate_children %s", abs)

t = get_type_from(t, abs)
if not filters.should_filter(abs, filter_status) and not nodes_by_path[abs] and Watcher.is_fs_event_capable(abs) then
---@type uv.fs_stat.result|nil
local stat = vim.loop.fs_stat(abs)

if not filters.should_filter(abs, stat, filter_status) and not nodes_by_path[abs] and Watcher.is_fs_event_capable(abs) then
local child = nil
if t == "directory" and vim.loop.fs_access(abs, "R") then
child = builders.folder(node, abs, name)
child = builders.folder(node, abs, name, stat)
elseif t == "file" then
child = builders.file(node, abs, name)
child = builders.file(node, abs, name, stat)
elseif t == "link" then
local link = builders.link(node, abs, name)
local link = builders.link(node, abs, name, stat)
if link.link_to ~= nil then
child = link
end
Expand Down
42 changes: 32 additions & 10 deletions lua/nvim-tree/explorer/filters.lua
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,36 @@ local function dotfile(path)
end

---@param path string
---@param bookmarks table<string, boolean> absolute paths bookmarked
local function bookmark(path, bookmarks)
---@param path_type string|nil filetype of path
---@param bookmarks table<string, string|nil> path, filetype table of bookmarked files
local function bookmark(path, path_type, bookmarks)
if not M.config.filter_no_bookmark then
return false
end
-- if bookmark is empty, we should see a empty filetree
if next(bookmarks) == nil then
return true
end

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the interests of efficiency let's return early in the first line if bookmarks is empty or nil.

That will avoid the first utils.path_add_trailing

-- add trailing slash to make it match only mark's parent directory
-- not it's siblings
local parent = utils.path_add_trailing(path)
for mark, _ in pairs(bookmarks) do
if path == mark or vim.fn.stridx(mark, parent) == 0 then
local mark_parent = utils.path_add_trailing(path)
for mark, mark_type in pairs(bookmarks) do
if path == mark then
return false
end

if path_type == "directory" then
-- check if path is mark's parent
if vim.fn.stridx(mark, mark_parent) == 0 then
return false
end
end
if mark_type == "directory" then
-- check if mark is path's parent
local path_parent = utils.path_add_trailing(mark)
if vim.fn.stridx(path, path_parent) == 0 then
return false
end
end
end

return true
Expand Down Expand Up @@ -139,17 +156,18 @@ function M.prepare(git_status)
end

for _, node in pairs(marks.get_marks()) do
status.bookmarks[node.absolute_path] = true
status.bookmarks[node.absolute_path] = node.type
Copy link
Member

@alex-courtis alex-courtis Mar 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nicely efficient.

Future PR: create a proper class for the return. It will be done when we apply all the 0.10 annotations and the enum is present.

end

return status
end

---Check if the given path should be filtered.
---@param path string Absolute path
---@param fs_stat uv.fs_stat.result|nil fs_stat of file
---@param status table from prepare
---@return boolean
function M.should_filter(path, status)
function M.should_filter(path, fs_stat, status)
if not M.config.enable then
return false
end
Expand All @@ -159,7 +177,11 @@ function M.should_filter(path, status)
return false
end

return git(path, status.git_status) or buf(path, status.bufinfo) or dotfile(path) or custom(path) or bookmark(path, status.bookmarks)
return git(path, status.git_status)
or buf(path, status.bufinfo)
or dotfile(path)
or custom(path)
or bookmark(path, fs_stat and fs_stat.type, status.bookmarks)
end

function M.setup(opts)
Expand Down
15 changes: 9 additions & 6 deletions lua/nvim-tree/explorer/node-builders.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ local M = {}
---@param parent Node
---@param absolute_path string
---@param name string
---@param fs_stat uv.fs_stat.result|nil
---@return Node
function M.folder(parent, absolute_path, name)
function M.folder(parent, absolute_path, name, fs_stat)
local handle = vim.loop.fs_scandir(absolute_path)
local has_children = handle and vim.loop.fs_scandir_next(handle) ~= nil

local node = {
type = "directory",
absolute_path = absolute_path,
fs_stat = vim.loop.fs_stat(absolute_path),
fs_stat = fs_stat,
group_next = nil, -- If node is grouped, this points to the next child dir/link node
has_children = has_children,
name = name,
Expand Down Expand Up @@ -43,16 +44,17 @@ end
---@param parent Node
---@param absolute_path string
---@param name string
---@param fs_stat uv.fs_stat.result|nil
---@return Node
function M.file(parent, absolute_path, name)
function M.file(parent, absolute_path, name, fs_stat)
local ext = string.match(name, ".?[^.]+%.(.*)") or ""

return {
type = "file",
absolute_path = absolute_path,
executable = M.is_executable(absolute_path),
extension = ext,
fs_stat = vim.loop.fs_stat(absolute_path),
fs_stat = fs_stat,
name = name,
parent = parent,
}
Expand All @@ -66,8 +68,9 @@ end
---@param parent Node
---@param absolute_path string
---@param name string
---@param fs_stat uv.fs_stat.result|nil
---@return Node
function M.link(parent, absolute_path, name)
function M.link(parent, absolute_path, name, fs_stat)
--- 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)
local open, nodes, has_children
Expand All @@ -84,7 +87,7 @@ function M.link(parent, absolute_path, name)
local node = {
type = "link",
absolute_path = absolute_path,
fs_stat = vim.loop.fs_stat(absolute_path),
fs_stat = fs_stat,
group_next = nil, -- If node is grouped, this points to the next child dir/link node
has_children = has_children,
link_to = link_to,
Expand Down
47 changes: 20 additions & 27 deletions lua/nvim-tree/explorer/reload.lua
Original file line number Diff line number Diff line change
Expand Up @@ -85,30 +85,23 @@ function M.reload(node, git_status)
node.group_next = nil
end

local child_names = {}
local remain_childs = {}

local node_ignored = explorer_node.is_git_ignored(node)
---@type table<string, Node>
local nodes_by_path = utils.key_by(node.nodes, "absolute_path")
while true do
local name, t = vim.loop.fs_scandir_next(handle, cwd)
if not name then
break
end

local stat
local function fs_stat_cached(path)
if stat ~= nil then
return stat
end

stat = vim.loop.fs_stat(path)
return stat
end

local abs = utils.path_join { cwd, name }
t = t or (fs_stat_cached(abs) or {}).type
if not filters.should_filter(abs, filter_status) then
child_names[abs] = true
---@type uv.fs_stat.result|nil
local stat = vim.loop.fs_stat(abs)

if not filters.should_filter(abs, stat, filter_status) then
remain_childs[abs] = true

-- Recreate node if type changes.
if nodes_by_path[abs] then
Expand All @@ -122,26 +115,26 @@ function M.reload(node, git_status)
end

if not nodes_by_path[abs] then
local new_child = nil
if t == "directory" and vim.loop.fs_access(abs, "R") and Watcher.is_fs_event_capable(abs) then
local folder = builders.folder(node, abs, name)
nodes_by_path[abs] = folder
table.insert(node.nodes, folder)
new_child = builders.folder(node, abs, name, stat)
elseif t == "file" then
local file = builders.file(node, abs, name)
nodes_by_path[abs] = file
table.insert(node.nodes, file)
new_child = builders.file(node, abs, name, stat)
elseif t == "link" then
local link = builders.link(node, abs, name)
local link = builders.link(node, abs, name, stat)
if link.link_to ~= nil then
nodes_by_path[abs] = link
table.insert(node.nodes, link)
new_child = link
end
end
if new_child then
table.insert(node.nodes, new_child)
nodes_by_path[abs] = new_child
end
else
local n = nodes_by_path[abs]
if n then
n.executable = builders.is_executable(abs)
n.fs_stat = fs_stat_cached(abs)
n.executable = builders.is_executable(abs) or false
n.fs_stat = stat
end
end
end
Expand All @@ -150,8 +143,8 @@ function M.reload(node, git_status)
node.nodes = vim.tbl_map(
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]
if remain_childs[n.absolute_path] then
return remain_childs[n.absolute_path]
else
explorer_node.node_destroy(n)
return false
Expand Down
1 change: 1 addition & 0 deletions lua/nvim-tree/lib.lua
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ local function clone_node(node)
name = node.name,
open = node.open,
type = node.type,
fs_stat = node.fs_stat,
}

if type(node.nodes) == "table" then
Expand Down
2 changes: 1 addition & 1 deletion lua/nvim-tree/node.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
---@class BaseNode
---@field absolute_path string
---@field executable boolean
---@field fs_stat uv.uv_fs_t
---@field fs_stat uv.fs_stat.result|nil
---@field git_status GitStatus|nil
---@field hidden boolean
---@field name string
Expand Down
Loading