Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Hard Reset for Terminal #4909

Merged
4 commits merged into from
Mar 16, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions src/cascadia/TerminalCore/TerminalDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,3 +401,100 @@ bool TerminalDispatch::_PrivateModeParamsHelper(const DispatchTypes::PrivateMode
}
return success;
}

bool TerminalDispatch::SoftReset() noexcept
{
// TODO:GH#1883 much of this method is not yet implemented in the Terminal,
// because the Terminal _doesn't need to_ yet. The terminal is only ever
// connected to conpty, so it doesn't implement most of these things that
// Hard/Soft Reset would reset. As those things ar implemented, they should
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
// also get cleared here.
//
// This code is left here (from its original form in conhost) as a reminder
// of what needs to be done.

bool success = CursorVisibility(true); // Cursor enabled.
// if (success)
// {
// success = SetOriginMode(false); // Absolute cursor addressing.
// }
// if (success)
// {
// success = SetAutoWrapMode(true); // Wrap at end of line.
// }
Comment on lines +418 to +425
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, i accept the reason for these comments

if (success)
{
success = SetCursorKeysMode(false); // Normal characters.
}
if (success)
{
success = SetKeypadMode(false); // Numeric characters.
}
// if (success)
// {
// // Top margin = 1; bottom margin = page length.
// success = _DoSetTopBottomScrollingMargins(0, 0);
// }
// if (success)
// {
// success = DesignateCharset(DispatchTypes::VTCharacterSets::USASCII); // Default Charset
// }
if (success)
{
const auto opt = DispatchTypes::GraphicsOptions::Off;
success = SetGraphicsRendition({ &opt, 1 }); // Normal rendition.
}
// if (success)
// {
// // Reset the saved cursor state.
// // Note that XTerm only resets the main buffer state, but that
// // seems likely to be a bug. Most other terminals reset both.
// _savedCursorState.at(0) = {}; // Main buffer
// _savedCursorState.at(1) = {}; // Alt buffer
// }

return success;
}

bool TerminalDispatch::HardReset() noexcept
{
// TODO:GH#1883 much of this method is not yet implemented in the Terminal,
// because the Terminal _doesn't need to_ yet. The terminal is only ever
// connected to conpty, so it doesn't implement most of these things that
// Hard/Soft Reset would reset. As those things ar implemented, they should
// also get cleared here.
//
// This code is left here (from its original form in conhost) as a reminder
// of what needs to be done.

// Sets the SGR state to normal - this must be done before EraseInDisplay
// to ensure that it clears with the default background color.
bool success = SoftReset();

// Clears the screen - Needs to be done in two operations.
if (success)
{
success = EraseInDisplay(DispatchTypes::EraseType::All);
}
if (success)
{
success = EraseInDisplay(DispatchTypes::EraseType::Scrollback);
}

// // Set the DECSCNM screen mode back to normal.
// if (success)
// {
// success = SetScreenMode(false);
// }

// Cursor to 1,1 - the Soft Reset guarantees this is absolute
if (success)
{
success = CursorPosition(1, 1);
}

// // delete all current tab stops and reapply
// _pConApi->PrivateSetDefaultTabStops();

return success;
}
3 changes: 3 additions & 0 deletions src/cascadia/TerminalCore/TerminalDispatch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ class TerminalDispatch : public Microsoft::Console::VirtualTerminal::TermDispatc
bool SetCursorKeysMode(const bool applicationMode) noexcept override; // DECCKM
bool SetKeypadMode(const bool applicationMode) noexcept override; // DECKPAM, DECKPNM

bool SoftReset() noexcept override; // DECSTR
bool HardReset() noexcept override; // RIS

bool EnableVT200MouseMode(const bool enabled) noexcept override; // ?1000
bool EnableUTF8ExtendedMouseMode(const bool enabled) noexcept override; // ?1005
bool EnableSGRExtendedMouseMode(const bool enabled) noexcept override; // ?1006
Expand Down
72 changes: 70 additions & 2 deletions src/cascadia/UnitTests_TerminalCore/ConptyRoundtripTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ class TerminalCoreUnitTests::ConptyRoundtripTests final

TEST_METHOD(PassthroughClearScrollback);

TEST_METHOD(PassthroughHardReset);

TEST_METHOD(PassthroughCursorShapeImmediately);

TEST_METHOD(TestWrappingALongString);
Expand Down Expand Up @@ -926,7 +928,7 @@ void ConptyRoundtripTests::PassthroughCursorShapeImmediately()
void ConptyRoundtripTests::PassthroughClearScrollback()
{
Log::Comment(NoThrowString().Format(
L"Write more lines of outout. We should use \r\n to move the cursor"));
L"Write more lines of output than there are lines in the viewport. Clear the scrollback with ^[[3J"));
VERIFY_IS_NOT_NULL(_pVtRenderEngine.get());

auto& g = ServiceLocator::LocateGlobals();
Expand Down Expand Up @@ -985,7 +987,7 @@ void ConptyRoundtripTests::PassthroughClearScrollback()
const auto termSecondView = term->GetViewport();
VERIFY_ARE_EQUAL(0, termSecondView.Top());

// Verify the top of the Terminal veiwoprt contains the contents of the old viewport
// Verify the top of the Terminal viewport contains the contents of the old viewport
for (short y = 0; y < termSecondView.BottomInclusive(); y++)
{
TestUtils::VerifyExpectedString(termTb, L"X ", { 0, y });
Expand All @@ -997,3 +999,69 @@ void ConptyRoundtripTests::PassthroughClearScrollback()
TestUtils::VerifyExpectedString(termTb, std::wstring(TerminalViewWidth, L' '), { 0, y });
}
}

void ConptyRoundtripTests::PassthroughHardReset()
{
// This test is highly similar to PassthroughClearScrollback.
Log::Comment(NoThrowString().Format(
L"Write more lines of output than there are lines in the viewport. Clear everything with ^[c"));
VERIFY_IS_NOT_NULL(_pVtRenderEngine.get());

auto& g = ServiceLocator::LocateGlobals();
auto& renderer = *g.pRender;
auto& gci = g.getConsoleInformation();
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();

auto& termTb = *term->_buffer;

_flushFirstFrame();

_logConpty = true;

const auto hostView = si.GetViewport();
const auto end = 2 * hostView.Height();
for (auto i = 0; i < end; i++)
{
Log::Comment(NoThrowString().Format(L"Writing line %d/%d", i, end));
expectedOutput.push_back("X");
if (i < hostView.BottomInclusive())
{
expectedOutput.push_back("\r\n");
}
else
{
// After we hit the bottom of the viewport, the newlines come in
// seperated for whatever reason.
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
expectedOutput.push_back("\r");
expectedOutput.push_back("\n");
expectedOutput.push_back("");
}

hostSm.ProcessString(L"X\n");

VERIFY_SUCCEEDED(renderer.PaintFrame());
}

VERIFY_SUCCEEDED(renderer.PaintFrame());

// Verify that we've printed height*2 lines of X's to the Terminal
const auto termFirstView = term->GetViewport();
for (short y = 0; y < 2 * termFirstView.Height(); y++)
{
TestUtils::VerifyExpectedString(termTb, L"X ", { 0, y });
}

// Write a Hard Reset VT sequence to the host, it should come through to the Terminal
expectedOutput.push_back("\033c");
hostSm.ProcessString(L"\033c");

const auto termSecondView = term->GetViewport();
VERIFY_ARE_EQUAL(0, termSecondView.Top());

// Verify everything has been cleared out
for (short y = 0; y < termFirstView.BottomInclusive(); y++)
{
TestUtils::VerifyExpectedString(termTb, std::wstring(TerminalViewWidth, L' '), { 0, y });
}
}
11 changes: 9 additions & 2 deletions src/terminal/adapter/adaptDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1461,6 +1461,9 @@ bool AdaptDispatch::DesignateCharset(const wchar_t wchCharset) noexcept
// True if handled successfully. False otherwise.
bool AdaptDispatch::SoftReset()
{
bool isPty = false;
_pConApi->IsConsolePty(isPty);

bool success = CursorVisibility(true); // Cursor enabled.
if (success)
{
Expand All @@ -1474,11 +1477,15 @@ bool AdaptDispatch::SoftReset()
{
success = SetCursorKeysMode(false); // Normal characters.
}
if (success)
// SetCursorKeysMode will return false if we're in conpty mode, as to
// trigger a passthrough. If that's the case, just power through here.
if (success || isPty)
{
success = SetKeypadMode(false); // Numeric characters.
}
if (success)
// SetKeypadMode will return false if we're in conpty mode, as to trigger a
// passthrough. If that's the case, just power through here.
if (success || isPty)
{
// Top margin = 1; bottom margin = page length.
success = _DoSetTopBottomScrollingMargins(0, 0);
Expand Down
7 changes: 7 additions & 0 deletions src/terminal/parser/OutputStateMachineEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,13 @@ bool OutputStateMachineEngine::ActionEscDispatch(const wchar_t wch,
}
}

// If we were unable to process the string, and there's a TTY attached to us,
// trigger the state machine to flush the string to the terminal.
if (_pfnFlushToTerminal != nullptr && !success)
{
success = _pfnFlushToTerminal();
}

_ClearLastChar();

return success;
Expand Down