Skip to content

Commit 3d35e39

Browse files
carlos-zamoraDHowett
authored andcommitted
Bugfix: CLS should clear current active buffer (#2729)
CLS calls two functions: - `SetConsoleCursorPositionImpl()` - `ScrollConsoleScreenBufferWImpl()` Both of these were not checking which buffer to apply to (main vs active buffer). Now we get the active buffer and apply the changes to that one. Also, we forgot to switch out of the alt buffer in the previous test. Added that in. Closes #1189.
1 parent b693fd4 commit 3d35e39

File tree

2 files changed

+104
-7
lines changed

2 files changed

+104
-7
lines changed

src/host/getset.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,9 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
632632

633633
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
634634

635-
const COORD coordScreenBufferSize = context.GetBufferSize().Dimensions();
635+
auto& buffer = context.GetActiveBuffer();
636+
637+
const COORD coordScreenBufferSize = buffer.GetBufferSize().Dimensions();
636638
// clang-format off
637639
RETURN_HR_IF(E_INVALIDARG, (position.X >= coordScreenBufferSize.X ||
638640
position.Y >= coordScreenBufferSize.Y ||
@@ -643,15 +645,15 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
643645
// MSFT: 15813316 - Try to use this SetCursorPosition call to inherit the cursor position.
644646
RETURN_IF_FAILED(gci.GetVtIo()->SetCursorPosition(position));
645647

646-
RETURN_IF_NTSTATUS_FAILED(context.SetCursorPosition(position, true));
648+
RETURN_IF_NTSTATUS_FAILED(buffer.SetCursorPosition(position, true));
647649

648650
LOG_IF_FAILED(ConsoleImeResizeCompStrView());
649651

650652
COORD WindowOrigin;
651653
WindowOrigin.X = 0;
652654
WindowOrigin.Y = 0;
653655
{
654-
const SMALL_RECT currentViewport = context.GetViewport().ToInclusive();
656+
const SMALL_RECT currentViewport = buffer.GetViewport().ToInclusive();
655657
if (currentViewport.Left > position.X)
656658
{
657659
WindowOrigin.X = position.X - currentViewport.Left;
@@ -671,7 +673,7 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
671673
}
672674
}
673675

674-
RETURN_IF_NTSTATUS_FAILED(context.SetViewportOrigin(false, WindowOrigin, true));
676+
RETURN_IF_NTSTATUS_FAILED(buffer.SetViewportOrigin(false, WindowOrigin, true));
675677

676678
return S_OK;
677679
}
@@ -820,6 +822,8 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
820822
LockConsole();
821823
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
822824

825+
auto& buffer = context.GetActiveBuffer();
826+
823827
TextAttribute useThisAttr(fillAttribute);
824828

825829
// Here we're being a little clever - similar to FillConsoleOutputAttributeImpl
@@ -835,18 +839,19 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
835839
// this scenario is highly unlikely, and we can reasonably do this
836840
// on their behalf.
837841
// see MSFT:19853701
838-
if (context.InVTMode())
842+
843+
if (buffer.InVTMode())
839844
{
840845
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
841-
const auto currentAttributes = context.GetAttributes();
846+
const auto currentAttributes = buffer.GetAttributes();
842847
const auto bufferLegacy = gci.GenerateLegacyAttributes(currentAttributes);
843848
if (bufferLegacy == fillAttribute)
844849
{
845850
useThisAttr = currentAttributes;
846851
}
847852
}
848853

849-
ScrollRegion(context, source, clip, target, fillCharacter, useThisAttr);
854+
ScrollRegion(buffer, source, clip, target, fillCharacter, useThisAttr);
850855

851856
return S_OK;
852857
}

src/host/ut_host/ScreenBufferTests.cpp

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ class ScreenBufferTests
178178
TEST_METHOD(HardResetBuffer);
179179

180180
TEST_METHOD(RestoreDownAltBufferWithTerminalScrolling);
181+
182+
TEST_METHOD(ClearAlternateBuffer);
181183
};
182184

183185
void ScreenBufferTests::SingleAlternateBufferCreationTest()
@@ -4219,6 +4221,8 @@ void ScreenBufferTests::RestoreDownAltBufferWithTerminalScrolling()
42194221
VERIFY_ARE_EQUAL(0, altBuffer._viewport.Top());
42204222
VERIFY_ARE_EQUAL(altBuffer._viewport.BottomInclusive(), altBuffer._virtualBottom);
42214223

4224+
auto useMain = wil::scope_exit([&] { altBuffer.UseMainScreenBuffer(); });
4225+
42224226
const COORD originalSize = originalView.Dimensions();
42234227
const COORD doubledSize = { originalSize.X * 2, originalSize.Y * 2 };
42244228

@@ -4255,3 +4259,91 @@ void ScreenBufferTests::RestoreDownAltBufferWithTerminalScrolling()
42554259
VERIFY_ARE_EQUAL(altBuffer._viewport.BottomInclusive(), altBuffer._virtualBottom);
42564260
}
42574261
}
4262+
4263+
void ScreenBufferTests::ClearAlternateBuffer()
4264+
{
4265+
// This is a test for microsoft/terminal#1189. Refer to that issue for more
4266+
// context
4267+
4268+
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
4269+
auto& g = ServiceLocator::LocateGlobals();
4270+
gci.LockConsole(); // Lock must be taken to manipulate buffer.
4271+
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
4272+
4273+
auto& siMain = gci.GetActiveOutputBuffer();
4274+
auto WriteText = [&](TextBuffer& tbi) {
4275+
// Write text to buffer
4276+
auto& stateMachine = siMain.GetStateMachine();
4277+
auto& cursor = tbi.GetCursor();
4278+
stateMachine.ProcessString(L"foo\nfoo");
4279+
VERIFY_ARE_EQUAL(cursor.GetPosition().X, 3);
4280+
VERIFY_ARE_EQUAL(cursor.GetPosition().Y, 1);
4281+
};
4282+
4283+
auto VerifyText = [&](TextBuffer& tbi) {
4284+
// Verify written text in buffer
4285+
{
4286+
auto iter00 = tbi.GetCellDataAt({ 0, 0 });
4287+
auto iter10 = tbi.GetCellDataAt({ 1, 0 });
4288+
auto iter20 = tbi.GetCellDataAt({ 2, 0 });
4289+
auto iter30 = tbi.GetCellDataAt({ 3, 0 });
4290+
auto iter01 = tbi.GetCellDataAt({ 0, 1 });
4291+
auto iter02 = tbi.GetCellDataAt({ 1, 1 });
4292+
auto iter03 = tbi.GetCellDataAt({ 2, 1 });
4293+
VERIFY_ARE_EQUAL(L"f", iter00->Chars());
4294+
VERIFY_ARE_EQUAL(L"o", iter10->Chars());
4295+
VERIFY_ARE_EQUAL(L"o", iter20->Chars());
4296+
VERIFY_ARE_EQUAL(L"\x20", iter30->Chars());
4297+
VERIFY_ARE_EQUAL(L"f", iter01->Chars());
4298+
VERIFY_ARE_EQUAL(L"o", iter02->Chars());
4299+
VERIFY_ARE_EQUAL(L"o", iter03->Chars());
4300+
}
4301+
};
4302+
4303+
WriteText(siMain.GetTextBuffer());
4304+
VerifyText(siMain.GetTextBuffer());
4305+
4306+
Log::Comment(L"Create an alternate buffer");
4307+
if (VERIFY_IS_TRUE(NT_SUCCESS(siMain.UseAlternateScreenBuffer())))
4308+
{
4309+
VERIFY_IS_NOT_NULL(siMain._psiAlternateBuffer);
4310+
auto& altBuffer = *siMain._psiAlternateBuffer;
4311+
VERIFY_ARE_EQUAL(0, altBuffer._viewport.Top());
4312+
VERIFY_ARE_EQUAL(altBuffer._viewport.BottomInclusive(), altBuffer._virtualBottom);
4313+
4314+
auto useMain = wil::scope_exit([&] { altBuffer.UseMainScreenBuffer(); });
4315+
4316+
WriteText(altBuffer.GetTextBuffer());
4317+
VerifyText(altBuffer.GetTextBuffer());
4318+
4319+
#pragma region Test ScrollConsoleScreenBufferWImpl()
4320+
// Clear text of alt buffer (same params as in CMD)
4321+
VERIFY_SUCCEEDED(g.api.ScrollConsoleScreenBufferWImpl(siMain,
4322+
{ 0, 0, 120, 9001 },
4323+
{ 0, -9001 },
4324+
std::nullopt,
4325+
L' ',
4326+
7));
4327+
4328+
// Verify text is now gone
4329+
VERIFY_ARE_EQUAL(L" ", altBuffer.GetTextBuffer().GetCellDataAt({ 0, 0 })->Chars());
4330+
#pragma endregion
4331+
4332+
#pragma region Test SetConsoleCursorPositionImpl()
4333+
// Reset cursor position as we do with CLS command (same params as in CMD)
4334+
VERIFY_SUCCEEDED(g.api.SetConsoleCursorPositionImpl(siMain, { 0 }));
4335+
4336+
// Verify state of alt buffer
4337+
auto& altBufferCursor = altBuffer.GetTextBuffer().GetCursor();
4338+
VERIFY_ARE_EQUAL(altBufferCursor.GetPosition().X, 0);
4339+
VERIFY_ARE_EQUAL(altBufferCursor.GetPosition().Y, 0);
4340+
#pragma endregion
4341+
}
4342+
4343+
// Verify state of main buffer is untouched
4344+
auto& cursor = siMain.GetTextBuffer().GetCursor();
4345+
VERIFY_ARE_EQUAL(cursor.GetPosition().X, 3);
4346+
VERIFY_ARE_EQUAL(cursor.GetPosition().Y, 1);
4347+
4348+
VerifyText(siMain.GetTextBuffer());
4349+
}

0 commit comments

Comments
 (0)