feat(explorer): show symlink target

This commit is contained in:
Folke Lemaitre 2025-02-04 19:31:47 +01:00
parent 7ad3b42d7b
commit dfa79e0443
No known key found for this signature in database
GPG key ID: 41F8B1FBACAE2040
5 changed files with 27 additions and 17 deletions

View file

@ -151,7 +151,7 @@ function M.next(cwd, path, up)
local next ---@type snacks.picker.explorer.Node?
local found = false
Tree:walk(root, function(node)
local want = node.type ~= "directory" and node.status and not node.ignored
local want = not node.dir and node.status and not node.ignored
if node.path == path then
found = true
end

View file

@ -5,6 +5,7 @@
---@field status? string
---@field ignored? boolean
---@field type "file"|"directory"|"link"|"fifo"|"socket"|"char"|"block"|"unknown"
---@field dir? boolean
---@field open? boolean wether the node should be expanded (only for directories)
---@field expanded? boolean wether the node is expanded (only for directories)
---@field parent? snacks.picker.explorer.Node
@ -34,7 +35,7 @@ Tree.__index = Tree
function Tree.new()
local self = setmetatable({}, Tree)
self.root = { name = "", children = {}, type = "directory", path = "" }
self.root = { name = "", children = {}, dir = true, type = "directory", path = "" }
self.nodes = {}
return self
end
@ -75,6 +76,7 @@ function Tree:child(node, name, type)
parent = node,
children = {},
type = type,
dir = type == "directory" or (type == "link" and vim.fn.isdirectory(path) == 1),
hidden = name:sub(1, 1) == ".",
}
self.nodes[path] = node.children[name]
@ -121,18 +123,17 @@ function Tree:expand(node)
return
end
local found = {} ---@type table<string, boolean>
assert(node.type == "directory", "Can only expand directories")
assert(node.dir, "Can only expand directories")
local fs = uv.fs_scandir(node.path)
while fs do
local name, t = uv.fs_scandir_next(fs)
if not name then
break
end
if t == "link" and vim.fn.isdirectory(node.path .. "/" .. name) == 1 then
t = "directory"
end
found[name] = true
self:child(node, name, t).type = t
local child = self:child(node, name, t)
child.type = t
child.dir = t == "directory" or (t == "link" and vim.fn.isdirectory(child.path) == 1)
end
for name in pairs(node.children) do
if not found[name] then
@ -172,17 +173,15 @@ function Tree:walk(node, fn, opts)
end
local children = vim.tbl_values(node.children) ---@type snacks.picker.explorer.Node[]
table.sort(children, function(a, b)
local a_dir = a.type == "directory"
local b_dir = b.type == "directory"
if a_dir ~= b_dir then
return a_dir
if a.dir ~= b.dir then
return a.dir
end
return a.name < b.name
end)
for c, child in ipairs(children) do
child.last = c == #children
abort = false
if child.type == "directory" and (child.open or (opts and opts.all)) then
if child.dir and (child.open or (opts and opts.all)) then
abort = self:walk(child, fn, opts)
else
abort = fn(child)
@ -210,7 +209,7 @@ function Tree:get(cwd, cb, opts)
return false
end
end
if n.type == "directory" and n.open and not n.expanded and opts.expand ~= false then
if n.dir and n.open and not n.expanded and opts.expand ~= false then
self:expand(n)
end
cb(n)
@ -223,7 +222,7 @@ function Tree:is_dirty(cwd, opts)
opts = opts or {}
local dirty = false
self:get(cwd, function(n)
if n.type == "directory" and n.open and not n.expanded then
if n.dir and n.open and not n.expanded then
dirty = true
end
end, { hidden = opts.hidden, ignored = opts.ignored, expand = false })

View file

@ -10,6 +10,7 @@ Snacks.util.set_hl({
Label = "SnacksPickerSpecial",
Totals = "NonText",
File = "", -- basename of a file path
Link = "Comment",
Directory = "Directory", -- basename of a directory path
PathIgnored = "NonText", -- any ignored file or directory
PathHidden = "NonText", -- any hidden file or directory

View file

@ -2,6 +2,8 @@
---@field [string] snacks.picker.format
local M = {}
local uv = vim.uv or vim.loop
function M.severity(item, picker)
local ret = {} ---@type snacks.picker.Highlight[]
local severity = item.severity
@ -95,6 +97,14 @@ function M.filename(item, picker)
end
end
ret[#ret + 1] = { " " }
if item.type == "link" then
local real = uv.fs_realpath(item.file) or uv.fs_readlink(item.file)
if real then
ret[#ret + 1] = { "-> ", "SnacksPickerDelim" }
ret[#ret + 1] = { Snacks.picker.util.truncpath(real, 20), "SnacksPickerLink" }
ret[#ret + 1] = { " " }
end
end
return ret
end

View file

@ -211,13 +211,13 @@ function M.explorer(opts, ctx)
Tree:get(ctx.filter.cwd, function(node)
local item = {
file = node.path,
dir = node.type == "directory",
dir = node.dir,
open = node.open,
text = node.path,
parent = node.parent and items[node.parent.path] or nil,
hidden = node.hidden,
ignored = node.ignored,
status = (node.type ~= "directory" or not node.open or opts.git_status_open) and node.status or nil,
status = (not node.dir or not node.open or opts.git_status_open) and node.status or nil,
last = node.last,
type = node.type,
}
@ -298,7 +298,7 @@ function M.search(opts, ctx)
end
local node = Tree:find(item.file)
if node then
item.status = (node.type ~= "directory" or opts.git_status_open) and node.status or nil
item.status = (not node.dir or opts.git_status_open) and node.status or nil
end
if opts.tree then