Skip to content

Commit 7cd5db3

Browse files
committed
fix: distinguish symbolic links in workspace resource (fixes #268)
- Changed from fs_stat to fs_lstat to detect symlinks without following them - Added symlink_target field to FileInfo type - Updated workspace resource output to show 'symlink -> target' format - Fixed path handling to use specified directory instead of cwd - Added cross-platform path support using git -C flag and vim.fs.joinpath
1 parent 415d9d0 commit 7cd5db3

File tree

2 files changed

+64
-20
lines changed

2 files changed

+64
-20
lines changed

lua/mcphub/native/neovim/files/environment.lua

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ return {
3333

3434
-- Format workspace files
3535
local workspace_files = vim.tbl_map(function(file)
36-
return string.format("%s (%s, %.2fKB)", file.name, file.type, file.size / 1024)
36+
if file.type == "link" and file.symlink_target then
37+
return string.format("%s (symlink -> %s, %.2fKB)", file.name, file.symlink_target, file.size / 1024)
38+
else
39+
return string.format("%s (%s, %.2fKB)", file.name, file.type, file.size / 1024)
40+
end
3741
end, dir_info.files)
3842

3943
local text = string.format(

lua/mcphub/native/neovim/utils/buffer.lua

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,61 @@ local M = {}
22

33
---@class FileInfo
44
---@field name string # File name or path
5-
---@field type string # File type (file/directory/etc)
5+
---@field type string # File type (file/directory/link/etc)
66
---@field size number # File size in bytes
77
---@field modified number # Last modification timestamp
8+
---@field symlink_target string|nil # If type is 'link', the target path
89

910
---@class DirectoryInfo
1011
---@field path string # Current directory path
1112
---@field is_git boolean # Whether the directory is a git repository
1213
---@field files FileInfo[] # List of files in the directory
1314

15+
---@param path? string # Directory path to scan (defaults to current working directory)
16+
---@return DirectoryInfo
1417
---@param path? string # Directory path to scan (defaults to current working directory)
1518
---@return DirectoryInfo
1619
function M.get_directory_info(path)
1720
path = path or vim.loop.cwd()
18-
-- Check if git repo
19-
local is_git = vim.fn.system("git rev-parse --is-inside-work-tree 2>/dev/null"):match("true")
21+
22+
-- Normalize path separators
23+
path = vim.fn.fnamemodify(path, ":p:h")
24+
25+
-- Check if the specified path is a git repo
26+
-- Use -C flag to specify directory instead of cd command for better cross-platform support
27+
local is_git = vim.fn
28+
.system(string.format("git -C %s rev-parse --is-inside-work-tree 2>/dev/null", vim.fn.shellescape(path)))
29+
:match("true")
2030
local files = {}
2131

2232
if is_git then
23-
-- Use git ls-files for git-aware listing
24-
local git_files = vim.fn.systemlist("git ls-files --cached --others --exclude-standard")
33+
-- Use git ls-files for git-aware listing in the specified directory
34+
local git_files = vim.fn.systemlist(
35+
string.format("git -C %s ls-files --cached --others --exclude-standard", vim.fn.shellescape(path))
36+
)
2537
for _, file in ipairs(git_files) do
26-
local stat = vim.loop.fs_stat(file)
27-
if stat then
28-
table.insert(files, {
38+
-- Build full path using cross-platform path joining
39+
local full_path = vim.fs.joinpath and vim.fs.joinpath(path, file) or (path .. "/" .. file)
40+
41+
-- Use lstat to detect symlinks without following them
42+
local lstat = vim.loop.fs_lstat(full_path)
43+
if lstat then
44+
local file_info = {
2945
name = file,
30-
type = stat.type,
31-
size = stat.size,
32-
modified = stat.mtime.sec,
33-
})
46+
type = lstat.type,
47+
size = lstat.size,
48+
modified = lstat.mtime.sec,
49+
}
50+
51+
-- If it's a symlink, get the target path
52+
if lstat.type == "link" then
53+
local target = vim.loop.fs_readlink(full_path)
54+
if target then
55+
file_info.symlink_target = target
56+
end
57+
end
58+
59+
table.insert(files, file_info)
3460
end
3561
end
3662
else
@@ -43,14 +69,28 @@ function M.get_directory_info(path)
4369
break
4470
end
4571

46-
local stat = vim.loop.fs_stat(name)
47-
if stat then
48-
table.insert(files, {
72+
-- Build full path using cross-platform path joining
73+
local full_path = vim.fs.joinpath and vim.fs.joinpath(path, name) or (path .. "/" .. name)
74+
75+
-- Use lstat to detect symlinks without following them
76+
local lstat = vim.loop.fs_lstat(full_path)
77+
if lstat then
78+
local file_info = {
4979
name = name,
50-
type = type or stat.type,
51-
size = stat.size,
52-
modified = stat.mtime.sec,
53-
})
80+
type = type or lstat.type,
81+
size = lstat.size,
82+
modified = lstat.mtime.sec,
83+
}
84+
85+
-- If it's a symlink, get the target path
86+
if lstat.type == "link" then
87+
local target = vim.loop.fs_readlink(full_path)
88+
if target then
89+
file_info.symlink_target = target
90+
end
91+
end
92+
93+
table.insert(files, file_info)
5494
end
5595
end
5696
end

0 commit comments

Comments
 (0)