Skip to content

feat: @ 文件引用弹窗增强 — 分层分组、树形层级、路径 tooltip 【PR 二次审核已完成】#362

Merged
ErlichLiu merged 5 commits intoErlichLiu:mainfrom
Andreaseszhang:feat/mention-file-tree-grouping
May 3, 2026
Merged

feat: @ 文件引用弹窗增强 — 分层分组、树形层级、路径 tooltip 【PR 二次审核已完成】#362
ErlichLiu merged 5 commits intoErlichLiu:mainfrom
Andreaseszhang:feat/mention-file-tree-grouping

Conversation

@Andreaseszhang
Copy link
Copy Markdown
Contributor

@Andreaseszhang Andreaseszhang commented Apr 30, 2026

概述

对 @ 文件引用弹窗进行全面增强:会话/工作区双分组、树形层级、文件夹展开折叠、完整路径 tooltip、以及对中文/特殊字符路径的正确处理。

改动内容

  • FileMentionList.tsx — 重写:会话文件 / 工作区文件双分组、递归树形渲染带缩进、Tab / → / ← 键控制文件夹展开折叠、路径显示、悬停显示完整路径的 tooltip
  • file-mention-suggestion.tsx — 更新 props 适配分组数据、兼容旧 IPC、用 ResizeObserver 动态重定位弹窗、弹窗底部锚定向上生长
  • mention-popup-utils.ts — 增加 anchorBottom 选项(底部锚定在光标处,向上生长)
  • main/ipc.ts — 文件搜索返回分组结果(sessionEntries / workspaceEntries)并带 source 标记、新增 sessionPaths 参数支持会话级附加目录、空 query 每分组返回最多 100 条、附加目录根目录作为树形条目、"workspace-files" 重命名为 "工作文件"
  • preload/index.ts — searchWorkspaceFiles 新增 sessionPaths 参数
  • AgentView.tsx — 拆分附加目录为会话级与工作区级,正确打 source 标记
  • rich-text-input.tsx — 新增 sessionAttachedDirs prop、htmlToMarkdown 中对文件路径做 encodeURIComponent
  • message.tsxremarkMentions 对 mention:// URL 路径做 encode、智能检测防止重复编码、MentionChipsafeDecode 正确显示中文文件名
  • types/agent.tsFileIndexEntry 新增 source 字段,FileSearchResult 新增 sessionEntries / workspaceEntries

📝 最新改动(回应 code review 反馈)

提交 af6312f 针对 review 反馈修复了以下问题:

🐛 Bug 修复

  • main/ipc.ts:2041 — 修复 matchEntries 模糊匹配 bug:nameLower[i] === q(与整个查询字符串比较,永远为 false)修正为 nameLower[i] === q[qi]
  • message.tsx:311 — 修复 remarkMentionsmValue 的 TypeScript 类型错误,|| 链改为 ?? 链并加默认值 '',消除 string | undefined 推断

⚠️ 代码规范(CLAUDE.md 项目规则)

  • file-mention-suggestion.tsx:79 — 移除 any 类型,改为 SuggestionProps<FileIndexEntry>(从 @tiptap/suggestion 导入)
  • file-mention-suggestion.tsx:41,49 — 移除两处调试用的 console.log,保留 console.warn / console.error

✨ 交互增强

  • FileMentionList.tsx — 支持鼠标双击文件夹直接选中并插入 @ 引用(180ms 延迟识别单击/双击;单击仍是展开/折叠)

🧹 代码简化

  • FileMentionList.tsx — 合并结构完全相同的 SessionSectionWorkspaceSection 为统一的 FileSection(label) 组件
  • file-mention-suggestion.tsx — 简化 splitEntries,移除 IPC 已总是返回分组数据后永不命中的 fallback dead code
  • FileMentionList.tsx — 空状态移除多余的 TooltipProvider + MentionErrorBoundary 包裹

✅ 验证

  • bun run typecheck 全绿
  • 未 force-push,保留完整 commit 历史

测试步骤

  1. 启动开发模式:bun run dev
  2. 打开一个含会话级和工作区级附加目录的工作区
  3. 在输入框中输入 @
  4. 验证弹出"会话文件 / 工作区文件"双分组列表
  5. 验证 Tab 键展开/折叠文件夹(→ 展开,← 折叠)
  6. 新增:验证鼠标双击文件夹可直接选中并插入
  7. 验证悬停文件查看完整路径 tooltip
  8. 选择含中文和空格的路径文件并发送消息
  9. 验证消息中 mention 正确渲染(无 URL 编码、无断裂的 chip)
  10. 验证 @ 引用目录(文件和目录均可选中)

Andreaseszhang and others added 4 commits April 30, 2026 18:49
- FileMentionList 完全重写:双 banner(会话文件/工作区文件)、树形层级结构、目录展开/折叠(→/← 键)、路径显示、按键提示
- IPC 文件搜索:按 source(session/workspace)分组返回,空查询扩展至 100 条/组,附加目录顶层文件夹作为条目显示
- file-mention-suggestion:支持向后兼容旧版 IPC 返回格式
- RichTextInput:新增 sessionAttachedDirs prop,区分会话级/工作区级附加目录
- AgentView:拆分 workspaceDirs 和 sessionAttachedDirs 分别传递
- FileIndexEntry 新增 source 字段,FileSearchResult 新增 sessionEntries/workspaceEntries

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- 展开键从 ` 改为 Tab(toggle),→ 展开/← 折叠保持不动
- positionPopup 新增 anchorBottom 选项,弹窗底部锚定光标上方,展开文件夹时向上生长
- ResizeObserver 监听弹窗高度变化自动重新定位
- workspace-files 顶层目录显示名改为“工作文件”

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- 复用 Proma 现有 Radix Tooltip 组件
- 鼠标悬停 300ms 后在条目右侧显示完整路径
- z-[10000] 确保 tooltip 在弹窗之上

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- htmlToMarkdown 源头 encodeURIComponent 路径,确保 markdown 中路径不含特殊字符
- remarkMentions 智能检测已编码路径(%XX),避免双重编码
- MentionChip safeDecode 还原原始文件名
- 同时兼容旧消息(未编码原始路径)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown
Owner

@ErlichLiu ErlichLiu left a comment

Choose a reason for hiding this comment

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

PR Review — Quality Score: 3/5

整体是一个不错的功能增强,将 @ 引用从扁平列表升级为分组树形视图,UX 设计合理。但存在以下需要修复的问题:


🐛 Bug(严重):模糊匹配逻辑错误

文件: apps/electron/src/main/ipc.tsmatchEntries 函数

let qi = 0
for (let i = 0; i < nameLower.length && qi < q.length; i++) {
  if (nameLower[i] === q) qi++  // ❌ 应为 q[qi]
}
return qi === q.length

nameLower[i] === q 是将单个字符与整个查询字符串比较,永远为 false(除非 query 是单字符)。应改为 nameLower[i] === q[qi]。这导致多字符模糊匹配完全失效。


⚠️ 违反项目规范:使用了 any 类型

文件: apps/electron/src/renderer/components/file-browser/file-mention-suggestion.tsx

function createRenderer(props: any) { ... }

项目规范要求不使用 any,请为 props 定义具体接口。


⚠️ 遗留调试日志

文件: apps/electron/src/renderer/components/file-browser/file-mention-suggestion.tsx

console.log('[FileMention] searching files, query:', ...)
console.log('[FileMention] search result:', ...)

请在合并前移除这些 console.log,或替换为 if (DEBUG) 条件输出。


💡 建议:目录点击行为

当前行为:点击目录 → 仅展开/折叠;Enter → 选中。
建议:考虑双击目录选中,或在已展开目录上单击执行选中,以提升鼠标操作的可发现性。


💡 建议:TreeNodeList offset 副作用

renderNode 内通过闭包修改 let offset 追踪索引,依赖渲染顺序。建议改为 flattenVisible 后直接用数组 index 映射,避免潜在的 concurrent mode 问题。


修复以上 bug 和规范问题后 LGTM 👍

review 改动:
- 修复 matchEntries 模糊匹配 bug(nameLower[i] 原本与整个 q 比较,应为 q[qi])
- 修复 remarkMentions 中 mValue 的 TS 类型错误(?? 链 + 默认值)
- 移除 file-mention-suggestion 的 any 类型,改为 SuggestionProps<FileIndexEntry>
- 移除 file-mention-suggestion 两处调试 console.log

交互增强:
- 鼠标双击目录选中并插入 @ 引用(180ms 延迟判定单/双击)

代码简化:
- 合并 SessionSection / WorkspaceSection 为单个 FileSection(label)
- 简化 splitEntries,移除永不命中的 fallback dead code
- 空状态移除多余的 TooltipProvider / MentionErrorBoundary 包裹
@Andreaseszhang Andreaseszhang requested a review from ErlichLiu May 1, 2026 08:51
@Andreaseszhang Andreaseszhang changed the title feat: @ 文件引用弹窗增强 — 分层分组、树形层级、路径 tooltip feat: @ 文件引用弹窗增强 — 分层分组、树形层级、路径 tooltip 【已审核】 May 1, 2026
@Andreaseszhang Andreaseszhang changed the title feat: @ 文件引用弹窗增强 — 分层分组、树形层级、路径 tooltip 【已审核】 feat: @ 文件引用弹窗增强 — 分层分组、树形层级、路径 tooltip 【已审核 PR】 May 1, 2026
@Andreaseszhang Andreaseszhang changed the title feat: @ 文件引用弹窗增强 — 分层分组、树形层级、路径 tooltip 【已审核 PR】 feat: @ 文件引用弹窗增强 — 分层分组、树形层级、路径 tooltip 【PR 二次审核已完成】 May 1, 2026
@ErlichLiu ErlichLiu merged commit c374da5 into ErlichLiu:main May 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants