Skip to content

Commit 12b1d25

Browse files
author
SqlRush
committed
Tokenize modified SS3 cursor sequences
1 parent 879b0ed commit 12b1d25

5 files changed

Lines changed: 19 additions & 2 deletions

File tree

docs/cc-100-roadmap.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -996,6 +996,8 @@ M7 补充:prompt history `LogEntry` 读取现在接受 `sessionID`/`session`/`
996996

997997
本轮补充:terminal tokenizer 增加官方 streaming escape boundary 状态机,支持跨 chunk buffer/flush/reset、CSI/SS3/OSC/DCS/APC 序列边界、OSC BEL/ST terminator、ESC intermediate charset 序列、invalid CSI text fallback 和 opt-in X10 mouse payload 消费;完整 text grapheme action parser 仍继续推进。
998998

999+
本轮补充:terminal tokenizer 的 SS3 状态现在会消费参数字节后再等待 final byte,`ESC O 1;5D` 这类 modified SS3 cursor 序列可跨 chunk 作为完整 sequence token 进入 dispatcher。
1000+
9991001
本轮补充:terminal parser 增加轻量 ANSI action pipeline,串接 tokenizer、CSI/OSC/ESC dispatcher 和 SGR style state,输出 text/bell/cursor/erase/scroll/mode/title/link/tabStatus/reset/unknown action,文本宽度覆盖 ASCII、emoji 和 East Asian wide;完整 grapheme cluster segmentation 和 renderer style parity 仍继续推进。
10001002

10011003
本轮补充:terminal parser 跟踪 OSC 8 hyperlink start/end 状态,暴露当前 `inLink``linkUrl`,reset 时清空链接状态,贴近官方 parser 的 link range 状态语义。

docs/claude-code-go-rewrite-plan.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,7 @@ test/parity/ # golden tests against TS/official behavior
565565
- 本轮补充:terminal SGR helper 增加官方 `TextStyle` 状态解析基础,覆盖 reset、bold/dim/italic/underline/blink/inverse/hidden/strikethrough/overline、普通/亮色命名色、256 色、RGB 色、underline color、分号和冒号参数格式;完整 ANSI parser/render style 应用仍继续推进。
566566
- 本轮补充:terminal sequence dispatcher 增加官方 `identifySequence` 等价分流,按 CSI/OSC/ESC/SS3/unknown 识别并委派现有 parser,SS3 按官方 output parser 作为 unknown action;streaming tokenizer 和 text grapheme action 仍继续推进。
567567
- 本轮补充:terminal tokenizer 增加官方 streaming escape boundary 状态机,支持跨 chunk buffer/flush/reset、CSI/SS3/OSC/DCS/APC 序列边界、OSC BEL/ST terminator、ESC intermediate charset 序列、invalid CSI text fallback 和 opt-in X10 mouse payload 消费;完整 text grapheme action parser 仍继续推进。
568+
- 本轮补充:terminal tokenizer 的 SS3 状态现在会消费参数字节后再等待 final byte,`ESC O 1;5D` 这类 modified SS3 cursor 序列可跨 chunk 作为完整 sequence token 进入 dispatcher。
568569
- 本轮补充:terminal parser 增加轻量 ANSI action pipeline,串接 tokenizer、CSI/OSC/ESC dispatcher 和 SGR style state,输出 text/bell/cursor/erase/scroll/mode/title/link/tabStatus/reset/unknown action,文本宽度覆盖 ASCII、emoji 和 East Asian wide;完整 grapheme cluster segmentation 与 renderer style 应用仍继续推进。
569570
- 本轮补充:terminal parser 跟踪 OSC 8 hyperlink start/end 状态,暴露当前 `inLink``linkUrl`,reset 时清空链接状态,贴近官方 parser 的 link range 状态语义。
570571
- 本轮补充:terminal parser 的 text grapheme 基础分段补齐 combining mark、variation selector、emoji modifier、ZWJ emoji 序列和 regional indicator flag pair;宽度计算现在让 base+combining-mark cluster 保持 base glyph 宽度,emoji presentation/ZWJ/flag 仍按宽 grapheme 处理,完整 Unicode UAX #29 分段仍未宣称完成。

docs/first-second-parity-audit.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ M7 progress now includes:
426426
- `internal/tui`: terminal CSI parsing now emits reset actions for DECSTR soft reset `CSI !p`, and the terminal parser clears SGR/link state through the existing reset path.
427427
- `internal/tui`: terminal sequence dispatch now parses SS3 application cursor sequences such as `ESC OA`/`OB`/`OC`/`OD` as structured cursor move actions.
428428
- `internal/tui`: terminal sequence dispatch now also parses modified SS3 application cursor sequences such as `ESC O 1;2A`, `ESC O 1;5B`, and `ESC O 1;16D` as structured cursor move actions instead of unknown SS3 sequences.
429+
- `internal/tui`: terminal tokenizer now keeps SS3 parameter bytes buffered until a final byte, so modified SS3 cursor sequences such as `ESC O 1;5D` can cross chunk boundaries and still reach the dispatcher as one sequence token.
429430
- `internal/tui`: terminal grapheme width now keeps base+combining-mark clusters at the base glyph width while preserving wide treatment for emoji presentation, ZWJ, regional-indicator, and tag sequences.
430431
- `internal/tui`: terminal grapheme segmentation now treats emoji keycap sequences such as `1️⃣` and `2⃣` as single wide graphemes, including streaming chunks split after the keycap base or variation selector.
431432
- `internal/tui`: terminal grapheme segmentation now applies Hangul L/V/T jamo joining, keeping decomposed syllables such as `한` as one wide grapheme across full input and streaming chunk boundaries.

internal/tui/terminal_tokenizer.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,9 @@ func tokenizeTerminal(input string, initialState TerminalTokenizerState, initial
198198
textStart = seqStart
199199
}
200200
case terminalTokenizerSS3:
201-
if code >= 0x40 && code <= 0x7e {
201+
if IsCSIParam(code) {
202+
i++
203+
} else if IsCSIFinal(code) {
202204
i++
203205
emitSequence(data[seqStart:i])
204206
} else {

internal/tui/terminal_tokenizer_test.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,11 @@ func TestTerminalTokenizerHandlesOSCAndStringControls(t *testing.T) {
8181

8282
func TestTerminalTokenizerHandlesESCIntermediateSS3AndInvalidSequences(t *testing.T) {
8383
tokenizer := NewTerminalTokenizer(TerminalTokenizerOptions{})
84-
tokens := tokenizer.Feed("\x1b(B\x1bOA\x1b[31x")
84+
tokens := tokenizer.Feed("\x1b(B\x1bOA\x1bO1;2A\x1b[31x")
8585
want := []TerminalToken{
8686
{Type: TerminalTokenSequence, Value: "\x1b(B"},
8787
{Type: TerminalTokenSequence, Value: "\x1bOA"},
88+
{Type: TerminalTokenSequence, Value: "\x1bO1;2A"},
8889
{Type: TerminalTokenSequence, Value: "\x1b[31x"},
8990
}
9091
if !reflect.DeepEqual(tokens, want) {
@@ -99,6 +100,16 @@ func TestTerminalTokenizerHandlesESCIntermediateSS3AndInvalidSequences(t *testin
99100
if !reflect.DeepEqual(tokens, want) {
100101
t.Fatalf("invalid csi tokens = %#v", tokens)
101102
}
103+
104+
tokens = tokenizer.Feed("\x1bO1;")
105+
if len(tokens) != 0 || tokenizer.Buffer() != "\x1bO1;" {
106+
t.Fatalf("partial modified ss3 tokens=%#v buffer=%q", tokens, tokenizer.Buffer())
107+
}
108+
tokens = tokenizer.Feed("5D")
109+
want = []TerminalToken{{Type: TerminalTokenSequence, Value: "\x1bO1;5D"}}
110+
if !reflect.DeepEqual(tokens, want) || tokenizer.Buffer() != "" {
111+
t.Fatalf("completed modified ss3 tokens=%#v buffer=%q", tokens, tokenizer.Buffer())
112+
}
102113
}
103114

104115
func TestTerminalTokenizerX10MouseOption(t *testing.T) {

0 commit comments

Comments
 (0)