Qwen Code 终端补全分类 Tab 的鼠标点击支持:Completion Category Mouse Selection 设计解析与验证 Qwen Code 终端补全分类 Tab 的鼠标点击支持Completion Category Mouse Selection 设计解析与验证【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code导读Qwen Code 是一款运行在终端中的开源 AI 编码智能体仓库根目录见 README.md其补全选择器-mention completion picker支持按All / Files / Sessions等分类 Tab 过滤候选项。本篇技术指南围绕 e2e 测试计划 2026-08-03-completion-category-mouse.md 展开系统讲解在终端鼠标追踪mouse tracking开启时补全面板如何支持鼠标点击精确切换分类 Tab并保持键盘分类导航与建议行鼠标行为不变。读完本文你将掌握该功能的测试范围、手动验证路径、回归约束以及其底层源码实现原理含精确命中判定与挂载条件。功能背景Tab 化的补全选择器在 Qwen Code 的交互界面中补全用于引用文件、会话、MCP 资源、扩展等实体。当可用分类多于两个时SuggestionsDisplay组件会渲染一个分类 Tab 栏每个 Tab 对应一个精确的分类如 All、Files、Sessions键盘方向键可在 Tab 间循环切换。该功能在引入鼠标支持之前的已知缺陷是建议行可以接受点击而分类 Tab 标签没有 refs 也没有点击处理器据原 e2e 文档引用的 issue SGR 鼠标复现报告。本 e2e 计划的核心目标即验证启用终端鼠标追踪后Tab 栏能否通过鼠标点击切换到精确分类同时不破坏已有的键盘分类导航和建议行鼠标行为。源码实现CompletionCategoryMouseController分类 Tab 的鼠标点击层是一个无渲染headless的 React 组件 CompletionCategoryMouseController.tsx它只负责接收鼠标事件并计算命中自身不渲染任何 DOM通过useTerminalSize()获取当前终端高度rows通过useMouseEvents(handleMouse, { isActive: true, tracking: button })订阅鼠标事件button追踪模式在handleMouse中仅当事件名为left-press左键按下时才处理——指针移动move与按键释放left-release一律忽略命中判定委托给findElementAtMouseEvent(containerRef.current, categoryRefs.current, event, terminalHeight, rect)其中rect模式要求指针落在子元素的完整矩形范围内命中索引有效时调用onSelectCategory(categories[index])激活对应分类。组件只接收containerRef、categoryRefs、categories与onSelectCategory四个 props并通过mouseEnabled门控挂载注释明确inline 模式不受支持仅在宿主界面mouseEnabled之后挂载。对应单元测试 CompletionCategoryMouseController.test.tsxvitest-environment jsdom验证了四条核心行为精确命中findElementAtMouseEvent返回索引 2 时点击 col19、row5 会触发onSelectCategory(session)越界忽略点击落在 Tab 之外列越界或行越界不会触发任何回调非按下事件忽略move与left-release事件即使命中也不触发溢出帧坐标校正当合成帧溢出时findElementAtMouseEvent必须以终端高度40参与调用验证layoutRowForEvent的坐标换算链路被正确传递。命中判定底层mouse-hit.ts 的共享坐标换算分类 Tab 与建议行同处 alternate-screen 的虚拟视口布局因此它们必须共享同一套 SGR 坐标换算逻辑实现在 packages/cli/src/ui/utils/mouse-hit.tsfindElementAtMouseEvent首先将事件行列转换为布局坐标x event.col - 1y layoutRowForEvent(container, event.row, terminalHeight)。由于 Ink 会把溢出的 frame 底部锚定终端行号必须经过layoutRowForEvent换算后才能与布局空间的矩形比较随后测量容器containerRect若容器有宽度且指针 x 落在容器列区间之外直接返回null容器列边界检查row模式建议行使用基于子元素的垂直跨度调用findItemAtLayoutRow按行匹配rect模式分类 Tab 使用遍历每个子元素通过measureElementPosition取得矩形跳过height 0 || width 0的退化矩形再用containsPointx rect.x x rect.x rect.width且y落在行区间内判断精确命中。注释强调退化矩形处理、帧锚点校正、容器列边界是两类命中共用的逻辑这正是Tab 命中区域在正常与溢出布局下都跟随渲染的 Tab 边界这一回归约束的代码依据。集成点SuggestionsDisplay 的挂载条件分类 Tab 栏及其鼠标控制器在 SuggestionsDisplay.tsx 中集成建议行鼠标由RowMouseController负责mouseEnabled onHoverIndex onSelectIndex时挂载保持原有的悬停高亮与点击选中行为分类鼠标控制器在mouseEnabled showTabBar availableCategories onSelectCategory四个条件同时满足时挂载其中showTabBar (availableCategories?.length ?? 0) 2——即只有可用分类超过两个时才渲染 Tab 栏这也是少于等于两个分类不出现 Tab的行为来源Tab 栏渲染时通过categoryRefsref 回调逐个收集每个 Tab 的 DOM 节点供命中判定使用Tab 文案由categoryLabel()映射All / Files / Sessions / MCP / Extensions激活项使用theme.background.primary前景与theme.text.accent背景强调键盘导航为裸Left/Right源码注释说明原先的Ctrl←/→会被终端和 macOS Mission Control 拦截issue #8069因此改为裸方向键并在 Tab 栏右侧渲染(←/→ to switch)提示组件内还含一层防御性过滤父组件useCompletion通常已按激活分类过滤数组保证滚动与 active 索引对齐但SuggestionsDisplay内部再次按activeCategory过滤确保即使传入全量列表渲染也正确。挂载行为的集成测试见 SuggestionsDisplay.mouse.test.tsx覆盖启用时挂载分类控制器并传入精确的[all, file, session]与各 Tab 文本All/Files/SessionsmouseEnabled为 false、缺少onSelectCategory回调、或 Tab 栏隐藏仅两个分类时均不挂载分类控制器同时验证RowMouseController的scrollOffset传递可见位置到原始索引的映射。开关配置ui.mouseTracking鼠标行为由设置项ui.mouseTracking控制定义于 settingsSchema.ts。从 schema 测试 settingsSchema.test.ts 可以确认其约束类型为boolean默认值为trueshowInDialog为 true可在设置对话框展示requiresRestart为 true——修改后需要重启 Qwen Code 生效这正对应 e2e 场景中将ui.mouseTracking置为 false 后重启的步骤。运行时读取通过 HookuseMouseTrackingEnabled见 use-mouse-tracking-enabled.tsmerged.ui?.mouseTracking ! false即视为开启。该开关与虚拟视口ui.useTerminalBuffer组合决定是否启用 SGR 鼠标事件流ui.mouseTracking同时被 workspace-settings.ts 列入工作区设置的白名单键可在 TUI 之外通过 serve 路由读取。手动验证场景复现 e2e 计划以下步骤直接对应 e2e 文档 2026-08-03-completion-category-mouse.md 的手动场景用于在支持 SGR 鼠标的终端如 Warp中验证功能在 Warp 中运行 Qwen Code确保ui.mouseTracking为 true 且终端缓冲区terminal buffer / virtual viewport已启用打开一个工作区使补全至少显示三个分类 Tab例如All / Files / Sessions依次点击Files→Sessions→All确认每次点击都精确激活指针下的 Tab将高亮建议重置为第一个可见结果并按该分类过滤建议行确认点击所有 Tab 之外的区域不会改变当前激活 TabTab 栏可见时确认裸Left/Right可循环切换分类按Esc关闭补全面板后方向键恢复为普通输入光标行为将ui.mouseTracking设为 false重启 Qwen Code确认 Tab 点击不再被 Qwen Code 拦截终端恢复原生文本选择。注意本 e2e 场景的运行前提是支持 SGR 鼠标追踪的交互式终端原文档以 Warp 为验证载体且修改ui.mouseTracking后必须重启进程requiresRestart: true。回归检查项为保证新增分类点击不破坏既有交互e2e 计划要求以下行为保持不变仅左键按下left-press激活分类指针移动与按键释放均不触发——由CompletionCategoryMouseController的事件名过滤保证并由单测覆盖分类命中区域在正常与溢出布局下都跟随渲染的 Tab 边界——由layoutRowForEvent坐标换算与rect矩形命中共同保证建议行的悬停与点击继续走其原有RowMouseController控制器导出补全export completion、命令搜索、反向搜索不接收分类选择回调——分类回调仅通过补全的onSelectCategory通道触发。自动化验证命令e2e 文档给出的自动化验证聚焦四组测试文件均位于 packages/cli 的 TUI 组件测试cd packages/cli npx vitest run \ src/ui/components/CompletionCategoryMouseController.test.tsx \ src/ui/components/SuggestionsDisplay.mouse.test.tsx \ src/ui/components/InputPrompt.suggestionMouse.test.tsx \ src/ui/hooks/useCompletion.test.ts cd ../.. npm run lint npm run build npm run typecheck其中InputPrompt.suggestionMouse.test.tsx负责验证输入提示层的建议鼠标行为含ui.mouseTracking为 false 时禁用建议鼠标的用例useCompletion.test.ts覆盖补全状态机分类过滤、激活索引与滚动对齐与CompletionCategoryMouseController/SuggestionsDisplay的鼠标测试共同构成鼠标/分类回归套件。验证结果与状态根据 e2e 文档记录聚焦的鼠标/分类回归套件通过4 个文件、41 个测试仓库级 lint、build、typecheck 全部通过由于环境中没有 Warp 终端与已发布的全局qwen可执行文件手动 Warp 执行留待评审者验证CompletionCategoryMouseController的单元测试中坐标换算链路含终端高度参与findElementAtMouseEvent已通过 jsdom 环境自动化覆盖。小结Completion Category Mouse Selection以极小的侵入面补全了补全面板的鼠标可用性一个 headless 的CompletionCategoryMouseController负责左键命中判定复用了mouse-hit.ts中与建议行一致的 SGR 坐标换算、容器列边界与矩形命中逻辑SuggestionsDisplay以四个显式条件控制挂载确保分类点击只出现在补全且多分类、鼠标开启的场景导出补全、命令搜索、反向搜索完全不受影响。配套的 4 文件 41 测试套件与手动场景清单为后续在真实终端环境如 Warp中的回归验证提供了可复用的完整基线。【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考