From eecdd53eb89f8d30f0fa3568e69214c8f9241d22 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 19 Aug 2020 12:33:19 -0500 Subject: [PATCH] Add support for commands iterable on color schemes (#7329) ## Summary of the Pull Request ![cmdpal-set-color-scheme](https://user-images.githubusercontent.com/18356694/90517094-8eddd480-e12a-11ea-8be4-8b6782d8d88c.gif) Allows for creating commands that iterate over the user's color schemes. Also adds a top-level nested command to `defaults.json` that allows the user to select a color scheme (pictured above). I'm not sure there are really any other use cases that make sense, but it _really_ makes sense for this one. ## References * #5400 - cmdpal megathread * made possible by #6856, _and support from viewers like you._ * All this is being done in pursuit of #6689 ## PR Checklist * [x] Closes wait what? I could have swore there was an issue for this one... * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - okay maybe now I'll write some docs ## Detailed Description of the Pull Request / Additional comments Most of the hard work for this was already done in #6856. This is just another thing to iterate over. ## Validation Steps Performed * Played with this default command. It works great. * Added tests. --- .../LocalTests_TerminalApp/SettingsTests.cpp | 155 +++++++++++++++++- src/cascadia/TerminalApp/Command.cpp | 74 ++++++--- src/cascadia/TerminalApp/Command.h | 11 +- .../Resources/en-US/Resources.resw | 3 + src/cascadia/TerminalApp/SettingsTypes.h | 7 + src/cascadia/TerminalApp/TerminalPage.cpp | 27 ++- src/cascadia/TerminalApp/TerminalPage.h | 3 +- .../TerminalSettingsSerializationHelpers.h | 8 + src/cascadia/TerminalApp/defaults.json | 13 +- 9 files changed, 258 insertions(+), 43 deletions(-) diff --git a/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp b/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp index b99d86e35db..26c764bc8c4 100644 --- a/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp +++ b/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp @@ -97,6 +97,8 @@ namespace TerminalAppLocalTests TEST_METHOD(TestUnbindNestedCommand); TEST_METHOD(TestRebindNestedCommand); + TEST_METHOD(TestIterableColorSchemeCommands); + TEST_CLASS_SETUP(ClassSetup) { InitializeJsonReader(); @@ -2681,7 +2683,7 @@ namespace TerminalAppLocalTests VERIFY_ARE_EQUAL(L"${profile.name}", realArgs.TerminalArgs().Profile()); } - auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands.GetView(), settings.GetProfiles()); + auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands.GetView(), settings.GetProfiles(), settings._globals.GetColorSchemes()); _logCommandNames(expandedCommands); VERIFY_ARE_EQUAL(0u, settings._warnings.size()); @@ -2811,7 +2813,7 @@ namespace TerminalAppLocalTests VERIFY_ARE_EQUAL(L"${profile.name}", realArgs.TerminalArgs().Profile()); } - auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands.GetView(), settings.GetProfiles()); + auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands.GetView(), settings.GetProfiles(), settings._globals.GetColorSchemes()); _logCommandNames(expandedCommands); VERIFY_ARE_EQUAL(0u, settings._warnings.size()); @@ -2944,7 +2946,7 @@ namespace TerminalAppLocalTests } settings._ValidateSettings(); - auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands.GetView(), settings.GetProfiles()); + auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands.GetView(), settings.GetProfiles(), settings._globals.GetColorSchemes()); _logCommandNames(expandedCommands); VERIFY_ARE_EQUAL(0u, settings._warnings.size()); @@ -3065,7 +3067,7 @@ namespace TerminalAppLocalTests auto& commands = settings._globals.GetCommands(); settings._ValidateSettings(); - auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands.GetView(), settings.GetProfiles()); + auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands.GetView(), settings.GetProfiles(), settings._globals.GetColorSchemes()); _logCommandNames(expandedCommands); VERIFY_ARE_EQUAL(0u, settings._warnings.size()); @@ -3173,7 +3175,7 @@ namespace TerminalAppLocalTests auto& commands = settings._globals.GetCommands(); settings._ValidateSettings(); - auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands.GetView(), settings.GetProfiles()); + auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands.GetView(), settings.GetProfiles(), settings._globals.GetColorSchemes()); _logCommandNames(expandedCommands); VERIFY_ARE_EQUAL(0u, settings._warnings.size()); @@ -3312,7 +3314,7 @@ namespace TerminalAppLocalTests auto& commands = settings._globals.GetCommands(); settings._ValidateSettings(); - auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands.GetView(), settings.GetProfiles()); + auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands.GetView(), settings.GetProfiles(), settings._globals.GetColorSchemes()); _logCommandNames(expandedCommands); VERIFY_ARE_EQUAL(0u, settings._warnings.size()); @@ -3465,7 +3467,7 @@ namespace TerminalAppLocalTests auto& commands = settings._globals.GetCommands(); settings._ValidateSettings(); - auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands.GetView(), settings.GetProfiles()); + auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands.GetView(), settings.GetProfiles(), settings._globals.GetColorSchemes()); _logCommandNames(expandedCommands); VERIFY_ARE_EQUAL(0u, settings._warnings.size()); @@ -3578,7 +3580,7 @@ namespace TerminalAppLocalTests auto& commands = settings._globals.GetCommands(); settings._ValidateSettings(); - auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands.GetView(), settings.GetProfiles()); + auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands.GetView(), settings.GetProfiles(), settings._globals.GetColorSchemes()); _logCommandNames(expandedCommands); VERIFY_ARE_EQUAL(0u, settings._warnings.size()); @@ -3942,4 +3944,141 @@ namespace TerminalAppLocalTests } } + void SettingsTests::TestIterableColorSchemeCommands() + { + // For this test, put an iterable command with a given `name`, + // containing a ${profile.name} to replace. When we expand it, it should + // have created one command for each profile. + + const std::string settingsJson{ R"( + { + "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", + "profiles": [ + { + "name": "profile0", + "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", + "historySize": 1, + "commandline": "cmd.exe" + }, + { + "name": "profile1", + "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "historySize": 2, + "commandline": "pwsh.exe" + }, + { + "name": "profile2", + "historySize": 3, + "commandline": "wsl.exe" + } + ], + "schemes": [ + { "name": "scheme_0" }, + { "name": "scheme_1" }, + { "name": "scheme_2" }, + ], + "bindings": [ + { + "name": "iterable command ${scheme.name}", + "iterateOn": "schemes", + "command": { "action": "splitPane", "profile": "${scheme.name}" } + }, + ] + })" }; + + VerifyParseSucceeded(settingsJson); + CascadiaSettings settings{}; + settings._ParseJsonString(settingsJson, false); + settings.LayerJson(settings._userSettings); + + VERIFY_ARE_EQUAL(0u, settings._warnings.size()); + + VERIFY_ARE_EQUAL(3u, settings.GetProfiles().size()); + + auto& commands = settings._globals.GetCommands(); + VERIFY_ARE_EQUAL(1u, commands.Size()); + + { + auto command = commands.Lookup(L"iterable command ${scheme.name}"); + VERIFY_IS_NOT_NULL(command); + auto actionAndArgs = command.Action(); + VERIFY_IS_NOT_NULL(actionAndArgs); + VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action()); + const auto& realArgs = actionAndArgs.Args().try_as(); + VERIFY_IS_NOT_NULL(realArgs); + // Verify the args have the expected value + VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle()); + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"${scheme.name}", realArgs.TerminalArgs().Profile()); + } + + auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands.GetView(), settings.GetProfiles(), settings._globals.GetColorSchemes()); + _logCommandNames(expandedCommands); + + VERIFY_ARE_EQUAL(0u, settings._warnings.size()); + VERIFY_ARE_EQUAL(3u, expandedCommands.Size()); + + // Yes, this test is testing splitPane with profiles named after each + // color scheme. These would obviously not work in real life, they're + // just easy tests to write. + + { + auto command = expandedCommands.Lookup(L"iterable command scheme_0"); + VERIFY_IS_NOT_NULL(command); + auto actionAndArgs = command.Action(); + VERIFY_IS_NOT_NULL(actionAndArgs); + VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action()); + const auto& realArgs = actionAndArgs.Args().try_as(); + VERIFY_IS_NOT_NULL(realArgs); + // Verify the args have the expected value + VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle()); + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"scheme_0", realArgs.TerminalArgs().Profile()); + } + + { + auto command = expandedCommands.Lookup(L"iterable command scheme_1"); + VERIFY_IS_NOT_NULL(command); + auto actionAndArgs = command.Action(); + VERIFY_IS_NOT_NULL(actionAndArgs); + VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action()); + const auto& realArgs = actionAndArgs.Args().try_as(); + VERIFY_IS_NOT_NULL(realArgs); + // Verify the args have the expected value + VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle()); + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"scheme_1", realArgs.TerminalArgs().Profile()); + } + + { + auto command = expandedCommands.Lookup(L"iterable command scheme_2"); + VERIFY_IS_NOT_NULL(command); + auto actionAndArgs = command.Action(); + VERIFY_IS_NOT_NULL(actionAndArgs); + VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action()); + const auto& realArgs = actionAndArgs.Args().try_as(); + VERIFY_IS_NOT_NULL(realArgs); + // Verify the args have the expected value + VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle()); + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"scheme_2", realArgs.TerminalArgs().Profile()); + } + } + } diff --git a/src/cascadia/TerminalApp/Command.cpp b/src/cascadia/TerminalApp/Command.cpp index 10b7adba0aa..b8b8540ef33 100644 --- a/src/cascadia/TerminalApp/Command.cpp +++ b/src/cascadia/TerminalApp/Command.cpp @@ -9,6 +9,7 @@ #include "ActionAndArgs.h" #include "JsonUtils.h" #include +#include "TerminalSettingsSerializationHelpers.h" using namespace winrt::TerminalApp; using namespace winrt::Windows::Foundation; @@ -21,9 +22,8 @@ static constexpr std::string_view ArgsKey{ "args" }; static constexpr std::string_view IterateOnKey{ "iterateOn" }; static constexpr std::string_view CommandsKey{ "commands" }; -static constexpr std::string_view IterateOnProfilesValue{ "profiles" }; - -static constexpr std::string_view ProfileName{ "${profile.name}" }; +static constexpr std::string_view ProfileNameToken{ "${profile.name}" }; +static constexpr std::string_view SchemeNameToken{ "${scheme.name}" }; namespace winrt::TerminalApp::implementation { @@ -121,14 +121,7 @@ namespace winrt::TerminalApp::implementation auto result = winrt::make_self(); bool nested = false; - if (const auto iterateOnJson{ json[JsonKey(IterateOnKey)] }) - { - auto s = iterateOnJson.asString(); - if (s == IterateOnProfilesValue) - { - result->_IterateOn = ExpandCommandType::Profiles; - } - } + JsonUtils::GetValueForKey(json, IterateOnKey, result->_IterateOn); // For iterable commands, we'll make another pass at parsing them once // the json is patched. So ignore parsing sub-commands for now. Commands @@ -290,6 +283,7 @@ namespace winrt::TerminalApp::implementation // - void Command::ExpandCommands(Windows::Foundation::Collections::IMap& commands, gsl::span profiles, + gsl::span schemes, std::vector<::TerminalApp::SettingsLoadWarnings>& warnings) { std::vector commandsToRemove; @@ -300,7 +294,7 @@ namespace winrt::TerminalApp::implementation { auto cmd{ get_self(nameAndCmd.Value()) }; - auto newCommands = _expandCommand(cmd, profiles, warnings); + auto newCommands = _expandCommand(cmd, profiles, schemes, warnings); if (newCommands.size() > 0) { commandsToRemove.push_back(nameAndCmd.Key()); @@ -345,13 +339,14 @@ namespace winrt::TerminalApp::implementation // the newly-created commands. std::vector Command::_expandCommand(Command* const expandable, gsl::span profiles, + gsl::span schemes, std::vector<::TerminalApp::SettingsLoadWarnings>& warnings) { std::vector newCommands; if (expandable->HasNestedCommands()) { - ExpandCommands(expandable->_subcommands, profiles, warnings); + ExpandCommands(expandable->_subcommands, profiles, schemes, warnings); } if (expandable->_IterateOn == ExpandCommandType::None) @@ -365,6 +360,26 @@ namespace winrt::TerminalApp::implementation // First, get a string for the original Json::Value auto oldJsonString = expandable->_originalJson.toStyledString(); + auto reParseJson = [&](const auto& newJsonString) -> bool { + // - Now, re-parse the modified value. + Json::Value newJsonValue; + const auto actualDataStart = newJsonString.data(); + const auto actualDataEnd = newJsonString.data() + newJsonString.size(); + if (!reader->parse(actualDataStart, actualDataEnd, &newJsonValue, &errs)) + { + warnings.push_back(::TerminalApp::SettingsLoadWarnings::FailedToParseCommandJson); + // If we encounter a re-parsing error, just stop processing the rest of the commands. + return false; + } + + // Pass the new json back though FromJson, to get the new expanded value. + if (auto newCmd{ Command::FromJson(newJsonValue, warnings) }) + { + newCommands.push_back(*newCmd); + } + return true; + }; + if (expandable->_IterateOn == ExpandCommandType::Profiles) { for (const auto& p : profiles) @@ -382,24 +397,35 @@ namespace winrt::TerminalApp::implementation // - Escape the profile name for JSON appropriately auto escapedProfileName = _escapeForJson(til::u16u8(p.GetName())); auto newJsonString = til::replace_needle_in_haystack(oldJsonString, - ProfileName, + ProfileNameToken, escapedProfileName); - // - Now, re-parse the modified value. - Json::Value newJsonValue; - const auto actualDataStart = newJsonString.data(); - const auto actualDataEnd = newJsonString.data() + newJsonString.size(); - if (!reader->parse(actualDataStart, actualDataEnd, &newJsonValue, &errs)) + // If we encounter a re-parsing error, just stop processing the rest of the commands. + if (!reParseJson(newJsonString)) { - warnings.push_back(::TerminalApp::SettingsLoadWarnings::FailedToParseCommandJson); - // If we encounter a re-parsing error, just stop processing the rest of the commands. break; } + } + } + else if (expandable->_IterateOn == ExpandCommandType::ColorSchemes) + { + for (const auto& s : schemes) + { + // For each scheme, create a new command. We'll take the + // original json, replace any instances of "${scheme.name}" with + // the scheme's name, then re-attempt to parse the action and + // args. - // Pass the new json back though FromJson, to get the new expanded value. - if (auto newCmd{ Command::FromJson(newJsonValue, warnings) }) + // - Escape the profile name for JSON appropriately + auto escapedSchemeName = _escapeForJson(til::u16u8(s.Name())); + auto newJsonString = til::replace_needle_in_haystack(oldJsonString, + SchemeNameToken, + escapedSchemeName); + + // If we encounter a re-parsing error, just stop processing the rest of the commands. + if (!reParseJson(newJsonString)) { - newCommands.push_back(*newCmd); + break; } } } diff --git a/src/cascadia/TerminalApp/Command.h b/src/cascadia/TerminalApp/Command.h index 700dd87e2d7..1b14ba8031d 100644 --- a/src/cascadia/TerminalApp/Command.h +++ b/src/cascadia/TerminalApp/Command.h @@ -22,6 +22,7 @@ Author(s): #include "TerminalWarnings.h" #include "Profile.h" #include "..\inc\cppwinrt_utils.h" +#include "SettingsTypes.h" // fwdecl unittest classes namespace TerminalAppLocalTests @@ -32,12 +33,6 @@ namespace TerminalAppLocalTests namespace winrt::TerminalApp::implementation { - enum class ExpandCommandType : uint32_t - { - None = 0, - Profiles - }; - struct Command : CommandT { Command(); @@ -47,6 +42,7 @@ namespace winrt::TerminalApp::implementation static void ExpandCommands(Windows::Foundation::Collections::IMap& commands, gsl::span profiles, + gsl::span schemes, std::vector<::TerminalApp::SettingsLoadWarnings>& warnings); static std::vector<::TerminalApp::SettingsLoadWarnings> LayerJson(Windows::Foundation::Collections::IMap& commands, @@ -62,7 +58,7 @@ namespace winrt::TerminalApp::implementation OBSERVABLE_GETSET_PROPERTY(winrt::hstring, KeyChordText, _PropertyChangedHandlers); OBSERVABLE_GETSET_PROPERTY(winrt::Windows::UI::Xaml::Controls::IconSource, IconSource, _PropertyChangedHandlers, nullptr); - GETSET_PROPERTY(ExpandCommandType, IterateOn, ExpandCommandType::None); + GETSET_PROPERTY(::TerminalApp::ExpandCommandType, IterateOn, ::TerminalApp::ExpandCommandType::None); private: Json::Value _originalJson; @@ -70,6 +66,7 @@ namespace winrt::TerminalApp::implementation static std::vector _expandCommand(Command* const expandable, gsl::span profiles, + gsl::span schemes, std::vector<::TerminalApp::SettingsLoadWarnings>& warnings); friend class TerminalAppLocalTests::SettingsTests; friend class TerminalAppLocalTests::CommandTests; diff --git a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw index 9d9cd244648..a7384c7ac4a 100644 --- a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw @@ -573,6 +573,9 @@ Close tabs after index {0} {0} will be replaced with a number + + Select color scheme... + Tab Switcher diff --git a/src/cascadia/TerminalApp/SettingsTypes.h b/src/cascadia/TerminalApp/SettingsTypes.h index 66903ab41a4..5a3cc3da00c 100644 --- a/src/cascadia/TerminalApp/SettingsTypes.h +++ b/src/cascadia/TerminalApp/SettingsTypes.h @@ -25,4 +25,11 @@ namespace TerminalApp std::optional x; std::optional y; }; + + enum class ExpandCommandType : uint32_t + { + None = 0, + Profiles, + ColorSchemes + }; }; diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 307ba9edfea..7049dcf2841 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -2046,6 +2046,14 @@ namespace winrt::TerminalApp::implementation _alwaysOnTopChangedHandlers(*this, nullptr); } + // This is a helper to aid in sorting commands by their `Name`s, alphabetically. + static bool _compareSchemeNames(const winrt::TerminalApp::ColorScheme& lhs, const winrt::TerminalApp::ColorScheme& rhs) + { + std::wstring leftName{ lhs.Name() }; + std::wstring rightName{ rhs.Name() }; + return leftName.compare(rightName) < 0; + } + // Method Description: // - Takes a mapping of names->commands and expands them // Arguments: @@ -2053,9 +2061,22 @@ namespace winrt::TerminalApp::implementation // Return Value: // - IMap TerminalPage::_ExpandCommands(IMapView commandsToExpand, - gsl::span profiles) + gsl::span profiles, + const std::unordered_map& schemes) { std::vector<::TerminalApp::SettingsLoadWarnings> warnings; + + std::vector sortedSchemes; + sortedSchemes.reserve(schemes.size()); + + for (const auto& nameAndScheme : schemes) + { + sortedSchemes.push_back(nameAndScheme.second); + } + std::sort(sortedSchemes.begin(), + sortedSchemes.end(), + _compareSchemeNames); + IMap copyOfCommands = winrt::single_threaded_map(); for (const auto& nameAndCommand : commandsToExpand) { @@ -2064,6 +2085,7 @@ namespace winrt::TerminalApp::implementation Command::ExpandCommands(copyOfCommands, profiles, + sortedSchemes, warnings); return copyOfCommands; @@ -2079,7 +2101,8 @@ namespace winrt::TerminalApp::implementation void TerminalPage::_UpdateCommandsForPalette() { IMap copyOfCommands = _ExpandCommands(_settings->GlobalSettings().GetCommands().GetView(), - _settings->GetProfiles()); + _settings->GetProfiles(), + _settings->GlobalSettings().GetColorSchemes()); _recursiveUpdateCommandKeybindingLabels(_settings, copyOfCommands.GetView()); _recursiveUpdateCommandIcons(copyOfCommands.GetView()); diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index c19c404bc13..17724e198a0 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -137,7 +137,8 @@ namespace winrt::TerminalApp::implementation void _UpdateTabWidthMode(); void _UpdateCommandsForPalette(); static winrt::Windows::Foundation::Collections::IMap _ExpandCommands(Windows::Foundation::Collections::IMapView commandsToExpand, - gsl::span profiles); + gsl::span profiles, + const std::unordered_map& schemes); void _DuplicateTabViewItem(); void _RemoveTabViewItem(const Microsoft::UI::Xaml::Controls::TabViewItem& tabViewItem); diff --git a/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h b/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h index c83d0ae1298..06054eab69a 100644 --- a/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h +++ b/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h @@ -184,6 +184,14 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode) }; }; +JSON_ENUM_MAPPER(::TerminalApp::ExpandCommandType) +{ + JSON_MAPPINGS(2) = { + pair_type{ "profiles", ValueType::Profiles }, + pair_type{ "schemes", ValueType::ColorSchemes }, + }; +}; + JSON_FLAG_MAPPER(::winrt::Microsoft::Terminal::TerminalControl::CopyFormat) { JSON_MAPPINGS(5) = { diff --git a/src/cascadia/TerminalApp/defaults.json b/src/cascadia/TerminalApp/defaults.json index a05668723f8..d4f6b40839d 100644 --- a/src/cascadia/TerminalApp/defaults.json +++ b/src/cascadia/TerminalApp/defaults.json @@ -340,6 +340,17 @@ // Visual Adjustments { "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+=" }, { "command": { "action": "adjustFontSize", "delta": -1 }, "keys": "ctrl+-" }, - { "command": "resetFontSize", "keys": "ctrl+0" } + { "command": "resetFontSize", "keys": "ctrl+0" }, + + { + "name": { "key": "SetColorSchemeParentCommandName" }, + "commands": [ + { + "iterateOn": "schemes", + "name": "${scheme.name}", + "command": { "action": "setColorScheme", "colorScheme": "${scheme.name}" } + } + ] + }, ] }