mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 17:53:06 -06:00
Fix wide char support for WriteConsoleOutputAttribute (#18796)
When we overwrite the attributes during the fill, we must retain the lead/trail byte attributes. Closes #18746 ## Validation Steps Performed * Added a unit test ✅
This commit is contained in:
parent
6682bed311
commit
90c312f7da
@ -110,15 +110,25 @@ static FillConsoleResult FillConsoleImpl(SCREEN_INFORMATION& screenInfo, FillCon
|
||||
switch (mode)
|
||||
{
|
||||
case FillConsoleMode::WriteAttribute:
|
||||
{
|
||||
for (; columns < columnsAvailable && inputPos < lengthToWrite; ++columns, ++inputPos)
|
||||
{
|
||||
infoBuffer[columns].Attributes = input[inputPos];
|
||||
// Overwrite all attributes except for the lead/trail byte markers.
|
||||
// Those are used by WriteConsoleOutputWImplHelper to correctly serialize the input.
|
||||
constexpr auto LT = COMMON_LVB_LEADING_BYTE | COMMON_LVB_TRAILING_BYTE;
|
||||
auto& attributes = infoBuffer[columns].Attributes;
|
||||
attributes = (input[inputPos] & ~LT) | (attributes & LT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FillConsoleMode::FillAttribute:
|
||||
for (const auto attr = input[0]; columns < columnsAvailable && inputPos < lengthToWrite; ++columns, ++inputPos)
|
||||
{
|
||||
infoBuffer[columns].Attributes = attr;
|
||||
// Overwrite all attributes except for the lead/trail byte markers.
|
||||
// Those are used by WriteConsoleOutputWImplHelper to correctly serialize the input.
|
||||
constexpr auto LT = COMMON_LVB_LEADING_BYTE | COMMON_LVB_TRAILING_BYTE;
|
||||
auto& attributes = infoBuffer[columns].Attributes;
|
||||
attributes = (attr & ~LT) | (attributes & LT);
|
||||
}
|
||||
break;
|
||||
case FillConsoleMode::WriteCharacter:
|
||||
|
||||
@ -52,6 +52,16 @@ static constexpr std::wstring_view s_initialContentVT{
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
static constexpr std::wstring_view s_initialContentVTWide{
|
||||
// clang-format off
|
||||
L""
|
||||
sgr_red("〇") sgr_blu("一") sgr_red("二") sgr_blu("三") "\r\n"
|
||||
sgr_red("四") sgr_blu("五") sgr_red("六") sgr_blu("七") "\r\n"
|
||||
sgr_blu("八") sgr_red("九") sgr_blu("十") sgr_red("百") "\r\n"
|
||||
sgr_blu("千") sgr_red("万") sgr_blu("億") sgr_red("兆")
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
class ::Microsoft::Console::VirtualTerminal::VtIoTests
|
||||
{
|
||||
BEGIN_TEST_CLASS(VtIoTests)
|
||||
@ -71,11 +81,11 @@ class ::Microsoft::Console::VirtualTerminal::VtIoTests
|
||||
return { &rxBuf[0], read };
|
||||
}
|
||||
|
||||
void setupInitialContents() const
|
||||
void setupInitialContents(bool wide) const
|
||||
{
|
||||
auto& sm = screenInfo->GetStateMachine();
|
||||
sm.ProcessString(L"\033c");
|
||||
sm.ProcessString(s_initialContentVT);
|
||||
sm.ProcessString(wide ? s_initialContentVTWide : s_initialContentVT);
|
||||
sm.ProcessString(L"\x1b[H" sgr_rst());
|
||||
}
|
||||
|
||||
@ -277,7 +287,7 @@ class ::Microsoft::Console::VirtualTerminal::VtIoTests
|
||||
|
||||
TEST_METHOD(WriteConsoleOutputAttribute)
|
||||
{
|
||||
setupInitialContents();
|
||||
setupInitialContents(false);
|
||||
|
||||
static constexpr std::array payload{ red, blu, red, blu };
|
||||
static constexpr til::point target{ 6, 1 };
|
||||
@ -295,7 +305,7 @@ class ::Microsoft::Console::VirtualTerminal::VtIoTests
|
||||
|
||||
TEST_METHOD(WriteConsoleOutputCharacterW)
|
||||
{
|
||||
setupInitialContents();
|
||||
setupInitialContents(false);
|
||||
|
||||
size_t written = 0;
|
||||
std::string_view expected;
|
||||
@ -354,7 +364,7 @@ class ::Microsoft::Console::VirtualTerminal::VtIoTests
|
||||
actual = readOutput();
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
|
||||
setupInitialContents();
|
||||
setupInitialContents(false);
|
||||
|
||||
// Writing at the start of a line.
|
||||
THROW_IF_FAILED(routines.FillConsoleOutputAttributeImpl(*screenInfo, red, 3, { 0, 0 }, cellsModified, false));
|
||||
@ -388,6 +398,25 @@ class ::Microsoft::Console::VirtualTerminal::VtIoTests
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(FillConsoleOutputAttributeWide)
|
||||
{
|
||||
setupInitialContents(true);
|
||||
|
||||
size_t cellsModified = 0;
|
||||
std::string_view expected;
|
||||
std::string_view actual;
|
||||
|
||||
// Writing nothing should produce nothing.
|
||||
THROW_IF_FAILED(routines.FillConsoleOutputAttributeImpl(*screenInfo, red, 4, { 2, 1 }, cellsModified, false));
|
||||
expected =
|
||||
decsc() //
|
||||
cup(2, 3) sgr_red("五六") //
|
||||
decrc();
|
||||
actual = readOutput();
|
||||
VERIFY_ARE_EQUAL(4u, cellsModified);
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(FillConsoleOutputCharacterW)
|
||||
{
|
||||
size_t cellsModified = 0;
|
||||
@ -407,7 +436,7 @@ class ::Microsoft::Console::VirtualTerminal::VtIoTests
|
||||
actual = readOutput();
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
|
||||
setupInitialContents();
|
||||
setupInitialContents(false);
|
||||
|
||||
// Writing at the start of a line.
|
||||
THROW_IF_FAILED(routines.FillConsoleOutputCharacterWImpl(*screenInfo, L'a', 3, { 0, 0 }, cellsModified, false));
|
||||
@ -453,7 +482,7 @@ class ::Microsoft::Console::VirtualTerminal::VtIoTests
|
||||
std::string_view expected;
|
||||
std::string_view actual;
|
||||
|
||||
setupInitialContents();
|
||||
setupInitialContents(false);
|
||||
|
||||
// Scrolling from nowhere to somewhere are no-ops and should not emit anything.
|
||||
THROW_IF_FAILED(routines.ScrollConsoleScreenBufferWImpl(*screenInfo, { 0, 0, -1, -1 }, {}, std::nullopt, L' ', 0, false));
|
||||
@ -487,7 +516,7 @@ class ::Microsoft::Console::VirtualTerminal::VtIoTests
|
||||
//
|
||||
// m n M N o p O P
|
||||
//
|
||||
setupInitialContents();
|
||||
setupInitialContents(false);
|
||||
|
||||
// Scrolling from somewhere to somewhere.
|
||||
//
|
||||
@ -626,7 +655,7 @@ class ::Microsoft::Console::VirtualTerminal::VtIoTests
|
||||
std::string_view expected;
|
||||
std::string_view actual;
|
||||
|
||||
setupInitialContents();
|
||||
setupInitialContents(false);
|
||||
|
||||
// Scrolling from nowhere to somewhere are no-ops and should not emit anything.
|
||||
THROW_IF_FAILED(routines.ScrollConsoleScreenBufferWImpl(*screenInfo, { 0, 0, -1, -1 }, {}, std::nullopt, L' ', 0, false));
|
||||
@ -660,7 +689,7 @@ class ::Microsoft::Console::VirtualTerminal::VtIoTests
|
||||
//
|
||||
// m n M N o p O P
|
||||
//
|
||||
setupInitialContents();
|
||||
setupInitialContents(false);
|
||||
|
||||
// Scrolling from somewhere to somewhere.
|
||||
//
|
||||
@ -797,7 +826,7 @@ class ::Microsoft::Console::VirtualTerminal::VtIoTests
|
||||
&screenInfoAlt));
|
||||
|
||||
routines.SetConsoleActiveScreenBufferImpl(*screenInfoAlt);
|
||||
setupInitialContents();
|
||||
setupInitialContents(false);
|
||||
THROW_IF_FAILED(routines.SetConsoleOutputModeImpl(*screenInfoAlt, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING));
|
||||
readOutput();
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user