mirror of
https://github.com/microsoft/terminal.git
synced 2026-07-08 18:16:28 +00:00
Add restore recently closed panes (#11471)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Add an action to restore the last closed pane or tab. When all you have is restoring last sessions everything looks like a `std::vector<ActionAndArgs>`. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #9800 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Partially closes #960 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [x] Schema updated. * [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments - 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. - Buffer is limited to 100 entries which might as well be "infinite" by most reasonable standards, but prevents complaints about there being memory leaks in long running instances. - The action name could be potentially changed, but it felt unwieldy as "restoreLastClosedPaneOrTab". - This does not handle restoring the actual running contents of a pane. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
This commit is contained in:
committed by
GitHub
parent
5c64cf64ab
commit
ec226ee553
@@ -340,6 +340,7 @@
|
||||
"toggleShaderEffects",
|
||||
"wt",
|
||||
"quit",
|
||||
"restoreLastClosed",
|
||||
"unbound"
|
||||
],
|
||||
"type": "string"
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -38,6 +38,22 @@ namespace winrt::TerminalApp::implementation
|
||||
settingsUI.UpdateSettings(settings);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Creates a list of actions that can be run to recreate the state of this tab
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - The list of actions.
|
||||
std::vector<ActionAndArgs> SettingsTab::BuildStartupActions() const
|
||||
{
|
||||
ActionAndArgs action;
|
||||
action.Action(ShortcutAction::OpenSettings);
|
||||
OpenSettingsArgs args{ SettingsTarget::SettingsUI };
|
||||
action.Args(args);
|
||||
|
||||
return std::vector{ std::move(action) };
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Focus the settings UI
|
||||
// Arguments:
|
||||
|
||||
@@ -29,6 +29,8 @@ namespace winrt::TerminalApp::implementation
|
||||
void UpdateSettings(Microsoft::Terminal::Settings::Model::CascadiaSettings settings);
|
||||
void Focus(winrt::Windows::UI::Xaml::FocusState focusState) override;
|
||||
|
||||
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions() const override;
|
||||
|
||||
private:
|
||||
void _MakeTabViewItem() override;
|
||||
winrt::fire_and_forget _CreateIcon();
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void UpdateTabViewIndex(const uint32_t idx, const uint32_t numTabs);
|
||||
void SetActionMap(const Microsoft::Terminal::Settings::Model::IActionMapView& actionMap);
|
||||
virtual std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions() const = 0;
|
||||
|
||||
WINRT_CALLBACK(RequestFocusActiveControl, winrt::delegate<void()>);
|
||||
|
||||
|
||||
@@ -392,6 +392,26 @@ namespace winrt::TerminalApp::implementation
|
||||
CATCH_LOG();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Record the configuration information of the last closed thing .
|
||||
// - Will occasionally prune the list so it doesn't grow infinitely.
|
||||
// Arguments:
|
||||
// - args: the list of actions to take to remake the pane/tab
|
||||
void TerminalPage::_AddPreviouslyClosedPaneOrTab(std::vector<ActionAndArgs>&& args)
|
||||
{
|
||||
// Just make sure we don't get infinitely large, but still
|
||||
// maintain a large replay buffer.
|
||||
if (const auto size = _previouslyClosedPanesAndTabs.size(); size > 150)
|
||||
{
|
||||
const auto it = _previouslyClosedPanesAndTabs.begin();
|
||||
// delete 50 at a time so that we don't have to do an erase
|
||||
// of the buffer every time when at capacity.
|
||||
_previouslyClosedPanesAndTabs.erase(it, it + (size - 100));
|
||||
}
|
||||
|
||||
_previouslyClosedPanesAndTabs.emplace_back(args);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Removes the tab (both TerminalControl and XAML) after prompting for approval
|
||||
// Arguments:
|
||||
@@ -408,6 +428,11 @@ namespace winrt::TerminalApp::implementation
|
||||
co_return;
|
||||
}
|
||||
}
|
||||
|
||||
auto t = winrt::get_self<implementation::TabBase>(tab);
|
||||
auto actions = t->BuildStartupActions();
|
||||
_AddPreviouslyClosedPaneOrTab(std::move(actions));
|
||||
|
||||
_RemoveTab(tab);
|
||||
}
|
||||
|
||||
@@ -709,6 +734,23 @@ namespace winrt::TerminalApp::implementation
|
||||
});
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
_AddPreviouslyClosedPaneOrTab(std::move(state.args));
|
||||
|
||||
pane->Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1440,20 +1440,9 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
for (auto tab : _tabs)
|
||||
{
|
||||
if (auto terminalTab = _GetTerminalTabImpl(tab))
|
||||
{
|
||||
auto tabActions = terminalTab->BuildStartupActions();
|
||||
actions.insert(actions.end(), std::make_move_iterator(tabActions.begin()), std::make_move_iterator(tabActions.end()));
|
||||
}
|
||||
else if (tab.try_as<SettingsTab>())
|
||||
{
|
||||
ActionAndArgs action;
|
||||
action.Action(ShortcutAction::OpenSettings);
|
||||
OpenSettingsArgs args{ SettingsTarget::SettingsUI };
|
||||
action.Args(args);
|
||||
|
||||
actions.emplace_back(std::move(action));
|
||||
}
|
||||
auto t = winrt::get_self<implementation::TabBase>(tab);
|
||||
auto tabActions = t->BuildStartupActions();
|
||||
actions.insert(actions.end(), std::make_move_iterator(tabActions.begin()), std::make_move_iterator(tabActions.end()));
|
||||
}
|
||||
|
||||
// if the focused tab was not the last tab, restore that
|
||||
|
||||
@@ -193,6 +193,8 @@ namespace winrt::TerminalApp::implementation
|
||||
std::optional<int> _rearrangeTo{};
|
||||
bool _removing{ false };
|
||||
|
||||
std::vector<std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs>> _previouslyClosedPanesAndTabs{};
|
||||
|
||||
uint32_t _systemRowsToScroll{ DefaultRowsToScroll };
|
||||
|
||||
// use a weak reference to prevent circular dependency with AppLogic
|
||||
@@ -304,6 +306,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
winrt::fire_and_forget _SetFocusedTab(const winrt::TerminalApp::TabBase tab);
|
||||
winrt::fire_and_forget _CloseFocusedPane();
|
||||
void _AddPreviouslyClosedPaneOrTab(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs>&& args);
|
||||
|
||||
winrt::fire_and_forget _RemoveOnCloseRoutine(Microsoft::UI::Xaml::Controls::TabViewItem tabViewItem, winrt::com_ptr<TerminalPage> page);
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void EnterZoom();
|
||||
void ExitZoom();
|
||||
|
||||
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions() const;
|
||||
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions() const override;
|
||||
|
||||
int GetLeafPaneCount() const noexcept;
|
||||
|
||||
|
||||
@@ -72,6 +72,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" };
|
||||
|
||||
@@ -380,6 +381,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") },
|
||||
};
|
||||
}();
|
||||
|
||||
|
||||
@@ -85,7 +85,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) \
|
||||
|
||||
@@ -496,4 +496,7 @@
|
||||
<data name="QuitCommandKey" xml:space="preserve">
|
||||
<value>Quit the Terminal</value>
|
||||
</data>
|
||||
<data name="RestoreLastClosedCommandKey" xml:space="preserve">
|
||||
<value>Restore the last closed pane or tab</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -305,6 +305,7 @@
|
||||
{ "command": "quakeMode", "keys":"win+sc(41)" },
|
||||
{ "command": "openSystemMenu", "keys": "alt+space" },
|
||||
{ "command": "quit" },
|
||||
{ "command": "restoreLastClosed"},
|
||||
|
||||
// Tab Management
|
||||
// "command": "closeTab" is unbound by default.
|
||||
|
||||
Reference in New Issue
Block a user