Skip to content

Commit

Permalink
Add a system message to session restore (#17113)
Browse files Browse the repository at this point in the history
This adds a system message which displays the time at which the
buffer snapshot was written to disk.

Additionally, this PR moves the snapshot loading into a background
thread, so that the UI thread is unblocked and that multiple
tabs/panes can load simultaneously.

Closes #17031
Closes #17074

## Validation Steps Performed
Repeatedly closing and opening WT adds more and more messages.
Currently, the messages get somewhat corrupted due to a bug
in our line-wrap handling, or some similar part.
  • Loading branch information
lhecker committed Apr 24, 2024
1 parent 19f43f7 commit 0c3c747
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 7 deletions.
1 change: 1 addition & 0 deletions .github/actions/spelling/expect/expect.txt
Expand Up @@ -1718,6 +1718,7 @@ sysparams
sysparamsext
SYSTEMHAND
SYSTEMMENU
SYSTEMTIME
tabview
TAdd
taef
Expand Down
46 changes: 43 additions & 3 deletions src/cascadia/TerminalControl/ControlCore.cpp
Expand Up @@ -1777,6 +1777,38 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return;
}

FILETIME lastWriteTime;
SYSTEMTIME lastWriteSystemTime;
if (!GetFileTime(file.get(), nullptr, nullptr, &lastWriteTime) ||
!FileTimeToSystemTime(&lastWriteTime, &lastWriteSystemTime))
{
return;
}

wchar_t dateBuf[256];
const auto dateLen = GetDateFormatEx(nullptr, 0, &lastWriteSystemTime, nullptr, &dateBuf[0], ARRAYSIZE(dateBuf), nullptr);
wchar_t timeBuf[256];
const auto timeLen = GetTimeFormatEx(nullptr, 0, &lastWriteSystemTime, nullptr, &timeBuf[0], ARRAYSIZE(timeBuf));

std::wstring message;
if (dateLen > 0 && timeLen > 0)
{
const auto msg = RS_(L"SessionRestoreMessage");
const std::wstring_view date{ &dateBuf[0], gsl::narrow_cast<size_t>(dateLen) };
const std::wstring_view time{ &timeBuf[0], gsl::narrow_cast<size_t>(timeLen) };
// This escape sequence string
// * sets the color to white on a bright black background ("\x1b[100;37m")
// * prints " [Restored <date> <time>] <spaces until end of line> "
// * resets the color ("\x1b[m")
// * newlines
// * clears the screen ("\x1b[2J")
// The last step is necessary because we launch ConPTY without PSEUDOCONSOLE_INHERIT_CURSOR by default.
// This will cause ConPTY to emit a \x1b[2J sequence on startup to ensure it and the terminal are in-sync.
// If we didn't do a \x1b[2J ourselves as well, the user would briefly see the last state of the terminal,
// before it's quickly scrolled away once ConPTY has finished starting up, which looks weird.
message = fmt::format(FMT_COMPILE(L"\x1b[100;37m [{} {} {}]\x1b[K\x1b[m\r\n\x1b[2J"), msg, date, time);
}

wchar_t buffer[32 * 1024];
DWORD read = 0;

Expand All @@ -1802,9 +1834,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}

// This pushes the restored contents up into the scrollback.
const auto lock = _terminal->LockForWriting();
_terminal->Write(L"\x1b[2J");
{
const auto lock = _terminal->LockForWriting();

// Normally the cursor should already be at the start of the line, but let's be absolutely sure it is.
if (_terminal->GetCursorPosition().x != 0)
{
_terminal->Write(L"\r\n");
}

_terminal->Write(message);
}
}

void ControlCore::_rendererWarning(const HRESULT hr, wil::zwstring_view parameter)
Expand Down
4 changes: 4 additions & 0 deletions src/cascadia/TerminalControl/Resources/en-US/Resources.resw
Expand Up @@ -296,4 +296,8 @@ Please either install the missing font or choose another one.</value>
<value>Select output</value>
<comment>The tooltip for a button for selecting all of a command's output</comment>
</data>
<data name="SessionRestoreMessage" xml:space="preserve">
<value>Restored</value>
<comment>"Restored" as in "This content was restored"</comment>
</data>
</root>
47 changes: 43 additions & 4 deletions src/cascadia/TerminalControl/TermControl.cpp
Expand Up @@ -1187,11 +1187,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation

if (!_restorePath.empty())
{
winrt::get_self<ControlCore>(_core)->RestoreFromPath(_restorePath.c_str());
_restorePath = {};
_restoreInBackground();
}
else
{
_core.Connection().Start();
}

_core.Connection().Start();
}
else
{
Expand Down Expand Up @@ -1278,6 +1279,44 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return true;
}

winrt::fire_and_forget TermControl::_restoreInBackground()
{
const auto path = std::exchange(_restorePath, {});
const auto weakSelf = get_weak();
winrt::apartment_context uiThread;

try
{
co_await winrt::resume_background();

const auto self = weakSelf.get();
if (!self)
{
co_return;
}

winrt::get_self<ControlCore>(_core)->RestoreFromPath(path.c_str());
}
CATCH_LOG();

try
{
co_await uiThread;

const auto self = weakSelf.get();
if (!self)
{
co_return;
}

if (const auto connection = _core.Connection())
{
connection.Start();
}
}
CATCH_LOG();
}

void TermControl::_CharacterHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const Input::CharacterReceivedRoutedEventArgs& e)
{
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalControl/TermControl.h
Expand Up @@ -319,6 +319,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
Reattach
};
bool _InitializeTerminal(const InitializeReason reason);
winrt::fire_and_forget _restoreInBackground();
void _SetFontSize(int fontSize);
void _TappedHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& e);
void _KeyDownHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::KeyRoutedEventArgs& e);
Expand Down

0 comments on commit 0c3c747

Please sign in to comment.