Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions .github/actions/spelling/expect/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1138,6 +1138,7 @@ NOYIELD
NOZORDER
NPFS
nrcs
NRNW
NSTATUS
ntapi
ntdef
Expand Down
7 changes: 2 additions & 5 deletions src/buffer/out/textBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2628,11 +2628,8 @@ void TextBuffer::_AppendRTFText(std::string& contentBuilder, const std::wstring_
}
}

void TextBuffer::SerializeToPath(const wchar_t* destination) const
void TextBuffer::SerializeTo(HANDLE handle) const
{
const wil::unique_handle file{ CreateFileW(destination, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr) };
THROW_LAST_ERROR_IF(!file);

static constexpr size_t writeThreshold = 32 * 1024;
std::wstring buffer;
buffer.reserve(writeThreshold + writeThreshold / 2);
Expand Down Expand Up @@ -2661,7 +2658,7 @@ void TextBuffer::SerializeToPath(const wchar_t* destination) const
{
const auto fileSize = gsl::narrow<DWORD>(buffer.size() * sizeof(wchar_t));
DWORD bytesWritten = 0;
THROW_IF_WIN32_BOOL_FALSE(WriteFile(file.get(), buffer.data(), fileSize, &bytesWritten, nullptr));
THROW_IF_WIN32_BOOL_FALSE(WriteFile(handle, buffer.data(), fileSize, &bytesWritten, nullptr));
THROW_WIN32_IF_MSG(ERROR_WRITE_FAULT, bytesWritten != fileSize, "failed to write");
buffer.clear();
}
Expand Down
2 changes: 1 addition & 1 deletion src/buffer/out/textBuffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ class TextBuffer final
const bool isIntenseBold,
std::function<std::tuple<COLORREF, COLORREF, COLORREF>(const TextAttribute&)> GetAttributeColors) const noexcept;

void SerializeToPath(const wchar_t* destination) const;
void SerializeTo(HANDLE handle) const;

struct PositionInformation
{
Expand Down
21 changes: 0 additions & 21 deletions src/cascadia/CascadiaPackage/Package-Dev.appxmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -107,27 +107,6 @@
</uap3:Properties>
</uap3:AppExtension>
</uap3:Extension>
<com:Extension Category="windows.comInterface">
<com:ComInterface>
<com:ProxyStub Id="DEC4804D-56D1-4F73-9FBE-6828E7C85C56" DisplayName="OpenConsoleHandoffProxy" Path="OpenConsoleProxy.dll"/>
<com:Interface Id="E686C757-9A35-4A1C-B3CE-0BCC8B5C69F4" ProxyStubClsid="DEC4804D-56D1-4F73-9FBE-6828E7C85C56"/>
<com:Interface Id="6F23DA90-15C5-4203-9DB0-64E73F1B1B00" ProxyStubClsid="DEC4804D-56D1-4F73-9FBE-6828E7C85C56"/> <!-- ITerminalHandoff3 -->
<com:Interface Id="746E6BC0-AB05-4E38-AB14-71E86763141F" ProxyStubClsid="DEC4804D-56D1-4F73-9FBE-6828E7C85C56"/>
</com:ComInterface>
</com:Extension>
<com:Extension Category="windows.comServer">
<com:ComServer>
<com:ExeServer DisplayName="OpenConsole" Executable="OpenConsole.exe">
<com:Class Id="1F9F2BF5-5BC3-4F17-B0E6-912413F1F451"/>
</com:ExeServer>
<com:ExeServer DisplayName="WindowsTerminal" Executable="WindowsTerminal.exe">
<com:Class Id="051F34EE-C1FD-4B19-AF75-9BA54648434C"/>
</com:ExeServer>
<com:SurrogateServer DisplayName="WindowsTerminalShellExt">
<com:Class Id="52065414-e077-47ec-a3ac-1cc5455e1b54" Path="WindowsTerminalShellExt.dll" ThreadingModel="STA"/>
</com:SurrogateServer>
</com:ComServer>
</com:Extension>
Comment on lines -110 to -130
Copy link
Member

Choose a reason for hiding this comment

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

Why?

Copy link
Member Author

Choose a reason for hiding this comment

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

Woops. I keep this staged locally, because this makes it build & deploy with VS 2026 for me. I didn't intend to push this.

<desktop4:Extension Category="windows.fileExplorerContextMenus">
<desktop4:FileExplorerContextMenus>
<desktop5:ItemType Type="Directory">
Expand Down
3 changes: 1 addition & 2 deletions src/cascadia/TerminalApp/IPaneContent.idl
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ namespace TerminalApp
None,
Content,
MovePane,
PersistLayout,
PersistAll
Persist,
Copy link
Member

Choose a reason for hiding this comment

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

Don't we want to keep the distinction between PersistLayout and PersistAll? See #19341

};

runtimeclass BellEventArgs
Expand Down
34 changes: 30 additions & 4 deletions src/cascadia/TerminalApp/TerminalPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2218,7 +2218,7 @@ namespace winrt::TerminalApp::implementation
}
}

void TerminalPage::PersistState(bool serializeBuffer)
void TerminalPage::PersistState()
{
// This method may be called for a window even if it hasn't had a tab yet or lost all of them.
// We shouldn't persist such windows.
Expand All @@ -2233,7 +2233,7 @@ namespace winrt::TerminalApp::implementation
for (auto tab : _tabs)
{
auto t = winrt::get_self<implementation::Tab>(tab);
auto tabActions = t->BuildStartupActions(serializeBuffer ? BuildStartupKind::PersistAll : BuildStartupKind::PersistLayout);
auto tabActions = t->BuildStartupActions(BuildStartupKind::Persist);
actions.insert(actions.end(), std::make_move_iterator(tabActions.begin()), std::make_move_iterator(tabActions.end()));
}

Expand Down Expand Up @@ -2319,6 +2319,29 @@ namespace winrt::TerminalApp::implementation
CloseWindowRequested.raise(*this, nullptr);
}

std::vector<IPaneContent> TerminalPage::Panes() const
{
std::vector<IPaneContent> panes;

for (const auto tab : _tabs)
{
const auto impl = _GetTabImpl(tab);
if (!impl)
{
continue;
}

impl->GetRootPane()->WalkTree([&](auto&& pane) {
if (auto content = pane->GetContent())
{
panes.push_back(std::move(content));
}
});
}

return panes;
}

// Method Description:
// - Move the viewport of the terminal of the currently focused tab up or
// down a number of lines.
Expand Down Expand Up @@ -3527,9 +3550,12 @@ namespace winrt::TerminalApp::implementation

if (hasSessionId)
{
using namespace std::string_view_literals;

const auto settingsDir = CascadiaSettings::SettingsDirectory();
const auto idStr = Utils::GuidToPlainString(sessionId);
const auto path = fmt::format(FMT_COMPILE(L"{}\\buffer_{}.txt"), settingsDir, idStr);
const auto admin = IsRunningElevated();
const auto filenamePrefix = admin ? L"elevated_"sv : L"buffer_"sv;
const auto path = fmt::format(FMT_COMPILE(L"{}\\{}{}.txt"), settingsDir, filenamePrefix, sessionId);
control.RestoreFromPath(path);
}

Expand Down
3 changes: 2 additions & 1 deletion src/cascadia/TerminalApp/TerminalPage.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ namespace winrt::TerminalApp::implementation

safe_void_coroutine RequestQuit();
safe_void_coroutine CloseWindow();
void PersistState(bool serializeBuffer);
void PersistState();
std::vector<IPaneContent> Panes() const;

void ToggleFocusMode();
void ToggleFullscreen();
Expand Down
8 changes: 1 addition & 7 deletions src/cascadia/TerminalApp/TerminalPaneContent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,22 +140,16 @@ namespace winrt::TerminalApp::implementation
// "attach existing" rather than a "create"
args.ContentId(_control.ContentId());
break;
case BuildStartupKind::PersistAll:
case BuildStartupKind::Persist:
{
const auto connection = _control.Connection();
const auto id = connection ? connection.SessionId() : winrt::guid{};

if (id != winrt::guid{})
{
const auto settingsDir = CascadiaSettings::SettingsDirectory();
const auto idStr = ::Microsoft::Console::Utils::GuidToPlainString(id);
const auto path = fmt::format(FMT_COMPILE(L"{}\\buffer_{}.txt"), settingsDir, idStr);
_control.PersistToPath(path);
args.SessionId(id);
}
break;
}
case BuildStartupKind::PersistLayout:
Copy link
Member

Choose a reason for hiding this comment

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

Seems like we'd want to keep the branches separate

default:
break;
}
Expand Down
9 changes: 7 additions & 2 deletions src/cascadia/TerminalApp/TerminalWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,11 +253,11 @@ namespace winrt::TerminalApp::implementation
AppLogic::Current()->NotifyRootInitialized();
}

void TerminalWindow::PersistState(bool serializeBuffer)
void TerminalWindow::PersistState()
{
if (_root)
{
_root->PersistState(serializeBuffer);
_root->PersistState();
}
}

Expand Down Expand Up @@ -830,6 +830,11 @@ namespace winrt::TerminalApp::implementation
return _root.as<winrt::Windows::UI::Xaml::Controls::Control>();
}

winrt::Windows::Foundation::Collections::IVector<IPaneContent> TerminalWindow::Panes() const
{
return winrt::single_threaded_vector(_root->Panes());
}

// Method Description:
// - Gets the title of the currently focused terminal control. If there
// isn't a control selected for any reason, returns "Terminal"
Expand Down
3 changes: 2 additions & 1 deletion src/cascadia/TerminalApp/TerminalWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ namespace winrt::TerminalApp::implementation

void Create();

void PersistState(bool serializeBuffer);
void PersistState();

void UpdateSettings(winrt::TerminalApp::SettingsLoadEventArgs args);

Expand Down Expand Up @@ -111,6 +111,7 @@ namespace winrt::TerminalApp::implementation
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;

Windows::UI::Xaml::UIElement GetRoot() noexcept;
winrt::Windows::Foundation::Collections::IVector<IPaneContent> Panes() const;

hstring Title();
void TitlebarClicked();
Expand Down
4 changes: 3 additions & 1 deletion src/cascadia/TerminalApp/TerminalWindow.idl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import "IPaneContent.idl";
import "TerminalPage.idl";
import "ShortcutActionDispatch.idl";

Expand Down Expand Up @@ -59,9 +60,10 @@ namespace TerminalApp
Boolean ShouldImmediatelyHandoffToElevated();
void HandoffToElevated();

void PersistState(Boolean serializeBuffer);
void PersistState();

Windows.UI.Xaml.UIElement GetRoot();
IVector<IPaneContent> Panes { get; };

String Title { get; };
Boolean FocusMode { get; };
Expand Down
34 changes: 31 additions & 3 deletions src/cascadia/TerminalControl/ControlCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1806,15 +1806,43 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_closeConnection();
}

void ControlCore::PersistToPath(const wchar_t* path) const
void ControlCore::PersistTo(HANDLE handle) const
{
const auto lock = _terminal->LockForReading();
_terminal->SerializeMainBuffer(path);
_terminal->SerializeMainBuffer(handle);
}

void ControlCore::RestoreFromPath(const wchar_t* path) const
{
const wil::unique_handle file{ CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, nullptr) };
wil::unique_handle file{ CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, nullptr) };

// This block of code exists temporarily to fix buffer dumps that were
// previously persisted as "buffer_" but really should be named "elevated_".
// If loading the properly named file fails, retry with the old name.
if (!file)
{
static constexpr std::wstring_view needle{ L"\\elevated_" };

// Check if the path contains "\elevated_", indicating that we're in an elevated session.
const std::wstring_view pathView{ path };
const auto idx = pathView.find(needle);

if (idx != std::wstring_view::npos)
{
// If so, try to open the file with "\buffer_" instead, which is what we previously used.
std::wstring altPath{ pathView };
altPath.replace(idx, needle.size(), L"\\buffer_");

file.reset(CreateFileW(altPath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, nullptr));

// If the alternate file is found, move it to the correct location.
if (file)
{
LOG_IF_WIN32_BOOL_FALSE(MoveFileW(altPath.c_str(), path));
}
}
}

if (!file)
{
return;
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalControl/ControlCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void ColorSelection(const Control::SelectionColor& fg, const Control::SelectionColor& bg, Core::MatchMode matchMode);

void Close();
void PersistToPath(const wchar_t* path) const;
void PersistTo(HANDLE handle) const;
void RestoreFromPath(const wchar_t* path) const;

void ClearQuickFix();
Expand Down
4 changes: 2 additions & 2 deletions src/cascadia/TerminalControl/TermControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2681,7 +2681,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_restorePath = std::move(path);
}

void TermControl::PersistToPath(const winrt::hstring& path) const
void TermControl::PersistTo(int64_t handle) const
{
// Don't persist us if we weren't ever initialized. In that case, we
// never got an initial size, never instantiated a buffer, and didn't
Expand All @@ -2693,7 +2693,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// file then.
if (_initializedTerminal)
{
winrt::get_self<ControlCore>(_core)->PersistToPath(path.c_str());
winrt::get_self<ControlCore>(_core)->PersistTo(reinterpret_cast<HANDLE>(handle));
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalControl/TermControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool SwitchSelectionEndpoint();
bool ExpandSelectionToWord();
void RestoreFromPath(winrt::hstring path);
void PersistToPath(const winrt::hstring& path) const;
void PersistTo(int64_t handle) const;
void OpenCWD();
void Close();
Windows::Foundation::Size CharacterDimensions() const;
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalControl/TermControl.idl
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ namespace Microsoft.Terminal.Control
Boolean ExpandSelectionToWord();
void ClearBuffer(ClearBufferType clearType);
void RestoreFromPath(String path);
void PersistToPath(String path);
void PersistTo(Int64 handle);
void OpenCWD();
void Close();
Windows.Foundation.Size CharacterDimensions { get; };
Expand Down
4 changes: 2 additions & 2 deletions src/cascadia/TerminalCore/Terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1530,9 +1530,9 @@ std::wstring Terminal::CurrentCommand() const
return _activeBuffer().CurrentCommand();
}

void Terminal::SerializeMainBuffer(const wchar_t* destination) const
void Terminal::SerializeMainBuffer(HANDLE handle) const
{
_mainBuffer->SerializeToPath(destination);
_mainBuffer->SerializeTo(handle);
}

void Terminal::ColorSelection(const TextAttribute& attr, winrt::Microsoft::Terminal::Core::MatchMode matchMode)
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalCore/Terminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class Microsoft::Terminal::Core::Terminal final :

std::wstring CurrentCommand() const;

void SerializeMainBuffer(const wchar_t* destination) const;
void SerializeMainBuffer(HANDLE handle) const;

#pragma region ITerminalApi
// These methods are defined in TerminalApi.cpp
Expand Down
Loading
Loading