2019-05-03 00:29:04 +02:00
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
|
|
// Licensed under the MIT license.
|
|
|
|
|
|
|
|
#include "precomp.h"
|
|
|
|
#include <wextestclass.h>
|
|
|
|
#include "../../inc/consoletaeftemplates.hpp"
|
|
|
|
#include "../../types/inc/Viewport.hpp"
|
|
|
|
|
|
|
|
#include "../../renderer/vt/Xterm256Engine.hpp"
|
|
|
|
#include "../../renderer/vt/XtermEngine.hpp"
|
|
|
|
#include "../../renderer/vt/WinTelnetEngine.hpp"
|
|
|
|
#include "../Settings.hpp"
|
|
|
|
|
|
|
|
using namespace WEX::Common;
|
|
|
|
using namespace WEX::Logging;
|
|
|
|
using namespace WEX::TestExecution;
|
|
|
|
|
|
|
|
namespace Microsoft
|
|
|
|
{
|
|
|
|
namespace Console
|
|
|
|
{
|
|
|
|
namespace Render
|
|
|
|
{
|
|
|
|
class VtRendererTest;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
using namespace Microsoft::Console;
|
|
|
|
using namespace Microsoft::Console::Render;
|
|
|
|
using namespace Microsoft::Console::Types;
|
|
|
|
|
|
|
|
COLORREF g_ColorTable[COLOR_TABLE_SIZE];
|
|
|
|
static const std::string CLEAR_SCREEN = "\x1b[2J";
|
|
|
|
static const std::string CURSOR_HOME = "\x1b[H";
|
|
|
|
// Sometimes when we're expecting the renderengine to not write anything,
|
|
|
|
// we'll add this to the expected input, and manually write this to the callback
|
|
|
|
// to make sure nothing else gets written.
|
|
|
|
// We don't use null because that will confuse the VERIFY macros re: string length.
|
|
|
|
const char* const EMPTY_CALLBACK_SENTINEL = "\xff";
|
|
|
|
|
|
|
|
class VtRenderTestColorProvider : public Microsoft::Console::IDefaultColorProvider
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
virtual ~VtRenderTestColorProvider() = default;
|
|
|
|
|
|
|
|
COLORREF GetDefaultForeground() const
|
|
|
|
{
|
|
|
|
return g_ColorTable[15];
|
|
|
|
}
|
|
|
|
COLORREF GetDefaultBackground() const
|
|
|
|
{
|
|
|
|
return g_ColorTable[0];
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
VtRenderTestColorProvider p;
|
|
|
|
|
|
|
|
class Microsoft::Console::Render::VtRendererTest
|
|
|
|
{
|
|
|
|
TEST_CLASS(VtRendererTest);
|
|
|
|
|
2019-09-21 00:43:11 +02:00
|
|
|
wil::shared_event _shutdownEvent;
|
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
TEST_CLASS_SETUP(ClassSetup)
|
|
|
|
{
|
2019-06-11 22:27:09 +02:00
|
|
|
// clang-format off
|
2019-05-03 00:29:04 +02:00
|
|
|
g_ColorTable[0] = RGB( 12, 12, 12); // Black
|
|
|
|
g_ColorTable[1] = RGB( 0, 55, 218); // Dark Blue
|
|
|
|
g_ColorTable[2] = RGB( 19, 161, 14); // Dark Green
|
|
|
|
g_ColorTable[3] = RGB( 58, 150, 221); // Dark Cyan
|
|
|
|
g_ColorTable[4] = RGB(197, 15, 31); // Dark Red
|
|
|
|
g_ColorTable[5] = RGB(136, 23, 152); // Dark Magenta
|
|
|
|
g_ColorTable[6] = RGB(193, 156, 0); // Dark Yellow
|
|
|
|
g_ColorTable[7] = RGB(204, 204, 204); // Dark White
|
|
|
|
g_ColorTable[8] = RGB(118, 118, 118); // Bright Black
|
|
|
|
g_ColorTable[9] = RGB( 59, 120, 255); // Bright Blue
|
|
|
|
g_ColorTable[10] = RGB( 22, 198, 12); // Bright Green
|
|
|
|
g_ColorTable[11] = RGB( 97, 214, 214); // Bright Cyan
|
|
|
|
g_ColorTable[12] = RGB(231, 72, 86); // Bright Red
|
|
|
|
g_ColorTable[13] = RGB(180, 0, 158); // Bright Magenta
|
|
|
|
g_ColorTable[14] = RGB(249, 241, 165); // Bright Yellow
|
|
|
|
g_ColorTable[15] = RGB(242, 242, 242); // White
|
2019-06-11 22:27:09 +02:00
|
|
|
// clang-format on
|
2019-09-21 00:43:11 +02:00
|
|
|
|
|
|
|
_shutdownEvent.create(wil::EventOptions::ManualReset);
|
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CLASS_CLEANUP(ClassCleanup)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-09-21 00:43:11 +02:00
|
|
|
TEST_METHOD_SETUP(MethodSetup)
|
|
|
|
{
|
|
|
|
_shutdownEvent.ResetEvent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
// Defining a TEST_METHOD_CLEANUP seemed to break x86 test pass. Not sure why,
|
|
|
|
// something about the clipboard tests and
|
|
|
|
// YOU_CAN_ONLY_DESIGNATE_ONE_CLASS_METHOD_TO_BE_A_TEST_METHOD_SETUP_METHOD
|
|
|
|
// It's probably more correct to leave it out anyways.
|
|
|
|
|
|
|
|
TEST_METHOD(VtSequenceHelperTests);
|
|
|
|
|
|
|
|
TEST_METHOD(Xterm256TestInvalidate);
|
|
|
|
TEST_METHOD(Xterm256TestColors);
|
|
|
|
TEST_METHOD(Xterm256TestCursor);
|
|
|
|
|
|
|
|
TEST_METHOD(XtermTestInvalidate);
|
|
|
|
TEST_METHOD(XtermTestColors);
|
|
|
|
TEST_METHOD(XtermTestCursor);
|
|
|
|
|
|
|
|
TEST_METHOD(WinTelnetTestInvalidate);
|
|
|
|
TEST_METHOD(WinTelnetTestColors);
|
|
|
|
TEST_METHOD(WinTelnetTestCursor);
|
|
|
|
|
|
|
|
TEST_METHOD(TestWrapping);
|
|
|
|
|
|
|
|
TEST_METHOD(TestResize);
|
|
|
|
|
2019-10-03 01:11:27 +02:00
|
|
|
TEST_METHOD(TestCursorVisibility);
|
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
void Test16Colors(VtEngine* engine);
|
|
|
|
|
|
|
|
std::deque<std::string> qExpectedInput;
|
|
|
|
bool WriteCallback(const char* const pch, size_t const cch);
|
|
|
|
void TestPaint(VtEngine& engine, std::function<void()> pfn);
|
|
|
|
Viewport SetUpViewport();
|
|
|
|
};
|
|
|
|
|
|
|
|
Viewport VtRendererTest::SetUpViewport()
|
|
|
|
{
|
|
|
|
SMALL_RECT view = {};
|
|
|
|
view.Top = view.Left = 0;
|
|
|
|
view.Bottom = 31;
|
|
|
|
view.Right = 79;
|
|
|
|
|
|
|
|
return Viewport::FromInclusive(view);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VtRendererTest::WriteCallback(const char* const pch, size_t const cch)
|
|
|
|
{
|
|
|
|
std::string actualString = std::string(pch, cch);
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_IS_GREATER_THAN(qExpectedInput.size(),
|
|
|
|
static_cast<size_t>(0),
|
2019-05-03 00:29:04 +02:00
|
|
|
NoThrowString().Format(L"writing=\"%hs\", expecting %u strings", actualString.c_str(), qExpectedInput.size()));
|
|
|
|
|
|
|
|
std::string first = qExpectedInput.front();
|
|
|
|
qExpectedInput.pop_front();
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(L"Expected =\t\"%hs\"", first.c_str()));
|
|
|
|
Log::Comment(NoThrowString().Format(L"Actual =\t\"%hs\"", actualString.c_str()));
|
|
|
|
|
|
|
|
VERIFY_ARE_EQUAL(first.length(), cch);
|
|
|
|
VERIFY_ARE_EQUAL(first, actualString);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Function Description:
|
|
|
|
// - Small helper to do a series of testing wrapped by StartPaint/EndPaint calls
|
|
|
|
// Arguments:
|
|
|
|
// - engine: the engine to operate on
|
|
|
|
// - pfn: A function pointer to some test code to run.
|
|
|
|
// Return Value:
|
|
|
|
// - <none>
|
|
|
|
void VtRendererTest::TestPaint(VtEngine& engine, std::function<void()> pfn)
|
|
|
|
{
|
|
|
|
VERIFY_SUCCEEDED(engine.StartPaint());
|
|
|
|
pfn();
|
|
|
|
VERIFY_SUCCEEDED(engine.EndPaint());
|
|
|
|
}
|
|
|
|
|
|
|
|
void VtRendererTest::VtSequenceHelperTests()
|
|
|
|
{
|
|
|
|
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
|
2019-09-21 00:43:11 +02:00
|
|
|
std::unique_ptr<Xterm256Engine> engine = std::make_unique<Xterm256Engine>(std::move(hFile), _shutdownEvent, p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
|
2019-05-03 00:29:04 +02:00
|
|
|
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
|
|
|
|
|
|
|
|
engine->SetTestCallback(pfn);
|
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[?12l");
|
|
|
|
VERIFY_SUCCEEDED(engine->_StopCursorBlinking());
|
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[?12h");
|
|
|
|
VERIFY_SUCCEEDED(engine->_StartCursorBlinking());
|
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[?25l");
|
|
|
|
VERIFY_SUCCEEDED(engine->_HideCursor());
|
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[?25h");
|
|
|
|
VERIFY_SUCCEEDED(engine->_ShowCursor());
|
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[K");
|
|
|
|
VERIFY_SUCCEEDED(engine->_EraseLine());
|
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[M");
|
|
|
|
VERIFY_SUCCEEDED(engine->_DeleteLine(1));
|
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[2M");
|
|
|
|
VERIFY_SUCCEEDED(engine->_DeleteLine(2));
|
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[L");
|
|
|
|
VERIFY_SUCCEEDED(engine->_InsertLine(1));
|
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[2L");
|
|
|
|
VERIFY_SUCCEEDED(engine->_InsertLine(2));
|
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[2X");
|
|
|
|
VERIFY_SUCCEEDED(engine->_EraseCharacter(2));
|
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[2;3H");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_CursorPosition({ 2, 1 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[1;1H");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_CursorPosition({ 0, 0 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[H");
|
|
|
|
VERIFY_SUCCEEDED(engine->_CursorHome());
|
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[8;32;80t");
|
|
|
|
VERIFY_SUCCEEDED(engine->_ResizeWindow(80, 32));
|
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[2J");
|
|
|
|
VERIFY_SUCCEEDED(engine->_ClearScreen());
|
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[10C");
|
|
|
|
VERIFY_SUCCEEDED(engine->_CursorForward(10));
|
|
|
|
}
|
|
|
|
|
|
|
|
void VtRendererTest::Xterm256TestInvalidate()
|
|
|
|
{
|
|
|
|
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
|
2019-09-21 00:43:11 +02:00
|
|
|
std::unique_ptr<Xterm256Engine> engine = std::make_unique<Xterm256Engine>(std::move(hFile), _shutdownEvent, p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
|
2019-05-03 00:29:04 +02:00
|
|
|
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
|
|
|
|
engine->SetTestCallback(pfn);
|
|
|
|
|
|
|
|
// Verify the first paint emits a clear and go home
|
|
|
|
qExpectedInput.push_back("\x1b[2J");
|
|
|
|
VERIFY_IS_TRUE(engine->_firstPaint);
|
|
|
|
TestPaint(*engine, [&]() {
|
|
|
|
VERIFY_IS_FALSE(engine->_firstPaint);
|
|
|
|
});
|
|
|
|
|
|
|
|
Viewport view = SetUpViewport();
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Make sure that invalidating all invalidates the whole viewport."));
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateAll());
|
|
|
|
qExpectedInput.push_back("\x1b[2J");
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_ARE_EQUAL(view, engine->_invalidRect);
|
|
|
|
});
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Make sure that invalidating anything only invalidates that portion"));
|
|
|
|
SMALL_RECT invalid = { 1, 1, 1, 1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->Invalidate(&invalid));
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_ARE_EQUAL(invalid, engine->_invalidRect.ToExclusive());
|
|
|
|
});
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Make sure that scrolling only invalidates part of the viewport, and sends the right sequences"));
|
|
|
|
COORD scrollDelta = { 0, 1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
2019-10-03 01:11:27 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"---- Scrolled one down, only top line is invalid. ----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
invalid = view.ToExclusive();
|
|
|
|
invalid.Bottom = 1;
|
|
|
|
|
|
|
|
VERIFY_ARE_EQUAL(invalid, engine->_invalidRect.ToExclusive());
|
|
|
|
qExpectedInput.push_back("\x1b[H"); // Go Home
|
|
|
|
qExpectedInput.push_back("\x1b[L"); // insert a line
|
|
|
|
|
|
|
|
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
|
|
|
});
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
scrollDelta = { 0, 3 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
|
|
|
|
2019-10-03 01:11:27 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"---- Scrolled three down, only top 3 lines are invalid. ----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
invalid = view.ToExclusive();
|
|
|
|
invalid.Bottom = 3;
|
|
|
|
|
|
|
|
VERIFY_ARE_EQUAL(invalid, engine->_invalidRect.ToExclusive());
|
|
|
|
// We would expect a CUP here, but the cursor is already at the home position
|
|
|
|
qExpectedInput.push_back("\x1b[3L"); // insert 3 lines
|
|
|
|
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
|
|
|
});
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
scrollDelta = { 0, -1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
2019-10-03 01:11:27 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"---- Scrolled one up, only bottom line is invalid. ----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
invalid = view.ToExclusive();
|
|
|
|
invalid.Top = invalid.Bottom - 1;
|
|
|
|
|
|
|
|
VERIFY_ARE_EQUAL(invalid, engine->_invalidRect.ToExclusive());
|
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[32;1H"); // Bottom of buffer
|
|
|
|
qExpectedInput.push_back("\n"); // Scroll down once
|
|
|
|
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
|
|
|
});
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
scrollDelta = { 0, -3 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
2019-10-03 01:11:27 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"---- Scrolled three up, only bottom 3 lines are invalid. ----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
invalid = view.ToExclusive();
|
|
|
|
invalid.Top = invalid.Bottom - 3;
|
|
|
|
|
|
|
|
VERIFY_ARE_EQUAL(invalid, engine->_invalidRect.ToExclusive());
|
|
|
|
|
|
|
|
// We would expect a CUP here, but we're already at the bottom from the last call.
|
|
|
|
qExpectedInput.push_back("\n\n\n"); // Scroll down three times
|
|
|
|
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
|
|
|
});
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Multiple scrolls are coalesced"));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
scrollDelta = { 0, 1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
2019-06-11 22:27:09 +02:00
|
|
|
scrollDelta = { 0, 2 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
2019-10-03 01:11:27 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"---- Scrolled three down, only top 3 lines are invalid. ----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
invalid = view.ToExclusive();
|
|
|
|
invalid.Bottom = 3;
|
|
|
|
|
|
|
|
VERIFY_ARE_EQUAL(invalid, engine->_invalidRect.ToExclusive());
|
|
|
|
qExpectedInput.push_back("\x1b[H"); // Go to home
|
|
|
|
qExpectedInput.push_back("\x1b[3L"); // insert 3 lines
|
|
|
|
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
|
|
|
});
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
scrollDelta = { 0, 1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
VerifyOutputTraits<SMALL_RECT>::ToString(engine->_invalidRect.ToExclusive())));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
scrollDelta = { 0, -1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
VerifyOutputTraits<SMALL_RECT>::ToString(engine->_invalidRect.ToExclusive())));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[2J");
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
|
|
|
L"---- Scrolled one down and one up, nothing should change ----"
|
2019-06-11 22:27:09 +02:00
|
|
|
L" But it still does for now MSFT:14169294"));
|
2019-05-03 00:29:04 +02:00
|
|
|
invalid = view.ToExclusive();
|
|
|
|
VERIFY_ARE_EQUAL(invalid, engine->_invalidRect.ToExclusive());
|
|
|
|
|
|
|
|
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void VtRendererTest::Xterm256TestColors()
|
|
|
|
{
|
|
|
|
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
|
2019-09-21 00:43:11 +02:00
|
|
|
std::unique_ptr<Xterm256Engine> engine = std::make_unique<Xterm256Engine>(std::move(hFile), _shutdownEvent, p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
|
2019-05-03 00:29:04 +02:00
|
|
|
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
|
|
|
|
engine->SetTestCallback(pfn);
|
|
|
|
|
|
|
|
// Verify the first paint emits a clear and go home
|
|
|
|
qExpectedInput.push_back("\x1b[2J");
|
|
|
|
VERIFY_IS_TRUE(engine->_firstPaint);
|
|
|
|
TestPaint(*engine, [&]() {
|
|
|
|
VERIFY_IS_FALSE(engine->_firstPaint);
|
|
|
|
});
|
|
|
|
|
|
|
|
Viewport view = SetUpViewport();
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Test changing the text attributes"));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
|
|
|
L"Begin by setting some test values - FG,BG = (1,2,3), (4,5,6) to start"
|
2019-06-11 22:27:09 +02:00
|
|
|
L"These values were picked for ease of formatting raw COLORREF values."));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[38;2;1;2;3m");
|
|
|
|
qExpectedInput.push_back("\x1b[48;2;5;6;7m");
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(0x00030201,
|
|
|
|
0x00070605,
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Change only the BG----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[48;2;7;8;9m");
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(0x00030201,
|
|
|
|
0x00090807,
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Change only the FG----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[38;2;10;11;12m");
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(0x000c0b0a,
|
|
|
|
0x00090807,
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
});
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Make sure that color setting persists across EndPaint/StartPaint"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(0x000c0b0a,
|
|
|
|
0x00090807,
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback
|
|
|
|
});
|
|
|
|
|
|
|
|
// Now also do the body of the 16color test as well.
|
|
|
|
// The only change is that the "Change only the BG to something not in the table"
|
|
|
|
// test actually uses an RGB value instead of the closest match.
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Begin by setting the default colors - FG,BG = BRIGHT_WHITE,DARK_BLACK"));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[m");
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
|
|
|
g_ColorTable[0],
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Change only the BG----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[41m"); // Background DARK_RED
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
|
|
|
g_ColorTable[4],
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Change only the FG----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[37m"); // Foreground DARK_WHITE
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7],
|
|
|
|
g_ColorTable[4],
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Change only the BG to something not in the table----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[48;2;1;1;1m"); // Background DARK_BLACK
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7],
|
|
|
|
0x010101,
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Change only the BG to the 'Default' background----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[49m"); // Background DARK_BLACK
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7],
|
|
|
|
g_ColorTable[0],
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Back to defaults----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[m");
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
|
|
|
g_ColorTable[0],
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
});
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Make sure that color setting persists across EndPaint/StartPaint"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
|
|
|
g_ColorTable[0],
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void VtRendererTest::Xterm256TestCursor()
|
|
|
|
{
|
|
|
|
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
|
2019-09-21 00:43:11 +02:00
|
|
|
std::unique_ptr<Xterm256Engine> engine = std::make_unique<Xterm256Engine>(std::move(hFile), _shutdownEvent, p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
|
2019-05-03 00:29:04 +02:00
|
|
|
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
|
|
|
|
engine->SetTestCallback(pfn);
|
|
|
|
|
|
|
|
// Verify the first paint emits a clear and go home
|
|
|
|
qExpectedInput.push_back("\x1b[2J");
|
|
|
|
VERIFY_IS_TRUE(engine->_firstPaint);
|
|
|
|
TestPaint(*engine, [&]() {
|
|
|
|
VERIFY_IS_FALSE(engine->_firstPaint);
|
|
|
|
});
|
|
|
|
|
|
|
|
Viewport view = SetUpViewport();
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Test moving the cursor around. Every sequence should have both params to CUP explicitly."));
|
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[2;2H");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 1, 1 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Only move Y coord----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[31;2H");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 1, 30 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Only move X coord----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[29C");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 30, 30 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Sending the same move sends nothing----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 30, 30 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1);
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----moving home sends a simple sequence----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[H");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 0, 0 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----move into the line to test some other sequences----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[7C");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 7, 0 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----move down one line (x stays the same)----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\n");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 7, 1 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----move to the start of the next line----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\r\n");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 0, 2 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----move into the line to test some other sequnces----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[2;8H");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 7, 1 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----move to the start of this line (y stays the same)----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\r");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 0, 1 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
});
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
|
|
|
L"Sending the same move across paint calls sends nothing."
|
2019-06-11 22:27:09 +02:00
|
|
|
L"The cursor's last \"real\" position was 0,0"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 0, 1 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1);
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Paint some text at 0,0, then try moving the cursor to where it currently is."));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[1C");
|
|
|
|
qExpectedInput.push_back("asdfghjkl");
|
|
|
|
|
|
|
|
const wchar_t* const line = L"asdfghjkl";
|
2019-06-11 22:27:09 +02:00
|
|
|
const unsigned char rgWidths[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
std::vector<Cluster> clusters;
|
|
|
|
for (size_t i = 0; i < wcslen(line); i++)
|
|
|
|
{
|
|
|
|
clusters.emplace_back(std::wstring_view{ &line[i], 1 }, static_cast<size_t>(rgWidths[i]));
|
|
|
|
}
|
|
|
|
|
|
|
|
VERIFY_SUCCEEDED(engine->PaintBufferLine({ clusters.data(), clusters.size() }, { 1, 1 }, false));
|
|
|
|
|
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 10, 1 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Note that only PaintBufferLine updates the "Real" cursor position, which
|
|
|
|
// the cursor is moved back to at the end of each paint
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Sending the same move across paint calls sends nothing."));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 10, 1 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void VtRendererTest::XtermTestInvalidate()
|
|
|
|
{
|
|
|
|
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
|
2019-09-21 00:43:11 +02:00
|
|
|
std::unique_ptr<XtermEngine> engine = std::make_unique<XtermEngine>(std::move(hFile), _shutdownEvent, p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE), false);
|
2019-05-03 00:29:04 +02:00
|
|
|
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
|
|
|
|
engine->SetTestCallback(pfn);
|
|
|
|
|
|
|
|
// Verify the first paint emits a clear and go home
|
|
|
|
qExpectedInput.push_back("\x1b[2J");
|
|
|
|
VERIFY_IS_TRUE(engine->_firstPaint);
|
|
|
|
TestPaint(*engine, [&]() {
|
|
|
|
VERIFY_IS_FALSE(engine->_firstPaint);
|
|
|
|
});
|
|
|
|
|
|
|
|
Viewport view = SetUpViewport();
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Make sure that invalidating all invalidates the whole viewport."));
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateAll());
|
|
|
|
qExpectedInput.push_back("\x1b[2J");
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_ARE_EQUAL(view, engine->_invalidRect);
|
|
|
|
});
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Make sure that invalidating anything only invalidates that portion"));
|
|
|
|
SMALL_RECT invalid = { 1, 1, 1, 1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->Invalidate(&invalid));
|
2019-10-03 01:11:27 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_ARE_EQUAL(invalid, engine->_invalidRect.ToExclusive());
|
|
|
|
});
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Make sure that scrolling only invalidates part of the viewport, and sends the right sequences"));
|
|
|
|
COORD scrollDelta = { 0, 1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
2019-10-03 01:11:27 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"---- Scrolled one down, only top line is invalid. ----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
invalid = view.ToExclusive();
|
|
|
|
invalid.Bottom = 1;
|
|
|
|
|
|
|
|
VERIFY_ARE_EQUAL(invalid, engine->_invalidRect.ToExclusive());
|
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[H"); // Go Home
|
|
|
|
qExpectedInput.push_back("\x1b[L"); // insert a line
|
|
|
|
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
|
|
|
});
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
scrollDelta = { 0, 3 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
2019-10-03 01:11:27 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"---- Scrolled three down, only top 3 lines are invalid. ----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
invalid = view.ToExclusive();
|
|
|
|
invalid.Bottom = 3;
|
|
|
|
|
|
|
|
VERIFY_ARE_EQUAL(invalid, engine->_invalidRect.ToExclusive());
|
|
|
|
// We would expect a CUP here, but the cursor is already at the home position
|
|
|
|
qExpectedInput.push_back("\x1b[3L"); // insert 3 lines
|
|
|
|
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
|
|
|
});
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
scrollDelta = { 0, -1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
2019-10-03 01:11:27 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"---- Scrolled one up, only bottom line is invalid. ----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
invalid = view.ToExclusive();
|
|
|
|
invalid.Top = invalid.Bottom - 1;
|
|
|
|
|
|
|
|
VERIFY_ARE_EQUAL(invalid, engine->_invalidRect.ToExclusive());
|
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[32;1H"); // Bottom of buffer
|
|
|
|
qExpectedInput.push_back("\n"); // Scroll down once
|
|
|
|
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
|
|
|
});
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
scrollDelta = { 0, -3 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
2019-10-03 01:11:27 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"---- Scrolled three up, only bottom 3 lines are invalid. ----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
invalid = view.ToExclusive();
|
|
|
|
invalid.Top = invalid.Bottom - 3;
|
|
|
|
|
|
|
|
VERIFY_ARE_EQUAL(invalid, engine->_invalidRect.ToExclusive());
|
|
|
|
|
|
|
|
// We would expect a CUP here, but we're already at the bottom from the last call.
|
|
|
|
qExpectedInput.push_back("\n\n\n"); // Scroll down three times
|
|
|
|
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
|
|
|
});
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Multiple scrolls are coalesced"));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
scrollDelta = { 0, 1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
2019-06-11 22:27:09 +02:00
|
|
|
scrollDelta = { 0, 2 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
2019-10-03 01:11:27 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"---- Scrolled three down, only top 3 lines are invalid. ----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
invalid = view.ToExclusive();
|
|
|
|
invalid.Bottom = 3;
|
|
|
|
|
|
|
|
VERIFY_ARE_EQUAL(invalid, engine->_invalidRect.ToExclusive());
|
|
|
|
qExpectedInput.push_back("\x1b[H"); // Go to home
|
|
|
|
qExpectedInput.push_back("\x1b[3L"); // insert 3 lines
|
|
|
|
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
|
|
|
});
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
scrollDelta = { 0, 1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
VerifyOutputTraits<SMALL_RECT>::ToString(engine->_invalidRect.ToExclusive())));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
scrollDelta = { 0, -1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
VerifyOutputTraits<SMALL_RECT>::ToString(engine->_invalidRect.ToExclusive())));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[2J");
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
|
|
|
L"---- Scrolled one down and one up, nothing should change ----"
|
2019-06-11 22:27:09 +02:00
|
|
|
L" But it still does for now MSFT:14169294"));
|
2019-05-03 00:29:04 +02:00
|
|
|
invalid = view.ToExclusive();
|
|
|
|
VERIFY_ARE_EQUAL(view, engine->_invalidRect);
|
|
|
|
|
|
|
|
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void VtRendererTest::XtermTestColors()
|
|
|
|
{
|
|
|
|
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
|
2019-09-21 00:43:11 +02:00
|
|
|
std::unique_ptr<XtermEngine> engine = std::make_unique<XtermEngine>(std::move(hFile), _shutdownEvent, p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE), false);
|
2019-05-03 00:29:04 +02:00
|
|
|
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
|
|
|
|
engine->SetTestCallback(pfn);
|
|
|
|
|
|
|
|
// Verify the first paint emits a clear and go home
|
|
|
|
qExpectedInput.push_back("\x1b[2J");
|
|
|
|
VERIFY_IS_TRUE(engine->_firstPaint);
|
|
|
|
TestPaint(*engine, [&]() {
|
|
|
|
VERIFY_IS_FALSE(engine->_firstPaint);
|
|
|
|
});
|
|
|
|
|
|
|
|
Viewport view = SetUpViewport();
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Test changing the text attributes"));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Begin by setting the default colors - FG,BG = BRIGHT_WHITE,DARK_BLACK"));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[m");
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
|
|
|
g_ColorTable[0],
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Change only the BG----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[41m"); // Background DARK_RED
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
|
|
|
g_ColorTable[4],
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Change only the FG----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[37m"); // Foreground DARK_WHITE
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7],
|
|
|
|
g_ColorTable[4],
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Change only the BG to something not in the table----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[40m"); // Background DARK_BLACK
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7], 0x010101, 0, ExtendedAttributes::Normal, false));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Change only the BG to the 'Default' background----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[40m"); // Background DARK_BLACK
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7],
|
|
|
|
g_ColorTable[0],
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Back to defaults----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[m");
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
|
|
|
g_ColorTable[0],
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
});
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Make sure that color setting persists across EndPaint/StartPaint"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
|
|
|
g_ColorTable[0],
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void VtRendererTest::XtermTestCursor()
|
|
|
|
{
|
|
|
|
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
|
2019-09-21 00:43:11 +02:00
|
|
|
std::unique_ptr<XtermEngine> engine = std::make_unique<XtermEngine>(std::move(hFile), _shutdownEvent, p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE), false);
|
2019-05-03 00:29:04 +02:00
|
|
|
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
|
|
|
|
engine->SetTestCallback(pfn);
|
|
|
|
|
|
|
|
// Verify the first paint emits a clear and go home
|
|
|
|
qExpectedInput.push_back("\x1b[2J");
|
|
|
|
VERIFY_IS_TRUE(engine->_firstPaint);
|
|
|
|
TestPaint(*engine, [&]() {
|
|
|
|
VERIFY_IS_FALSE(engine->_firstPaint);
|
|
|
|
});
|
|
|
|
|
|
|
|
Viewport view = SetUpViewport();
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Test moving the cursor around. Every sequence should have both params to CUP explicitly."));
|
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[2;2H");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 1, 1 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Only move Y coord----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[31;2H");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 1, 30 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Only move X coord----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[29C");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 30, 30 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Sending the same move sends nothing----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 30, 30 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1);
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----moving home sends a simple sequence----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[H");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 0, 0 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----move into the line to test some other sequences----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[7C");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 7, 0 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----move down one line (x stays the same)----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\n");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 7, 1 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----move to the start of the next line----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\r\n");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 0, 2 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----move into the line to test some other sequnces----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[2;8H");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 7, 1 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----move to the start of this line (y stays the same)----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\r");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 0, 1 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
});
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
|
|
|
L"Sending the same move across paint calls sends nothing."
|
2019-06-11 22:27:09 +02:00
|
|
|
L"The cursor's last \"real\" position was 0,0"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 0, 1 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1);
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Paint some text at 0,0, then try moving the cursor to where it currently is."));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[1C");
|
|
|
|
qExpectedInput.push_back("asdfghjkl");
|
|
|
|
|
|
|
|
const wchar_t* const line = L"asdfghjkl";
|
2019-06-11 22:27:09 +02:00
|
|
|
const unsigned char rgWidths[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
std::vector<Cluster> clusters;
|
|
|
|
for (size_t i = 0; i < wcslen(line); i++)
|
|
|
|
{
|
|
|
|
clusters.emplace_back(std::wstring_view{ &line[i], 1 }, static_cast<size_t>(rgWidths[i]));
|
|
|
|
}
|
|
|
|
|
|
|
|
VERIFY_SUCCEEDED(engine->PaintBufferLine({ clusters.data(), clusters.size() }, { 1, 1 }, false));
|
|
|
|
|
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 10, 1 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Note that only PaintBufferLine updates the "Real" cursor position, which
|
|
|
|
// the cursor is moved back to at the end of each paint
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Sending the same move across paint calls sends nothing."));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 10, 1 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void VtRendererTest::WinTelnetTestInvalidate()
|
|
|
|
{
|
|
|
|
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
|
2019-09-21 00:43:11 +02:00
|
|
|
std::unique_ptr<WinTelnetEngine> engine = std::make_unique<WinTelnetEngine>(std::move(hFile), _shutdownEvent, p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
|
2019-05-03 00:29:04 +02:00
|
|
|
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
|
|
|
|
engine->SetTestCallback(pfn);
|
|
|
|
|
|
|
|
Viewport view = SetUpViewport();
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Make sure that invalidating all invalidates the whole viewport."));
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateAll());
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_ARE_EQUAL(view, engine->_invalidRect);
|
|
|
|
});
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Make sure that invalidating anything only invalidates that portion"));
|
|
|
|
SMALL_RECT invalid = { 1, 1, 1, 1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->Invalidate(&invalid));
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_ARE_EQUAL(invalid, engine->_invalidRect.ToExclusive());
|
|
|
|
});
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Make sure that scrolling invalidates the whole viewport, and sends no VT sequences"));
|
|
|
|
COORD scrollDelta = { 0, 1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_ARE_EQUAL(view, engine->_invalidRect);
|
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL); // sentinel
|
|
|
|
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback
|
|
|
|
});
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
scrollDelta = { 0, -1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_ARE_EQUAL(view, engine->_invalidRect);
|
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
|
|
|
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback
|
|
|
|
});
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
scrollDelta = { 1, 0 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_ARE_EQUAL(view, engine->_invalidRect);
|
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
|
|
|
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback
|
|
|
|
});
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
scrollDelta = { -1, 0 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_ARE_EQUAL(view, engine->_invalidRect);
|
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
|
|
|
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback
|
|
|
|
});
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
scrollDelta = { 1, -1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->InvalidateScroll(&scrollDelta));
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_ARE_EQUAL(view, engine->_invalidRect);
|
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
|
|
|
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void VtRendererTest::WinTelnetTestColors()
|
|
|
|
{
|
|
|
|
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
|
2019-09-21 00:43:11 +02:00
|
|
|
std::unique_ptr<WinTelnetEngine> engine = std::make_unique<WinTelnetEngine>(std::move(hFile), _shutdownEvent, p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
|
2019-05-03 00:29:04 +02:00
|
|
|
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
|
|
|
|
engine->SetTestCallback(pfn);
|
|
|
|
|
|
|
|
Viewport view = SetUpViewport();
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Test changing the text attributes"));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Begin by setting the default colors - FG,BG = BRIGHT_WHITE,DARK_BLACK"));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[m");
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
|
|
|
g_ColorTable[0],
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Change only the BG----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[41m"); // Background DARK_RED
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
|
|
|
g_ColorTable[4],
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Change only the FG----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[37m"); // Foreground DARK_WHITE
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7],
|
|
|
|
g_ColorTable[4],
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Change only the BG to something not in the table----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[40m"); // Background DARK_BLACK
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7], 0x010101, 0, ExtendedAttributes::Normal, false));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Change only the BG to the 'Default' background----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[40m"); // Background DARK_BLACK
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[7],
|
|
|
|
g_ColorTable[0],
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Back to defaults----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[m");
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
|
|
|
g_ColorTable[0],
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
});
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Make sure that color setting persists across EndPaint/StartPaint"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.
We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.
Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.
## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.
## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
<hr>
* store text with extended attributes too
* Plumb attributes through all the renderers
* parse extended attrs, though we're not renderering them right
* Render these states correctly
* Add a very extensive test
* Cleanup for PR
* a block of PR feedback
* add 512 test cases
* Fix the build
* Fix @carlos-zamora's suggestions
* @miniksa's PR feedback
2019-10-04 22:53:54 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(g_ColorTable[15],
|
|
|
|
g_ColorTable[0],
|
|
|
|
0,
|
|
|
|
ExtendedAttributes::Normal,
|
|
|
|
false));
|
2019-05-03 00:29:04 +02:00
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void VtRendererTest::WinTelnetTestCursor()
|
|
|
|
{
|
|
|
|
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
|
2019-09-21 00:43:11 +02:00
|
|
|
std::unique_ptr<WinTelnetEngine> engine = std::make_unique<WinTelnetEngine>(std::move(hFile), _shutdownEvent, p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
|
2019-05-03 00:29:04 +02:00
|
|
|
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
|
|
|
|
engine->SetTestCallback(pfn);
|
|
|
|
|
|
|
|
Viewport view = SetUpViewport();
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Test moving the cursor around. Every sequence should have both params to CUP explicitly."));
|
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[2;2H");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 1, 1 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Only move X coord----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[31;2H");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 1, 30 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Only move Y coord----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[31;31H");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 30, 30 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"----Sending the same move sends nothing----"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 30, 30 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1);
|
|
|
|
|
|
|
|
// The "real" location is the last place the cursor was moved to not
|
|
|
|
// during the course of VT operations - eg the last place text was written,
|
|
|
|
// or the cursor was manually painted at (MSFT 13310327)
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Make sure the cursor gets moved back to the last real location it was at"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[1;1H");
|
|
|
|
// EndPaint will send this sequence for us.
|
|
|
|
});
|
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
|
|
|
L"Sending the same move across paint calls sends nothing."
|
2019-06-11 22:27:09 +02:00
|
|
|
L"The cursor's last \"real\" position was 0,0"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 0, 0 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1);
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Paint some text at 0,0, then try moving the cursor to where it currently is."));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[2;2H");
|
|
|
|
qExpectedInput.push_back("asdfghjkl");
|
|
|
|
|
|
|
|
const wchar_t* const line = L"asdfghjkl";
|
2019-06-11 22:27:09 +02:00
|
|
|
const unsigned char rgWidths[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
std::vector<Cluster> clusters;
|
|
|
|
for (size_t i = 0; i < wcslen(line); i++)
|
|
|
|
{
|
|
|
|
clusters.emplace_back(std::wstring_view{ &line[i], 1 }, static_cast<size_t>(rgWidths[i]));
|
|
|
|
}
|
|
|
|
|
|
|
|
VERIFY_SUCCEEDED(engine->PaintBufferLine({ clusters.data(), clusters.size() }, { 1, 1 }, false));
|
|
|
|
|
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 10, 1 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Note that only PaintBufferLine updates the "Real" cursor position, which
|
|
|
|
// the cursor is moved back to at the end of each paint
|
2019-06-11 22:27:09 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Sending the same move across paint calls sends nothing."));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 10, 1 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void VtRendererTest::TestWrapping()
|
|
|
|
{
|
|
|
|
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
|
2019-09-21 00:43:11 +02:00
|
|
|
std::unique_ptr<Xterm256Engine> engine = std::make_unique<Xterm256Engine>(std::move(hFile), _shutdownEvent, p, SetUpViewport(), g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
|
2019-05-03 00:29:04 +02:00
|
|
|
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
|
|
|
|
engine->SetTestCallback(pfn);
|
|
|
|
|
|
|
|
// Verify the first paint emits a clear and go home
|
|
|
|
qExpectedInput.push_back("\x1b[2J");
|
|
|
|
VERIFY_IS_TRUE(engine->_firstPaint);
|
|
|
|
TestPaint(*engine, [&]() {
|
|
|
|
VERIFY_IS_FALSE(engine->_firstPaint);
|
|
|
|
});
|
|
|
|
|
|
|
|
Viewport view = SetUpViewport();
|
|
|
|
|
2019-10-03 01:11:27 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
2019-06-11 22:27:09 +02:00
|
|
|
L"Make sure the cursor is at 0,0"));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[H");
|
2019-06-11 22:27:09 +02:00
|
|
|
VERIFY_SUCCEEDED(engine->_MoveCursor({ 0, 0 }));
|
2019-05-03 00:29:04 +02:00
|
|
|
});
|
|
|
|
|
2019-10-03 01:11:27 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
Log::Comment(NoThrowString().Format(
|
|
|
|
L"Painting a line that wrapped, then painting another line, and "
|
2019-06-11 22:27:09 +02:00
|
|
|
L"making sure we don't manually move the cursor between those paints."));
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("asdfghjkl");
|
|
|
|
// TODO: Undoing this behavior due to 18123777. Will come back in MSFT:16485846
|
|
|
|
qExpectedInput.push_back("\r\n");
|
|
|
|
qExpectedInput.push_back("zxcvbnm,.");
|
|
|
|
|
|
|
|
const wchar_t* const line1 = L"asdfghjkl";
|
|
|
|
const wchar_t* const line2 = L"zxcvbnm,.";
|
2019-06-11 22:27:09 +02:00
|
|
|
const unsigned char rgWidths[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
std::vector<Cluster> clusters1;
|
|
|
|
for (size_t i = 0; i < wcslen(line1); i++)
|
|
|
|
{
|
|
|
|
clusters1.emplace_back(std::wstring_view{ &line1[i], 1 }, static_cast<size_t>(rgWidths[i]));
|
|
|
|
}
|
|
|
|
std::vector<Cluster> clusters2;
|
|
|
|
for (size_t i = 0; i < wcslen(line2); i++)
|
|
|
|
{
|
|
|
|
clusters2.emplace_back(std::wstring_view{ &line2[i], 1 }, static_cast<size_t>(rgWidths[i]));
|
|
|
|
}
|
|
|
|
|
|
|
|
VERIFY_SUCCEEDED(engine->PaintBufferLine({ clusters1.data(), clusters1.size() }, { 0, 0 }, false));
|
|
|
|
VERIFY_SUCCEEDED(engine->PaintBufferLine({ clusters2.data(), clusters2.size() }, { 0, 1 }, false));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void VtRendererTest::TestResize()
|
|
|
|
{
|
|
|
|
Viewport view = SetUpViewport();
|
|
|
|
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
|
2019-09-21 00:43:11 +02:00
|
|
|
auto engine = std::make_unique<Xterm256Engine>(std::move(hFile), _shutdownEvent, p, view, g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
|
2019-05-03 00:29:04 +02:00
|
|
|
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
|
|
|
|
engine->SetTestCallback(pfn);
|
|
|
|
|
|
|
|
// Verify the first paint emits a clear and go home
|
|
|
|
qExpectedInput.push_back("\x1b[2J");
|
|
|
|
VERIFY_IS_TRUE(engine->_firstPaint);
|
|
|
|
VERIFY_IS_TRUE(engine->_suppressResizeRepaint);
|
|
|
|
|
|
|
|
// The renderer (in Renderer@_PaintFrameForEngine..._CheckViewportAndScroll)
|
|
|
|
// will manually call UpdateViewport once before actually painting the
|
|
|
|
// first frame. Replicate that behavior here
|
|
|
|
VERIFY_SUCCEEDED(engine->UpdateViewport(view.ToInclusive()));
|
|
|
|
|
|
|
|
TestPaint(*engine, [&]() {
|
|
|
|
VERIFY_IS_FALSE(engine->_firstPaint);
|
|
|
|
VERIFY_IS_FALSE(engine->_suppressResizeRepaint);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Resize the viewport to 120x30
|
|
|
|
// Everything should be invalidated, and a resize message sent.
|
2019-06-11 22:27:09 +02:00
|
|
|
const auto newView = Viewport::FromDimensions({ 0, 0 }, { 120, 30 });
|
2019-05-03 00:29:04 +02:00
|
|
|
qExpectedInput.push_back("\x1b[8;30;120t");
|
|
|
|
|
|
|
|
VERIFY_SUCCEEDED(engine->UpdateViewport(newView.ToInclusive()));
|
|
|
|
|
2019-10-03 01:11:27 +02:00
|
|
|
TestPaint(*engine, [&]() {
|
2019-05-03 00:29:04 +02:00
|
|
|
VERIFY_ARE_EQUAL(newView, engine->_invalidRect);
|
|
|
|
VERIFY_IS_FALSE(engine->_firstPaint);
|
|
|
|
VERIFY_IS_FALSE(engine->_suppressResizeRepaint);
|
|
|
|
});
|
|
|
|
}
|
2019-10-03 01:11:27 +02:00
|
|
|
|
|
|
|
void VtRendererTest::TestCursorVisibility()
|
|
|
|
{
|
|
|
|
Viewport view = SetUpViewport();
|
|
|
|
wil::unique_hfile hFile = wil::unique_hfile(INVALID_HANDLE_VALUE);
|
|
|
|
auto engine = std::make_unique<Xterm256Engine>(std::move(hFile), _shutdownEvent, p, view, g_ColorTable, static_cast<WORD>(COLOR_TABLE_SIZE));
|
|
|
|
auto pfn = std::bind(&VtRendererTest::WriteCallback, this, std::placeholders::_1, std::placeholders::_2);
|
|
|
|
engine->SetTestCallback(pfn);
|
|
|
|
|
|
|
|
// Verify the first paint emits a clear
|
|
|
|
qExpectedInput.push_back("\x1b[2J");
|
|
|
|
VERIFY_IS_TRUE(engine->_firstPaint);
|
|
|
|
VERIFY_IS_FALSE(engine->_lastCursorIsVisible);
|
|
|
|
VERIFY_IS_TRUE(engine->_nextCursorIsVisible);
|
|
|
|
TestPaint(*engine, [&]() {
|
|
|
|
// During StartPaint, we'll mark the cursor as off. make sure that happens.
|
|
|
|
VERIFY_IS_FALSE(engine->_nextCursorIsVisible);
|
|
|
|
VERIFY_IS_FALSE(engine->_firstPaint);
|
|
|
|
});
|
|
|
|
|
|
|
|
// The cursor wasn't painted in the last frame.
|
|
|
|
VERIFY_IS_FALSE(engine->_lastCursorIsVisible);
|
|
|
|
VERIFY_IS_FALSE(engine->_nextCursorIsVisible);
|
|
|
|
|
|
|
|
COORD origin{ 0, 0 };
|
|
|
|
|
|
|
|
VERIFY_ARE_NOT_EQUAL(origin, engine->_lastText);
|
|
|
|
|
|
|
|
IRenderEngine::CursorOptions options{};
|
|
|
|
options.coordCursor = origin;
|
|
|
|
|
|
|
|
// Frame 1: Paint the cursor at the home position. At the end of the frame,
|
|
|
|
// the cursor should be on. Because we're moving the cursor with CUP, we
|
|
|
|
// need to disable the cursor during this frame.
|
|
|
|
TestPaint(*engine, [&]() {
|
|
|
|
VERIFY_IS_FALSE(engine->_lastCursorIsVisible);
|
|
|
|
VERIFY_IS_FALSE(engine->_nextCursorIsVisible);
|
|
|
|
VERIFY_IS_FALSE(engine->_needToDisableCursor);
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(L"Make sure the cursor is at 0,0"));
|
|
|
|
qExpectedInput.push_back("\x1b[H");
|
|
|
|
VERIFY_SUCCEEDED(engine->PaintCursor(options));
|
|
|
|
|
|
|
|
VERIFY_IS_TRUE(engine->_nextCursorIsVisible);
|
|
|
|
VERIFY_IS_TRUE(engine->_needToDisableCursor);
|
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[?25h");
|
|
|
|
});
|
|
|
|
|
|
|
|
VERIFY_IS_TRUE(engine->_lastCursorIsVisible);
|
|
|
|
VERIFY_IS_TRUE(engine->_nextCursorIsVisible);
|
|
|
|
VERIFY_IS_FALSE(engine->_needToDisableCursor);
|
|
|
|
|
|
|
|
// Frame 2: Paint the cursor again at the home position. At the end of the
|
|
|
|
// frame, the cursor should be on, the same as before. We aren't moving the
|
|
|
|
// cursor during this frame, so _needToDisableCursor will stay false.
|
|
|
|
TestPaint(*engine, [&]() {
|
|
|
|
VERIFY_IS_TRUE(engine->_lastCursorIsVisible);
|
|
|
|
VERIFY_IS_FALSE(engine->_nextCursorIsVisible);
|
|
|
|
VERIFY_IS_FALSE(engine->_needToDisableCursor);
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(L"If we just paint the cursor again at the same position, the cursor should not need to be disabled"));
|
|
|
|
VERIFY_SUCCEEDED(engine->PaintCursor(options));
|
|
|
|
|
|
|
|
VERIFY_IS_TRUE(engine->_nextCursorIsVisible);
|
|
|
|
VERIFY_IS_FALSE(engine->_needToDisableCursor);
|
|
|
|
});
|
|
|
|
|
|
|
|
VERIFY_IS_TRUE(engine->_lastCursorIsVisible);
|
|
|
|
VERIFY_IS_TRUE(engine->_nextCursorIsVisible);
|
|
|
|
VERIFY_IS_FALSE(engine->_needToDisableCursor);
|
|
|
|
|
|
|
|
// Frame 3: Paint the cursor at 2,2. At the end of the frame, the cursor
|
|
|
|
// should be on, the same as before. Because we're moving the cursor with
|
|
|
|
// CUP, we need to disable the cursor during this frame.
|
|
|
|
TestPaint(*engine, [&]() {
|
|
|
|
VERIFY_IS_TRUE(engine->_lastCursorIsVisible);
|
|
|
|
VERIFY_IS_FALSE(engine->_nextCursorIsVisible);
|
|
|
|
VERIFY_IS_FALSE(engine->_needToDisableCursor);
|
|
|
|
|
|
|
|
Log::Comment(NoThrowString().Format(L"Move the cursor to 2,2"));
|
|
|
|
qExpectedInput.push_back("\x1b[3;3H");
|
|
|
|
|
|
|
|
options.coordCursor = { 2, 2 };
|
|
|
|
|
|
|
|
VERIFY_SUCCEEDED(engine->PaintCursor(options));
|
|
|
|
|
|
|
|
VERIFY_IS_TRUE(engine->_lastCursorIsVisible);
|
|
|
|
VERIFY_IS_TRUE(engine->_nextCursorIsVisible);
|
|
|
|
VERIFY_IS_TRUE(engine->_needToDisableCursor);
|
|
|
|
|
|
|
|
// Because _needToDisableCursor is true, we'll insert a ?25l at the
|
|
|
|
// start of the frame. Unfortunately, we can't test to make sure that
|
|
|
|
// it's there, but we can ensure that the matching ?25h is printed:
|
|
|
|
qExpectedInput.push_back("\x1b[?25h");
|
|
|
|
});
|
|
|
|
|
|
|
|
VERIFY_IS_TRUE(engine->_lastCursorIsVisible);
|
|
|
|
VERIFY_IS_TRUE(engine->_nextCursorIsVisible);
|
|
|
|
VERIFY_IS_FALSE(engine->_needToDisableCursor);
|
|
|
|
|
|
|
|
// Frame 4: Don't paint the cursor. At the end of the frame, the cursor
|
|
|
|
// should be off.
|
|
|
|
Log::Comment(NoThrowString().Format(L"Painting without calling PaintCursor will hide the cursor"));
|
|
|
|
TestPaint(*engine, [&]() {
|
|
|
|
VERIFY_IS_TRUE(engine->_lastCursorIsVisible);
|
|
|
|
VERIFY_IS_FALSE(engine->_nextCursorIsVisible);
|
|
|
|
VERIFY_IS_FALSE(engine->_needToDisableCursor);
|
|
|
|
|
|
|
|
qExpectedInput.push_back("\x1b[?25l");
|
|
|
|
});
|
|
|
|
|
|
|
|
VERIFY_IS_FALSE(engine->_lastCursorIsVisible);
|
|
|
|
VERIFY_IS_FALSE(engine->_nextCursorIsVisible);
|
|
|
|
VERIFY_IS_FALSE(engine->_needToDisableCursor);
|
|
|
|
}
|