Skip to content

Commit 06fae5b

Browse files
committed
docs(cmdbar): 同步转义设计到 command-bar-design.md 与 AGENTS.md
- command-bar-design.md §2.1 转义节: 列出已知转义集 (\n \r \t \ " ...), 说明宽松白名单策略与三条路径一致性, 引用 command-bar-escape-support.md; 补 \ + ASCII 字母保留命名空间约定 (Windows 路径请写 \)。 - command-bar-design.md §5: 追加候选标签换行符渲染为 ↵ 防御说明。 - cmdbar/AGENTS.md: Key Files 新增 escape.go 条目; lexer.go / parser.go 描述末尾追加 '未知转义原样保留 (宽松白名单)'。
1 parent 0b84b05 commit 06fae5b

2 files changed

Lines changed: 15 additions & 3 deletions

File tree

docs/design/command-bar-design.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,15 @@ func_name = ident ("." ident)? # 仅命名空间, 不允许 a.b.c
4949
expr_list = expr ("," expr)*
5050
```
5151

52-
转义: `\"` `\\` `\{` `\}` `\(` `\)` 在字符串中按字面值处理。
52+
转义: `\"` `\\` `\{` `\}` `\(` `\)` `\n` `\t` `\r` 在字符串中按转义解码。
53+
未知转义 (`\` + 其它字符) 原样保留反斜杠与后续字符, 不报错 —— 宽松白名单
54+
策略, 三条短语路径 (`$CC`/`$SS` 字符串、模板短语、纯字面短语) 行为一致。
55+
纯字面短语的转义解码由 dict 短语层的 `decodePhraseEscapes` 完成 (因为不含
56+
`$` 的字面短语不经过 cmdbar parser)。完整方案见
57+
`command-bar-escape-support.md`
58+
59+
> **`\` + ASCII 字母是保留命名空间**: 用户不应依赖未知 `\X` 组合保持字面值。
60+
> Windows 路径请写 `\\` (如 `C:\\Users`), 避免 `\n` `\t` `\r` 被解码。
5361
5462
### 2.2 `$CC` 调用约定
5563

@@ -308,6 +316,9 @@ weight 时写回 `PhraseRecord.Weight`, Position 自然弃用。下一版本可
308316
- 输入未补全 (如 `bd` 还没补全 `bdxxx`) 时, `tail(code, 3)` 返回空字符串, 候选显示 "百度搜索 " (空尾巴正常显示)
309317
- 显示名表达式**禁止**调用动作类函数。解析器在构建 AST 时按"动作白名单"反向检查, 命中即报错并退化为字面短语
310318
- 显示名求值若抛错, 退化为短语 key 本身, 不阻断输入流程
319+
- 候选标签是单行控件。候选文本 (任何来源) 含换行符 (`\r` / `\n`) 时, 渲染层
320+
统一替换为可见符号 `↵` (`ui.CandidateNewlineGlyph`), 仅作用于显示, 候选
321+
实际上屏文本保留真实换行。
311322

312323
## 6. 安全模型
313324

wind_input/internal/cmdbar/AGENTS.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@
1313
|------|-------------|
1414
| `context.go` | `EvalContext` 接口 (含 `Services()`) 与 `MemoryContext` 测试实现; 含环形 `History` (容量自定, 默认 16) |
1515
| `services.go` | 动作函数所需依赖接口集: `ClipboardService` / `KeyInjector` / `URLOpener` / `ProcessRunner` (含 `Shell` + `ShellEx(cmd, flags)`) / `DictService` / `IMEController` / `SearchEngine``Services` 聚合; `ErrServiceUnavailable` 用于缺失服务降级 |
16+
| `escape.go` | `DecodeEscapes(s)` 宽松转义解码器: `\n \r \t \\` 解码, 未知 `\X` 原样保留; 供 dict 短语层解码纯字面短语转义。详见 docs/design/command-bar-escape-support.md |
1617
| `registry.go` | `FuncSpec` 元信息 + 线程安全 `Registry`; Category / Deterministic / Deprecated / AliasOf / Description / ExampleSrc 字段; `ListFuncs()` 返回完整 spec 列表供 wind_setting 渲染函数手册; 默认注册命名宪法新名 (proc.run / proc.shell / dict.add / setting.open / web.search) 为 Pure=false stub, 等 `funcs.RegisterActions` 调用后被真实实现覆盖。2026-05-18: 旧名 alias (run/shell/dict.addword/ime.setting/search) 已彻底删除 (发布前清理, 不留迁移负担); `Deprecated` / `AliasOf` 字段保留供未来潜在 alias 使用 |
1718
| `ast/ast.go` | `Expr` / `Phrase` 节点定义 (`StringLit`/`NumberLit`/`Ident`/`Call`/`ObjectLit` + `LiteralPhrase`/`TemplatePhrase`/`CommandPhrase`/`ArrayPhrase`); `CommandPhrase` 同时实现 Expr (用于嵌入 `$SS` 元素位置) 与 Phrase 接口, 带 `Modifiers map[string]any` 字段 (2026-05-16 引入, 详见 follow-up §3.2); `ObjectLit` 是 trailing options bag 字面量; `ArrayPhrase``$SS(name, elem...)` 字符串数组短语, Elements 类型为 `[]Expr` (StringLit 或 CommandPhrase) |
18-
| `parser/lexer.go` | 手写词法; 字符串内 `{...}` 切出 interp 段, 支持 `\" \\ \{ \} \( \) \n \t \r` 转义; 表达式位置 (字符串外) `{` `}` `:` 作为 ObjectLit 标点 token |
19-
| `parser/parser.go` | 入口 `Parse(src) (Phrase, error)`; 顶层 `findTopLevelMarker` 识别 `$CC(` / `$CC1(` / `$SS(` 三种 marker (与 `{` interpolation 互斥), 分流到 `parseCommandPhrase``parseArrayPhrase`; marker syntax sugar (`$CC1``$CC + {prefix:true}`, `$SS` 隐含 `{prefix:true, expand:"exact", nav:true}`) 在 `markerDefaults` 表里, parser 自动合并显式 options; `parseArrayPhrase``splitArrayArgs` 按顶层 `,` 切元素, 每个 span 自识别 `$CC(` 走 embedded CommandPhrase 路径, 嵌套深度上限 1 (内层 `$CC` 禁用 prefix modifier) |
19+
| `parser/lexer.go` | 手写词法; 字符串内 `{...}` 切出 interp 段, 支持 `\" \\ \{ \} \( \) \n \t \r` 转义; 表达式位置 (字符串外) `{` `}` `:` 作为 ObjectLit 标点 token; 未知转义原样保留 (宽松白名单) |
20+
| `parser/parser.go` | 入口 `Parse(src) (Phrase, error)`; 顶层 `findTopLevelMarker` 识别 `$CC(` / `$CC1(` / `$SS(` 三种 marker (与 `{` interpolation 互斥), 分流到 `parseCommandPhrase``parseArrayPhrase`; marker syntax sugar (`$CC1``$CC + {prefix:true}`, `$SS` 隐含 `{prefix:true, expand:"exact", nav:true}`) 在 `markerDefaults` 表里, parser 自动合并显式 options; `parseArrayPhrase``splitArrayArgs` 按顶层 `,` 切元素, 每个 span 自识别 `$CC(` 走 embedded CommandPhrase 路径, 嵌套深度上限 1 (内层 `$CC` 禁用 prefix modifier); 未知转义原样保留 (宽松白名单) |
2021
| `eval/eval.go` | `Evaluate(phrase, ctx, reg)` → display + actions (支持 LiteralPhrase / TemplatePhrase / CommandPhrase, 显式拒绝 ArrayPhrase 引导调用方走 ExpandArray); `ExpandArray(ArrayPhrase, ctx, reg)` 把 $SS 展开为 N 个 `ArrayElement` (Display + Actions + ElementModifiers), string lit 元素 Actions=nil, 嵌入 CommandPhrase 走完整 Evaluate |
2122
| `action.go` | P5 引入的 `ResolvedAction` 模型 (`Kind ActionEffect/ActionText` + `Run func() (string, error)`), 把动作区分为纯副作用与文本上屏 |
2223
| `funcs/value.go` | §3.1 取值函数 (`code/tail/last/clip/sel/app/title/date/time/now/env`); `code` 返回触发候选时的 inputBuffer 快照, 旧名 `input` 已迁移。**注意**: `code()` / `tail(code, n)` 在 cmdbar 短语场景实际不可用 — 短语精确码触发, 输入码偏移即脱离命中, 不存在 "prefix 命中后追加输入"。这两个函数与 `calc(tail(...))` 组合在短语 yaml 中不应出现, 仅在外部脚本上下文有意义。详见 docs/design/command-bar-design.md §3.1 caveat 节 |

0 commit comments

Comments
 (0)