Allow closing tabs by index (#10447)
## Summary of the Pull Request Updates the `closeTab` action to optionally take an index. ## PR Checklist * [x] Closes #7180 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: MicrosoftDocs/terminal#347 * [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 ## Validation Steps Performed Added the following configuration to `settings.json` and validated both key combinations behaved as expected. Also opened the command palette and ensured that the actions were displayed. ```json { "command": "closeTab", "keys": "ctrl+shift+delete" }, { "command": { "action": "closeTab", "index": 0 }, "keys": "ctrl+shift+end" } ```
This commit is contained in:
parent
8c00dd7d55
commit
8c057a04a8
|
@ -648,6 +648,25 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"CloseTabAction": {
|
||||
"description": "Arguments for a closeTab action",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ShortcutAction" },
|
||||
{
|
||||
"properties": {
|
||||
"action": { "type": "string", "pattern": "closeTab" },
|
||||
"index": {
|
||||
"oneOf": [
|
||||
{ "type": "integer" },
|
||||
{ "type": "null" }
|
||||
],
|
||||
"default": null,
|
||||
"description": "Close the tab at this index. If no index is provided, use the focused tab's index."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"ScrollUpAction": {
|
||||
"description": "Arguments for a scrollUp action",
|
||||
"allOf": [
|
||||
|
@ -899,6 +918,7 @@
|
|||
{ "$ref": "#/definitions/WtAction" },
|
||||
{ "$ref": "#/definitions/CloseOtherTabsAction" },
|
||||
{ "$ref": "#/definitions/CloseTabsAfterAction" },
|
||||
{ "$ref": "#/definitions/CloseTabAction" },
|
||||
{ "$ref": "#/definitions/ScrollUpAction" },
|
||||
{ "$ref": "#/definitions/ScrollDownAction" },
|
||||
{ "$ref": "#/definitions/MoveTabAction" },
|
||||
|
|
|
@ -46,8 +46,26 @@ namespace winrt::TerminalApp::implementation
|
|||
void TerminalPage::_HandleCloseTab(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
_CloseFocusedTab();
|
||||
args.Handled(true);
|
||||
if (const auto realArgs = args.ActionArgs().try_as<CloseTabArgs>())
|
||||
{
|
||||
uint32_t index;
|
||||
if (realArgs.Index())
|
||||
{
|
||||
index = realArgs.Index().Value();
|
||||
}
|
||||
else if (auto focusedTabIndex = _GetFocusedTabIndex())
|
||||
{
|
||||
index = *focusedTabIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Handled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
_CloseTabAtIndex(index);
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleClosePane(const IInspectable& /*sender*/,
|
||||
|
|
|
@ -617,17 +617,6 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Close the currently focused tab. Focus will move to the left, if possible.
|
||||
void TerminalPage::_CloseFocusedTab()
|
||||
{
|
||||
if (auto index{ _GetFocusedTabIndex() })
|
||||
{
|
||||
auto tab{ _tabs.GetAt(*index) };
|
||||
_HandleCloseTabRequested(tab);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Close the currently focused pane. If the pane is the last pane in the
|
||||
// tab, the tab will also be closed. This will happen when we handle the
|
||||
|
@ -675,6 +664,20 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Close the tab at the given index.
|
||||
void TerminalPage::_CloseTabAtIndex(uint32_t index)
|
||||
{
|
||||
if (index >= _tabs.Size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (auto tab{ _tabs.GetAt(index) })
|
||||
{
|
||||
_HandleCloseTabRequested(tab);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Closes provided tabs one by one
|
||||
// Arguments:
|
||||
|
|
|
@ -216,6 +216,7 @@ namespace winrt::TerminalApp::implementation
|
|||
void _DuplicateTab(const TerminalTab& tab);
|
||||
|
||||
winrt::Windows::Foundation::IAsyncAction _HandleCloseTabRequested(winrt::TerminalApp::TabBase tab);
|
||||
void _CloseTabAtIndex(uint32_t index);
|
||||
void _RemoveTab(const winrt::TerminalApp::TabBase& tab);
|
||||
winrt::fire_and_forget _RemoveTabs(const std::vector<winrt::TerminalApp::TabBase> tabs);
|
||||
|
||||
|
@ -238,7 +239,6 @@ namespace winrt::TerminalApp::implementation
|
|||
TerminalApp::TabBase _GetTabByTabViewItem(const Microsoft::UI::Xaml::Controls::TabViewItem& tabViewItem) const noexcept;
|
||||
|
||||
winrt::fire_and_forget _SetFocusedTab(const winrt::TerminalApp::TabBase tab);
|
||||
void _CloseFocusedTab();
|
||||
winrt::fire_and_forget _CloseFocusedPane();
|
||||
|
||||
winrt::fire_and_forget _RemoveOnCloseRoutine(Microsoft::UI::Xaml::Controls::TabViewItem tabViewItem, winrt::com_ptr<TerminalPage> page);
|
||||
|
|
|
@ -280,7 +280,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
{ ShortcutAction::AdjustFontSize, RS_(L"AdjustFontSizeCommandKey") },
|
||||
{ ShortcutAction::CloseOtherTabs, L"" }, // Intentionally omitted, must be generated by GenerateName
|
||||
{ ShortcutAction::ClosePane, RS_(L"ClosePaneCommandKey") },
|
||||
{ ShortcutAction::CloseTab, RS_(L"CloseTabCommandKey") },
|
||||
{ ShortcutAction::CloseTab, L"" }, // Intentionally omitted, must be generated by GenerateName
|
||||
{ ShortcutAction::CloseTabsAfter, L"" }, // Intentionally omitted, must be generated by GenerateName
|
||||
{ ShortcutAction::CloseWindow, RS_(L"CloseWindowCommandKey") },
|
||||
{ ShortcutAction::CopyText, RS_(L"CopyTextCommandKey") },
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "ExecuteCommandlineArgs.g.cpp"
|
||||
#include "CloseOtherTabsArgs.g.cpp"
|
||||
#include "CloseTabsAfterArgs.g.cpp"
|
||||
#include "CloseTabArgs.g.cpp"
|
||||
#include "MoveTabArgs.g.cpp"
|
||||
#include "FindMatchArgs.g.cpp"
|
||||
#include "ToggleCommandPaletteArgs.g.cpp"
|
||||
|
@ -469,6 +470,19 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
return RS_(L"CloseTabsAfterDefaultCommandKey");
|
||||
}
|
||||
|
||||
winrt::hstring CloseTabArgs::GenerateName() const
|
||||
{
|
||||
if (Index())
|
||||
{
|
||||
// "Close tab at index {0}"
|
||||
return winrt::hstring{
|
||||
fmt::format(std::wstring_view(RS_(L"CloseTabAtIndexCommandKey")),
|
||||
Index().Value())
|
||||
};
|
||||
}
|
||||
return RS_(L"CloseTabCommandKey");
|
||||
}
|
||||
|
||||
winrt::hstring ScrollUpArgs::GenerateName() const
|
||||
{
|
||||
if (RowsToScroll())
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "ExecuteCommandlineArgs.g.h"
|
||||
#include "CloseOtherTabsArgs.g.h"
|
||||
#include "CloseTabsAfterArgs.g.h"
|
||||
#include "CloseTabArgs.g.h"
|
||||
#include "ScrollUpArgs.g.h"
|
||||
#include "ScrollDownArgs.g.h"
|
||||
#include "MoveTabArgs.g.h"
|
||||
|
@ -996,6 +997,57 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
}
|
||||
};
|
||||
|
||||
struct CloseTabArgs : public CloseTabArgsT<CloseTabArgs>
|
||||
{
|
||||
CloseTabArgs() = default;
|
||||
CloseTabArgs(uint32_t tabIndex) :
|
||||
_Index{ tabIndex } {};
|
||||
ACTION_ARG(Windows::Foundation::IReference<uint32_t>, Index, nullptr);
|
||||
|
||||
static constexpr std::string_view IndexKey{ "index" };
|
||||
|
||||
public:
|
||||
hstring GenerateName() const;
|
||||
|
||||
bool Equals(const IActionArgs& other)
|
||||
{
|
||||
auto otherAsUs = other.try_as<CloseTabArgs>();
|
||||
if (otherAsUs)
|
||||
{
|
||||
return otherAsUs->_Index == _Index;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
static FromJsonResult FromJson(const Json::Value& json)
|
||||
{
|
||||
// LOAD BEARING: Not using make_self here _will_ break you in the future!
|
||||
auto args = winrt::make_self<CloseTabArgs>();
|
||||
JsonUtils::GetValueForKey(json, IndexKey, args->_Index);
|
||||
return { *args, {} };
|
||||
}
|
||||
static Json::Value ToJson(const IActionArgs& val)
|
||||
{
|
||||
if (!val)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
Json::Value json{ Json::ValueType::objectValue };
|
||||
const auto args{ get_self<CloseTabArgs>(val) };
|
||||
JsonUtils::SetValueForKey(json, IndexKey, args->_Index);
|
||||
return json;
|
||||
}
|
||||
IActionArgs Copy() const
|
||||
{
|
||||
auto copy{ winrt::make_self<CloseTabArgs>() };
|
||||
copy->_Index = _Index;
|
||||
return *copy;
|
||||
}
|
||||
size_t Hash() const
|
||||
{
|
||||
return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(Index());
|
||||
}
|
||||
};
|
||||
|
||||
struct MoveTabArgs : public MoveTabArgsT<MoveTabArgs>
|
||||
{
|
||||
MoveTabArgs() = default;
|
||||
|
@ -1600,6 +1652,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation
|
|||
BASIC_FACTORY(ExecuteCommandlineArgs);
|
||||
BASIC_FACTORY(CloseOtherTabsArgs);
|
||||
BASIC_FACTORY(CloseTabsAfterArgs);
|
||||
BASIC_FACTORY(CloseTabArgs);
|
||||
BASIC_FACTORY(MoveTabArgs);
|
||||
BASIC_FACTORY(OpenSettingsArgs);
|
||||
BASIC_FACTORY(FindMatchArgs);
|
||||
|
|
|
@ -221,6 +221,12 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
Windows.Foundation.IReference<UInt32> Index { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass CloseTabArgs : IActionArgs
|
||||
{
|
||||
CloseTabArgs(UInt32 tabIndex);
|
||||
Windows.Foundation.IReference<UInt32> Index { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass MoveTabArgs : IActionArgs
|
||||
{
|
||||
MoveTabArgs(MoveTabDirection direction);
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
ON_ALL_ACTIONS_WITH_ARGS(AdjustFontSize) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(CloseOtherTabs) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(CloseTabsAfter) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(CloseTab) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(CopyText) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(ExecuteCommandline) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(FindMatch) \
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
|
@ -26,36 +26,36 @@
|
|||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
|
@ -147,6 +147,10 @@
|
|||
<data name="ClosePaneCommandKey" xml:space="preserve">
|
||||
<value>Close pane</value>
|
||||
</data>
|
||||
<data name="CloseTabAtIndexCommandKey" xml:space="preserve">
|
||||
<value>Close tab at index {0}</value>
|
||||
<comment>{0} will be replaced with a number</comment>
|
||||
</data>
|
||||
<data name="CloseTabCommandKey" xml:space="preserve">
|
||||
<value>Close tab</value>
|
||||
</data>
|
||||
|
@ -413,4 +417,4 @@
|
|||
<value>Windows Console Host</value>
|
||||
<comment>Name describing the usage of the classic windows console as the terminal UI. (`conhost.exe`)</comment>
|
||||
</data>
|
||||
</root>
|
||||
</root>
|
Loading…
Reference in New Issue