Skip to content

Commit f1ff7d9

Browse files
author
SqlRush
committed
Parse CSI backward cursor aliases
1 parent 5c91924 commit f1ff7d9

5 files changed

Lines changed: 17 additions & 0 deletions

File tree

docs/cc-100-roadmap.md

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

511511
本轮补充:terminal CSI parser 接受 `CSI a`/`CSI e`/`CSI \`` cursor alias final bytes,并映射到已有 cursor-forward/cursor-down/cursor-column actions。
512512

513+
本轮补充:terminal CSI parser 接受 ECMA `CSI Ps j` / `CSI Ps k` HPB/VPB backward cursor final bytes,并映射到已有 cursor-back/cursor-up actions。
514+
513515
本轮补充:terminal CSI parser 接受 DEC private mode `?1047h/l` alternate-screen buffer 和 `?1048h/l` save/restore cursor,复用已有 mode/cursor actions。
514516

515517
本轮补充:terminal CSI parser 把 DECREQTPARM terminal-parameters (`CSI x`) 归入 report action,保留 code/private marker。

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ test/parity/ # golden tests against TS/official behavior
268268
- 本轮补充:terminal CSI-u/kitty keyboard parser 接受无 modifier 字段或 modifier `1` 的 base key 序列,覆盖 printable rune、Enter、Tab、Esc 和 Backspace,避免 extended-key 模式下普通键序列被解析成 unknown。
269269
- 本轮补充:terminal CSI parser 把 DA/device attributes (`CSI c``CSI >c``CSI =c`) 归入 report action,并在 terminal parser dispatcher 中作为 `TerminalActionReport` 暴露。
270270
- 本轮补充:terminal CSI parser 接受 `CSI a`/`CSI e`/`CSI \`` cursor alias final bytes,并映射到已有 cursor-forward/cursor-down/cursor-column actions。
271+
- 本轮补充:terminal CSI parser 接受 ECMA `CSI Ps j` / `CSI Ps k` HPB/VPB backward cursor final bytes,并映射到已有 cursor-back/cursor-up actions。
271272
- 本轮补充:terminal CSI parser 接受 DEC private mode `?1047h/l` alternate-screen buffer 和 `?1048h/l` save/restore cursor,复用已有 mode/cursor actions。
272273
- 本轮补充:terminal CSI parser 把 DECREQTPARM terminal-parameters (`CSI x`) 归入 report action,保留 code/private marker。
273274
- 本轮补充:terminal CSI parser 把 xterm window manipulation/report (`CSI t`) 归入 report action,覆盖常见 `CSI 14t`/`CSI 18t` 窗口/文本区尺寸查询。

docs/first-second-parity-audit.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ M7 progress now includes:
260260
- `internal/tui`: terminal CSI-u/kitty keyboard parsing now also accepts base/unmodified sequences such as `CSI 97u` and `CSI 13;1u`, mapping printable runes plus Enter, Tab, Esc, and Backspace instead of treating ordinary extended-key reports as unknown.
261261
- `internal/tui`: terminal CSI parsing now emits report actions for DA/device attributes queries such as `CSI c`, `CSI >c`, and `CSI =c`, preserving the private marker and code through the terminal parser dispatcher.
262262
- `internal/tui`: terminal CSI parsing now accepts ECMA/xterm cursor alias final bytes `CSI a`, `CSI e`, and `CSI \`` as cursor-forward, cursor-down, and cursor-column actions.
263+
- `internal/tui`: terminal CSI parsing now accepts ECMA HPB/VPB final bytes `CSI Ps j` / `CSI Ps k` as cursor-back and cursor-up actions.
263264
- `internal/tui`: terminal CSI parsing now accepts DEC private mode `?1046h/l` alternate-screen switching, `?1047h/l` alternate-screen buffer, and `?1048h/l` save/restore cursor variants using distinct mode/cursor action surfaces.
264265
- `internal/tui`: terminal CSI parsing now emits report actions for DECREQTPARM terminal-parameters queries such as `CSI x`, preserving code and private marker fields.
265266
- `internal/tui`: terminal CSI parsing now emits report actions for xterm window manipulation/report queries such as `CSI 14t` and `CSI 18t`, preserving code and private marker fields.

internal/tui/terminal_csi.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ const (
5757
CSICommandResetMode byte = 'l'
5858
CSICommandSGR byte = 'm'
5959
CSICommandDSR byte = 'n'
60+
CSICommandCursorBackAlt byte = 'j'
61+
CSICommandCursorUpAlt byte = 'k'
6062
CSICommandSoftReset byte = 'p'
6163
CSICommandCursorStyle byte = 'q'
6264
CSICommandScrollRegion byte = 'r'
@@ -390,6 +392,8 @@ func ParseCSISequence(sequence string) (CSIAction, bool) {
390392
return csiEdit(CSIEditActionRepeatChars, p0), true
391393
case CSICommandCursorBack:
392394
return csiCursorMove(CSICursorBack, p0), true
395+
case CSICommandCursorBackAlt:
396+
return csiCursorMove(CSICursorBack, p0), true
393397
case CSICommandCursorNextLine:
394398
return CSIAction{Type: CSIActionCursor, Cursor: CSICursorAction{Type: CSICursorActionNextLine, Count: p0}}, true
395399
case CSICommandCursorPrevLine:
@@ -410,6 +414,8 @@ func ParseCSISequence(sequence string) (CSIAction, bool) {
410414
return csiCursorMove(CSICursorDown, p0), true
411415
case CSICommandVerticalPosition:
412416
return CSIAction{Type: CSIActionCursor, Cursor: CSICursorAction{Type: CSICursorActionRow, Row: p0}}, true
417+
case CSICommandCursorUpAlt:
418+
return csiCursorMove(CSICursorUp, p0), true
413419
case CSICommandTabClear:
414420
return CSIAction{Type: CSIActionCursor, Cursor: CSICursorAction{Type: CSICursorActionTabClear, Count: csiParamDefault(params, 0, 0)}}, true
415421
case CSICommandEraseDisplay:

internal/tui/tui_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3719,6 +3719,8 @@ func TestParseCSISequenceActions(t *testing.T) {
37193719
{seq: CSISequence(4, "C"), want: CSICursorAction{Type: CSICursorActionMove, Direction: CSICursorForward, Count: 4}},
37203720
{seq: CSISequence(6, "a"), want: CSICursorAction{Type: CSICursorActionMove, Direction: CSICursorForward, Count: 6}},
37213721
{seq: CSISequence(5, "D"), want: CSICursorAction{Type: CSICursorActionMove, Direction: CSICursorBack, Count: 5}},
3722+
{seq: CSISequence(7, "j"), want: CSICursorAction{Type: CSICursorActionMove, Direction: CSICursorBack, Count: 7}},
3723+
{seq: CSISequence(3, "k"), want: CSICursorAction{Type: CSICursorActionMove, Direction: CSICursorUp, Count: 3}},
37223724
{seq: CSISequence(2, "E"), want: CSICursorAction{Type: CSICursorActionNextLine, Count: 2}},
37233725
{seq: CSISequence(3, "F"), want: CSICursorAction{Type: CSICursorActionPrevLine, Count: 3}},
37243726
{seq: CSISequence(2, "I"), want: CSICursorAction{Type: CSICursorActionTab, Count: 2}},
@@ -3937,6 +3939,11 @@ func TestParseCSISequenceActions(t *testing.T) {
39373939
t.Fatalf("terminal parser area erase actions = %#v", actions)
39383940
}
39393941

3942+
actions = parser.Feed(CSISequence(4, "j") + CSISequence(2, "k"))
3943+
if len(actions) != 2 || actions[0].Type != TerminalActionCursor || actions[0].Cursor.Direction != CSICursorBack || actions[0].Cursor.Count != 4 || actions[1].Type != TerminalActionCursor || actions[1].Cursor.Direction != CSICursorUp || actions[1].Cursor.Count != 2 {
3944+
t.Fatalf("terminal parser alternate backward cursor actions = %#v", actions)
3945+
}
3946+
39403947
actions = parser.Feed(CSISequence(5, 40, "s"))
39413948
if len(actions) != 1 || actions[0].Type != TerminalActionScroll || actions[0].Scroll.Type != CSIScrollActionSetHorizontalRegion || actions[0].Scroll.Left != 5 || actions[0].Scroll.Right != 40 {
39423949
t.Fatalf("terminal parser horizontal region actions = %#v", actions)

0 commit comments

Comments
 (0)