Appearance
功能规格说明:输入编辑键与清空
创建日期:2026-08-01
用户场景与测试 (必填)
用户故事:原始 DEL 字符过滤,修复 SSH/tmux 退格失效(优先级:P1)
作为通过 SSH/tmux 远程操作 Wave CLI 的用户,我希望退格键在远程环境下可靠地删除字符,以便残留字符(如 b/)能够被正常清除而不是越删越多。
为什么是这个优先级:这是本次调研发现的根本原因。标准 ink 6.7.0 将单字节 \x7f 映射为 key.delete,但在 SSH/tmux 下退格会同时产生按键事件和原始 DEL 字符(\x7f),长按连续退格时还会聚合成多字节 chunk(如 \x7f\x7f),无法匹配任何键位模式,被 Wave 的粘贴判定当成"粘贴"从而把 DEL 字符字面插入输入框。对齐 Claude Code Issue #1853 的修复(useTextInput.ts:442-465):当按键不是 backspace/delete 但输入包含 \x7f 时,将每个 DEL 作为一个同步退格操作处理。不修复则远程场景下的输入编辑始终不可用。
独立测试:通过 useInput 注入包含 \x7f\x7f 的原始输入 chunk(模拟 SSH 连续退格),验证输入框文本每次减少一个字符,而不是插入 \x7f 字面量。
验收场景:
- 假设输入框中有文本
b/且光标在末尾,当收到包含\x7f的原始输入 chunk(非 backspace/delete 按键事件)时,则输入框文本变为b,DEL 字符不进入文本。 - 假设输入框中有文本
abc,当一次收到\x7f\x7f聚合 chunk 时,则文本变为a(每个 DEL 顺序执行一次退格)。 - 假设输入框为空,当收到
\x7f原始输入时,则输入框保持为空且不报错。 - 假设正在执行正常的 backspace 按键事件(
key.backspace === true),当按下退格键时,则行为不变,仍走既有的字符删除路径。
用户故事:Ctrl+U 删除到行首(优先级:P1)
作为用户,我希望按 Ctrl+U 删除光标前到行首的全部内容,以便在长输入或残留字符场景下能一键清空光标前内容,而不是反复按退格。
为什么是这个优先级:这是用户最初反馈中明确提到的编辑键("Ctrl+U 都无法清除")。当前 Wave 的 reducer 仅实现了 ctrl+v/r/b,缺少 emacs 风格的行编辑快捷键。Ctrl+U 是 CC(useTextInput.ts:224-238,u → killToLineStart)与终端惯例中最常用的"清行"键,单独实现即可覆盖主要场景。
独立测试:在输入框中输入 abc 并让光标位于行尾,按 Ctrl+U,验证光标前文本被删除、光标回到行首。
验收场景:
- 假设输入框中有
prefix rest且光标位于rest之后,当按 Ctrl+U 时,则光标前内容(prefix)被删除,光标前的文本变为rest。 - 假设光标已在行首,当按 Ctrl+U 时,则文本无变化,不报错。
用户故事:空闲状态下 Esc 双击清空输入(优先级:P1)
作为用户,我希望在空闲状态(无 AI 响应、无命令运行)下按 Esc 两次清空整个输入框,以便在无法正常退格的环境中有一个可靠的输入清理手段。
为什么是这个优先级:这是除退格修复外最直接的"可靠清空"手段,对齐 CC 的 Esc 双击清空(useTextInput.ts:126-153)。CC 的设计为状态互斥:Esc 中止语义仅绑定在"存在可中止任务"时(useCancelRequest.ts:150-167:isEscapeActive = isContextActive && (canCancelRunningTask || hasQueuedCommands)),空闲时 Esc 落到文本层执行双击清空。约束:Esc 双击清空只作用于空闲状态,AI 运行时的 Esc 仍保持中止响应语义,不影响运行中的中断行为。
独立测试:空闲状态下输入文本后连续按两次 Esc,验证第一次 Esc 出现"再次按 Esc 清空"提示、第二次 Esc 清空输入框;再在 AI 响应进行中按一次 Esc,验证仍立即中止响应。
验收场景:
- 假设空闲状态(
isLoading/isCommandRunning/isCompacting均为 false)且输入框有内容,当按第一次 Esc 时,则显示"再次按 Esc 清空输入"的提示,输入内容保持不变。 - 假设上述状态下已在 1 秒内按了第二次 Esc,当再次按 Esc 时,则输入框被清空,且原内容保存到输入历史(对齐 CC 的
addToHistory(originalValue))。 - 假设第一次 Esc 后超过 1 秒未按第二次,当再次按 Esc 时,则视为新一轮双击,仅重新显示提示,不清空输入。
- 假设空闲状态且输入框为空,当按 Esc 时,则不产生提示,无副作用。
- 假设AI 正在响应(
isLoading === true)或命令正在运行(isCommandRunning === true),当按一次 Esc 时,则保持现有中止响应语义(abortMessage),不触发双击清空逻辑。 - 假设AI 响应结束后回到空闲状态,当按 Esc 两次时,则恢复双击清空行为。
用户故事:补充 emacs 风格行编辑键 Ctrl+K/W/A/E(优先级:P2)
作为用户,我希望输入框支持 Ctrl+K(删除到行尾)、Ctrl+W(删除光标前一个词)、Ctrl+A/E(光标移到行首/行尾),以便获得与 Claude Code 和终端惯例一致的行编辑体验。
为什么是这个优先级:这些键与 Ctrl+U 同属 CC 的 emacs 编辑体系(useTextInput.ts:224-238),但对"清空输入"这一核心诉求不是必需,属于体验完整性补充,故列为 P2。
独立测试:分别在输入框验证 Ctrl+K 删除光标后内容、Ctrl+W 删除光标前一个词、Ctrl+A 光标到行首、Ctrl+E 光标到行尾。
验收场景:
- 假设输入框中有
foo bar baz且光标位于bar中间,当按 Ctrl+K 时,则光标后到行尾的内容被删除。 - 假设输入框中有
foo bar且光标位于行尾,当按 Ctrl+W 时,则删除光标前一个词bar,文本变为foo。 - 假设输入框中有
foo bar且光标位于行尾,当按 Ctrl+A 时,则光标移到行首;当再按 Ctrl+E 时,则光标移回行尾。
用户故事:长文本/图片占位符参与删除键(优先级:P1)
作为粘贴了长文本(被折叠为 [LongText#N])或附加了图片([Image #N])的用户,我希望 Backspace 能整块删除占位符、Ctrl+U/K/W 将其作为普通字符串参与切片删除,以便粘贴的长文本能被编辑键可靠清除,而不是只能按 Enter 提交或留下残缺占位符片段。
为什么是这个优先级:当前 Backspace 对 [LongText#N] 逐字符删除,一次只删一个字符,且会留下 [LongText#1 这类残缺文本,随后按 Enter 会把残缺占位符当字面文本发送,原文(已存入 longTextMap)丢失。对齐 Claude Code:Backspace 走 deleteTokenBefore 正则整块删除(Cursor.ts:937-969,正则覆盖 [Pasted text #N]/[Image #N] 等 token,且仅当光标位于 token 末尾、后随空白或行尾时触发);Ctrl+U/K/W 为纯文本切片/词删除(useTextInput.ts:224-238 的 killToLineStart/killToLineEnd/killWordBefore),占位符就是 input text 里的普通字符串,光标位于占位符中间时切片会留下残缺片段(与 CC 一致);原始 DEL 字符(\x7f,SSH/tmux 退格)同样按 token 优先删除(useTextInput.ts:442-465)。不修复则长文本粘贴后编辑不可用。
独立测试:粘贴超长文本折叠为 [LongText#1] 后按 Backspace,验证一次删除整个占位符且 longTextMap 条目被清理;光标位于占位符中间时 Backspace 仅删除单字符;Ctrl+U/K/W 按普通文本切片删除。
验收场景:
- 假设输入框中有
prefix [LongText#1]且光标位于占位符之后(行尾),当按 Backspace 时,则整个[LongText#1]占位符被删除,文本变为prefix,且longTextMap中对应条目被清理。 - 假设输入框中有
[LongText#1] suffix且光标位于占位符之后(占位符后随空白),当按 Backspace 时,则整个[LongText#1]占位符被删除,文本变为suffix。 - 假设光标位于
[LongText#1]占位符中间,当按 Backspace 时,则仅删除光标前一个字符,不触发整块删除(对齐 CC 的 word-boundary 守卫)。 - 假设输入框中有
[LongText#1]x(占位符后紧跟非空白字符)且光标位于]之后,当按 Backspace 时,则仅删除光标前一个字符(CC 仅当光标后是空白或行尾时触发整块删除)。 - 假设输入框中有
[LongText#1]且光标位于行尾,当按 Ctrl+U 时,则占位符作为普通字符串随整行删除,输入框清空。 - 假设输入框中有
hello [LongText#1]且光标位于行尾,当按 Ctrl+W 时,则删除光标前一个词(含无空格的整个占位符),文本变为hello。 - 假设光标位于
[LongText#1]占位符中间,当按 Ctrl+K 时,则纯文本切片删除光标后内容,占位符可能被切成残缺片段(如[Long),与 CC 行为一致。 - 假设输入框中有
[LongText#1]且光标位于行尾,当收到含\x7f的原始 DEL chunk 时,则每个 DEL 按 token 优先整块删除占位符(对齐 CCuseTextInput.ts:442-465)。
边界情况
- 粘贴与退格判定:
isPasteOperation(输入长度 > 1 且不含退格语义)与\x7f过滤需要互斥——包含\x7f的多字符 chunk 必须走退格路径而非粘贴路径。 - Ctrl 组合键与现有快捷键冲突:Ctrl+A/E 与终端行编辑默认行为一致;Ctrl+C 保留现有中止语义不纳入本次范围。
- 历史导航:Esc 双击清空保存原内容到历史后,上/下方向键应能找回该内容。
- 长文本/图片占位符:
[LongText#N]/[Image #N]是输入框中的普通字符串。Ctrl+U/K/W 走纯文本切片/词删除(光标在占位符中间时留下残缺片段,与 CC 一致);Backspace 与原始 DEL 走deleteTokenBefore正则整块删除(对齐 CCCursor.ts:937-969)——光标位于占位符末尾且后随空白或行尾时触发,并清理longTextMap条目。 - 待澄清:空闲状态下输入框有内容但存在排队消息(
hasQueuedMessages)时,Esc 是否应中止排队消息?[待澄清]
假设
- 空闲状态定义为
isLoading、isCommandRunning、isCompacting均为 false。 - "再次按 Esc 清空"提示沿用项目内现有提示机制(若无 toast 机制,可用输入框上方提示行或状态栏文本呈现)。
- 对齐 Claude Code 的互斥设计:Esc 的中止语义与双击清空语义互斥,由"是否有正在运行的任务"决定,不共存。