From 96b2b2f5b3564d033d20fc6f674608e298202371 Mon Sep 17 00:00:00 2001 From: Schuyler Rosefield Date: Sat, 9 Oct 2021 15:50:24 -0400 Subject: [PATCH] GH960 Add restore recently closed panes - Keep a buffer of panes/tabs that were closed recently in the form of a list of actions to remake it. - To restore the pane or tab just run the list of actions. - This (deliberately) does not restore the exact visual state as focus could have changed / new panes might have been created in the mean time. Mostly this means that restoring a pane will just attach to the currently focused pane instead of whatever its old neighbor was. --- doc/cascadia/profiles.schema.json | 1 + .../TerminalApp/AppActionHandlers.cpp | 16 +++++++ src/cascadia/TerminalApp/TabManagement.cpp | 42 +++++++++++++++++++ src/cascadia/TerminalApp/TerminalPage.h | 2 + .../TerminalSettingsModel/ActionAndArgs.cpp | 2 + .../AllShortcutActions.h | 3 +- .../Resources/en-US/Resources.resw | 5 ++- .../TerminalSettingsModel/defaults.json | 1 + 8 files changed, 70 insertions(+), 2 deletions(-) diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index f61e74f4e..08c1c7786 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -337,6 +337,7 @@ "toggleShaderEffects", "wt", "quit", + "restoreLastClosed", "unbound" ], "type": "string" diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index ae79289fa..9d0f69c08 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -75,6 +75,22 @@ namespace winrt::TerminalApp::implementation args.Handled(true); } + void TerminalPage::_HandleRestoreLastClosed(const IInspectable& /*sender*/, + const ActionEventArgs& args) + { + if (_previouslyClosedPanesAndTabs.size() > 0) + { + const auto restoreActions = _previouslyClosedPanesAndTabs.back(); + for (const auto& action : restoreActions) + { + _actionDispatch->DoAction(action); + } + _previouslyClosedPanesAndTabs.pop_back(); + + args.Handled(true); + } + } + void TerminalPage::_HandleCloseWindow(const IInspectable& /*sender*/, const ActionEventArgs& args) { diff --git a/src/cascadia/TerminalApp/TabManagement.cpp b/src/cascadia/TerminalApp/TabManagement.cpp index b99af3236..0d3d6a21c 100644 --- a/src/cascadia/TerminalApp/TabManagement.cpp +++ b/src/cascadia/TerminalApp/TabManagement.cpp @@ -474,6 +474,23 @@ namespace winrt::TerminalApp::implementation co_return; } } + + if (const auto terminalTab = _GetTerminalTabImpl(tab)) + { + const auto actions = terminalTab->BuildStartupActions(); + + _previouslyClosedPanesAndTabs.emplace_back(std::move(actions)); + } + else if (tab.try_as()) + { + ActionAndArgs action; + action.Action(ShortcutAction::OpenSettings); + OpenSettingsArgs args{ SettingsTarget::SettingsUI }; + action.Args(args); + + _previouslyClosedPanesAndTabs.emplace_back(std::vector{ std::move(action) }); + } + _RemoveTab(tab); } @@ -776,6 +793,31 @@ namespace winrt::TerminalApp::implementation }); } + // Just make sure we don't get infinitely large, but still + // maintain a large replay buffer. + if (const auto size = _previouslyClosedPanesAndTabs.size(); size > 100) + { + const auto it = _previouslyClosedPanesAndTabs.begin(); + _previouslyClosedPanesAndTabs.erase(it, it + (size - 100)); + } + + // Build the list of actions to recreate the closed pane, + // BuildStartupActions returns the "first" pane and the rest of + // its actions are assuming that first pane has been created first. + // This doesn't handle refocusing anything in particular, the + // result will be that the last pane created is focused. In the + // case of a single pane that is the desired behavior anyways. + auto state = pane->BuildStartupActions(0, 1); + { + ActionAndArgs splitPaneAction{}; + splitPaneAction.Action(ShortcutAction::SplitPane); + SplitPaneArgs splitPaneArgs{ SplitDirection::Automatic, state.firstPane->GetTerminalArgsForPane() }; + splitPaneAction.Args(splitPaneArgs); + + state.args.emplace(state.args.begin(), std::move(splitPaneAction)); + } + _previouslyClosedPanesAndTabs.emplace_back(std::move(state.args)); + pane->Close(); } } diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index e3b9f2f97..847dd13d8 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -180,6 +180,8 @@ namespace winrt::TerminalApp::implementation std::optional _rearrangeTo{}; bool _removing{ false }; + std::vector> _previouslyClosedPanesAndTabs{}; + uint32_t _systemRowsToScroll{ DefaultRowsToScroll }; // use a weak reference to prevent circular dependency with AppLogic diff --git a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp index 2ae6bb6da..6b563e4e6 100644 --- a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp @@ -69,6 +69,7 @@ static constexpr std::string_view OpenSystemMenuKey{ "openSystemMenu" }; static constexpr std::string_view ClearBufferKey{ "clearBuffer" }; static constexpr std::string_view MultipleActionsKey{ "multipleActions" }; static constexpr std::string_view QuitKey{ "quit" }; +static constexpr std::string_view RestoreLastClosedKey{ "restoreLastClosed" }; static constexpr std::string_view ActionKey{ "action" }; @@ -374,6 +375,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { ShortcutAction::ClearBuffer, L"" }, // Intentionally omitted, must be generated by GenerateName { ShortcutAction::MultipleActions, L"" }, // Intentionally omitted, must be generated by GenerateName { ShortcutAction::Quit, RS_(L"QuitCommandKey") }, + { ShortcutAction::RestoreLastClosed, RS_(L"RestoreLastClosedCommandKey") }, }; }(); diff --git a/src/cascadia/TerminalSettingsModel/AllShortcutActions.h b/src/cascadia/TerminalSettingsModel/AllShortcutActions.h index aa06ae70c..ce659701f 100644 --- a/src/cascadia/TerminalSettingsModel/AllShortcutActions.h +++ b/src/cascadia/TerminalSettingsModel/AllShortcutActions.h @@ -82,7 +82,8 @@ ON_ALL_ACTIONS(OpenSystemMenu) \ ON_ALL_ACTIONS(ClearBuffer) \ ON_ALL_ACTIONS(MultipleActions) \ - ON_ALL_ACTIONS(Quit) + ON_ALL_ACTIONS(Quit) \ + ON_ALL_ACTIONS(RestoreLastClosed) #define ALL_SHORTCUT_ACTIONS_WITH_ARGS \ ON_ALL_ACTIONS_WITH_ARGS(AdjustFontSize) \ diff --git a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw index 8bbbbfb7f..fbb5da46d 100644 --- a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw @@ -1,4 +1,4 @@ - +