Skip to content

Commit 8f0ae92

Browse files
fix: add missing DECRPM mode responses for permanently set/reset and dynamic modes
Add cases to privateModeSetting and ansiModeSetting for modes that upstream xterm.js reports but the Go port returned NOT_RECOGNIZED: ANSI modes: - Mode 2 (KAM): permanently reset - Mode 12 (SRM): permanently set DEC private modes: - Mode 8 (DECARM): permanently set - Mode 12 (cursor blink): dynamic based on CursorBlink option - Mode 67 (DECBKM): permanently reset - Mode 1005 (UTF-8 mouse): permanently reset - Mode 1015 (urxvt mouse): permanently reset - Mode 1048 (save cursor): always set Fixes #27 Fixes #28 Co-authored-by: Ona <no-reply@ona.com>
1 parent ecf1a79 commit 8f0ae92

2 files changed

Lines changed: 54 additions & 0 deletions

File tree

inputhandler_csi.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,12 +776,18 @@ func (h *InputHandler) privateModeSetting(mode int) int {
776776
return boolToPm(dm.Origin)
777777
case 7:
778778
return boolToPm(dm.Wraparound)
779+
case 8:
780+
return 3 // DECARM: permanently set
781+
case 12:
782+
return boolToPm(h.optionsService.Options.CursorBlink)
779783
case 25:
780784
return boolToPm(!h.coreService.IsCursorHidden)
781785
case 45:
782786
return boolToPm(dm.ReverseWraparound)
783787
case 66:
784788
return boolToPm(dm.ApplicationKeypad)
789+
case 67:
790+
return 4 // DECBKM: permanently reset
785791
case 9:
786792
return boolToPm(dm.MouseTrackingMode == "X10")
787793
case 1000:
@@ -792,10 +798,16 @@ func (h *InputHandler) privateModeSetting(mode int) int {
792798
return boolToPm(dm.MouseTrackingMode == "ANY")
793799
case 1004:
794800
return boolToPm(dm.SendFocus)
801+
case 1005:
802+
return 4 // UTF-8 mouse: permanently reset
795803
case 1006:
796804
return boolToPm(dm.MouseEncoding == "SGR")
805+
case 1015:
806+
return 4 // urxvt mouse: permanently reset
797807
case 1016:
798808
return boolToPm(dm.MouseEncoding == "SGR_PIXELS")
809+
case 1048:
810+
return 1 // save cursor: always set
799811
case 47, 1047, 1049:
800812
return boolToPm(h.bufferService.Buffers.Active() == h.bufferService.Buffers.Alt())
801813
case 2004:
@@ -814,8 +826,12 @@ func (h *InputHandler) privateModeSetting(mode int) int {
814826
// ansiModeSetting returns the DECRPM Pm value for an ANSI mode.
815827
func (h *InputHandler) ansiModeSetting(mode int) int {
816828
switch mode {
829+
case 2:
830+
return 4 // KAM: permanently reset
817831
case 4:
818832
return boolToPm(h.coreService.Modes.InsertMode)
833+
case 12:
834+
return 3 // SRM: permanently set
819835
case 20:
820836
return boolToPm(h.optionsService.Options.ConvertEol)
821837
default:

inputhandler_csi_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,6 +1217,14 @@ func TestRequestModePrivate(t *testing.T) {
12171217
{"mouse_encoding_sgr", "\x1b[?1006h", "\x1b[?1006$p", "\x1b[?1006;1$y"},
12181218
{"color_scheme_updates_set", "\x1b[?2031h", "\x1b[?2031$p", "\x1b[?2031;1$y"},
12191219
{"win32_input_set", "\x1b[?9001h", "\x1b[?9001$p", "\x1b[?9001;1$y"},
1220+
// Permanently set/reset modes (issue #27)
1221+
{"DECARM_permanently_set", "", "\x1b[?8$p", "\x1b[?8;3$y"},
1222+
{"DECBKM_permanently_reset", "", "\x1b[?67$p", "\x1b[?67;4$y"},
1223+
{"UTF8_mouse_permanently_reset", "", "\x1b[?1005$p", "\x1b[?1005;4$y"},
1224+
{"urxvt_mouse_permanently_reset", "", "\x1b[?1015$p", "\x1b[?1015;4$y"},
1225+
// Dynamic mode reports (issue #28)
1226+
{"cursor_blink_default_reset", "", "\x1b[?12$p", "\x1b[?12;2$y"},
1227+
{"save_cursor_always_set", "", "\x1b[?1048$p", "\x1b[?1048;1$y"},
12201228
}
12211229
for _, tc := range tests {
12221230
t.Run(tc.Name, func(t *testing.T) {
@@ -1248,6 +1256,9 @@ func TestRequestModeANSI(t *testing.T) {
12481256
{"insert_mode_default", "", "\x1b[4$p", "\x1b[4;2$y"},
12491257
{"insert_mode_set", "\x1b[4h", "\x1b[4$p", "\x1b[4;1$y"},
12501258
{"convert_eol_default", "", "\x1b[20$p", "\x1b[20;2$y"},
1259+
// Permanently set/reset modes (issue #27)
1260+
{"KAM_permanently_reset", "", "\x1b[2$p", "\x1b[2;4$y"},
1261+
{"SRM_permanently_set", "", "\x1b[12$p", "\x1b[12;3$y"},
12511262
{"unrecognized_ansi_mode", "", "\x1b[99$p", "\x1b[99;0$y"},
12521263
}
12531264
for _, tc := range tests {
@@ -1269,6 +1280,33 @@ func TestRequestModeANSI(t *testing.T) {
12691280
}
12701281
}
12711282

1283+
func TestRequestModeCursorBlinkEnabled(t *testing.T) {
1284+
t.Parallel()
1285+
// CursorBlink enabled should report SET (Pm=1) for mode 12.
1286+
opts := DefaultOptions()
1287+
opts.Cols = 80
1288+
opts.Rows = 24
1289+
opts.Scrollback = 1000
1290+
opts.CursorBlink = true
1291+
optsSvc := NewOptionsService(&opts)
1292+
bufSvc := NewBufferService(optsSvc)
1293+
charSvc := NewCharsetService()
1294+
coreSvc := NewCoreService(optsSvc)
1295+
oscLinkSvc := NewOscLinkService(bufSvc)
1296+
uniSvc := NewUnicodeService()
1297+
h := NewInputHandler(bufSvc, charSvc, coreSvc, optsSvc, oscLinkSvc, uniSvc)
1298+
1299+
var response string
1300+
h.coreService.OnDataEmitter.Event(func(data string) {
1301+
response = data
1302+
})
1303+
h.ParseString("\x1b[?12$p")
1304+
expected := "\x1b[?12;1$y"
1305+
if response != expected {
1306+
t.Errorf("expected response %q, got %q", expected, response)
1307+
}
1308+
}
1309+
12721310
func TestWindowOptionsReportSize(t *testing.T) {
12731311
t.Parallel()
12741312
h := newTestInputHandler(80, 24)

0 commit comments

Comments
 (0)