mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-11 22:48:41 -06:00
Allow actions in the new tab dropdown (#17281)
Allows the user to define entries in the new tab menu that execute actions, based on their action Id Closes #3759 Closes #9362
This commit is contained in:
parent
d6b6aacb4f
commit
aeed0782bc
@ -629,7 +629,8 @@
|
|||||||
"folder",
|
"folder",
|
||||||
"separator",
|
"separator",
|
||||||
"remainingProfiles",
|
"remainingProfiles",
|
||||||
"matchProfiles"
|
"matchProfiles",
|
||||||
|
"action"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"NewTabMenuEntry": {
|
"NewTabMenuEntry": {
|
||||||
@ -781,6 +782,28 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"ActionEntry": {
|
||||||
|
"description": "An action in the new tab dropdown",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/$defs/NewTabMenuEntry"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"const": "action"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "",
|
||||||
|
"description": "The ID of the action to show in this entry"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"SwitchToAdjacentTabArgs": {
|
"SwitchToAdjacentTabArgs": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{
|
||||||
@ -2054,6 +2077,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$ref": "#/$defs/RemainingProfilesEntry"
|
"$ref": "#/$defs/RemainingProfilesEntry"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/$defs/ActionEntry"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1004,6 +1004,18 @@ namespace winrt::TerminalApp::implementation
|
|||||||
items.push_back(profileItem);
|
items.push_back(profileItem);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case NewTabMenuEntryType::Action:
|
||||||
|
{
|
||||||
|
const auto actionEntry = entry.as<ActionEntry>();
|
||||||
|
const auto actionId = actionEntry.ActionId();
|
||||||
|
if (_settings.ActionMap().GetActionByID(actionId))
|
||||||
|
{
|
||||||
|
auto actionItem = _CreateNewTabFlyoutAction(actionId);
|
||||||
|
items.push_back(actionItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1094,6 +1106,41 @@ namespace winrt::TerminalApp::implementation
|
|||||||
return profileMenuItem;
|
return profileMenuItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Description:
|
||||||
|
// - This method creates a flyout menu item for a given action
|
||||||
|
// It makes sure to set the correct icon, keybinding, and click-action.
|
||||||
|
WUX::Controls::MenuFlyoutItem TerminalPage::_CreateNewTabFlyoutAction(const winrt::hstring& actionId)
|
||||||
|
{
|
||||||
|
auto actionMenuItem = WUX::Controls::MenuFlyoutItem{};
|
||||||
|
const auto action{ _settings.ActionMap().GetActionByID(actionId) };
|
||||||
|
const auto actionKeyChord{ _settings.ActionMap().GetKeyBindingForAction(actionId) };
|
||||||
|
|
||||||
|
if (actionKeyChord)
|
||||||
|
{
|
||||||
|
_SetAcceleratorForMenuItem(actionMenuItem, actionKeyChord);
|
||||||
|
}
|
||||||
|
|
||||||
|
actionMenuItem.Text(action.Name());
|
||||||
|
|
||||||
|
// If there's an icon set for this action, set it as the icon for
|
||||||
|
// this flyout item
|
||||||
|
const auto& iconPath = action.IconPath();
|
||||||
|
if (!iconPath.empty())
|
||||||
|
{
|
||||||
|
const auto icon = _CreateNewTabFlyoutIcon(iconPath);
|
||||||
|
actionMenuItem.Icon(icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
actionMenuItem.Click([action, weakThis{ get_weak() }](auto&&, auto&&) {
|
||||||
|
if (auto page{ weakThis.get() })
|
||||||
|
{
|
||||||
|
page->_actionDispatch->DoAction(action.ActionAndArgs());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return actionMenuItem;
|
||||||
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Helper method to create an IconElement that can be passed to MenuFlyoutItems and
|
// - Helper method to create an IconElement that can be passed to MenuFlyoutItems and
|
||||||
// MenuFlyoutSubItems
|
// MenuFlyoutSubItems
|
||||||
|
|||||||
@ -300,6 +300,7 @@ namespace winrt::TerminalApp::implementation
|
|||||||
std::vector<winrt::Windows::UI::Xaml::Controls::MenuFlyoutItemBase> _CreateNewTabFlyoutItems(winrt::Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::NewTabMenuEntry> entries);
|
std::vector<winrt::Windows::UI::Xaml::Controls::MenuFlyoutItemBase> _CreateNewTabFlyoutItems(winrt::Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::NewTabMenuEntry> entries);
|
||||||
winrt::Windows::UI::Xaml::Controls::IconElement _CreateNewTabFlyoutIcon(const winrt::hstring& icon);
|
winrt::Windows::UI::Xaml::Controls::IconElement _CreateNewTabFlyoutIcon(const winrt::hstring& icon);
|
||||||
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _CreateNewTabFlyoutProfile(const Microsoft::Terminal::Settings::Model::Profile profile, int profileIndex);
|
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _CreateNewTabFlyoutProfile(const Microsoft::Terminal::Settings::Model::Profile profile, int profileIndex);
|
||||||
|
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _CreateNewTabFlyoutAction(const winrt::hstring& actionId);
|
||||||
|
|
||||||
void _OpenNewTabDropdown();
|
void _OpenNewTabDropdown();
|
||||||
HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::INewContentArgs& newContentArgs);
|
HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::INewContentArgs& newContentArgs);
|
||||||
|
|||||||
36
src/cascadia/TerminalSettingsModel/ActionEntry.cpp
Normal file
36
src/cascadia/TerminalSettingsModel/ActionEntry.cpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
#include "pch.h"
|
||||||
|
#include "ActionEntry.h"
|
||||||
|
#include "JsonUtils.h"
|
||||||
|
|
||||||
|
#include "ActionEntry.g.cpp"
|
||||||
|
|
||||||
|
using namespace Microsoft::Terminal::Settings::Model;
|
||||||
|
using namespace winrt::Microsoft::Terminal::Settings::Model::implementation;
|
||||||
|
|
||||||
|
static constexpr std::string_view ActionIdKey{ "id" };
|
||||||
|
|
||||||
|
ActionEntry::ActionEntry() noexcept :
|
||||||
|
ActionEntryT<ActionEntry, NewTabMenuEntry>(NewTabMenuEntryType::Action)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value ActionEntry::ToJson() const
|
||||||
|
{
|
||||||
|
auto json = NewTabMenuEntry::ToJson();
|
||||||
|
|
||||||
|
JsonUtils::SetValueForKey(json, ActionIdKey, _ActionId);
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
winrt::com_ptr<NewTabMenuEntry> ActionEntry::FromJson(const Json::Value& json)
|
||||||
|
{
|
||||||
|
auto entry = winrt::make_self<ActionEntry>();
|
||||||
|
|
||||||
|
JsonUtils::GetValueForKey(json, ActionIdKey, entry->_ActionId);
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
37
src/cascadia/TerminalSettingsModel/ActionEntry.h
Normal file
37
src/cascadia/TerminalSettingsModel/ActionEntry.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*++
|
||||||
|
Copyright (c) Microsoft Corporation
|
||||||
|
Licensed under the MIT license.
|
||||||
|
|
||||||
|
Module Name:
|
||||||
|
- ActionEntry.h
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
- An action entry in the "new tab" dropdown menu
|
||||||
|
|
||||||
|
Author(s):
|
||||||
|
- Pankaj Bhojwani - May 2024
|
||||||
|
|
||||||
|
--*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "NewTabMenuEntry.h"
|
||||||
|
#include "ActionEntry.g.h"
|
||||||
|
|
||||||
|
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||||
|
{
|
||||||
|
struct ActionEntry : ActionEntryT<ActionEntry, NewTabMenuEntry>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ActionEntry() noexcept;
|
||||||
|
|
||||||
|
Json::Value ToJson() const override;
|
||||||
|
static com_ptr<NewTabMenuEntry> FromJson(const Json::Value& json);
|
||||||
|
|
||||||
|
WINRT_PROPERTY(winrt::hstring, ActionId);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation
|
||||||
|
{
|
||||||
|
BASIC_FACTORY(ActionEntry);
|
||||||
|
}
|
||||||
@ -596,6 +596,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||||||
return _GetActionByKeyChordInternal(keys).value_or(nullptr);
|
return _GetActionByKeyChordInternal(keys).value_or(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Model::Command ActionMap::GetActionByID(const winrt::hstring& cmdID) const
|
||||||
|
{
|
||||||
|
return _GetActionByID(cmdID);
|
||||||
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Retrieves the assigned command ID with the given key chord.
|
// - Retrieves the assigned command ID with the given key chord.
|
||||||
// - Can return nullopt to differentiate explicit unbinding vs lack of binding.
|
// - Can return nullopt to differentiate explicit unbinding vs lack of binding.
|
||||||
|
|||||||
@ -60,6 +60,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||||||
|
|
||||||
// queries
|
// queries
|
||||||
Model::Command GetActionByKeyChord(const Control::KeyChord& keys) const;
|
Model::Command GetActionByKeyChord(const Control::KeyChord& keys) const;
|
||||||
|
Model::Command GetActionByID(const winrt::hstring& cmdID) const;
|
||||||
bool IsKeyChordExplicitlyUnbound(const Control::KeyChord& keys) const;
|
bool IsKeyChordExplicitlyUnbound(const Control::KeyChord& keys) const;
|
||||||
Control::KeyChord GetKeyBindingForAction(const winrt::hstring& cmdID);
|
Control::KeyChord GetKeyBindingForAction(const winrt::hstring& cmdID);
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,7 @@ namespace Microsoft.Terminal.Settings.Model
|
|||||||
Boolean IsKeyChordExplicitlyUnbound(Microsoft.Terminal.Control.KeyChord keys);
|
Boolean IsKeyChordExplicitlyUnbound(Microsoft.Terminal.Control.KeyChord keys);
|
||||||
|
|
||||||
Command GetActionByKeyChord(Microsoft.Terminal.Control.KeyChord keys);
|
Command GetActionByKeyChord(Microsoft.Terminal.Control.KeyChord keys);
|
||||||
|
Command GetActionByID(String cmdID);
|
||||||
Microsoft.Terminal.Control.KeyChord GetKeyBindingForAction(String cmdID);
|
Microsoft.Terminal.Control.KeyChord GetKeyBindingForAction(String cmdID);
|
||||||
|
|
||||||
Windows.Foundation.Collections.IMapView<String, ActionAndArgs> AvailableActions { get; };
|
Windows.Foundation.Collections.IMapView<String, ActionAndArgs> AvailableActions { get; };
|
||||||
|
|||||||
@ -28,6 +28,9 @@
|
|||||||
<ClInclude Include="SeparatorEntry.h">
|
<ClInclude Include="SeparatorEntry.h">
|
||||||
<DependentUpon>NewTabMenuEntry.idl</DependentUpon>
|
<DependentUpon>NewTabMenuEntry.idl</DependentUpon>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="ActionEntry.h">
|
||||||
|
<DependentUpon>NewTabMenuEntry.idl</DependentUpon>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="FolderEntry.h">
|
<ClInclude Include="FolderEntry.h">
|
||||||
<DependentUpon>NewTabMenuEntry.idl</DependentUpon>
|
<DependentUpon>NewTabMenuEntry.idl</DependentUpon>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@ -185,6 +188,9 @@
|
|||||||
<ClCompile Include="SeparatorEntry.cpp">
|
<ClCompile Include="SeparatorEntry.cpp">
|
||||||
<DependentUpon>NewTabMenuEntry.idl</DependentUpon>
|
<DependentUpon>NewTabMenuEntry.idl</DependentUpon>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="ActionEntry.cpp">
|
||||||
|
<DependentUpon>NewTabMenuEntry.idl</DependentUpon>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="FolderEntry.cpp">
|
<ClCompile Include="FolderEntry.cpp">
|
||||||
<DependentUpon>NewTabMenuEntry.idl</DependentUpon>
|
<DependentUpon>NewTabMenuEntry.idl</DependentUpon>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
#include "SeparatorEntry.h"
|
#include "SeparatorEntry.h"
|
||||||
#include "FolderEntry.h"
|
#include "FolderEntry.h"
|
||||||
#include "ProfileEntry.h"
|
#include "ProfileEntry.h"
|
||||||
|
#include "ActionEntry.h"
|
||||||
#include "RemainingProfilesEntry.h"
|
#include "RemainingProfilesEntry.h"
|
||||||
#include "MatchProfilesEntry.h"
|
#include "MatchProfilesEntry.h"
|
||||||
|
|
||||||
@ -52,6 +53,8 @@ winrt::com_ptr<NewTabMenuEntry> NewTabMenuEntry::FromJson(const Json::Value& jso
|
|||||||
return RemainingProfilesEntry::FromJson(json);
|
return RemainingProfilesEntry::FromJson(json);
|
||||||
case NewTabMenuEntryType::MatchProfiles:
|
case NewTabMenuEntryType::MatchProfiles:
|
||||||
return MatchProfilesEntry::FromJson(json);
|
return MatchProfilesEntry::FromJson(json);
|
||||||
|
case NewTabMenuEntryType::Action:
|
||||||
|
return ActionEntry::FromJson(json);
|
||||||
default:
|
default:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,8 @@ namespace Microsoft.Terminal.Settings.Model
|
|||||||
Separator,
|
Separator,
|
||||||
Folder,
|
Folder,
|
||||||
RemainingProfiles,
|
RemainingProfiles,
|
||||||
MatchProfiles
|
MatchProfiles,
|
||||||
|
Action
|
||||||
};
|
};
|
||||||
|
|
||||||
[default_interface] unsealed runtimeclass NewTabMenuEntry
|
[default_interface] unsealed runtimeclass NewTabMenuEntry
|
||||||
@ -34,6 +35,13 @@ namespace Microsoft.Terminal.Settings.Model
|
|||||||
Int32 ProfileIndex;
|
Int32 ProfileIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[default_interface] runtimeclass ActionEntry : NewTabMenuEntry
|
||||||
|
{
|
||||||
|
ActionEntry();
|
||||||
|
|
||||||
|
String ActionId;
|
||||||
|
}
|
||||||
|
|
||||||
enum FolderEntryInlining
|
enum FolderEntryInlining
|
||||||
{
|
{
|
||||||
Never = 0,
|
Never = 0,
|
||||||
|
|||||||
@ -678,8 +678,9 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Control::ScrollToMarkDirection)
|
|||||||
// Possible NewTabMenuEntryType values
|
// Possible NewTabMenuEntryType values
|
||||||
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::NewTabMenuEntryType)
|
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::NewTabMenuEntryType)
|
||||||
{
|
{
|
||||||
JSON_MAPPINGS(5) = {
|
JSON_MAPPINGS(6) = {
|
||||||
pair_type{ "profile", ValueType::Profile },
|
pair_type{ "profile", ValueType::Profile },
|
||||||
|
pair_type{ "action", ValueType::Action },
|
||||||
pair_type{ "separator", ValueType::Separator },
|
pair_type{ "separator", ValueType::Separator },
|
||||||
pair_type{ "folder", ValueType::Folder },
|
pair_type{ "folder", ValueType::Folder },
|
||||||
pair_type{ "remainingProfiles", ValueType::RemainingProfiles },
|
pair_type{ "remainingProfiles", ValueType::RemainingProfiles },
|
||||||
|
|||||||
@ -38,6 +38,9 @@
|
|||||||
<ClInclude Include="../Profile.h" />
|
<ClInclude Include="../Profile.h" />
|
||||||
<ClInclude Include="../TerminalWarnings.h" />
|
<ClInclude Include="../TerminalWarnings.h" />
|
||||||
<ClInclude Include="../NewTabMenuEntry.h" />
|
<ClInclude Include="../NewTabMenuEntry.h" />
|
||||||
|
<ClInclude Include="../ActionEntry.h">
|
||||||
|
<DependentUpon>../NewTabMenuEntry.h</DependentUpon>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="../SeparatorEntry.h">
|
<ClInclude Include="../SeparatorEntry.h">
|
||||||
<DependentUpon>../NewTabMenuEntry.h</DependentUpon>
|
<DependentUpon>../NewTabMenuEntry.h</DependentUpon>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user