@@ -4050,6 +4050,158 @@ TEST_CASE("HorizontalTab.AfterScreenClear", "[screen]")
40504050 CHECK (" X Y \n \n " == screen.renderMainPageText ());
40514051}
40524052
4053+ // {{{ DECCIR — Cursor Information Report
4054+
4055+ TEST_CASE (" DECCIR.default_state" , " [screen]" )
4056+ {
4057+ // Verify DECCIR response with all defaults: cursor at (1,1), no attributes, no wrap pending,
4058+ // GL=G0, GR=G2, all charsets USASCII.
4059+ auto mock = MockTerm { PageSize { LineCount (3 ), ColumnCount (10 ) } };
4060+
4061+ mock.writeToScreen (DECRQPSR (1 ));
4062+
4063+ // Expected: DCS 1 $ u 1;1;1;@;@;@;0;2;@;BBBB ST
4064+ // Pr=1, Pc=1, Pp=1
4065+ // Srend='@' (0x40, no attributes)
4066+ // Satt='@' (0x40, no protection)
4067+ // Sflag='@' (0x40, no flags)
4068+ // Pgl=0 (G0 in GL)
4069+ // Pgr=2 (G2 in GR, default)
4070+ // Scss='@' (0x40, all 94-char sets)
4071+ // Sdesig="BBBB" (all USASCII)
4072+ CHECK (e (mock.terminal .peekInput ()) == e (" \033 P1$u1;1;1;@;@;@;0;2;@;BBBB\033\\ " ));
4073+ }
4074+
4075+ TEST_CASE (" DECCIR.cursor_position" , " [screen]" )
4076+ {
4077+ // Verify DECCIR correctly reports cursor position after movement.
4078+ auto mock = MockTerm { PageSize { LineCount (5 ), ColumnCount (10 ) } };
4079+
4080+ mock.writeToScreen (CUP (3 , 7 )); // Move to line 3, column 7
4081+
4082+ mock.writeToScreen (DECRQPSR (1 ));
4083+
4084+ // Pr=3, Pc=7
4085+ CHECK (e (mock.terminal .peekInput ()) == e (" \033 P1$u3;7;1;@;@;@;0;2;@;BBBB\033\\ " ));
4086+ }
4087+
4088+ TEST_CASE (" DECCIR.bold_and_underline" , " [screen]" )
4089+ {
4090+ // Verify Srend field encodes bold (bit 1) and underline (bit 2).
4091+ auto mock = MockTerm { PageSize { LineCount (3 ), ColumnCount (10 ) } };
4092+
4093+ mock.writeToScreen (SGR (1 )); // Bold
4094+ mock.writeToScreen (SGR (4 )); // Underline
4095+ mock.writeToScreen (DECRQPSR (1 ));
4096+
4097+ // Srend = 0x40 + 0x01 (bold) + 0x02 (underline) = 0x43 = 'C'
4098+ CHECK (e (mock.terminal .peekInput ()) == e (" \033 P1$u1;1;1;C;@;@;0;2;@;BBBB\033\\ " ));
4099+ }
4100+
4101+ TEST_CASE (" DECCIR.blinking_and_inverse" , " [screen]" )
4102+ {
4103+ // Verify Srend field encodes blinking (bit 3) and inverse (bit 4).
4104+ auto mock = MockTerm { PageSize { LineCount (3 ), ColumnCount (10 ) } };
4105+
4106+ mock.writeToScreen (SGR (5 )); // Blinking
4107+ mock.writeToScreen (SGR (7 )); // Inverse
4108+ mock.writeToScreen (DECRQPSR (1 ));
4109+
4110+ // Srend = 0x40 + 0x04 (blink) + 0x08 (inverse) = 0x4C = 'L'
4111+ CHECK (e (mock.terminal .peekInput ()) == e (" \033 P1$u1;1;1;L;@;@;0;2;@;BBBB\033\\ " ));
4112+ }
4113+
4114+ TEST_CASE (" DECCIR.all_rendition_attributes" , " [screen]" )
4115+ {
4116+ // Verify Srend field with all attributes enabled: bold+underline+blink+inverse.
4117+ auto mock = MockTerm { PageSize { LineCount (3 ), ColumnCount (10 ) } };
4118+
4119+ mock.writeToScreen (SGR (1 )); // Bold
4120+ mock.writeToScreen (SGR (4 )); // Underline
4121+ mock.writeToScreen (SGR (5 )); // Blinking
4122+ mock.writeToScreen (SGR (7 )); // Inverse
4123+ mock.writeToScreen (DECRQPSR (1 ));
4124+
4125+ // Srend = 0x40 + 0x01 + 0x02 + 0x04 + 0x08 = 0x4F = 'O'
4126+ CHECK (e (mock.terminal .peekInput ()) == e (" \033 P1$u1;1;1;O;@;@;0;2;@;BBBB\033\\ " ));
4127+ }
4128+
4129+ TEST_CASE (" DECCIR.character_protection" , " [screen]" )
4130+ {
4131+ // Verify Satt field reports DECSCA character protection attribute.
4132+ auto mock = MockTerm { PageSize { LineCount (3 ), ColumnCount (10 ) } };
4133+
4134+ mock.writeToScreen (DECSCA (1 )); // Enable character protection
4135+ mock.writeToScreen (DECRQPSR (1 ));
4136+
4137+ // Satt = 0x41 = 'A' (bit 1 set for protection)
4138+ CHECK (e (mock.terminal .peekInput ()) == e (" \033 P1$u1;1;1;@;A;@;0;2;@;BBBB\033\\ " ));
4139+ }
4140+
4141+ TEST_CASE (" DECCIR.origin_mode" , " [screen]" )
4142+ {
4143+ // Verify Sflag bit 1 reports origin mode (DECOM).
4144+ auto mock = MockTerm { PageSize { LineCount (5 ), ColumnCount (10 ) } };
4145+
4146+ mock.writeToScreen (DECSM (toDECModeNum (DECMode::Origin)));
4147+ mock.writeToScreen (DECRQPSR (1 ));
4148+
4149+ // Sflag = 0x40 + 0x01 = 0x41 = 'A' (origin mode set)
4150+ // Note: cursor is at (1,1) because origin mode homes the cursor.
4151+ CHECK (e (mock.terminal .peekInput ()) == e (" \033 P1$u1;1;1;@;@;A;0;2;@;BBBB\033\\ " ));
4152+ }
4153+
4154+ TEST_CASE (" DECCIR.wrap_pending" , " [screen]" )
4155+ {
4156+ // Verify Sflag bit 4 reports wrap-pending state.
4157+ auto mock = MockTerm { PageSize { LineCount (3 ), ColumnCount (5 ) } };
4158+
4159+ // Write exactly enough characters to reach the right margin and trigger wrap pending.
4160+ mock.writeToScreen (" ABCDE" );
4161+ mock.writeToScreen (DECRQPSR (1 ));
4162+
4163+ // Cursor is at column 5, wrap pending. Sflag = 0x40 + 0x08 = 0x48 = 'H'
4164+ CHECK (e (mock.terminal .peekInput ()) == e (" \033 P1$u1;5;1;@;@;H;0;2;@;BBBB\033\\ " ));
4165+ }
4166+
4167+ TEST_CASE (" DECCIR.charset_designation_special" , " [screen]" )
4168+ {
4169+ // Verify Sdesig reports DEC Special charset when designated into G0.
4170+ auto mock = MockTerm { PageSize { LineCount (3 ), ColumnCount (10 ) } };
4171+
4172+ mock.writeToScreen (SCS_G0_SPECIAL ()); // Designate G0 = DEC Special
4173+ mock.writeToScreen (DECRQPSR (1 ));
4174+
4175+ // Sdesig: G0='0' (Special), G1-G3='B' (USASCII)
4176+ CHECK (e (mock.terminal .peekInput ()) == e (" \033 P1$u1;1;1;@;@;@;0;2;@;0BBB\033\\ " ));
4177+ }
4178+
4179+ TEST_CASE (" DECCIR.charset_designation_g1" , " [screen]" )
4180+ {
4181+ // Verify Sdesig reports charset designated into G1.
4182+ auto mock = MockTerm { PageSize { LineCount (3 ), ColumnCount (10 ) } };
4183+
4184+ mock.writeToScreen (SCS_G1_SPECIAL ()); // Designate G1 = DEC Special
4185+ mock.writeToScreen (DECRQPSR (1 ));
4186+
4187+ // Sdesig: G0='B', G1='0' (Special), G2-G3='B'
4188+ CHECK (e (mock.terminal .peekInput ()) == e (" \033 P1$u1;1;1;@;@;@;0;2;@;B0BB\033\\ " ));
4189+ }
4190+
4191+ TEST_CASE (" DECCIR.gl_charset_after_locking_shift" , " [screen]" )
4192+ {
4193+ // Verify Pgl reports G1 after a locking shift (SO → LS1 maps G1 into GL).
4194+ auto mock = MockTerm { PageSize { LineCount (3 ), ColumnCount (10 ) } };
4195+
4196+ mock.writeToScreen (" \x0E " ); // SO (Shift Out) = LS1 → map G1 into GL
4197+ mock.writeToScreen (DECRQPSR (1 ));
4198+
4199+ // Pgl=1 (G1 in GL)
4200+ CHECK (e (mock.terminal .peekInput ()) == e (" \033 P1$u1;1;1;@;@;@;1;2;@;BBBB\033\\ " ));
4201+ }
4202+
4203+ // }}} DECCIR
4204+
40534205// NOLINTEND(misc-const-correctness,readability-function-cognitive-complexity)
40544206
40554207// NOLINTBEGIN(misc-const-correctness)
0 commit comments