From 81260e841501b03356ad5478870fd935c36b56a3 Mon Sep 17 00:00:00 2001 From: Schuyler Rosefield Date: Wed, 25 Aug 2021 22:59:26 -0400 Subject: [PATCH 1/5] Add action to run multiple actions. --- doc/cascadia/profiles.schema.json | 20 +++++ .../TerminalApp/AppActionHandlers.cpp | 17 ++++ .../TerminalSettingsModel/ActionAndArgs.cpp | 2 + .../TerminalSettingsModel/ActionAndArgs.h | 31 ++++++++ .../TerminalSettingsModel/ActionArgs.cpp | 11 +++ .../TerminalSettingsModel/ActionArgs.h | 54 +++++++++++++ .../TerminalSettingsModel/ActionArgs.idl | 9 +++ .../AllShortcutActions.h | 6 +- .../TerminalSettingsModel/JsonUtils.h | 77 +++++++++++++++++++ .../Resources/en-US/Resources.resw | 3 + 10 files changed, 228 insertions(+), 2 deletions(-) diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index 13e3a2b0cbb..ad720074d73 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -252,6 +252,7 @@ "movePane", "swapPane", "moveTab", + "multipleActions", "newTab", "newWindow", "nextTab", @@ -808,6 +809,25 @@ ], "required": [ "direction" ] }, + "MultipleActionsAction": { + "description": "Arguments for the multiple actions command", + "allOf": [ + { "$ref": "#/definitions/ShortcutAction" }, + { + "properties": { + "action": { "type": "string", "pattern": "multipleActions" }, + "name": { "type": "string"}, + "actions" : { + "$ref": "#/definitions/ShortcutAction" + "type": "array", + "minItems": 1, + "description": "A list of other actions." + } + } + } + ], + "required": [ "name", "actions" ] + }, "CommandPaletteAction": { "description": "Arguments for a commandPalette action", "allOf": [ diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index ee62b60c825..e7f1cfb9566 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -874,4 +874,21 @@ namespace winrt::TerminalApp::implementation } } } + + void TerminalPage::_HandleMultipleActions(const IInspectable& /*sender*/, + const ActionEventArgs& args) + { + if (args) + { + if (const auto& realArgs = args.ActionArgs().try_as()) + { + for (const auto& action : realArgs.Actions()) + { + _actionDispatch->DoAction(action); + } + + args.Handled(true); + } + } + } } diff --git a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp index acef483be3a..02bb1d486df 100644 --- a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp @@ -65,6 +65,7 @@ static constexpr std::string_view OpenWindowRenamerKey{ "openWindowRenamer" }; static constexpr std::string_view GlobalSummonKey{ "globalSummon" }; static constexpr std::string_view QuakeModeKey{ "quakeMode" }; static constexpr std::string_view FocusPaneKey{ "focusPane" }; +static constexpr std::string_view MultipleActionsKey{ "multipleActions" }; static constexpr std::string_view ActionKey{ "action" }; @@ -366,6 +367,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { ShortcutAction::GlobalSummon, L"" }, // Intentionally omitted, must be generated by GenerateName { ShortcutAction::QuakeMode, RS_(L"QuakeModeCommandKey") }, { ShortcutAction::FocusPane, L"" }, // Intentionally omitted, must be generated by GenerateName + { ShortcutAction::MultipleActions, L"" }, // Intentionally omitted, must be generated by GenerateName }; }(); diff --git a/src/cascadia/TerminalSettingsModel/ActionAndArgs.h b/src/cascadia/TerminalSettingsModel/ActionAndArgs.h index 892b5405060..abf9a482383 100644 --- a/src/cascadia/TerminalSettingsModel/ActionAndArgs.h +++ b/src/cascadia/TerminalSettingsModel/ActionAndArgs.h @@ -35,3 +35,34 @@ namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation { BASIC_FACTORY(ActionAndArgs); } + +namespace Microsoft::Terminal::Settings::Model::JsonUtils +{ + using namespace winrt::Microsoft::Terminal::Settings::Model; + + template<> + struct ConversionTrait + { + ActionAndArgs FromJson(const Json::Value& json) + { + std::vector v; + return *implementation::ActionAndArgs::FromJson(json, v); + } + + bool CanConvert(const Json::Value& json) const + { + // commands without args might just be a string + return json.isString() || json.isObject(); + } + + Json::Value ToJson(const ActionAndArgs& val) + { + return implementation::ActionAndArgs::ToJson(val); + } + + std::string TypeDescription() const + { + return "ActionAndArgs"; + } + }; +} diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionArgs.cpp index bd49bf43d0f..ce44b73546e 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.cpp @@ -34,6 +34,7 @@ #include "RenameWindowArgs.g.cpp" #include "GlobalSummonArgs.g.cpp" #include "FocusPaneArgs.g.cpp" +#include "MultipleActionsArgs.g.cpp" #include @@ -681,4 +682,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation Id()) }; } + + winrt::hstring MultipleActionsArgs::GenerateName() const + { + if (!_Name.empty()) + { + return _Name; + } + + return RS_(L"MultipleActionsMissingName"); + } } diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.h b/src/cascadia/TerminalSettingsModel/ActionArgs.h index ebf35a1aa24..c746fb1edc0 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.h +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.h @@ -36,6 +36,7 @@ #include "RenameWindowArgs.g.h" #include "GlobalSummonArgs.g.h" #include "FocusPaneArgs.g.h" +#include "MultipleActionsArgs.g.h" #include "../../cascadia/inc/cppwinrt_utils.h" #include "JsonUtils.h" @@ -1754,6 +1755,58 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation } }; + struct MultipleActionsArgs : public MultipleActionsArgsT + { + MultipleActionsArgs() = default; + WINRT_PROPERTY(hstring, Name, L""); + WINRT_PROPERTY(Windows::Foundation::Collections::IVector, Actions); + static constexpr std::string_view NameKey{ "name" }; + static constexpr std::string_view ActionsKey{ "actions" }; + + public: + hstring GenerateName() const; + + bool Equals(const IActionArgs& other) + { + auto otherAsUs = other.try_as(); + if (otherAsUs) + { + return otherAsUs->_Name == _Name && otherAsUs->_Actions == _Actions; + } + 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(); + JsonUtils::GetValueForKey(json, NameKey, args->_Name); + JsonUtils::GetValueForKey(json, ActionsKey, args->_Actions); + return { *args, {} }; + } + static Json::Value ToJson(const IActionArgs& val) + { + if (!val) + { + return {}; + } + Json::Value json{ Json::ValueType::objectValue }; + const auto args{ get_self(val) }; + JsonUtils::SetValueForKey(json, NameKey, args->_Name); + JsonUtils::SetValueForKey(json, ActionsKey, args->_Actions); + return json; + } + IActionArgs Copy() const + { + auto copy{ winrt::make_self() }; + copy->_Name = _Name; + copy->_Actions = _Actions; + return *copy; + } + size_t Hash() const + { + return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(_Name, _Actions); + } + }; } namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation @@ -1778,4 +1831,5 @@ namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation BASIC_FACTORY(FocusPaneArgs); BASIC_FACTORY(PrevTabArgs); BASIC_FACTORY(NextTabArgs); + BASIC_FACTORY(MultipleActionsArgs); } diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.idl b/src/cascadia/TerminalSettingsModel/ActionArgs.idl index 2369a813503..5e4af95d238 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.idl +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.idl @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. +import "Command.idl"; + namespace Microsoft.Terminal.Settings.Model { interface IActionArgs @@ -307,4 +309,11 @@ namespace Microsoft.Terminal.Settings.Model FocusPaneArgs(UInt32 Id); UInt32 Id { get; }; }; + + [default_interface] runtimeclass MultipleActionsArgs : IActionArgs + { + MultipleActionsArgs(); + String Name; + Windows.Foundation.Collections.IVector Actions; + } } diff --git a/src/cascadia/TerminalSettingsModel/AllShortcutActions.h b/src/cascadia/TerminalSettingsModel/AllShortcutActions.h index 7d0d0a728ec..e2f5488e45b 100644 --- a/src/cascadia/TerminalSettingsModel/AllShortcutActions.h +++ b/src/cascadia/TerminalSettingsModel/AllShortcutActions.h @@ -78,7 +78,8 @@ ON_ALL_ACTIONS(OpenWindowRenamer) \ ON_ALL_ACTIONS(GlobalSummon) \ ON_ALL_ACTIONS(QuakeMode) \ - ON_ALL_ACTIONS(FocusPane) + ON_ALL_ACTIONS(FocusPane) \ + ON_ALL_ACTIONS(MultipleActions) #define ALL_SHORTCUT_ACTIONS_WITH_ARGS \ ON_ALL_ACTIONS_WITH_ARGS(AdjustFontSize) \ @@ -109,4 +110,5 @@ ON_ALL_ACTIONS_WITH_ARGS(SplitPane) \ ON_ALL_ACTIONS_WITH_ARGS(SwitchToTab) \ ON_ALL_ACTIONS_WITH_ARGS(ToggleCommandPalette) \ - ON_ALL_ACTIONS_WITH_ARGS(FocusPane) + ON_ALL_ACTIONS_WITH_ARGS(FocusPane) \ + ON_ALL_ACTIONS_WITH_ARGS(MultipleActions) diff --git a/src/cascadia/TerminalSettingsModel/JsonUtils.h b/src/cascadia/TerminalSettingsModel/JsonUtils.h index 220ec1df372..9f720ed83eb 100644 --- a/src/cascadia/TerminalSettingsModel/JsonUtils.h +++ b/src/cascadia/TerminalSettingsModel/JsonUtils.h @@ -177,6 +177,47 @@ namespace Microsoft::Terminal::Settings::Model::JsonUtils } }; + template + struct ConversionTrait> + { + std::vector FromJson(const Json::Value& json) + { + std::vector val; + val.reserve(json.size()); + + ConversionTrait trait; + for (const auto& element : json) + { + val.push_back(trait.FromJson(element)); + } + + return val; + } + + bool CanConvert(const Json::Value& json) const + { + ConversionTrait trait; + return json.isArray() && std::all_of(json.begin(), json.end(), [trait](const auto& json) mutable -> bool { return trait.CanConvert(json); }); + } + + Json::Value ToJson(const std::vector& val) + { + Json::Value json{ Json::arrayValue }; + + ConversionTrait trait; + for (const auto& v : val) + { + json.append(trait.ToJson(v)); + } + + return json; + } + std::string TypeDescription() const + { + return fmt::format("{}[]", ConversionTrait{}.TypeDescription()); + } + }; + template struct ConversionTrait> { @@ -259,6 +300,42 @@ namespace Microsoft::Terminal::Settings::Model::JsonUtils } }; + template + struct ConversionTrait> + { + winrt::Windows::Foundation::Collections::IVector FromJson(const Json::Value& json) + { + ConversionTrait> trait; + return winrt::single_threaded_vector(std::move(trait.FromJson(json))); + } + + bool CanConvert(const Json::Value& json) const + { + ConversionTrait> trait; + return trait.CanConvert(json); + } + + Json::Value ToJson(const winrt::Windows::Foundation::Collections::IVector& val) + { + Json::Value json{ Json::arrayValue }; + + if (val) + { + ConversionTrait trait; + for (const auto& v : val) + { + json.append(trait.ToJson(v)); + } + } + + return json; + } + std::string TypeDescription() const + { + return fmt::format("{}[]", ConversionTrait{}.TypeDescription()); + } + }; + template struct ConversionTrait> { diff --git a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw index 0f2f883535f..741cf4a287a 100644 --- a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw @@ -451,4 +451,7 @@ Minimize current window to tray + + Multiple Actions (give this a name) + From a2d072a3ab2806464df60b9a4bc42c1ce8dc9dd2 Mon Sep 17 00:00:00 2001 From: Schuyler Rosefield Date: Thu, 26 Aug 2021 09:33:26 -0400 Subject: [PATCH 2/5] missing comma --- doc/cascadia/profiles.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index ad720074d73..cd07637450c 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -818,7 +818,7 @@ "action": { "type": "string", "pattern": "multipleActions" }, "name": { "type": "string"}, "actions" : { - "$ref": "#/definitions/ShortcutAction" + "$ref": "#/definitions/ShortcutAction", "type": "array", "minItems": 1, "description": "A list of other actions." From 516ead49de383f22060b0dadd1ab98ba03739e85 Mon Sep 17 00:00:00 2001 From: Schuyler Rosefield Date: Thu, 26 Aug 2021 10:40:47 -0400 Subject: [PATCH 3/5] Remove name field entirely, force user to specify a name on the comand. --- src/cascadia/TerminalSettingsModel/ActionArgs.cpp | 7 +------ src/cascadia/TerminalSettingsModel/ActionArgs.h | 9 ++------- src/cascadia/TerminalSettingsModel/ActionArgs.idl | 1 - .../TerminalSettingsModel/Resources/en-US/Resources.resw | 3 --- 4 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionArgs.cpp index ce44b73546e..f24632dfef0 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.cpp @@ -685,11 +685,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation winrt::hstring MultipleActionsArgs::GenerateName() const { - if (!_Name.empty()) - { - return _Name; - } - - return RS_(L"MultipleActionsMissingName"); + return L""; } } diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.h b/src/cascadia/TerminalSettingsModel/ActionArgs.h index c746fb1edc0..96dbe07ce63 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.h +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.h @@ -1758,9 +1758,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation struct MultipleActionsArgs : public MultipleActionsArgsT { MultipleActionsArgs() = default; - WINRT_PROPERTY(hstring, Name, L""); WINRT_PROPERTY(Windows::Foundation::Collections::IVector, Actions); - static constexpr std::string_view NameKey{ "name" }; static constexpr std::string_view ActionsKey{ "actions" }; public: @@ -1771,7 +1769,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation auto otherAsUs = other.try_as(); if (otherAsUs) { - return otherAsUs->_Name == _Name && otherAsUs->_Actions == _Actions; + return otherAsUs->_Actions == _Actions; } return false; }; @@ -1779,7 +1777,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { // LOAD BEARING: Not using make_self here _will_ break you in the future! auto args = winrt::make_self(); - JsonUtils::GetValueForKey(json, NameKey, args->_Name); JsonUtils::GetValueForKey(json, ActionsKey, args->_Actions); return { *args, {} }; } @@ -1791,20 +1788,18 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation } Json::Value json{ Json::ValueType::objectValue }; const auto args{ get_self(val) }; - JsonUtils::SetValueForKey(json, NameKey, args->_Name); JsonUtils::SetValueForKey(json, ActionsKey, args->_Actions); return json; } IActionArgs Copy() const { auto copy{ winrt::make_self() }; - copy->_Name = _Name; copy->_Actions = _Actions; return *copy; } size_t Hash() const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(_Name, _Actions); + return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(_Actions); } }; } diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.idl b/src/cascadia/TerminalSettingsModel/ActionArgs.idl index 5e4af95d238..98313d43536 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.idl +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.idl @@ -313,7 +313,6 @@ namespace Microsoft.Terminal.Settings.Model [default_interface] runtimeclass MultipleActionsArgs : IActionArgs { MultipleActionsArgs(); - String Name; Windows.Foundation.Collections.IVector Actions; } } diff --git a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw index 741cf4a287a..0f2f883535f 100644 --- a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw @@ -451,7 +451,4 @@ Minimize current window to tray - - Multiple Actions (give this a name) - From f16efda8ffa0994fceb86ecc6736d73ed8759825 Mon Sep 17 00:00:00 2001 From: Schuyler Rosefield Date: Thu, 26 Aug 2021 10:43:02 -0400 Subject: [PATCH 4/5] remove name from the schema too --- doc/cascadia/profiles.schema.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index cd07637450c..9268c5ea987 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -816,7 +816,6 @@ { "properties": { "action": { "type": "string", "pattern": "multipleActions" }, - "name": { "type": "string"}, "actions" : { "$ref": "#/definitions/ShortcutAction", "type": "array", @@ -826,7 +825,7 @@ } } ], - "required": [ "name", "actions" ] + "required": [ "actions" ] }, "CommandPaletteAction": { "description": "Arguments for a commandPalette action", From 666050bd6f4954a0189d005d7d210b9d915d370e Mon Sep 17 00:00:00 2001 From: Schuyler Rosefield Date: Tue, 31 Aug 2021 14:25:18 -0400 Subject: [PATCH 5/5] Remove duplicate converter --- .../ApplicationState.cpp | 42 ------------------- 1 file changed, 42 deletions(-) diff --git a/src/cascadia/TerminalSettingsModel/ApplicationState.cpp b/src/cascadia/TerminalSettingsModel/ApplicationState.cpp index f0f536ecfec..0984a5330cf 100644 --- a/src/cascadia/TerminalSettingsModel/ApplicationState.cpp +++ b/src/cascadia/TerminalSettingsModel/ApplicationState.cpp @@ -55,48 +55,6 @@ namespace Microsoft::Terminal::Settings::Model::JsonUtils return fmt::format("{}[]", ConversionTrait{}.TypeDescription()); } }; - - template - struct ConversionTrait> - { - winrt::Windows::Foundation::Collections::IVector FromJson(const Json::Value& json) const - { - ConversionTrait trait; - std::vector val; - val.reserve(json.size()); - - for (const auto& element : json) - { - val.push_back(trait.FromJson(element)); - } - - return winrt::single_threaded_vector(move(val)); - } - - bool CanConvert(const Json::Value& json) const - { - ConversionTrait trait; - return json.isArray() && std::all_of(json.begin(), json.end(), [trait](const auto& json) -> bool { return trait.CanConvert(json); }); - } - - Json::Value ToJson(const winrt::Windows::Foundation::Collections::IVector& val) - { - ConversionTrait trait; - Json::Value json{ Json::arrayValue }; - - for (const auto& key : val) - { - json.append(trait.ToJson(key)); - } - - return json; - } - - std::string TypeDescription() const - { - return fmt::format("vector ({})", ConversionTrait{}.TypeDescription()); - } - }; } using namespace ::Microsoft::Terminal::Settings::Model;