diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 9bf2da143f2..26f36e22fac 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -381,6 +381,18 @@ void Terminal::_WriteBuffer(const std::wstring_view& stringView) } } + // If we're about to try to place the cursor past the right edge of the buffer, move it down a row + // This is another patch that GH#780 should supersede. This is really correcting for other bad situations + // like bisecting (writing only the leading half because there's no room for the trailing) a wide character + // into the buffer. However, it's not really all-up correctable without implementing a full WriteStream here. + // Also, this particular code RIGHT HERE shouldn't need to know anything about the cursor or the cells advanced + // which also will be solved by GH#780 (hopefully). + if (proposedCursorPosition.X > bufferSize.RightInclusive()) + { + proposedCursorPosition.X = 0; + proposedCursorPosition.Y++; + } + // If we're about to scroll past the bottom of the buffer, instead cycle the buffer. const auto newRows = proposedCursorPosition.Y - bufferSize.Height() + 1; if (newRows > 0) diff --git a/src/cascadia/UnitTests_TerminalCore/TerminalApiTests.cpp b/src/cascadia/UnitTests_TerminalCore/TerminalApiTests.cpp new file mode 100644 index 00000000000..0a39d5652e3 --- /dev/null +++ b/src/cascadia/UnitTests_TerminalCore/TerminalApiTests.cpp @@ -0,0 +1,92 @@ +/* +* Copyright (c) Microsoft Corporation. +* Licensed under the MIT license. +*/ +#include "precomp.h" +#include + +#include "../cascadia/TerminalCore/Terminal.hpp" +#include "../cascadia/UnitTests_TerminalCore/MockTermSettings.h" +#include "../renderer/inc/DummyRenderTarget.hpp" +#include "consoletaeftemplates.hpp" + +using namespace WEX::Logging; +using namespace WEX::TestExecution; + +using namespace Microsoft::Terminal::Core; +using namespace winrt::Microsoft::Terminal::Settings; + +namespace TerminalCoreUnitTests +{ + class TerminalApiTests + { + TEST_CLASS(TerminalApiTests); + + struct Baton + { + HANDLE ev; + std::wstring text; + Terminal* pTerm; + }; + + TEST_METHOD(PrintStringOfEmojiBisectingFinalColumn) + { + Terminal term; + DummyRenderTarget emptyRT; + term.Create({ 100, 100 }, 0, emptyRT); + + std::wstring textToPrint; + textToPrint.push_back(L'A'); // A is half-width, push it in. + + // Put a ton of copies of a full-width emoji here. + const wchar_t* emoji = L"\xD83D\xDE00"; // 1F600 is wide in https://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt + for (size_t i = 0; i < 120; ++i) + { + textToPrint = textToPrint.append(emoji); + } + + Baton b; + b.ev = CreateEventW(nullptr, TRUE, FALSE, L"It is an event"); + b.text = textToPrint; + b.pTerm = &term; + + Log::Comment(L"Launching thread to write data."); + + HANDLE hThread = CreateThread( + nullptr, 0, [](LPVOID c) -> DWORD { + Baton& b = *reinterpret_cast(c); + Log::Comment(L"Writing data."); + b.pTerm->PrintString(b.text); + Log::Comment(L"Setting event."); + SetEvent(b.ev); + return 0; + }, + (LPVOID)&b, + 0, + nullptr); + + Log::Comment(L"Waiting for the write."); + switch (WaitForSingleObject(b.ev, 2000)) + { + case WAIT_OBJECT_0: + Log::Comment(L"Didn't get stuck. Success."); + break; + case WAIT_TIMEOUT: + Log::Comment(L"Wait timed out. It got stuck."); + Log::Result(WEX::Logging::TestResults::Failed); + break; + case WAIT_FAILED: + Log::Comment(L"Wait failed for some reason. We didn't expect this."); + Log::Result(WEX::Logging::TestResults::Failed); + break; + default: + Log::Comment(L"Wait return code that no one expected. Fail."); + Log::Result(WEX::Logging::TestResults::Failed); + break; + } + + TerminateThread(hThread, 0); + return; + } + }; +} diff --git a/src/cascadia/UnitTests_TerminalCore/UnitTests.vcxproj b/src/cascadia/UnitTests_TerminalCore/UnitTests.vcxproj index af44b123721..6872fccc206 100644 --- a/src/cascadia/UnitTests_TerminalCore/UnitTests.vcxproj +++ b/src/cascadia/UnitTests_TerminalCore/UnitTests.vcxproj @@ -9,6 +9,7 @@ Create + @@ -51,4 +52,4 @@ - + \ No newline at end of file