Skip to content

Commit e0a59c6

Browse files
author
SqlRush
committed
Preserve device attribute codes
1 parent 17334dd commit e0a59c6

5 files changed

Lines changed: 31 additions & 5 deletions

File tree

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ test/parity/ # golden tests against TS/official behavior
404404
- 本轮补充:terminal input parser 现在把 xterm modified navigation modifier 范围扩展到 `2..16`,覆盖 meta/shift+meta/ctrl+meta 组合(如 `CSI 1;10D``CSI 1;16C`)以及对应 Home/End/Delete/PageUp/PageDown 序列。
405405
- 本轮补充:terminal CSI-u/kitty keyboard parser 现在按 modifier bitfield 解码 `9..16` 扩展组合,把 meta/shift+meta 映射到现有 alt key surface,把 ctrl+meta 组合保留为 ctrl key,覆盖 `CSI 98;9u``CSI 97;13u` 等序列。
406406
- 本轮补充:terminal CSI parser 把 DA/device attributes (`CSI c``CSI >c``CSI =c`) 归入 report action,并在 terminal parser dispatcher 中作为 `TerminalActionReport` 暴露。
407+
- 本轮补充:terminal CSI parser 现在保留多参数 DA/device-attributes response 的完整 code list,例如 `CSI ?62;1;2;6c` 不再只留下首个 terminal type code。
407408
- 本轮补充:terminal CSI parser 接受 `CSI a`/`CSI e`/`CSI \`` cursor alias final bytes,并映射到已有 cursor-forward/cursor-down/cursor-column actions。
408409
- 本轮补充:terminal CSI parser 接受 ECMA `CSI Ps j` / `CSI Ps k` HPB/VPB backward cursor final bytes,并映射到已有 cursor-back/cursor-up actions。
409410
- 本轮补充:terminal CSI parser 接受 DEC private mode `?1047h/l` alternate-screen buffer 和 `?1048h/l` save/restore cursor,复用已有 mode/cursor actions。

docs/first-second-parity-audit.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ M7 progress now includes:
379379
- `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.
380380
- `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.
381381
- `internal/tui`: terminal CSI parsing now emits report actions for DECREQTPARM terminal-parameters queries such as `CSI x`, preserving code and private marker fields.
382+
- `internal/tui`: terminal CSI parsing now preserves the complete code list from multi-parameter DA/device-attributes responses such as `CSI ?62;1;2;6c` instead of dropping capability flags after the first code.
382383
- `internal/tui`: terminal CSI parsing now emits report actions for DECRQM mode requests such as `CSI 4$p` and `CSI ?25$p`, preserving mode code and private marker fields.
383384
- `internal/tui`: terminal CSI parsing now emits report actions for xterm window manipulation/report queries such as `CSI 14t` and `CSI 18t`, preserving code/private marker fields and structured dimensions for `CSI 4;height;width t` and `CSI 8;rows;cols t`.
384385
- `internal/tui`: terminal CSI parsing now emits cursor actions for TBC tab-clear sequences such as `CSI g` and `CSI 3g`, preserving the clear-current/all code.

internal/tui/terminal_csi.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ const (
230230
type CSIReportAction struct {
231231
Type CSIReportActionType
232232
Code int
233+
Codes []int
233234
Status int
234235
PrivateMode byte
235236
Height int
@@ -438,7 +439,7 @@ func ParseCSISequence(sequence string) (CSIAction, bool) {
438439
case CSICommandCursorPosition, CSICommandHorizontalVPos:
439440
return CSIAction{Type: CSIActionCursor, Cursor: CSICursorAction{Type: CSICursorActionPosition, Row: p0, Column: p1}}, true
440441
case CSICommandDeviceAttributes:
441-
return csiDeviceAttributes(csiParamDefault(params, 0, 0), privateMode), true
442+
return csiDeviceAttributes(rawP0, params, privateMode), true
442443
case CSICommandCursorDownAlt:
443444
return csiCursorMove(CSICursorDown, p0), true
444445
case CSICommandVerticalPosition:
@@ -607,10 +608,14 @@ func csiCursorPositionReport(row int, column int, page int, privateMode byte) CS
607608
}
608609
}
609610

610-
func csiDeviceAttributes(code int, privateMode byte) CSIAction {
611+
func csiDeviceAttributes(code int, params []int, privateMode byte) CSIAction {
612+
report := CSIReportAction{Type: CSIReportActionDeviceAttrs, Code: code, PrivateMode: privateMode}
613+
if len(params) > 1 {
614+
report.Codes = append([]int(nil), params...)
615+
}
611616
return CSIAction{
612617
Type: CSIActionReport,
613-
Report: CSIReportAction{Type: CSIReportActionDeviceAttrs, Code: code, PrivateMode: privateMode},
618+
Report: report,
614619
}
615620
}
616621

internal/tui/terminal_parser_test.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package tui
22

3-
import "testing"
3+
import (
4+
"reflect"
5+
"testing"
6+
)
47

58
func TestTerminalParserTextBellAndGraphemeWidths(t *testing.T) {
69
parser := NewTerminalParser()
@@ -461,6 +464,21 @@ func TestTerminalParserDispatchesWindowResizeReports(t *testing.T) {
461464
}
462465
}
463466

467+
func TestTerminalParserDispatchesDeviceAttributeReports(t *testing.T) {
468+
parser := NewTerminalParser()
469+
input := "a" + CSISequence("?62;1;2;6c") + "b"
470+
actions := parser.Feed(input)
471+
if len(actions) != 3 {
472+
t.Fatalf("actions = %#v", actions)
473+
}
474+
if actions[1].Type != TerminalActionReport || actions[1].Report.Type != CSIReportActionDeviceAttrs || actions[1].Report.PrivateMode != '?' || actions[1].Report.Code != 62 || !reflect.DeepEqual(actions[1].Report.Codes, []int{62, 1, 2, 6}) {
475+
t.Fatalf("device attribute report action = %#v", actions[1])
476+
}
477+
if got := TerminalVisibleText(input); got != "ab" {
478+
t.Fatalf("visible = %q", got)
479+
}
480+
}
481+
464482
func TestTerminalParserDispatchesCursorPositionReports(t *testing.T) {
465483
parser := NewTerminalParser()
466484
input := "a" + CSISequence("?12;34;2R") + "b"

internal/tui/tui_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5267,6 +5267,7 @@ func TestParseCSISequenceActions(t *testing.T) {
52675267
{seq: CSISequence("c"), want: CSIReportAction{Type: CSIReportActionDeviceAttrs}},
52685268
{seq: CSISequence(">1c"), want: CSIReportAction{Type: CSIReportActionDeviceAttrs, Code: 1, PrivateMode: '>'}},
52695269
{seq: CSISequence("=2c"), want: CSIReportAction{Type: CSIReportActionDeviceAttrs, Code: 2, PrivateMode: '='}},
5270+
{seq: CSISequence("?62;1;2;6c"), want: CSIReportAction{Type: CSIReportActionDeviceAttrs, Code: 62, Codes: []int{62, 1, 2, 6}, PrivateMode: '?'}},
52705271
{seq: CSISequence("x"), want: CSIReportAction{Type: CSIReportActionTerminalParams}},
52715272
{seq: CSISequence(1, "x"), want: CSIReportAction{Type: CSIReportActionTerminalParams, Code: 1}},
52725273
{seq: CSISequence("?2x"), want: CSIReportAction{Type: CSIReportActionTerminalParams, Code: 2, PrivateMode: '?'}},
@@ -5291,7 +5292,7 @@ func TestParseCSISequenceActions(t *testing.T) {
52915292
}
52925293
for _, tc := range reportCases {
52935294
action, ok := ParseCSISequence(tc.seq)
5294-
if !ok || action.Type != CSIActionReport || action.Report != tc.want {
5295+
if !ok || action.Type != CSIActionReport || !reflect.DeepEqual(action.Report, tc.want) {
52955296
t.Fatalf("report action for %q = %#v, want %#v", tc.seq, action, tc.want)
52965297
}
52975298
}

0 commit comments

Comments
 (0)