@@ -186,6 +186,7 @@ class ScreenBufferTests
186
186
TEST_METHOD (InsertReplaceMode);
187
187
TEST_METHOD (InsertChars);
188
188
TEST_METHOD (DeleteChars);
189
+ TEST_METHOD (HorizontalScrollOperations);
189
190
TEST_METHOD (ScrollingWideCharsHorizontally);
190
191
191
192
TEST_METHOD (EraseScrollbackTests);
@@ -4346,6 +4347,117 @@ void ScreenBufferTests::DeleteChars()
4346
4347
}
4347
4348
}
4348
4349
4350
+ void ScreenBufferTests::HorizontalScrollOperations ()
4351
+ {
4352
+ BEGIN_TEST_METHOD_PROPERTIES ()
4353
+ TEST_METHOD_PROPERTY (L" Data:op" , L" {0, 1, 2, 3}" )
4354
+ END_TEST_METHOD_PROPERTIES ();
4355
+
4356
+ enum Op : int
4357
+ {
4358
+ DECIC,
4359
+ DECDC,
4360
+ DECFI,
4361
+ DECBI
4362
+ } op;
4363
+ VERIFY_SUCCEEDED (TestData::TryGetValue (L" op" , (int &)op));
4364
+
4365
+ auto & gci = ServiceLocator::LocateGlobals ().getConsoleInformation ();
4366
+ auto & si = gci.GetActiveOutputBuffer ().GetActiveBuffer ();
4367
+ auto & stateMachine = si.GetStateMachine ();
4368
+ WI_SetFlag (si.OutputMode , ENABLE_VIRTUAL_TERMINAL_PROCESSING);
4369
+
4370
+ // Set the buffer width to 40, with a centered viewport of 20.
4371
+ const auto bufferWidth = 40 ;
4372
+ const auto bufferHeight = si.GetBufferSize ().Height ();
4373
+ const auto viewportStart = 10 ;
4374
+ const auto viewportEnd = viewportStart + 20 ;
4375
+ VERIFY_SUCCEEDED (si.ResizeScreenBuffer ({ bufferWidth, bufferHeight }, false ));
4376
+ si.SetViewport (Viewport::FromExclusive ({ viewportStart, 0 , viewportEnd, 25 }), true );
4377
+
4378
+ // Set the margin area to columns 10 to 29 and rows 14 to 19 (zero based).
4379
+ stateMachine.ProcessString (L" \x1b [?69h" );
4380
+ stateMachine.ProcessString (L" \x1b [11;30s" );
4381
+ stateMachine.ProcessString (L" \x1b [15;20r" );
4382
+ // Make sure we clear the margins on exit so they can't break other tests.
4383
+ auto clearMargins = wil::scope_exit ([&] {
4384
+ stateMachine.ProcessString (L" \x1b [r" );
4385
+ stateMachine.ProcessString (L" \x1b [s" );
4386
+ stateMachine.ProcessString (L" \x1b [?69l" );
4387
+ });
4388
+
4389
+ // Fill the buffer with text. Red on Blue.
4390
+ const auto bufferChars = L" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn" ;
4391
+ const auto bufferAttr = TextAttribute{ FOREGROUND_RED | BACKGROUND_BLUE };
4392
+ _FillLines (0 , 25 , bufferChars, bufferAttr);
4393
+
4394
+ // Set the attributes that will be used to fill the revealed area.
4395
+ auto fillAttr = TextAttribute{ RGB (12 , 34 , 56 ), RGB (78 , 90 , 12 ) };
4396
+ fillAttr.SetCrossedOut (true );
4397
+ fillAttr.SetReverseVideo (true );
4398
+ fillAttr.SetUnderlined (true );
4399
+ si.SetAttributes (fillAttr);
4400
+ // But note that the meta attributes are expected to be cleared.
4401
+ auto expectedFillAttr = fillAttr;
4402
+ expectedFillAttr.SetStandardErase ();
4403
+
4404
+ auto & cursor = si.GetTextBuffer ().GetCursor ();
4405
+ switch (op)
4406
+ {
4407
+ case DECIC:
4408
+ Log::Comment (L" Insert 4 columns in the middle of the margin area." );
4409
+ cursor.SetPosition ({ 20 , 17 });
4410
+ stateMachine.ProcessString (L" \x1b [4'}" );
4411
+ VERIFY_ARE_EQUAL (til::point (20 , 17 ), cursor.GetPosition (), L" The cursor should not move." );
4412
+ VERIFY_IS_TRUE (_ValidateLinesContain (10 , 14 , 20 , L" KLMNOPQRST" , bufferAttr),
4413
+ L" The margin area left of the cursor position should remain unchanged." );
4414
+ VERIFY_IS_TRUE (_ValidateLinesContain (20 , 14 , 20 , L" " , expectedFillAttr),
4415
+ L" 4 blank columns should be inserted at the cursor position." );
4416
+ VERIFY_IS_TRUE (_ValidateLinesContain (24 , 14 , 20 , L" UVWXYZ" , bufferAttr),
4417
+ L" The area right of that should be scrolled right by 4 columns." );
4418
+ break ;
4419
+ case DECDC:
4420
+ Log::Comment (L" Delete 4 columns in the middle of the margin area." );
4421
+ cursor.SetPosition ({ 20 , 17 });
4422
+ stateMachine.ProcessString (L" \x1b [4'~" );
4423
+ VERIFY_ARE_EQUAL (til::point (20 , 17 ), cursor.GetPosition (), L" The cursor should not move." );
4424
+ VERIFY_IS_TRUE (_ValidateLinesContain (10 , 14 , 20 , L" KLMNOPQRSTYZabcd" , bufferAttr),
4425
+ L" The area right of the cursor position should be scrolled left by 4 columns." );
4426
+ VERIFY_IS_TRUE (_ValidateLinesContain (26 , 14 , 20 , L" " , expectedFillAttr),
4427
+ L" 4 blank columns should be inserted at the right of the margin area." );
4428
+ break ;
4429
+ case DECFI:
4430
+ Log::Comment (L" Forward index 4 times, 2 columns before the right margin." );
4431
+ cursor.SetPosition ({ 27 , 17 });
4432
+ stateMachine.ProcessString (L" \x1b\x39\x1b\x39\x1b\x39\x1b\x39 " );
4433
+ VERIFY_ARE_EQUAL (til::point (29 , 17 ), cursor.GetPosition (), L" The cursor should not pass the right margin." );
4434
+ VERIFY_IS_TRUE (_ValidateLinesContain (10 , 14 , 20 , L" MNOPQRSTUVWXYZabcd" , bufferAttr),
4435
+ L" The margin area should scroll left by 2 columns." );
4436
+ VERIFY_IS_TRUE (_ValidateLinesContain (28 , 14 , 20 , L" " , expectedFillAttr),
4437
+ L" 2 blank columns should be inserted at the right of the margin area." );
4438
+ break ;
4439
+ case DECBI:
4440
+ Log::Comment (L" Back index 4 times, 2 columns before the left margin." );
4441
+ cursor.SetPosition ({ 12 , 17 });
4442
+ stateMachine.ProcessString (L" \x1b\x36\x1b\x36\x1b\x36\x1b\x36 " );
4443
+ VERIFY_ARE_EQUAL (til::point (10 , 17 ), cursor.GetPosition (), L" The cursor should not pass the left margin." );
4444
+ VERIFY_IS_TRUE (_ValidateLinesContain (10 , 14 , 20 , L" " , expectedFillAttr),
4445
+ L" 2 blank columns should be inserted at the left of the margin area." );
4446
+ VERIFY_IS_TRUE (_ValidateLinesContain (12 , 14 , 20 , L" KLMNOPQRSTUVWXYZab" , bufferAttr),
4447
+ L" The rest of the margin area should scroll right by 2 columns." );
4448
+ break ;
4449
+ }
4450
+
4451
+ VERIFY_IS_TRUE (_ValidateLinesContain (0 , 14 , bufferChars, bufferAttr),
4452
+ L" Content above the top margin should remain unchanged." );
4453
+ VERIFY_IS_TRUE (_ValidateLinesContain (20 , 25 , bufferChars, bufferAttr),
4454
+ L" Content below the bottom margin should remain unchanged." );
4455
+ VERIFY_IS_TRUE (_ValidateLinesContain (0 , 14 , 20 , L" ABCDEFGHIJ" , bufferAttr),
4456
+ L" Content before the left margin should remain unchanged." );
4457
+ VERIFY_IS_TRUE (_ValidateLinesContain (30 , 14 , 20 , L" efghijklmn" , bufferAttr),
4458
+ L" Content beyond the right margin should remain unchanged." );
4459
+ }
4460
+
4349
4461
void ScreenBufferTests::ScrollingWideCharsHorizontally ()
4350
4462
{
4351
4463
// The point of this test is to make sure wide characters can be
0 commit comments