diff --git a/OpenConsole.sln b/OpenConsole.sln index 82ab30fdc5a..b0934815d1a 100644 --- a/OpenConsole.sln +++ b/OpenConsole.sln @@ -87,8 +87,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Host.Tests.Feature", "src\h ProjectSection(ProjectDependencies) = postProject {18D09A24-8240-42D6-8CB6-236EEE820263} = {18D09A24-8240-42D6-8CB6-236EEE820263} {FC802440-AD6A-4919-8F2C-7701F2B38D79} = {FC802440-AD6A-4919-8F2C-7701F2B38D79} - {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} {58A03BB2-DF5A-4B66-91A0-7EF3BA01269A} = {58A03BB2-DF5A-4B66-91A0-7EF3BA01269A} + {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalParser.UnitTests", "src\terminal\parser\ut_parser\Parser.UnitTests.vcxproj", "{12144E07-FE63-4D33-9231-748B8D8C3792}" @@ -180,6 +180,7 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalApp", "src\cascadia\TerminalApp\dll\TerminalApp.vcxproj", "{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}" ProjectSection(ProjectDependencies) = postProject {CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746} + {CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076} {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} EndProjectSection @@ -225,16 +226,21 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests_TerminalApp", "src\cascadia\ut_app\TerminalApp.UnitTests.vcxproj", "{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}" ProjectSection(ProjectDependencies) = postProject {CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746} + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalAppLib", "src\cascadia\TerminalApp\TerminalAppLib.vcxproj", "{CA5CAD1A-9A12-429C-B551-8562EC954746}" ProjectSection(ProjectDependencies) = postProject + {CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076} {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LocalTests_TerminalApp", "src\cascadia\LocalTests_TerminalApp\TerminalApp.LocalTests.vcxproj", "{CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506}" ProjectSection(ProjectDependencies) = postProject {CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746} + {CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076} + {CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12} = {CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12} + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RendererUia", "src\renderer\uia\lib\uia.vcxproj", "{48D21369-3D7B-4431-9967-24E81292CF63}" @@ -250,6 +256,8 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestHostApp", "src\cascadia\LocalTests_TerminalApp\TestHostApp\TestHostApp.vcxproj", "{A021EDFF-45C8-4DC2-BEF7-36E1B3B8CFE8}" ProjectSection(ProjectDependencies) = postProject {CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506} = {CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506} + {CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076} + {CA5CAD1A-9B68-456A-B13E-C8218070DC42} = {CA5CAD1A-9B68-456A-B13E-C8218070DC42} EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{BDB237B6-1D1D-400F-84CC-40A58FA59C8E}" @@ -307,6 +315,24 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfTerminalTestNetCore", "s EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wt", "src\cascadia\wt\wt.vcxproj", "{506FD703-BAA7-4F6E-9361-64F550EC8FCA}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Settings.Model.Lib", "src\cascadia\TerminalSettingsModel\Microsoft.Terminal.Settings.ModelLib.vcxproj", "{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}" + ProjectSection(ProjectDependencies) = postProject + {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Settings.Model", "src\cascadia\TerminalSettingsModel\dll\Microsoft.Terminal.Settings.Model.vcxproj", "{CA5CAD1A-082C-4476-9F33-94B339494076}" + ProjectSection(ProjectDependencies) = postProject + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LocalTests_SettingsModel", "src\cascadia\LocalTests_SettingsModel\SettingsModel.LocalTests.vcxproj", "{CA5CAD1A-9B68-456A-B13E-C8218070DC42}" + ProjectSection(ProjectDependencies) = postProject + {CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076} + {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} + {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution AuditMode|Any CPU = AuditMode|Any CPU @@ -1986,6 +2012,84 @@ Global {506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x64.Build.0 = Release|x64 {506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x86.ActiveCfg = Release|Win32 {506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x86.Build.0 = Release|Win32 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|ARM64.Build.0 = AuditMode|ARM64 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|x64.ActiveCfg = Release|x64 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|x86.ActiveCfg = AuditMode|Win32 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|x86.Build.0 = AuditMode|Win32 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|ARM64.Build.0 = Debug|ARM64 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|x64.ActiveCfg = Debug|x64 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|x64.Build.0 = Debug|x64 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|x86.ActiveCfg = Debug|Win32 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Debug|x86.Build.0 = Debug|Win32 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|Any CPU.ActiveCfg = Release|Win32 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|ARM64.ActiveCfg = Release|ARM64 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|ARM64.Build.0 = Release|ARM64 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|DotNet_x64Test.ActiveCfg = Release|Win32 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|DotNet_x86Test.ActiveCfg = Release|Win32 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|x64.ActiveCfg = Release|x64 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|x64.Build.0 = Release|x64 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|x86.ActiveCfg = Release|Win32 + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|x86.Build.0 = Release|Win32 + {CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 + {CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64 + {CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|ARM64.Build.0 = AuditMode|ARM64 + {CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32 + {CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32 + {CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|x64.ActiveCfg = Release|x64 + {CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|x86.ActiveCfg = AuditMode|Win32 + {CA5CAD1A-082C-4476-9F33-94B339494076}.AuditMode|x86.Build.0 = AuditMode|Win32 + {CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|ARM64.Build.0 = Debug|ARM64 + {CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32 + {CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32 + {CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|x64.ActiveCfg = Debug|x64 + {CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|x64.Build.0 = Debug|x64 + {CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|x86.ActiveCfg = Debug|Win32 + {CA5CAD1A-082C-4476-9F33-94B339494076}.Debug|x86.Build.0 = Debug|Win32 + {CA5CAD1A-082C-4476-9F33-94B339494076}.Release|Any CPU.ActiveCfg = Release|Win32 + {CA5CAD1A-082C-4476-9F33-94B339494076}.Release|ARM64.ActiveCfg = Release|ARM64 + {CA5CAD1A-082C-4476-9F33-94B339494076}.Release|ARM64.Build.0 = Release|ARM64 + {CA5CAD1A-082C-4476-9F33-94B339494076}.Release|DotNet_x64Test.ActiveCfg = Release|Win32 + {CA5CAD1A-082C-4476-9F33-94B339494076}.Release|DotNet_x86Test.ActiveCfg = Release|Win32 + {CA5CAD1A-082C-4476-9F33-94B339494076}.Release|x64.ActiveCfg = Release|x64 + {CA5CAD1A-082C-4476-9F33-94B339494076}.Release|x64.Build.0 = Release|x64 + {CA5CAD1A-082C-4476-9F33-94B339494076}.Release|x86.ActiveCfg = Release|Win32 + {CA5CAD1A-082C-4476-9F33-94B339494076}.Release|x86.Build.0 = Release|Win32 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|ARM64.Build.0 = AuditMode|ARM64 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|x64.ActiveCfg = AuditMode|x64 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|x86.ActiveCfg = AuditMode|Win32 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.AuditMode|x86.Build.0 = AuditMode|Win32 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|ARM64.Build.0 = Debug|ARM64 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|x64.ActiveCfg = Debug|x64 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|x64.Build.0 = Debug|x64 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|x86.ActiveCfg = Debug|Win32 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Debug|x86.Build.0 = Debug|Win32 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|Any CPU.ActiveCfg = Release|Win32 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|ARM64.ActiveCfg = Release|ARM64 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|ARM64.Build.0 = Release|ARM64 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|DotNet_x64Test.ActiveCfg = Release|Win32 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|DotNet_x86Test.ActiveCfg = Release|Win32 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|x64.ActiveCfg = Release|x64 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|x64.Build.0 = Release|x64 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|x86.ActiveCfg = Release|Win32 + {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2066,6 +2170,9 @@ Global {6BAE5851-50D5-4934-8D5E-30361A8A40F3} = {81C352DB-1818-45B7-A284-18E259F1CC87} {1588FD7C-241E-4E7D-9113-43735F3E6BAD} = {59840756-302F-44DF-AA47-441A9D673202} {506FD703-BAA7-4F6E-9361-64F550EC8FCA} = {59840756-302F-44DF-AA47-441A9D673202} + {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {59840756-302F-44DF-AA47-441A9D673202} + {CA5CAD1A-082C-4476-9F33-94B339494076} = {59840756-302F-44DF-AA47-441A9D673202} + {CA5CAD1A-9B68-456A-B13E-C8218070DC42} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3140B1B7-C8EE-43D1-A772-D82A7061A271} diff --git a/src/cascadia/CascadiaResources.build.items b/src/cascadia/CascadiaResources.build.items index 4eb234e5164..b99fc3ba69d 100644 --- a/src/cascadia/CascadiaResources.build.items +++ b/src/cascadia/CascadiaResources.build.items @@ -26,7 +26,7 @@ ProfileIcons\%(RecursiveDir)%(FileName)%(Extension) - + true %(RecursiveDir)%(FileName)%(Extension) diff --git a/src/cascadia/LocalTests_TerminalApp/ColorSchemeTests.cpp b/src/cascadia/LocalTests_SettingsModel/ColorSchemeTests.cpp similarity index 95% rename from src/cascadia/LocalTests_TerminalApp/ColorSchemeTests.cpp rename to src/cascadia/LocalTests_SettingsModel/ColorSchemeTests.cpp index ac8d9a84d9c..64b96dd8490 100644 --- a/src/cascadia/LocalTests_TerminalApp/ColorSchemeTests.cpp +++ b/src/cascadia/LocalTests_SettingsModel/ColorSchemeTests.cpp @@ -3,18 +3,17 @@ #include "pch.h" -#include "../TerminalApp/ColorScheme.h" -#include "../TerminalApp/CascadiaSettings.h" +#include "../TerminalSettingsModel/ColorScheme.h" +#include "../TerminalSettingsModel/CascadiaSettings.h" #include "JsonTestClass.h" using namespace Microsoft::Console; -using namespace TerminalApp; -using namespace winrt::TerminalApp::implementation; +using namespace winrt::Microsoft::Terminal::Settings::Model::implementation; using namespace WEX::Logging; using namespace WEX::TestExecution; using namespace WEX::Common; -namespace TerminalAppLocalTests +namespace SettingsModelLocalTests { // TODO:microsoft/terminal#3838: // Unfortunately, these tests _WILL NOT_ work in our CI. We're waiting for @@ -193,7 +192,7 @@ namespace TerminalAppLocalTests const auto scheme2Json = VerifyParseSucceeded(scheme2String); const auto scheme3Json = VerifyParseSucceeded(scheme3String); - auto settings = winrt::make_self(); + auto settings = winrt::make_self(); VERIFY_ARE_EQUAL(0u, settings->_globals->ColorSchemes().Size()); VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme0Json)); diff --git a/src/cascadia/LocalTests_TerminalApp/CommandTests.cpp b/src/cascadia/LocalTests_SettingsModel/CommandTests.cpp similarity index 86% rename from src/cascadia/LocalTests_TerminalApp/CommandTests.cpp rename to src/cascadia/LocalTests_SettingsModel/CommandTests.cpp index c2fcc95af9c..b50dd6059d8 100644 --- a/src/cascadia/LocalTests_TerminalApp/CommandTests.cpp +++ b/src/cascadia/LocalTests_SettingsModel/CommandTests.cpp @@ -3,20 +3,19 @@ #include "pch.h" -#include "../TerminalApp/CascadiaSettings.h" +#include "../TerminalSettingsModel/CascadiaSettings.h" #include "JsonTestClass.h" #include "TestUtils.h" using namespace Microsoft::Console; -using namespace TerminalApp; -using namespace winrt::TerminalApp; +using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::TerminalControl; using namespace winrt::Windows::Foundation::Collections; using namespace WEX::Logging; using namespace WEX::TestExecution; using namespace WEX::Common; -namespace TerminalAppLocalTests +namespace SettingsModelLocalTests { // TODO:microsoft/terminal#3838: // Unfortunately, these tests _WILL NOT_ work in our CI. We're waiting for @@ -62,7 +61,7 @@ namespace TerminalAppLocalTests const auto commands1Json = VerifyParseSucceeded(commands1String); const auto commands2Json = VerifyParseSucceeded(commands2String); - IMap commands = winrt::single_threaded_map(); + IMap commands = winrt::single_threaded_map(); VERIFY_ARE_EQUAL(0u, commands.Size()); { auto warnings = implementation::Command::LayerJson(commands, commands0Json); @@ -96,7 +95,7 @@ namespace TerminalAppLocalTests const auto commands2Json = VerifyParseSucceeded(commands2String); const auto commands3Json = VerifyParseSucceeded(commands3String); - IMap commands = winrt::single_threaded_map(); + IMap commands = winrt::single_threaded_map(); VERIFY_ARE_EQUAL(0u, commands.Size()); { auto warnings = implementation::Command::LayerJson(commands, commands0Json); @@ -154,7 +153,7 @@ namespace TerminalAppLocalTests const auto commands0Json = VerifyParseSucceeded(commands0String); - IMap commands = winrt::single_threaded_map(); + IMap commands = winrt::single_threaded_map(); VERIFY_ARE_EQUAL(0u, commands.Size()); auto warnings = implementation::Command::LayerJson(commands, commands0Json); VERIFY_ARE_EQUAL(0u, warnings.size()); @@ -168,7 +167,7 @@ namespace TerminalAppLocalTests const auto& realArgs = command.Action().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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); } { auto command = commands.Lookup(L"command1"); @@ -178,7 +177,7 @@ namespace TerminalAppLocalTests const auto& realArgs = command.Action().Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); // Verify the args have the expected value - VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Vertical, realArgs.SplitStyle()); + VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle()); } { auto command = commands.Lookup(L"command2"); @@ -188,7 +187,7 @@ namespace TerminalAppLocalTests const auto& realArgs = command.Action().Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); // Verify the args have the expected value - VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Horizontal, realArgs.SplitStyle()); + VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle()); } { auto command = commands.Lookup(L"command4"); @@ -198,7 +197,7 @@ namespace TerminalAppLocalTests const auto& realArgs = command.Action().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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); } { auto command = commands.Lookup(L"command5"); @@ -208,7 +207,7 @@ namespace TerminalAppLocalTests const auto& realArgs = command.Action().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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); } } void CommandTests::TestResourceKeyName() @@ -218,7 +217,7 @@ namespace TerminalAppLocalTests const std::string commands0String{ R"([ { "name": { "key": "DuplicateTabCommandKey"}, "command": "copy" } ])" }; const auto commands0Json = VerifyParseSucceeded(commands0String); - IMap commands = winrt::single_threaded_map(); + IMap commands = winrt::single_threaded_map(); VERIFY_ARE_EQUAL(0u, commands.Size()); { auto warnings = implementation::Command::LayerJson(commands, commands0Json); @@ -266,7 +265,7 @@ namespace TerminalAppLocalTests const auto commands0Json = VerifyParseSucceeded(commands0String); - IMap commands = winrt::single_threaded_map(); + IMap commands = winrt::single_threaded_map(); VERIFY_ARE_EQUAL(0u, commands.Size()); auto warnings = implementation::Command::LayerJson(commands, commands0Json); VERIFY_ARE_EQUAL(0u, warnings.size()); @@ -284,7 +283,7 @@ namespace TerminalAppLocalTests const auto& realArgs = command.Action().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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); } { auto command = commands.Lookup(L"Split pane, split: vertical"); @@ -294,7 +293,7 @@ namespace TerminalAppLocalTests const auto& realArgs = command.Action().Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); // Verify the args have the expected value - VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Vertical, realArgs.SplitStyle()); + VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle()); } { auto command = commands.Lookup(L"Split pane, split: horizontal"); @@ -304,7 +303,7 @@ namespace TerminalAppLocalTests const auto& realArgs = command.Action().Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); // Verify the args have the expected value - VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Horizontal, realArgs.SplitStyle()); + VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle()); } } void CommandTests::TestLayerOnAutogeneratedName() @@ -316,7 +315,7 @@ namespace TerminalAppLocalTests const auto commands0Json = VerifyParseSucceeded(commands0String); - IMap commands = winrt::single_threaded_map(); + IMap commands = winrt::single_threaded_map(); VERIFY_ARE_EQUAL(0u, commands.Size()); auto warnings = implementation::Command::LayerJson(commands, commands0Json); VERIFY_ARE_EQUAL(0u, warnings.size()); @@ -330,7 +329,7 @@ namespace TerminalAppLocalTests const auto& realArgs = command.Action().Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); // Verify the args have the expected value - VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Vertical, realArgs.SplitStyle()); + VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle()); } } } diff --git a/src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp b/src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp new file mode 100644 index 00000000000..e6e9037760e --- /dev/null +++ b/src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp @@ -0,0 +1,2373 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "pch.h" + +#include "../TerminalSettingsModel/ColorScheme.h" +#include "../TerminalSettingsModel/CascadiaSettings.h" +#include "JsonTestClass.h" +#include "TestUtils.h" +#include +#include "../ut_app/TestDynamicProfileGenerator.h" + +using namespace Microsoft::Console; +using namespace WEX::Logging; +using namespace WEX::TestExecution; +using namespace WEX::Common; +using namespace winrt::Microsoft::Terminal::Settings::Model; +using namespace winrt::Microsoft::Terminal::TerminalControl; + +namespace SettingsModelLocalTests +{ + // TODO:microsoft/terminal#3838: + // Unfortunately, these tests _WILL NOT_ work in our CI. We're waiting for + // an updated TAEF that will let us install framework packages when the test + // package is deployed. Until then, these tests won't deploy in CI. + + class DeserializationTests : public JsonTestClass + { + // Use a custom AppxManifest to ensure that we can activate winrt types + // from our test. This property will tell taef to manually use this as + // the AppxManifest for this test class. + // This does not yet work for anything XAML-y. See TabTests.cpp for more + // details on that. + BEGIN_TEST_CLASS(DeserializationTests) + TEST_CLASS_PROPERTY(L"RunAs", L"UAP") + TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml") + END_TEST_CLASS() + + TEST_METHOD(ValidateProfilesExist); + TEST_METHOD(ValidateDefaultProfileExists); + TEST_METHOD(ValidateDuplicateProfiles); + TEST_METHOD(ValidateManyWarnings); + TEST_METHOD(LayerGlobalProperties); + TEST_METHOD(ValidateProfileOrdering); + TEST_METHOD(ValidateHideProfiles); + TEST_METHOD(ValidateProfilesGenerateGuids); + TEST_METHOD(GeneratedGuidRoundtrips); + TEST_METHOD(TestAllValidationsWithNullGuids); + TEST_METHOD(TestReorderWithNullGuids); + TEST_METHOD(TestReorderingWithoutGuid); + TEST_METHOD(TestLayeringNameOnlyProfiles); + TEST_METHOD(TestExplodingNameOnlyProfiles); + TEST_METHOD(TestHideAllProfiles); + TEST_METHOD(TestInvalidColorSchemeName); + TEST_METHOD(TestHelperFunctions); + + TEST_METHOD(TestProfileIconWithEnvVar); + TEST_METHOD(TestProfileBackgroundImageWithEnvVar); + + TEST_METHOD(TestCloseOnExitParsing); + TEST_METHOD(TestCloseOnExitCompatibilityShim); + + TEST_METHOD(TestLayerUserDefaultsBeforeProfiles); + TEST_METHOD(TestDontLayerGuidFromUserDefaults); + TEST_METHOD(TestLayerUserDefaultsOnDynamics); + + TEST_METHOD(FindMissingProfile); + + TEST_METHOD(ValidateKeybindingsWarnings); + + TEST_METHOD(ValidateExecuteCommandlineWarning); + + TEST_METHOD(ValidateLegacyGlobalsWarning); + + TEST_METHOD(TestTrailingCommas); + + TEST_METHOD(TestCommandsAndKeybindings); + + TEST_METHOD(TestNestedCommandWithoutName); + TEST_METHOD(TestUnbindNestedCommand); + TEST_METHOD(TestRebindNestedCommand); + + TEST_CLASS_SETUP(ClassSetup) + { + InitializeJsonReader(); + return true; + } + + private: + void _logCommandNames(winrt::Windows::Foundation::Collections::IMapView commands, const int indentation = 1) + { + if (indentation == 1) + { + Log::Comment((commands.Size() == 0) ? L"Commands:\n " : L"Commands:"); + } + for (const auto& nameAndCommand : commands) + { + Log::Comment(fmt::format(L"{0:>{1}}* {2}->{3}", + L"", + indentation, + nameAndCommand.Key(), + nameAndCommand.Value().Name()) + .c_str()); + + winrt::com_ptr cmdImpl; + cmdImpl.copy_from(winrt::get_self(nameAndCommand.Value())); + if (cmdImpl->HasNestedCommands()) + { + _logCommandNames(cmdImpl->_subcommands.GetView(), indentation + 2); + } + } + } + }; + + void DeserializationTests::ValidateProfilesExist() + { + const std::string settingsWithProfiles{ R"( + { + "profiles": [ + { + "name" : "profile0" + } + ] + })" }; + + const std::string settingsWithoutProfiles{ R"( + { + "defaultProfile": "{6239a42c-1de4-49a3-80bd-e8fdd045185c}" + })" }; + + const std::string settingsWithEmptyProfiles{ R"( + { + "profiles": [] + })" }; + + { + // Case 1: Good settings + const auto settingsObject = VerifyParseSucceeded(settingsWithProfiles); + auto settings = implementation::CascadiaSettings::FromJson(settingsObject); + settings->_ValidateProfilesExist(); + } + { + // Case 2: Bad settings + const auto settingsObject = VerifyParseSucceeded(settingsWithoutProfiles); + auto settings = implementation::CascadiaSettings::FromJson(settingsObject); + bool caughtExpectedException = false; + try + { + settings->_ValidateProfilesExist(); + } + catch (const implementation::SettingsException& ex) + { + VERIFY_IS_TRUE(ex.Error() == SettingsLoadErrors::NoProfiles); + caughtExpectedException = true; + } + VERIFY_IS_TRUE(caughtExpectedException); + } + { + // Case 3: Bad settings + const auto settingsObject = VerifyParseSucceeded(settingsWithEmptyProfiles); + auto settings = implementation::CascadiaSettings::FromJson(settingsObject); + bool caughtExpectedException = false; + try + { + settings->_ValidateProfilesExist(); + } + catch (const implementation::SettingsException& ex) + { + VERIFY_IS_TRUE(ex.Error() == SettingsLoadErrors::NoProfiles); + caughtExpectedException = true; + } + VERIFY_IS_TRUE(caughtExpectedException); + } + } + + void DeserializationTests::ValidateDefaultProfileExists() + { + const std::string goodProfiles{ R"( + { + "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "profiles": [ + { + "name" : "profile0", + "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile0", + "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" + } + ] + })" }; + + const std::string badProfiles{ R"( + { + "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "profiles": [ + { + "name" : "profile0", + "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile1", + "guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}" + } + ] + })" }; + + const std::string noDefaultAtAll{ R"( + { + "alwaysShowTabs": true, + "profiles": [ + { + "name" : "profile0", + "guid": "{6239a42c-5555-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile1", + "guid": "{6239a42c-6666-49a3-80bd-e8fdd045185c}" + } + ] + })" }; + + const std::string goodProfilesSpecifiedByName{ R"( + { + "defaultProfile": "profile1", + "profiles": [ + { + "name" : "profile0", + "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile1", + "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" + } + ] + })" }; + + { + // Case 1: Good settings + Log::Comment(NoThrowString().Format( + L"Testing a pair of profiles with unique guids, and the defaultProfile is one of those guids")); + const auto settingsObject = VerifyParseSucceeded(goodProfiles); + auto settings = implementation::CascadiaSettings::FromJson(settingsObject); + settings->_ResolveDefaultProfile(); + settings->_ValidateDefaultProfileExists(); + VERIFY_ARE_EQUAL(static_cast(0), settings->_warnings.Size()); + VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size()); + VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(0).Guid()); + } + { + // Case 2: Bad settings + Log::Comment(NoThrowString().Format( + L"Testing a pair of profiles with unique guids, but the defaultProfile is NOT one of those guids")); + const auto settingsObject = VerifyParseSucceeded(badProfiles); + auto settings = implementation::CascadiaSettings::FromJson(settingsObject); + settings->_ResolveDefaultProfile(); + settings->_ValidateDefaultProfileExists(); + VERIFY_ARE_EQUAL(static_cast(1), settings->_warnings.Size()); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingDefaultProfile, settings->_warnings.GetAt(0)); + + VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size()); + VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(0).Guid()); + } + { + // Case 2: Bad settings + Log::Comment(NoThrowString().Format( + L"Testing a pair of profiles with unique guids, and no defaultProfile at all")); + const auto settingsObject = VerifyParseSucceeded(badProfiles); + auto settings = implementation::CascadiaSettings::FromJson(settingsObject); + settings->_ResolveDefaultProfile(); + settings->_ValidateDefaultProfileExists(); + VERIFY_ARE_EQUAL(static_cast(1), settings->_warnings.Size()); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingDefaultProfile, settings->_warnings.GetAt(0)); + + VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size()); + VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(0).Guid()); + } + { + // Case 4: Good settings, default profile is a string + Log::Comment(NoThrowString().Format( + L"Testing a pair of profiles with unique guids, and the defaultProfile is one of the profile names")); + const auto settingsObject = VerifyParseSucceeded(goodProfilesSpecifiedByName); + auto settings = implementation::CascadiaSettings::FromJson(settingsObject); + settings->_ResolveDefaultProfile(); + settings->_ValidateDefaultProfileExists(); + VERIFY_ARE_EQUAL(static_cast(0), settings->_warnings.Size()); + VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size()); + VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(1).Guid()); + } + } + + void DeserializationTests::ValidateDuplicateProfiles() + { + const std::string goodProfiles{ R"( + { + "profiles": [ + { + "name" : "profile0", + "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile0", + "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" + } + ] + })" }; + + const std::string badProfiles{ R"( + { + "profiles": [ + { + "name" : "profile0", + "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile1", + "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}" + } + ] + })" }; + + const std::string veryBadProfiles{ R"( + { + "profiles": [ + { + "name" : "profile0", + "guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile1", + "guid": "{6239a42c-5555-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile2", + "guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile3", + "guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile4", + "guid": "{6239a42c-6666-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile5", + "guid": "{6239a42c-5555-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile6", + "guid": "{6239a42c-7777-49a3-80bd-e8fdd045185c}" + } + ] + })" }; + Profile profile0 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}")); + profile0.Name(L"profile0"); + Profile profile1 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-5555-49a3-80bd-e8fdd045185c}")); + profile1.Name(L"profile1"); + Profile profile2 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}")); + profile2.Name(L"profile2"); + Profile profile3 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}")); + profile3.Name(L"profile3"); + Profile profile4 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-6666-49a3-80bd-e8fdd045185c}")); + profile4.Name(L"profile4"); + Profile profile5 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-5555-49a3-80bd-e8fdd045185c}")); + profile5.Name(L"profile5"); + Profile profile6 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-7777-49a3-80bd-e8fdd045185c}")); + profile6.Name(L"profile6"); + + { + // Case 1: Good settings + Log::Comment(NoThrowString().Format( + L"Testing a pair of profiles with unique guids")); + + auto settings = winrt::make_self(); + settings->_profiles.Append(profile0); + settings->_profiles.Append(profile1); + + settings->_ValidateNoDuplicateProfiles(); + + VERIFY_ARE_EQUAL(static_cast(0), settings->_warnings.Size()); + VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size()); + } + { + // Case 2: Bad settings + Log::Comment(NoThrowString().Format( + L"Testing a pair of profiles with the same guid")); + + auto settings = winrt::make_self(); + settings->_profiles.Append(profile2); + settings->_profiles.Append(profile3); + + settings->_ValidateNoDuplicateProfiles(); + + VERIFY_ARE_EQUAL(static_cast(1), settings->_warnings.Size()); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::DuplicateProfile, settings->_warnings.GetAt(0)); + + VERIFY_ARE_EQUAL(static_cast(1), settings->_profiles.Size()); + VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name()); + } + { + // Case 3: Very bad settings + Log::Comment(NoThrowString().Format( + L"Testing a set of profiles, many of which with duplicated guids")); + + auto settings = winrt::make_self(); + settings->_profiles.Append(profile0); + settings->_profiles.Append(profile1); + settings->_profiles.Append(profile2); + settings->_profiles.Append(profile3); + settings->_profiles.Append(profile4); + settings->_profiles.Append(profile5); + settings->_profiles.Append(profile6); + + settings->_ValidateNoDuplicateProfiles(); + + VERIFY_ARE_EQUAL(static_cast(1), settings->_warnings.Size()); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::DuplicateProfile, settings->_warnings.GetAt(0)); + + VERIFY_ARE_EQUAL(static_cast(4), settings->_profiles.Size()); + VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(1).Name()); + VERIFY_ARE_EQUAL(L"profile4", settings->_profiles.GetAt(2).Name()); + VERIFY_ARE_EQUAL(L"profile6", settings->_profiles.GetAt(3).Name()); + } + } + + void DeserializationTests::ValidateManyWarnings() + { + const std::string badProfiles{ R"( + { + "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "profiles": [ + { + "name" : "profile0", + "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile1", + "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile2", + "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" + } + ] + })" }; + Profile profile4 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}")); + profile4.Name(L"profile4"); + Profile profile5 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}")); + profile5.Name(L"profile5"); + + // Case 2: Bad settings + Log::Comment(NoThrowString().Format( + L"Testing a pair of profiles with the same guid")); + const auto settingsObject = VerifyParseSucceeded(badProfiles); + auto settings = implementation::CascadiaSettings::FromJson(settingsObject); + + settings->_profiles.Append(profile4); + settings->_profiles.Append(profile5); + + settings->_ValidateSettings(); + + VERIFY_ARE_EQUAL(3u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::DuplicateProfile, settings->_warnings.GetAt(0)); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingDefaultProfile, settings->_warnings.GetAt(1)); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::UnknownColorScheme, settings->_warnings.GetAt(2)); + + VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(0).Guid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid()); + } + + void DeserializationTests::LayerGlobalProperties() + { + const std::string settings0String{ R"( + { + "alwaysShowTabs": true, + "initialCols" : 120, + "initialRows" : 30 + })" }; + const std::string settings1String{ R"( + { + "showTabsInTitlebar": false, + "initialCols" : 240, + "initialRows" : 60 + })" }; + const auto settings0Json = VerifyParseSucceeded(settings0String); + const auto settings1Json = VerifyParseSucceeded(settings1String); + + auto settings = winrt::make_self(); + + settings->LayerJson(settings0Json); + VERIFY_ARE_EQUAL(true, settings->_globals->AlwaysShowTabs()); + VERIFY_ARE_EQUAL(120, settings->_globals->InitialCols()); + VERIFY_ARE_EQUAL(30, settings->_globals->InitialRows()); + VERIFY_ARE_EQUAL(true, settings->_globals->ShowTabsInTitlebar()); + + settings->LayerJson(settings1Json); + VERIFY_ARE_EQUAL(true, settings->_globals->AlwaysShowTabs()); + VERIFY_ARE_EQUAL(240, settings->_globals->InitialCols()); + VERIFY_ARE_EQUAL(60, settings->_globals->InitialRows()); + VERIFY_ARE_EQUAL(false, settings->_globals->ShowTabsInTitlebar()); + } + + void DeserializationTests::ValidateProfileOrdering() + { + const std::string userProfiles0String{ R"( + { + "profiles": [ + { + "name" : "profile0", + "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile1", + "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" + } + ] + })" }; + + const std::string defaultProfilesString{ R"( + { + "profiles": [ + { + "name" : "profile2", + "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile3", + "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}" + } + ] + })" }; + + const std::string userProfiles1String{ R"( + { + "profiles": [ + { + "name" : "profile4", + "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile5", + "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" + } + ] + })" }; + + const auto userProfiles0Json = VerifyParseSucceeded(userProfiles0String); + const auto userProfiles1Json = VerifyParseSucceeded(userProfiles1String); + const auto defaultProfilesJson = VerifyParseSucceeded(defaultProfilesString); + + { + Log::Comment(NoThrowString().Format( + L"Case 1: Simple swapping of the ordering. The user has the " + L"default profiles in the opposite order of the default ordering.")); + + auto settings = winrt::make_self(); + settings->_ParseJsonString(defaultProfilesString, true); + settings->LayerJson(settings->_defaultSettings); + VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"profile3", settings->_profiles.GetAt(1).Name()); + + settings->_ParseJsonString(userProfiles0String, false); + settings->LayerJson(settings->_userSettings); + VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(1).Name()); + + settings->_ReorderProfilesToMatchUserSettingsOrder(); + VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(1).Name()); + } + + { + Log::Comment(NoThrowString().Format( + L"Case 2: Make sure all the user's profiles appear before the defaults.")); + + auto settings = winrt::make_self(); + settings->_ParseJsonString(defaultProfilesString, true); + settings->LayerJson(settings->_defaultSettings); + VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"profile3", settings->_profiles.GetAt(1).Name()); + + settings->_ParseJsonString(userProfiles1String, false); + settings->LayerJson(settings->_userSettings); + VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"profile4", settings->_profiles.GetAt(1).Name()); + VERIFY_ARE_EQUAL(L"profile5", settings->_profiles.GetAt(2).Name()); + + settings->_ReorderProfilesToMatchUserSettingsOrder(); + VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(L"profile4", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"profile5", settings->_profiles.GetAt(1).Name()); + VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(2).Name()); + } + } + + void DeserializationTests::ValidateHideProfiles() + { + const std::string defaultProfilesString{ R"( + { + "profiles": [ + { + "name" : "profile2", + "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile3", + "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}" + } + ] + })" }; + + const std::string userProfiles0String{ R"( + { + "profiles": [ + { + "name" : "profile0", + "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", + "hidden": true + }, + { + "name" : "profile1", + "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" + } + ] + })" }; + + const std::string userProfiles1String{ R"( + { + "profiles": [ + { + "name" : "profile4", + "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", + "hidden": true + }, + { + "name" : "profile5", + "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile6", + "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}", + "hidden": true + } + ] + })" }; + + const auto userProfiles0Json = VerifyParseSucceeded(userProfiles0String); + const auto userProfiles1Json = VerifyParseSucceeded(userProfiles1String); + const auto defaultProfilesJson = VerifyParseSucceeded(defaultProfilesString); + + { + auto settings = winrt::make_self(); + settings->_ParseJsonString(defaultProfilesString, true); + settings->LayerJson(settings->_defaultSettings); + VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"profile3", settings->_profiles.GetAt(1).Name()); + VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden()); + VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(1).Hidden()); + + settings->_ParseJsonString(userProfiles0String, false); + settings->LayerJson(settings->_userSettings); + VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(1).Name()); + VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden()); + VERIFY_ARE_EQUAL(true, settings->_profiles.GetAt(1).Hidden()); + + settings->_ReorderProfilesToMatchUserSettingsOrder(); + settings->_RemoveHiddenProfiles(); + VERIFY_ARE_EQUAL(1u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden()); + } + + { + auto settings = winrt::make_self(); + settings->_ParseJsonString(defaultProfilesString, true); + settings->LayerJson(settings->_defaultSettings); + VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"profile3", settings->_profiles.GetAt(1).Name()); + VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden()); + VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(1).Hidden()); + + settings->_ParseJsonString(userProfiles1String, false); + settings->LayerJson(settings->_userSettings); + VERIFY_ARE_EQUAL(4u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"profile4", settings->_profiles.GetAt(1).Name()); + VERIFY_ARE_EQUAL(L"profile5", settings->_profiles.GetAt(2).Name()); + VERIFY_ARE_EQUAL(L"profile6", settings->_profiles.GetAt(3).Name()); + VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden()); + VERIFY_ARE_EQUAL(true, settings->_profiles.GetAt(1).Hidden()); + VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(2).Hidden()); + VERIFY_ARE_EQUAL(true, settings->_profiles.GetAt(3).Hidden()); + + settings->_ReorderProfilesToMatchUserSettingsOrder(); + settings->_RemoveHiddenProfiles(); + VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(L"profile5", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(1).Name()); + VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden()); + VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(1).Hidden()); + } + } + + void DeserializationTests::ValidateProfilesGenerateGuids() + { + const std::string profile0String{ R"( + { + "name" : "profile0" + })" }; + const std::string profile1String{ R"( + { + "name" : "profile1" + })" }; + const std::string profile2String{ R"( + { + "name" : "profile2", + "guid" : null + })" }; + const std::string profile3String{ R"( + { + "name" : "profile3", + "guid" : "{00000000-0000-0000-0000-000000000000}" + })" }; + const std::string profile4String{ R"( + { + "name" : "profile4", + "guid" : "{6239a42c-1de4-49a3-80bd-e8fdd045185c}" + })" }; + const std::string profile5String{ R"( + { + "name" : "profile2" + })" }; + + const auto profile0Json = VerifyParseSucceeded(profile0String); + const auto profile1Json = VerifyParseSucceeded(profile1String); + const auto profile2Json = VerifyParseSucceeded(profile2String); + const auto profile3Json = VerifyParseSucceeded(profile3String); + const auto profile4Json = VerifyParseSucceeded(profile4String); + const auto profile5Json = VerifyParseSucceeded(profile5String); + + const auto profile0 = implementation::Profile::FromJson(profile0Json); + const auto profile1 = implementation::Profile::FromJson(profile1Json); + const auto profile2 = implementation::Profile::FromJson(profile2Json); + const auto profile3 = implementation::Profile::FromJson(profile3Json); + const auto profile4 = implementation::Profile::FromJson(profile4Json); + const auto profile5 = implementation::Profile::FromJson(profile5Json); + + const winrt::guid cmdGuid{ Utils::GuidFromString(L"{6239a42c-1de4-49a3-80bd-e8fdd045185c}") }; + const winrt::guid nullGuid{}; + + VERIFY_IS_FALSE(profile0->HasGuid()); + VERIFY_IS_FALSE(profile1->HasGuid()); + VERIFY_IS_FALSE(profile2->HasGuid()); + VERIFY_IS_TRUE(profile3->HasGuid()); + VERIFY_IS_TRUE(profile4->HasGuid()); + VERIFY_IS_FALSE(profile5->HasGuid()); + + VERIFY_ARE_EQUAL(profile3->Guid(), nullGuid); + VERIFY_ARE_EQUAL(profile4->Guid(), cmdGuid); + + auto settings = winrt::make_self(); + settings->_profiles.Append(*profile0); + settings->_profiles.Append(*profile1); + settings->_profiles.Append(*profile2); + settings->_profiles.Append(*profile3); + settings->_profiles.Append(*profile4); + settings->_profiles.Append(*profile5); + + settings->_ValidateProfilesHaveGuid(); + VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(4).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(5).HasGuid()); + + VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(0).Guid(), nullGuid); + VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(1).Guid(), nullGuid); + VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(2).Guid(), nullGuid); + VERIFY_ARE_EQUAL(settings->_profiles.GetAt(3).Guid(), nullGuid); + VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(4).Guid(), nullGuid); + VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(5).Guid(), nullGuid); + + VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(0).Guid(), cmdGuid); + VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(1).Guid(), cmdGuid); + VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(2).Guid(), cmdGuid); + VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(3).Guid(), cmdGuid); + VERIFY_ARE_EQUAL(settings->_profiles.GetAt(4).Guid(), cmdGuid); + VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(5).Guid(), cmdGuid); + + VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(0).Guid(), settings->_profiles.GetAt(2).Guid()); + VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(1).Guid(), settings->_profiles.GetAt(2).Guid()); + VERIFY_ARE_EQUAL(settings->_profiles.GetAt(2).Guid(), settings->_profiles.GetAt(2).Guid()); + VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(3).Guid(), settings->_profiles.GetAt(2).Guid()); + VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(4).Guid(), settings->_profiles.GetAt(2).Guid()); + VERIFY_ARE_EQUAL(settings->_profiles.GetAt(5).Guid(), settings->_profiles.GetAt(2).Guid()); + } + + void DeserializationTests::GeneratedGuidRoundtrips() + { + // Parse a profile without a guid. + // We should automatically generate a GUID for that profile. + // When that profile is serialized and deserialized again, the GUID we + // generated for it should persist. + const std::string profileWithoutGuid{ R"({ + "name" : "profile0" + })" }; + const auto profile0Json = VerifyParseSucceeded(profileWithoutGuid); + + const auto profile0 = implementation::Profile::FromJson(profile0Json); + const GUID nullGuid{ 0 }; + + VERIFY_IS_FALSE(profile0->HasGuid()); + + const auto serialized0Profile = profile0->GenerateStub(); + const auto profile1 = implementation::Profile::FromJson(serialized0Profile); + VERIFY_IS_FALSE(profile0->HasGuid()); + VERIFY_IS_FALSE(profile1->HasGuid()); + + auto settings = winrt::make_self(); + settings->_profiles.Append(*profile1); + settings->_ValidateProfilesHaveGuid(); + + VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); + + const auto profileImpl = winrt::get_self(settings->_profiles.GetAt(0)); + const auto serialized1Profile = profileImpl->GenerateStub(); + + const auto profile2 = implementation::Profile::FromJson(serialized1Profile); + VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); + VERIFY_IS_TRUE(profile2->HasGuid()); + VERIFY_ARE_EQUAL(settings->_profiles.GetAt(0).Guid(), profile2->Guid()); + } + + void DeserializationTests::TestAllValidationsWithNullGuids() + { + const std::string settings0String{ R"( + { + "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "profiles": [ + { + "name" : "profile0", + "guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile1" + } + ], + "schemes": [ + { "name": "Campbell" } + ] + })" }; + + const auto settings0Json = VerifyParseSucceeded(settings0String); + + auto settings = winrt::make_self(); + settings->_ParseJsonString(settings0String, false); + settings->LayerJson(settings->_userSettings); + + VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); + VERIFY_IS_FALSE(settings->_profiles.GetAt(1).HasGuid()); + + settings->_ValidateSettings(); + VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); + } + + void DeserializationTests::TestReorderWithNullGuids() + { + const std::string settings0String{ R"( + { + "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "profiles": [ + { + "name" : "profile0", + "guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile1" + }, + { + "name" : "cmdFromUserSettings", + "guid" : "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}" // from defaults.json + } + ] + })" }; + + const auto settings0Json = VerifyParseSucceeded(settings0String); + + auto settings = winrt::make_self(); + settings->_ParseJsonString(DefaultJson, true); + settings->LayerJson(settings->_defaultSettings); + VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); + VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name()); + + settings->_ParseJsonString(settings0String, false); + settings->LayerJson(settings->_userSettings); + + VERIFY_ARE_EQUAL(4u, settings->_profiles.Size()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid()); + VERIFY_IS_FALSE(settings->_profiles.GetAt(3).HasGuid()); + VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"cmdFromUserSettings", settings->_profiles.GetAt(1).Name()); + VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(2).Name()); + VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(3).Name()); + + settings->_ValidateSettings(); + VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(4u, settings->_profiles.Size()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid()); + VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(1).Name()); + VERIFY_ARE_EQUAL(L"cmdFromUserSettings", settings->_profiles.GetAt(2).Name()); + VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(3).Name()); + } + + void DeserializationTests::TestReorderingWithoutGuid() + { + Log::Comment(NoThrowString().Format( + L"During the GH#2515 PR, this set of settings was found to cause an" + L" exception, crashing the terminal. This test ensures that it doesn't.")); + + Log::Comment(NoThrowString().Format( + L"While similar to TestReorderWithNullGuids, there's something else" + L" about this scenario specifically that causes a crash, when " + L" TestReorderWithNullGuids did _not_.")); + + const std::string settings0String{ R"( + { + "defaultProfile" : "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}", + "profiles": [ + { + "guid" : "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}", + "acrylicOpacity" : 0.5, + "closeOnExit" : true, + "background" : "#8A00FF", + "foreground" : "#F2F2F2", + "commandline" : "cmd.exe", + "cursorColor" : "#FFFFFF", + "fontFace" : "Cascadia Code", + "fontSize" : 10, + "historySize" : 9001, + "padding" : "20", + "snapOnInput" : true, + "startingDirectory" : "%USERPROFILE%", + "useAcrylic" : true + }, + { + "name" : "ThisProfileShouldNotCrash", + "tabTitle" : "Ubuntu", + "acrylicOpacity" : 0.5, + "background" : "#2C001E", + "closeOnExit" : true, + "colorScheme" : "Campbell", + "commandline" : "wsl.exe", + "cursorColor" : "#FFFFFF", + "cursorShape" : "bar", + "fontSize" : 10, + "historySize" : 9001, + "padding" : "0, 0, 0, 0", + "snapOnInput" : true, + "useAcrylic" : true + }, + { + // This is the same profile that would be generated by the WSL profile generator. + "name" : "Ubuntu", + "guid" : "{2C4DE342-38B7-51CF-B940-2309A097F518}", + "acrylicOpacity" : 0.5, + "background" : "#2C001E", + "closeOnExit" : false, + "cursorColor" : "#FFFFFF", + "cursorShape" : "bar", + "fontSize" : 10, + "historySize" : 9001, + "snapOnInput" : true, + "useAcrylic" : true + } + ] + })" }; + + const auto settings0Json = VerifyParseSucceeded(settings0String); + + auto settings = winrt::make_self(); + settings->_ParseJsonString(DefaultJson, true); + settings->LayerJson(settings->_defaultSettings); + VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); + VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name()); + + settings->_ParseJsonString(settings0String, false); + settings->LayerJson(settings->_userSettings); + + VERIFY_ARE_EQUAL(4u, settings->_profiles.Size()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); + VERIFY_IS_FALSE(settings->_profiles.GetAt(2).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid()); + VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name()); + VERIFY_ARE_EQUAL(L"ThisProfileShouldNotCrash", settings->_profiles.GetAt(2).Name()); + VERIFY_ARE_EQUAL(L"Ubuntu", settings->_profiles.GetAt(3).Name()); + + settings->_ValidateSettings(); + VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(4u, settings->_profiles.Size()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid()); + VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"ThisProfileShouldNotCrash", settings->_profiles.GetAt(1).Name()); + VERIFY_ARE_EQUAL(L"Ubuntu", settings->_profiles.GetAt(2).Name()); + VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(3).Name()); + } + + void DeserializationTests::TestLayeringNameOnlyProfiles() + { + // This is a test discovered during GH#2782. When we add a name-only + // profile, it should only layer with other name-only profiles with the + // _same name_ + + const std::string settings0String{ R"( + { + "defaultProfile" : "{00000000-0000-5f56-a8ff-afceeeaa6101}", + "profiles": [ + { + "guid" : "{00000000-0000-5f56-a8ff-afceeeaa6101}", + "name" : "ThisProfileIsGood" + + }, + { + "name" : "ThisProfileShouldNotLayer" + }, + { + "name" : "NeitherShouldThisOne" + } + ] + })" }; + + const auto settings0Json = VerifyParseSucceeded(settings0String); + + auto settings = winrt::make_self(); + settings->_ParseJsonString(DefaultJson, true); + settings->LayerJson(settings->_defaultSettings); + VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); + VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name()); + + Log::Comment(NoThrowString().Format( + L"Parse the user settings")); + settings->_ParseJsonString(settings0String, false); + settings->LayerJson(settings->_userSettings); + + VERIFY_ARE_EQUAL(5u, settings->_profiles.Size()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid()); + VERIFY_IS_FALSE(settings->_profiles.GetAt(3).HasGuid()); + VERIFY_IS_FALSE(settings->_profiles.GetAt(4).HasGuid()); + VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name()); + VERIFY_ARE_EQUAL(L"ThisProfileIsGood", settings->_profiles.GetAt(2).Name()); + VERIFY_ARE_EQUAL(L"ThisProfileShouldNotLayer", settings->_profiles.GetAt(3).Name()); + VERIFY_ARE_EQUAL(L"NeitherShouldThisOne", settings->_profiles.GetAt(4).Name()); + } + + void DeserializationTests::TestExplodingNameOnlyProfiles() + { + // This is a test for GH#2782. When we add a name-only profile, we'll + // generate a GUID for it. We should make sure that we don't re-append + // that profile to the list of profiles. + + const std::string settings0String{ R"( + { + "defaultProfile" : "{00000000-0000-5f56-a8ff-afceeeaa6101}", + "profiles": [ + { + "guid" : "{00000000-0000-5f56-a8ff-afceeeaa6101}", + "name" : "ThisProfileIsGood" + + }, + { + "name" : "ThisProfileShouldNotDuplicate" + }, + { + "name" : "NeitherShouldThisOne" + } + ] + })" }; + + const auto settings0Json = VerifyParseSucceeded(settings0String); + + auto settings = winrt::make_self(); + settings->_ParseJsonString(DefaultJson, true); + settings->LayerJson(settings->_defaultSettings); + VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); + VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name()); + + Log::Comment(NoThrowString().Format( + L"Parse the user settings")); + settings->_ParseJsonString(settings0String, false); + settings->LayerJson(settings->_userSettings); + + VERIFY_ARE_EQUAL(5u, settings->_profiles.Size()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid()); + VERIFY_IS_FALSE(settings->_profiles.GetAt(3).HasGuid()); + VERIFY_IS_FALSE(settings->_profiles.GetAt(4).HasGuid()); + VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name()); + VERIFY_ARE_EQUAL(L"ThisProfileIsGood", settings->_profiles.GetAt(2).Name()); + VERIFY_ARE_EQUAL(L"ThisProfileShouldNotDuplicate", settings->_profiles.GetAt(3).Name()); + VERIFY_ARE_EQUAL(L"NeitherShouldThisOne", settings->_profiles.GetAt(4).Name()); + + Log::Comment(NoThrowString().Format( + L"Pretend like we're checking to append dynamic profiles to the " + L"user's settings file. We absolutely _shouldn't_ be adding anything here.")); + bool const needToWriteFile = settings->_AppendDynamicProfilesToUserSettings(); + VERIFY_IS_FALSE(needToWriteFile); + VERIFY_ARE_EQUAL(settings0String.size(), settings->_userSettingsString.size()); + + Log::Comment(NoThrowString().Format( + L"Re-parse the settings file. We should have the _same_ settings as before.")); + Log::Comment(NoThrowString().Format( + L"Do this to a _new_ settings object, to make sure it turns out the same.")); + { + auto settings2 = winrt::make_self(); + settings2->_ParseJsonString(DefaultJson, true); + settings2->LayerJson(settings2->_defaultSettings); + VERIFY_ARE_EQUAL(2u, settings2->_profiles.Size()); + // Initialize the second settings object from the first settings + // object's settings string, the one that we synthesized. + const auto firstSettingsString = settings->_userSettingsString; + settings2->_ParseJsonString(firstSettingsString, false); + settings2->LayerJson(settings2->_userSettings); + VERIFY_ARE_EQUAL(5u, settings2->_profiles.Size()); + VERIFY_IS_TRUE(settings2->_profiles.GetAt(0).HasGuid()); + VERIFY_IS_TRUE(settings2->_profiles.GetAt(1).HasGuid()); + VERIFY_IS_TRUE(settings2->_profiles.GetAt(2).HasGuid()); + VERIFY_IS_FALSE(settings2->_profiles.GetAt(3).HasGuid()); + VERIFY_IS_FALSE(settings2->_profiles.GetAt(4).HasGuid()); + VERIFY_ARE_EQUAL(L"Windows PowerShell", settings2->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"Command Prompt", settings2->_profiles.GetAt(1).Name()); + VERIFY_ARE_EQUAL(L"ThisProfileIsGood", settings2->_profiles.GetAt(2).Name()); + VERIFY_ARE_EQUAL(L"ThisProfileShouldNotDuplicate", settings2->_profiles.GetAt(3).Name()); + VERIFY_ARE_EQUAL(L"NeitherShouldThisOne", settings2->_profiles.GetAt(4).Name()); + } + + Log::Comment(NoThrowString().Format( + L"Validate the settings. All the profiles we have should be valid.")); + settings->_ValidateSettings(); + + VERIFY_ARE_EQUAL(5u, settings->_profiles.Size()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(4).HasGuid()); + VERIFY_ARE_EQUAL(L"ThisProfileIsGood", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"ThisProfileShouldNotDuplicate", settings->_profiles.GetAt(1).Name()); + VERIFY_ARE_EQUAL(L"NeitherShouldThisOne", settings->_profiles.GetAt(2).Name()); + VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(3).Name()); + VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(4).Name()); + } + + void DeserializationTests::TestHideAllProfiles() + { + const std::string settingsWithProfiles{ R"( + { + "profiles": [ + { + "name" : "profile0", + "hidden": false + }, + { + "name" : "profile1", + "hidden": true + } + ] + })" }; + + const std::string settingsWithoutProfiles{ R"( + { + "profiles": [ + { + "name" : "profile0", + "hidden": true + }, + { + "name" : "profile1", + "hidden": true + } + ] + })" }; + + VerifyParseSucceeded(settingsWithProfiles); + VerifyParseSucceeded(settingsWithoutProfiles); + + { + // Case 1: Good settings + auto settings = winrt::make_self(); + settings->_ParseJsonString(settingsWithProfiles, false); + settings->LayerJson(settings->_userSettings); + + settings->_RemoveHiddenProfiles(); + Log::Comment(NoThrowString().Format( + L"settingsWithProfiles successfully parsed and validated")); + VERIFY_ARE_EQUAL(1u, settings->_profiles.Size()); + } + { + // Case 2: Bad settings + auto settings = winrt::make_self(); + settings->_ParseJsonString(settingsWithoutProfiles, false); + settings->LayerJson(settings->_userSettings); + + bool caughtExpectedException = false; + try + { + settings->_RemoveHiddenProfiles(); + } + catch (const implementation::SettingsException& ex) + { + VERIFY_IS_TRUE(ex.Error() == SettingsLoadErrors::AllProfilesHidden); + caughtExpectedException = true; + } + VERIFY_IS_TRUE(caughtExpectedException); + } + } + + void DeserializationTests::TestInvalidColorSchemeName() + { + Log::Comment(NoThrowString().Format( + L"Ensure that setting a profile's scheme to a non-existent scheme causes a warning.")); + + const std::string settings0String{ R"( + { + "profiles": [ + { + "name" : "profile0", + "colorScheme": "schemeOne" + }, + { + "name" : "profile1", + "colorScheme": "InvalidSchemeName" + }, + { + "name" : "profile2" + // Will use the Profile default value, "Campbell" + } + ], + "schemes": [ + { + "name": "schemeOne", + "foreground": "#111111" + }, + { + "name": "schemeTwo", + "foreground": "#222222" + } + ] + })" }; + + VerifyParseSucceeded(settings0String); + + auto settings = winrt::make_self(); + settings->_ParseJsonString(settings0String, false); + settings->LayerJson(settings->_userSettings); + + VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(2u, settings->_globals->ColorSchemes().Size()); + + VERIFY_ARE_EQUAL(L"schemeOne", settings->_profiles.GetAt(0).ColorSchemeName()); + VERIFY_ARE_EQUAL(L"InvalidSchemeName", settings->_profiles.GetAt(1).ColorSchemeName()); + VERIFY_ARE_EQUAL(L"Campbell", settings->_profiles.GetAt(2).ColorSchemeName()); + + settings->_ValidateAllSchemesExist(); + + VERIFY_ARE_EQUAL(1u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::UnknownColorScheme, settings->_warnings.GetAt(0)); + + VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(2u, settings->_globals->ColorSchemes().Size()); + + VERIFY_ARE_EQUAL(L"schemeOne", settings->_profiles.GetAt(0).ColorSchemeName()); + VERIFY_ARE_EQUAL(L"Campbell", settings->_profiles.GetAt(1).ColorSchemeName()); + VERIFY_ARE_EQUAL(L"Campbell", settings->_profiles.GetAt(2).ColorSchemeName()); + } + + void DeserializationTests::TestHelperFunctions() + { + const std::string settings0String{ R"( + { + "defaultProfile" : "{2C4DE342-38B7-51CF-B940-2309A097F518}", + "profiles": [ + { + "name" : "profile0", + "guid": "{6239a42c-5555-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile1", + "guid": "{6239a42c-6666-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "ThisProfileShouldNotThrow" + }, + { + "name" : "Ubuntu", + "guid" : "{2C4DE342-38B7-51CF-B940-2309A097F518}" + } + ] + })" }; + + auto name0{ L"profile0" }; + auto name1{ L"profile1" }; + auto name2{ L"Ubuntu" }; + auto name3{ L"ThisProfileShouldNotThrow" }; + auto badName{ L"DoesNotExist" }; + + const winrt::guid guid0{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-5555-49a3-80bd-e8fdd045185c}") }; + const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-6666-49a3-80bd-e8fdd045185c}") }; + const winrt::guid guid2{ ::Microsoft::Console::Utils::GuidFromString(L"{2C4DE342-38B7-51CF-B940-2309A097F518}") }; + const winrt::guid fakeGuid{ ::Microsoft::Console::Utils::GuidFromString(L"{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}") }; + const std::optional badGuid{}; + + VerifyParseSucceeded(settings0String); + + auto settings = winrt::make_self(); + settings->_ParseJsonString(settings0String, false); + settings->LayerJson(settings->_userSettings); + + VERIFY_ARE_EQUAL(guid0, settings->_GetProfileGuidByName(name0)); + VERIFY_ARE_EQUAL(guid1, settings->_GetProfileGuidByName(name1)); + VERIFY_ARE_EQUAL(guid2, settings->_GetProfileGuidByName(name2)); + VERIFY_ARE_EQUAL(badGuid, settings->_GetProfileGuidByName(name3)); + VERIFY_ARE_EQUAL(badGuid, settings->_GetProfileGuidByName(badName)); + + auto prof0{ settings->FindProfile(guid0) }; + auto prof1{ settings->FindProfile(guid1) }; + auto prof2{ settings->FindProfile(guid2) }; + + auto badProf{ settings->FindProfile(fakeGuid) }; + VERIFY_ARE_EQUAL(badProf, nullptr); + + VERIFY_ARE_EQUAL(name0, prof0.Name()); + VERIFY_ARE_EQUAL(name1, prof1.Name()); + VERIFY_ARE_EQUAL(name2, prof2.Name()); + } + + void DeserializationTests::TestProfileIconWithEnvVar() + { + const auto expectedPath = wil::ExpandEnvironmentStringsW(L"%WINDIR%\\System32\\x_80.png"); + + const std::string settingsJson{ R"( + { + "profiles": [ + { + "name": "profile0", + "icon": "%WINDIR%\\System32\\x_80.png" + } + ] + })" }; + + VerifyParseSucceeded(settingsJson); + + auto settings = winrt::make_self(); + settings->_ParseJsonString(settingsJson, false); + settings->LayerJson(settings->_userSettings); + VERIFY_ARE_NOT_EQUAL(0u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(expectedPath, settings->_profiles.GetAt(0).ExpandedIconPath()); + } + void DeserializationTests::TestProfileBackgroundImageWithEnvVar() + { + const auto expectedPath = wil::ExpandEnvironmentStringsW(L"%WINDIR%\\System32\\x_80.png"); + + const std::string settingsJson{ R"( + { + "profiles": [ + { + "name": "profile0", + "backgroundImage": "%WINDIR%\\System32\\x_80.png" + } + ] + })" }; + + VerifyParseSucceeded(settingsJson); + + auto settings = winrt::make_self(); + settings->_ParseJsonString(settingsJson, false); + settings->LayerJson(settings->_userSettings); + VERIFY_ARE_NOT_EQUAL(0u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(expectedPath, settings->_profiles.GetAt(0).ExpandedBackgroundImagePath()); + } + void DeserializationTests::TestCloseOnExitParsing() + { + const std::string settingsJson{ R"( + { + "profiles": [ + { + "name": "profile0", + "closeOnExit": "graceful" + }, + { + "name": "profile1", + "closeOnExit": "always" + }, + { + "name": "profile2", + "closeOnExit": "never" + }, + { + "name": "profile3", + "closeOnExit": null + } + ] + })" }; + + VerifyParseSucceeded(settingsJson); + + auto settings = winrt::make_self(); + settings->_ParseJsonString(settingsJson, false); + settings->LayerJson(settings->_userSettings); + VERIFY_ARE_EQUAL(CloseOnExitMode::Graceful, settings->_profiles.GetAt(0).CloseOnExit()); + VERIFY_ARE_EQUAL(CloseOnExitMode::Always, settings->_profiles.GetAt(1).CloseOnExit()); + VERIFY_ARE_EQUAL(CloseOnExitMode::Never, settings->_profiles.GetAt(2).CloseOnExit()); + + // Unknown modes parse as "Graceful" + VERIFY_ARE_EQUAL(CloseOnExitMode::Graceful, settings->_profiles.GetAt(3).CloseOnExit()); + } + void DeserializationTests::TestCloseOnExitCompatibilityShim() + { + const std::string settingsJson{ R"( + { + "profiles": [ + { + "name": "profile0", + "closeOnExit": true + }, + { + "name": "profile1", + "closeOnExit": false + } + ] + })" }; + + VerifyParseSucceeded(settingsJson); + + auto settings = winrt::make_self(); + settings->_ParseJsonString(settingsJson, false); + settings->LayerJson(settings->_userSettings); + VERIFY_ARE_EQUAL(CloseOnExitMode::Graceful, settings->_profiles.GetAt(0).CloseOnExit()); + VERIFY_ARE_EQUAL(CloseOnExitMode::Never, settings->_profiles.GetAt(1).CloseOnExit()); + } + + void DeserializationTests::TestLayerUserDefaultsBeforeProfiles() + { + // Test for microsoft/terminal#2325. For this test, we'll be setting the + // "historySize" in the "defaultSettings", so it should apply to all + // profiles, unless they override it. In one of the user's profiles, + // we'll override that value, and in the other, we'll leave it + // untouched. + + const std::string settings0String{ R"( + { + "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "profiles": { + "defaults": { + "historySize": 1234 + }, + "list": [ + { + "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "name": "profile0", + "historySize": 2345 + }, + { + "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}", + "name": "profile1" + } + ] + } + })" }; + VerifyParseSucceeded(settings0String); + + const auto guid1String = L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"; + + { + auto settings = winrt::make_self(false); + settings->_ParseJsonString(settings0String, false); + VERIFY_IS_TRUE(settings->_userDefaultProfileSettings == Json::Value::null); + settings->_ApplyDefaultsFromUserSettings(); + VERIFY_IS_FALSE(settings->_userDefaultProfileSettings == Json::Value::null); + settings->LayerJson(settings->_userSettings); + + VERIFY_ARE_EQUAL(guid1String, settings->_globals->UnparsedDefaultProfile()); + VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); + + VERIFY_ARE_EQUAL(2345, settings->_profiles.GetAt(0).HistorySize()); + VERIFY_ARE_EQUAL(1234, settings->_profiles.GetAt(1).HistorySize()); + } + } + + void DeserializationTests::TestDontLayerGuidFromUserDefaults() + { + // Test for microsoft/terminal#2325. We don't want the user to put a + // "guid" in the "defaultSettings", and have that apply to all the other + // profiles + + const std::string settings0String{ R"( + { + "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "profiles": { + "defaults": { + "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" + }, + "list": [ + { + "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "name": "profile0", + "historySize": 2345 + }, + { + // Doesn't have a GUID, we'll auto-generate one + "name": "profile1" + } + ] + } + })" }; + VerifyParseSucceeded(settings0String); + + const auto guid1String = L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"; + const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(guid1String) }; + const winrt::guid guid2{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}") }; + + { + auto settings = winrt::make_self(false); + settings->_ParseJsonString(DefaultJson, true); + settings->LayerJson(settings->_defaultSettings); + VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); + + settings->_ParseJsonString(settings0String, false); + VERIFY_IS_TRUE(settings->_userDefaultProfileSettings == Json::Value::null); + settings->_ApplyDefaultsFromUserSettings(); + VERIFY_IS_FALSE(settings->_userDefaultProfileSettings == Json::Value::null); + + Log::Comment(NoThrowString().Format( + L"Ensure that cmd and powershell don't get their GUIDs overwritten")); + VERIFY_ARE_NOT_EQUAL(guid2, settings->_profiles.GetAt(0).Guid()); + VERIFY_ARE_NOT_EQUAL(guid2, settings->_profiles.GetAt(1).Guid()); + + settings->LayerJson(settings->_userSettings); + + VERIFY_ARE_EQUAL(guid1String, settings->_globals->UnparsedDefaultProfile()); + VERIFY_ARE_EQUAL(4u, settings->_profiles.Size()); + + VERIFY_ARE_EQUAL(guid1, settings->_profiles.GetAt(2).Guid()); + VERIFY_IS_FALSE(settings->_profiles.GetAt(3).HasGuid()); + } + } + + void DeserializationTests::TestLayerUserDefaultsOnDynamics() + { + // Test for microsoft/terminal#2325. For this test, we'll be setting the + // "historySize" in the "defaultSettings", so it should apply to all + // profiles, unless they override it. The dynamic profiles will _also_ + // set this value, but from discussion in GH#2325, we decided that + // settings in defaultSettings should apply _on top_ of settings from + // dynamic profiles. + + const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}") }; + const winrt::guid guid2{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}") }; + const winrt::guid guid3{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-3333-49a3-80bd-e8fdd045185c}") }; + + const std::string userProfiles{ R"( + { + "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "profiles": { + "defaults": { + "historySize": 1234 + }, + "list": [ + { + "name" : "profile0FromUserSettings", // this is _profiles.GetAt(0) + "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "source": "Terminal.App.UnitTest.0" + }, + { + "name" : "profile1FromUserSettings", // this is _profiles.GetAt(2) + "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}", + "source": "Terminal.App.UnitTest.1", + "historySize": 4444 + }, + { + "name" : "profile2FromUserSettings", // this is _profiles.GetAt(3) + "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}", + "historySize": 5555 + } + ] + } + })" }; + + auto gen0 = std::make_unique(L"Terminal.App.UnitTest.0"); + gen0->pfnGenerate = [guid1, guid2]() { + std::vector profiles; + Profile p0 = winrt::make(guid1); + p0.Name(L"profile0"); // this is _profiles.GetAt(0) + p0.HistorySize(1111); + profiles.push_back(p0); + return profiles; + }; + auto gen1 = std::make_unique(L"Terminal.App.UnitTest.1"); + gen1->pfnGenerate = [guid1, guid2]() { + std::vector profiles; + Profile p0 = winrt::make(guid1); + Profile p1 = winrt::make(guid2); + p0.Name(L"profile0"); // this is _profiles.GetAt(1) + p1.Name(L"profile1"); // this is _profiles.GetAt(2) + p0.HistorySize(2222); + profiles.push_back(p0); + p1.HistorySize(3333); + profiles.push_back(p1); + return profiles; + }; + + auto settings = winrt::make_self(false); + settings->_profileGenerators.emplace_back(std::move(gen0)); + settings->_profileGenerators.emplace_back(std::move(gen1)); + + Log::Comment(NoThrowString().Format( + L"All profiles with the same name have the same GUID. However, they" + L" will not be layered, because they have different source's")); + + // parse userProfiles as the user settings + settings->_ParseJsonString(userProfiles, false); + VERIFY_ARE_EQUAL(0u, settings->_profiles.Size(), L"Just parsing the user settings doesn't actually layer them"); + settings->_LoadDynamicProfiles(); + VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); + + VERIFY_ARE_EQUAL(1111, settings->_profiles.GetAt(0).HistorySize()); + VERIFY_ARE_EQUAL(2222, settings->_profiles.GetAt(1).HistorySize()); + VERIFY_ARE_EQUAL(3333, settings->_profiles.GetAt(2).HistorySize()); + + settings->_ApplyDefaultsFromUserSettings(); + + VERIFY_ARE_EQUAL(1234, settings->_profiles.GetAt(0).HistorySize()); + VERIFY_ARE_EQUAL(1234, settings->_profiles.GetAt(1).HistorySize()); + VERIFY_ARE_EQUAL(1234, settings->_profiles.GetAt(2).HistorySize()); + + settings->LayerJson(settings->_userSettings); + VERIFY_ARE_EQUAL(4u, settings->_profiles.Size()); + + VERIFY_IS_FALSE(settings->_profiles.GetAt(0).Source().empty()); + VERIFY_IS_FALSE(settings->_profiles.GetAt(1).Source().empty()); + VERIFY_IS_FALSE(settings->_profiles.GetAt(2).Source().empty()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(3).Source().empty()); + + VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.0", settings->_profiles.GetAt(0).Source()); + VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.1", settings->_profiles.GetAt(1).Source()); + VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.1", settings->_profiles.GetAt(2).Source()); + + VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); + VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid()); + + VERIFY_ARE_EQUAL(guid1, settings->_profiles.GetAt(0).Guid()); + VERIFY_ARE_EQUAL(guid1, settings->_profiles.GetAt(1).Guid()); + VERIFY_ARE_EQUAL(guid2, settings->_profiles.GetAt(2).Guid()); + + VERIFY_ARE_EQUAL(L"profile0FromUserSettings", settings->_profiles.GetAt(0).Name()); + VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(1).Name()); + VERIFY_ARE_EQUAL(L"profile1FromUserSettings", settings->_profiles.GetAt(2).Name()); + VERIFY_ARE_EQUAL(L"profile2FromUserSettings", settings->_profiles.GetAt(3).Name()); + + Log::Comment(NoThrowString().Format( + L"This is the real meat of the test: The two dynamic profiles that " + L"_didn't_ have historySize set in the userSettings should have " + L"1234 as their historySize(from the defaultSettings).The other two" + L" profiles should have their custom historySize value.")); + + VERIFY_ARE_EQUAL(1234, settings->_profiles.GetAt(0).HistorySize()); + VERIFY_ARE_EQUAL(1234, settings->_profiles.GetAt(1).HistorySize()); + VERIFY_ARE_EQUAL(4444, settings->_profiles.GetAt(2).HistorySize()); + VERIFY_ARE_EQUAL(5555, settings->_profiles.GetAt(3).HistorySize()); + } + + void DeserializationTests::FindMissingProfile() + { + // Test that CascadiaSettings::FindProfile returns null for a GUID that + // doesn't exist + const std::string settingsString{ R"( + { + "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "profiles": [ + { + "name" : "profile0", + "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile1", + "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" + } + ] + })" }; + const auto settingsJsonObj = VerifyParseSucceeded(settingsString); + auto settings = implementation::CascadiaSettings::FromJson(settingsJsonObj); + + const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"); + const auto guid2 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}"); + const auto guid3 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-3333-49a3-80bd-e8fdd045185c}"); + + const auto profile1 = settings->FindProfile(guid1); + const auto profile2 = settings->FindProfile(guid2); + const auto profile3 = settings->FindProfile(guid3); + + VERIFY_IS_NOT_NULL(profile1); + VERIFY_IS_NOT_NULL(profile2); + VERIFY_IS_NULL(profile3); + + VERIFY_ARE_EQUAL(L"profile0", profile1.Name()); + VERIFY_ARE_EQUAL(L"profile1", profile2.Name()); + } + + void DeserializationTests::ValidateKeybindingsWarnings() + { + const std::string badSettings{ R"( + { + "defaultProfile": "{6239a42c-2222-49a3-80bd-e8fdd045185c}", + "profiles": [ + { + "name" : "profile0", + "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile1", + "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}" + } + ], + "keybindings": [ + { "command": { "action": "splitPane", "split":"auto" }, "keys": [ "ctrl+alt+t", "ctrl+a" ] }, + { "command": { "action": "moveFocus" }, "keys": [ "ctrl+a" ] }, + { "command": { "action": "resizePane" }, "keys": [ "ctrl+b" ] } + ] + })" }; + + const auto settingsObject = VerifyParseSucceeded(badSettings); + auto settings = implementation::CascadiaSettings::FromJson(settingsObject); + + VERIFY_ARE_EQUAL(0u, settings->_globals->_keymap->_keyShortcuts.size()); + + VERIFY_ARE_EQUAL(3u, settings->_globals->_keybindingsWarnings.size()); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::TooManyKeysForChord, settings->_globals->_keybindingsWarnings.at(0)); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_globals->_keybindingsWarnings.at(1)); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_globals->_keybindingsWarnings.at(2)); + + settings->_ValidateKeybindings(); + + VERIFY_ARE_EQUAL(4u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::AtLeastOneKeybindingWarning, settings->_warnings.GetAt(0)); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::TooManyKeysForChord, settings->_warnings.GetAt(1)); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.GetAt(2)); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.GetAt(3)); + } + + void DeserializationTests::ValidateExecuteCommandlineWarning() + { + const std::string badSettings{ R"( + { + "defaultProfile": "{6239a42c-2222-49a3-80bd-e8fdd045185c}", + "profiles": [ + { + "name" : "profile0", + "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile1", + "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}" + } + ], + "keybindings": [ + { "name":null, "command": { "action": "wt" }, "keys": [ "ctrl+a" ] }, + { "name":null, "command": { "action": "wt", "commandline":"" }, "keys": [ "ctrl+b" ] }, + { "name":null, "command": { "action": "wt", "commandline":null }, "keys": [ "ctrl+c" ] } + ] + })" }; + + const auto settingsObject = VerifyParseSucceeded(badSettings); + + auto settings = implementation::CascadiaSettings::FromJson(settingsObject); + + VERIFY_ARE_EQUAL(0u, settings->_globals->_keymap->_keyShortcuts.size()); + + for (const auto& warning : settings->_globals->_keybindingsWarnings) + { + Log::Comment(NoThrowString().Format( + L"warning:%d", warning)); + } + VERIFY_ARE_EQUAL(3u, settings->_globals->_keybindingsWarnings.size()); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_globals->_keybindingsWarnings.at(0)); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_globals->_keybindingsWarnings.at(1)); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_globals->_keybindingsWarnings.at(2)); + + settings->_ValidateKeybindings(); + + VERIFY_ARE_EQUAL(4u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::AtLeastOneKeybindingWarning, settings->_warnings.GetAt(0)); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.GetAt(1)); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.GetAt(2)); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.GetAt(3)); + } + + void DeserializationTests::ValidateLegacyGlobalsWarning() + { + const std::string badSettings{ R"( + { + "globals": {}, + "defaultProfile": "{6239a42c-2222-49a3-80bd-e8fdd045185c}", + "profiles": [ + { + "name" : "profile0", + "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile1", + "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}" + } + ], + "keybindings": [] + })" }; + + // Create the default settings + auto settings = winrt::make_self(); + settings->_ParseJsonString(DefaultJson, true); + settings->LayerJson(settings->_defaultSettings); + + settings->_ValidateNoGlobalsKey(); + VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + + // Now layer on the user's settings + settings->_ParseJsonString(badSettings, false); + settings->LayerJson(settings->_userSettings); + + settings->_ValidateNoGlobalsKey(); + VERIFY_ARE_EQUAL(1u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(SettingsLoadWarnings::LegacyGlobalsProperty, settings->_warnings.GetAt(0)); + } + + void DeserializationTests::TestTrailingCommas() + { + const std::string badSettings{ R"( + { + "defaultProfile": "{6239a42c-2222-49a3-80bd-e8fdd045185c}", + "profiles": [ + { + "name" : "profile0", + "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" + }, + { + "name" : "profile1", + "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}" + }, + ], + "keybindings": [], + })" }; + + // Create the default settings + auto settings = winrt::make_self(); + settings->_ParseJsonString(DefaultJson, true); + settings->LayerJson(settings->_defaultSettings); + + // Now layer on the user's settings + try + { + settings->_ParseJsonString(badSettings, false); + settings->LayerJson(settings->_userSettings); + } + catch (...) + { + VERIFY_IS_TRUE(false, L"This call to LayerJson should succeed, even with the trailing comma"); + } + } + + void DeserializationTests::TestCommandsAndKeybindings() + { + 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" + } + ], + "actions": [ + { "keys": "ctrl+a", "command": { "action": "splitPane", "split": "vertical" } }, + { "name": "ctrl+b", "command": { "action": "splitPane", "split": "vertical" } }, + { "keys": "ctrl+c", "name": "ctrl+c", "command": { "action": "splitPane", "split": "vertical" } }, + { "keys": "ctrl+d", "command": { "action": "splitPane", "split": "vertical" } }, + { "keys": "ctrl+e", "command": { "action": "splitPane", "split": "horizontal" } }, + { "keys": "ctrl+f", "name":null, "command": { "action": "splitPane", "split": "horizontal" } } + ] + })" }; + + const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}"); + const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"); + + VerifyParseSucceeded(settingsJson); + + auto settings = winrt::make_self(); + settings->_ParseJsonString(settingsJson, false); + settings->LayerJson(settings->_userSettings); + settings->_ValidateSettings(); + + VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); + + const auto profile2Guid = settings->_profiles.GetAt(2).Guid(); + VERIFY_ARE_NOT_EQUAL(winrt::guid{}, profile2Guid); + + auto keymap = winrt::get_self(settings->_globals->KeyMap()); + VERIFY_ARE_EQUAL(5u, keymap->_keyShortcuts.size()); + + // A/D, B, C, E will be in the list of commands, for 4 total. + // * A and D share the same name, so they'll only generate a single action. + // * F's name is set manually to `null` + auto commands = settings->_globals->Commands(); + VERIFY_ARE_EQUAL(4u, commands.Size()); + + { + KeyChord kc{ true, false, false, static_cast('A') }; + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); + 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(SplitState::Vertical, 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_TRUE(realArgs.TerminalArgs().Profile().empty()); + } + + Log::Comment(L"Note that we're skipping ctrl+B, since that doesn't have `keys` set."); + + { + KeyChord kc{ true, false, false, static_cast('C') }; + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); + 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(SplitState::Vertical, 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_TRUE(realArgs.TerminalArgs().Profile().empty()); + } + { + KeyChord kc{ true, false, false, static_cast('D') }; + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); + 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(SplitState::Vertical, 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_TRUE(realArgs.TerminalArgs().Profile().empty()); + } + { + KeyChord kc{ true, false, false, static_cast('E') }; + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); + 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(SplitState::Horizontal, 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_TRUE(realArgs.TerminalArgs().Profile().empty()); + } + { + KeyChord kc{ true, false, false, static_cast('F') }; + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); + 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(SplitState::Horizontal, 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_TRUE(realArgs.TerminalArgs().Profile().empty()); + } + + Log::Comment(L"Now verify the commands"); + _logCommandNames(commands); + { + auto command = commands.Lookup(L"Split pane, split: vertical"); + 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(SplitState::Vertical, 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_TRUE(realArgs.TerminalArgs().Profile().empty()); + } + { + auto command = commands.Lookup(L"ctrl+b"); + 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(SplitState::Vertical, 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_TRUE(realArgs.TerminalArgs().Profile().empty()); + } + { + auto command = commands.Lookup(L"ctrl+c"); + 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(SplitState::Vertical, 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_TRUE(realArgs.TerminalArgs().Profile().empty()); + } + { + auto command = commands.Lookup(L"Split pane, split: horizontal"); + 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(SplitState::Horizontal, 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_TRUE(realArgs.TerminalArgs().Profile().empty()); + } + } + + void DeserializationTests::TestNestedCommandWithoutName() + { + // This test tests a nested command without a name specified. This type + // of command should just be ignored, since we can't auto-generate names + // for nested commands, they _must_ have names specified. + + 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" + } + ], + "actions": [ + { + "commands": [ + { + "name": "child1", + "command": { "action": "newTab", "commandline": "ssh me@first.com" } + }, + { + "name": "child2", + "command": { "action": "newTab", "commandline": "ssh me@second.com" } + } + ] + }, + ], + "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. + })" }; + + VerifyParseSucceeded(settingsJson); + + auto settings = winrt::make_self(); + settings->_ParseJsonString(settingsJson, false); + settings->LayerJson(settings->_userSettings); + + VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); + + auto commands = settings->_globals->Commands(); + settings->_ValidateSettings(); + _logCommandNames(commands); + + VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + + // Because the "parent" command didn't have a name, it couldn't be + // placed into the list of commands. It and it's children are just + // ignored. + VERIFY_ARE_EQUAL(0u, commands.Size()); + } + + void DeserializationTests::TestUnbindNestedCommand() + { + // Test that layering a command with `"commands": null` set will unbind a command that already exists. + + 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" + } + ], + "actions": [ + { + "name": "parent", + "commands": [ + { + "name": "child1", + "command": { "action": "newTab", "commandline": "ssh me@first.com" } + }, + { + "name": "child2", + "command": { "action": "newTab", "commandline": "ssh me@second.com" } + } + ] + }, + ], + "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. + })" }; + + const std::string settings1Json{ R"( + { + "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", + "actions": [ + { + "name": "parent", + "commands": null + }, + ], + })" }; + + VerifyParseSucceeded(settingsJson); + VerifyParseSucceeded(settings1Json); + + auto settings = winrt::make_self(); + settings->_ParseJsonString(settingsJson, false); + settings->LayerJson(settings->_userSettings); + + VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); + + auto commands = settings->_globals->Commands(); + settings->_ValidateSettings(); + _logCommandNames(commands); + + VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(1u, commands.Size()); + + Log::Comment(L"Layer second bit of json, to unbind the original command."); + + settings->_ParseJsonString(settings1Json, false); + settings->LayerJson(settings->_userSettings); + settings->_ValidateSettings(); + _logCommandNames(commands); + VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(0u, commands.Size()); + } + + void DeserializationTests::TestRebindNestedCommand() + { + // Test that layering a command with an action set on top of a command + // with nested commands replaces the nested commands with an action. + + 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" + } + ], + "actions": [ + { + "name": "parent", + "commands": [ + { + "name": "child1", + "command": { "action": "newTab", "commandline": "ssh me@first.com" } + }, + { + "name": "child2", + "command": { "action": "newTab", "commandline": "ssh me@second.com" } + } + ] + }, + ], + "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. + })" }; + + const std::string settings1Json{ R"( + { + "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", + "actions": [ + { + "name": "parent", + "command": "newTab" + }, + ], + })" }; + + VerifyParseSucceeded(settingsJson); + VerifyParseSucceeded(settings1Json); + + auto settings = winrt::make_self(); + settings->_ParseJsonString(settingsJson, false); + settings->LayerJson(settings->_userSettings); + + VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); + + auto commands = settings->_globals->Commands(); + settings->_ValidateSettings(); + _logCommandNames(commands); + + VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(1u, commands.Size()); + + { + winrt::hstring commandName{ L"parent" }; + auto commandProj = commands.Lookup(commandName); + VERIFY_IS_NOT_NULL(commandProj); + + winrt::com_ptr commandImpl; + commandImpl.copy_from(winrt::get_self(commandProj)); + + VERIFY_IS_TRUE(commandImpl->HasNestedCommands()); + VERIFY_ARE_EQUAL(2u, commandImpl->_subcommands.Size()); + } + + Log::Comment(L"Layer second bit of json, to unbind the original command."); + settings->_ParseJsonString(settings1Json, false); + settings->LayerJson(settings->_userSettings); + settings->_ValidateSettings(); + _logCommandNames(commands); + VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(1u, commands.Size()); + + { + winrt::hstring commandName{ L"parent" }; + auto commandProj = commands.Lookup(commandName); + + VERIFY_IS_NOT_NULL(commandProj); + auto actionAndArgs = commandProj.Action(); + VERIFY_IS_NOT_NULL(actionAndArgs); + VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); + const auto& realArgs = actionAndArgs.Args().try_as(); + VERIFY_IS_NOT_NULL(realArgs); + + winrt::com_ptr commandImpl; + commandImpl.copy_from(winrt::get_self(commandProj)); + + VERIFY_IS_FALSE(commandImpl->HasNestedCommands()); + } + } + +} diff --git a/src/cascadia/LocalTests_TerminalApp/JsonTestClass.h b/src/cascadia/LocalTests_SettingsModel/JsonTestClass.h similarity index 100% rename from src/cascadia/LocalTests_TerminalApp/JsonTestClass.h rename to src/cascadia/LocalTests_SettingsModel/JsonTestClass.h diff --git a/src/cascadia/LocalTests_TerminalApp/KeyBindingsTests.cpp b/src/cascadia/LocalTests_SettingsModel/KeyBindingsTests.cpp similarity index 85% rename from src/cascadia/LocalTests_TerminalApp/KeyBindingsTests.cpp rename to src/cascadia/LocalTests_SettingsModel/KeyBindingsTests.cpp index 3115d76abd4..5ff3f2facad 100644 --- a/src/cascadia/LocalTests_TerminalApp/KeyBindingsTests.cpp +++ b/src/cascadia/LocalTests_SettingsModel/KeyBindingsTests.cpp @@ -3,21 +3,20 @@ #include "pch.h" -#include "../TerminalApp/ColorScheme.h" -#include "../TerminalApp/CascadiaSettings.h" -#include "../KeyMapping.h" +#include "../TerminalSettingsModel/ColorScheme.h" +#include "../TerminalSettingsModel/CascadiaSettings.h" +#include "../TerminalSettingsModel/KeyMapping.h" #include "JsonTestClass.h" #include "TestUtils.h" using namespace Microsoft::Console; -using namespace TerminalApp; -using namespace winrt::TerminalApp; +using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::TerminalControl; using namespace WEX::Logging; using namespace WEX::TestExecution; using namespace WEX::Common; -namespace TerminalAppLocalTests +namespace SettingsModelLocalTests { // TODO:microsoft/terminal#3838: // Unfortunately, these tests _WILL NOT_ work in our CI. We're waiting for @@ -67,7 +66,7 @@ namespace TerminalAppLocalTests const auto bindings1Json = VerifyParseSucceeded(bindings1String); const auto bindings2Json = VerifyParseSucceeded(bindings2String); - auto keymap = winrt::make_self(); + auto keymap = winrt::make_self(); VERIFY_IS_NOT_NULL(keymap); VERIFY_ARE_EQUAL(0u, keymap->_keyShortcuts.size()); @@ -91,7 +90,7 @@ namespace TerminalAppLocalTests const auto bindings1Json = VerifyParseSucceeded(bindings1String); const auto bindings2Json = VerifyParseSucceeded(bindings2String); - auto keymap = winrt::make_self(); + auto keymap = winrt::make_self(); VERIFY_IS_NOT_NULL(keymap); VERIFY_ARE_EQUAL(0u, keymap->_keyShortcuts.size()); @@ -121,7 +120,7 @@ namespace TerminalAppLocalTests const auto bindings4Json = VerifyParseSucceeded(bindings4String); const auto bindings5Json = VerifyParseSucceeded(bindings5String); - auto keymap = winrt::make_self(); + auto keymap = winrt::make_self(); VERIFY_IS_NOT_NULL(keymap); VERIFY_ARE_EQUAL(0u, keymap->_keyShortcuts.size()); @@ -190,7 +189,7 @@ namespace TerminalAppLocalTests const auto bindings0Json = VerifyParseSucceeded(bindings0String); - auto keymap = winrt::make_self(); + auto keymap = winrt::make_self(); VERIFY_IS_NOT_NULL(keymap); VERIFY_ARE_EQUAL(0u, keymap->_keyShortcuts.size()); keymap->LayerJson(bindings0Json); @@ -200,7 +199,7 @@ namespace TerminalAppLocalTests Log::Comment(NoThrowString().Format( L"Verify that `copy` without args parses as Copy(SingleLine=false)")); KeyChord kc{ true, false, false, static_cast('C') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); const auto& realArgs = actionAndArgs.Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); // Verify the args have the expected value @@ -211,7 +210,7 @@ namespace TerminalAppLocalTests Log::Comment(NoThrowString().Format( L"Verify that `copy` with args parses them correctly")); KeyChord kc{ true, false, true, static_cast('C') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); const auto& realArgs = actionAndArgs.Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); // Verify the args have the expected value @@ -222,7 +221,7 @@ namespace TerminalAppLocalTests Log::Comment(NoThrowString().Format( L"Verify that `copy` with args parses them correctly")); KeyChord kc{ false, true, true, static_cast('C') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); const auto& realArgs = actionAndArgs.Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); // Verify the args have the expected value @@ -233,7 +232,7 @@ namespace TerminalAppLocalTests Log::Comment(NoThrowString().Format( L"Verify that `newTab` without args parses as NewTab(Index=null)")); KeyChord kc{ true, false, false, static_cast('T') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); const auto& realArgs = actionAndArgs.Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); @@ -245,7 +244,7 @@ namespace TerminalAppLocalTests Log::Comment(NoThrowString().Format( L"Verify that `newTab` parses args correctly")); KeyChord kc{ true, false, true, static_cast('T') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); const auto& realArgs = actionAndArgs.Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); @@ -259,7 +258,7 @@ namespace TerminalAppLocalTests L"Verify that `newTab` with an index greater than the legacy " L"args afforded parses correctly")); KeyChord kc{ true, false, true, static_cast('Y') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); const auto& realArgs = actionAndArgs.Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); @@ -273,7 +272,7 @@ namespace TerminalAppLocalTests Log::Comment(NoThrowString().Format( L"Verify that `copy` ignores args it doesn't understand")); KeyChord kc{ true, false, true, static_cast('B') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::CopyText, actionAndArgs.Action()); const auto& realArgs = actionAndArgs.Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); @@ -285,7 +284,7 @@ namespace TerminalAppLocalTests Log::Comment(NoThrowString().Format( L"Verify that `copy` null as it's `args` parses as the default option")); KeyChord kc{ true, false, true, static_cast('B') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::CopyText, actionAndArgs.Action()); const auto& realArgs = actionAndArgs.Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); @@ -297,7 +296,7 @@ namespace TerminalAppLocalTests Log::Comment(NoThrowString().Format( L"Verify that `adjustFontSize` with a positive delta parses args correctly")); KeyChord kc{ true, false, false, static_cast('F') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::AdjustFontSize, actionAndArgs.Action()); const auto& realArgs = actionAndArgs.Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); @@ -309,7 +308,7 @@ namespace TerminalAppLocalTests Log::Comment(NoThrowString().Format( L"Verify that `adjustFontSize` with a negative delta parses args correctly")); KeyChord kc{ true, false, false, static_cast('G') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::AdjustFontSize, actionAndArgs.Action()); const auto& realArgs = actionAndArgs.Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); @@ -330,7 +329,7 @@ namespace TerminalAppLocalTests const auto bindings0Json = VerifyParseSucceeded(bindings0String); - auto keymap = winrt::make_self(); + auto keymap = winrt::make_self(); VERIFY_IS_NOT_NULL(keymap); VERIFY_ARE_EQUAL(0u, keymap->_keyShortcuts.size()); keymap->LayerJson(bindings0Json); @@ -338,48 +337,48 @@ namespace TerminalAppLocalTests { KeyChord kc{ true, false, false, static_cast('C') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); 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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); } { KeyChord kc{ true, false, false, static_cast('D') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); 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::Vertical, realArgs.SplitStyle()); + VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle()); } { KeyChord kc{ true, false, false, static_cast('E') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); 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::Horizontal, realArgs.SplitStyle()); + VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle()); } { KeyChord kc{ true, false, false, static_cast('G') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); 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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); } { KeyChord kc{ true, false, false, static_cast('H') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); 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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); } } @@ -393,7 +392,7 @@ namespace TerminalAppLocalTests const auto bindings0Json = VerifyParseSucceeded(bindings0String); - auto keymap = winrt::make_self(); + auto keymap = winrt::make_self(); VERIFY_IS_NOT_NULL(keymap); VERIFY_ARE_EQUAL(0u, keymap->_keyShortcuts.size()); keymap->LayerJson(bindings0Json); @@ -401,7 +400,7 @@ namespace TerminalAppLocalTests { KeyChord kc{ true, false, false, static_cast('C') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::SetTabColor, actionAndArgs.Action()); const auto& realArgs = actionAndArgs.Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); @@ -410,7 +409,7 @@ namespace TerminalAppLocalTests } { KeyChord kc{ true, false, false, static_cast('D') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::SetTabColor, actionAndArgs.Action()); const auto& realArgs = actionAndArgs.Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); @@ -421,7 +420,7 @@ namespace TerminalAppLocalTests } { KeyChord kc{ true, false, false, static_cast('F') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::SetTabColor, actionAndArgs.Action()); const auto& realArgs = actionAndArgs.Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); @@ -438,7 +437,7 @@ namespace TerminalAppLocalTests const auto bindings0Json = VerifyParseSucceeded(bindings0String); - auto keymap = winrt::make_self(); + auto keymap = winrt::make_self(); VERIFY_IS_NOT_NULL(keymap); VERIFY_ARE_EQUAL(0u, keymap->_keyShortcuts.size()); keymap->LayerJson(bindings0Json); @@ -446,7 +445,7 @@ namespace TerminalAppLocalTests { KeyChord kc{ true, false, false, static_cast('C') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = ::TestUtils::GetActionAndArgs(*keymap, kc); const auto& realArgs = actionAndArgs.Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); // Verify the args have the expected value diff --git a/src/cascadia/LocalTests_SettingsModel/LocalTests_SettingsModel.def b/src/cascadia/LocalTests_SettingsModel/LocalTests_SettingsModel.def new file mode 100644 index 00000000000..8c1a02932d0 --- /dev/null +++ b/src/cascadia/LocalTests_SettingsModel/LocalTests_SettingsModel.def @@ -0,0 +1,3 @@ +EXPORTS +DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE +DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE diff --git a/src/cascadia/LocalTests_TerminalApp/ProfileTests.cpp b/src/cascadia/LocalTests_SettingsModel/ProfileTests.cpp similarity index 95% rename from src/cascadia/LocalTests_TerminalApp/ProfileTests.cpp rename to src/cascadia/LocalTests_SettingsModel/ProfileTests.cpp index 8f489bbf801..09f4fa053be 100644 --- a/src/cascadia/LocalTests_TerminalApp/ProfileTests.cpp +++ b/src/cascadia/LocalTests_SettingsModel/ProfileTests.cpp @@ -3,18 +3,17 @@ #include "pch.h" -#include "../TerminalApp/ColorScheme.h" -#include "../TerminalApp/CascadiaSettings.h" +#include "../TerminalSettingsModel/ColorScheme.h" +#include "../TerminalSettingsModel/CascadiaSettings.h" #include "JsonTestClass.h" using namespace Microsoft::Console; -using namespace TerminalApp; -using namespace winrt::TerminalApp; +using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace WEX::Logging; using namespace WEX::TestExecution; using namespace WEX::Common; -namespace TerminalAppLocalTests +namespace SettingsModelLocalTests { // TODO:microsoft/terminal#3838: // Unfortunately, these tests _WILL NOT_ work in our CI. We're waiting for @@ -253,7 +252,7 @@ namespace TerminalAppLocalTests const auto profile3Json = VerifyParseSucceeded(profile3String); const auto profile4Json = VerifyParseSucceeded(profile4String); - auto settings = winrt::make_self(); + auto settings = winrt::make_self(); VERIFY_ARE_EQUAL(0u, settings->_profiles.Size()); VERIFY_IS_NULL(settings->_FindMatchingProfile(profile0Json)); diff --git a/src/cascadia/LocalTests_SettingsModel/SettingsModel.LocalTests.vcxproj b/src/cascadia/LocalTests_SettingsModel/SettingsModel.LocalTests.vcxproj new file mode 100644 index 00000000000..44615a31755 --- /dev/null +++ b/src/cascadia/LocalTests_SettingsModel/SettingsModel.LocalTests.vcxproj @@ -0,0 +1,112 @@ + + + + + + + {CA5CAD1A-9B68-456A-B13E-C8218070DC42} + Win32Proj + SettingsModelLocalTests + LocalTests_SettingsModel + SettingsModel.LocalTests + DynamicLibrary + 10.0.18362.0 + 10.0.18362.0 + + true + + + + + $(SolutionDir)bin\$(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)obj\$(Platform)\$(Configuration)\$(ProjectName)\ + + + + + + + + + + + + + + + + + + + + Create + + + + NotUsing + + + + + + + + + + + + + + + + + + + + ..;$(OpenConsoleDir)\dep;$(OpenConsoleDir)\dep\jsoncpp\json;$(OpenConsoleDir)src\inc;$(OpenConsoleDir)src\inc\test;$(WinRT_IncludePath)\..\cppwinrt\winrt;"$(OpenConsoleDir)\src\cascadia\TerminalSettingsModel\Generated Files";%(AdditionalIncludeDirectories) + pch.h + + + 4702;%(DisableSpecificWarnings) + + + onecoreuap.lib;%(AdditionalDependencies) + + + + + true + true + + + + + + + + <_CppWinrtBinRoot>"$(OpenConsoleDir)$(Platform)\$(Configuration)\" + + x86 + $(Platform) + <_MUXBinRoot>"$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.200609001\runtimes\win10-$(Native-Platform)\native\" + + + + + + diff --git a/src/cascadia/LocalTests_TerminalApp/TestUtils.h b/src/cascadia/LocalTests_SettingsModel/TestUtils.h similarity index 83% rename from src/cascadia/LocalTests_TerminalApp/TestUtils.h rename to src/cascadia/LocalTests_SettingsModel/TestUtils.h index 0e06231432a..e211d50c43c 100644 --- a/src/cascadia/LocalTests_TerminalApp/TestUtils.h +++ b/src/cascadia/LocalTests_SettingsModel/TestUtils.h @@ -12,7 +12,7 @@ Author(s): Mike Griese (migrie) December-2019 --*/ -class TerminalAppLocalTests::TestUtils +class TestUtils { public: // Function Description: @@ -23,8 +23,8 @@ class TerminalAppLocalTests::TestUtils // - kc: The key chord to look up the bound ActionAndArgs for. // Return Value: // - The ActionAndArgs bound to the given key, or nullptr if nothing is bound to it. - static const winrt::TerminalApp::ActionAndArgs GetActionAndArgs(const winrt::TerminalApp::implementation::KeyMapping& keymap, - const winrt::Microsoft::Terminal::TerminalControl::KeyChord& kc) + static const winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs GetActionAndArgs(const winrt::Microsoft::Terminal::Settings::Model::KeyMapping& keymap, + const winrt::Microsoft::Terminal::TerminalControl::KeyChord& kc) { std::wstring buffer{ L"" }; if (WI_IsFlagSet(kc.Modifiers(), winrt::Microsoft::Terminal::TerminalControl::KeyModifiers::Ctrl)) diff --git a/src/cascadia/LocalTests_SettingsModel/pch.cpp b/src/cascadia/LocalTests_SettingsModel/pch.cpp new file mode 100644 index 00000000000..3c27d44d570 --- /dev/null +++ b/src/cascadia/LocalTests_SettingsModel/pch.cpp @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "pch.h" diff --git a/src/cascadia/LocalTests_SettingsModel/pch.h b/src/cascadia/LocalTests_SettingsModel/pch.h new file mode 100644 index 00000000000..9a06e029cc6 --- /dev/null +++ b/src/cascadia/LocalTests_SettingsModel/pch.h @@ -0,0 +1,65 @@ +/*++ +Copyright (c) Microsoft Corporation +Licensed under the MIT license. + +Module Name: +- precomp.h + +Abstract: +- Contains external headers to include in the precompile phase of console build process. +- Avoid including internal project headers. Instead include them only in the classes that need them (helps with test project building). + +Author(s): +- Carlos Zamora (cazamor) April 2019 +--*/ + +#pragma once + +// Manually include til after we include Windows.Foundation to give it winrt superpowers +#define BLOCK_TIL +// This includes support libraries from the CRT, STL, WIL, and GSL +#include "LibraryIncludes.h" +// This is inexplicable, but for whatever reason, cppwinrt conflicts with the +// SDK definition of this function, so the only fix is to undef it. +// from WinBase.h +// Windows::UI::Xaml::Media::Animation::IStoryboard::GetCurrentTime +#ifdef GetCurrentTime +#undef GetCurrentTime +#endif + +#include +#include +#include + +#include +#include +#include "consoletaeftemplates.hpp" + +#include +#include "winrt/Windows.UI.Xaml.Markup.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +// Manually include til after we include Windows.Foundation to give it winrt superpowers +#include "til.h" + +// Common includes for most tests: +#include "../../inc/argb.h" +#include "../../inc/conattrs.hpp" +#include "../../types/inc/utils.hpp" +#include "../../inc/DefaultSettings.h" diff --git a/src/cascadia/LocalTests_TerminalApp/CommandlineTest.cpp b/src/cascadia/LocalTests_TerminalApp/CommandlineTest.cpp index d9735e2ccd4..897bc4984f2 100644 --- a/src/cascadia/LocalTests_TerminalApp/CommandlineTest.cpp +++ b/src/cascadia/LocalTests_TerminalApp/CommandlineTest.cpp @@ -6,12 +6,12 @@ #include "../TerminalApp/TerminalPage.h" #include "../TerminalApp/AppCommandlineArgs.h" -#include "../TerminalApp/ActionArgs.h" using namespace WEX::Logging; using namespace WEX::Common; using namespace WEX::TestExecution; +using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace winrt::TerminalApp; using namespace ::TerminalApp; @@ -1076,9 +1076,8 @@ namespace TerminalAppLocalTests void CommandlineTest::TestSimpleExecuteCommandlineAction() { - auto args = winrt::make_self(); - args->Commandline(L"new-tab"); - auto actions = implementation::TerminalPage::ConvertExecuteCommandlineToActions(*args); + ExecuteCommandlineArgs args{ L"new-tab" }; + auto actions = implementation::TerminalPage::ConvertExecuteCommandlineToActions(args); VERIFY_ARE_EQUAL(1u, actions.size()); auto actionAndArgs = actions.at(0); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); @@ -1095,9 +1094,8 @@ namespace TerminalAppLocalTests void CommandlineTest::TestMultipleCommandExecuteCommandlineAction() { - auto args = winrt::make_self(); - args->Commandline(L"new-tab ; split-pane"); - auto actions = implementation::TerminalPage::ConvertExecuteCommandlineToActions(*args); + ExecuteCommandlineArgs args{ L"new-tab ; split-pane" }; + auto actions = implementation::TerminalPage::ConvertExecuteCommandlineToActions(args); VERIFY_ARE_EQUAL(2u, actions.size()); { auto actionAndArgs = actions.at(0); @@ -1129,10 +1127,9 @@ namespace TerminalAppLocalTests void CommandlineTest::TestInvalidExecuteCommandlineAction() { - auto args = winrt::make_self(); // -H and -V cannot be combined. - args->Commandline(L"split-pane -H -V"); - auto actions = implementation::TerminalPage::ConvertExecuteCommandlineToActions(*args); + ExecuteCommandlineArgs args{ L"split-pane -H -V" }; + auto actions = implementation::TerminalPage::ConvertExecuteCommandlineToActions(args); VERIFY_ARE_EQUAL(0u, actions.size()); } } diff --git a/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp b/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp index 12bd087a6db..af9cda0776e 100644 --- a/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp +++ b/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp @@ -3,21 +3,16 @@ #include "pch.h" -#include "../TerminalApp/ColorScheme.h" -#include "../TerminalApp/CascadiaSettings.h" #include "../TerminalApp/TerminalPage.h" #include "../TerminalApp/TerminalSettings.h" -#include "JsonTestClass.h" -#include "TestUtils.h" -#include -#include "../ut_app/TestDynamicProfileGenerator.h" +#include "../LocalTests_SettingsModel/TestUtils.h" using namespace Microsoft::Console; -using namespace TerminalApp; using namespace WEX::Logging; using namespace WEX::TestExecution; using namespace WEX::Common; using namespace winrt::TerminalApp; +using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::TerminalControl; namespace TerminalAppLocalTests @@ -27,7 +22,7 @@ namespace TerminalAppLocalTests // an updated TAEF that will let us install framework packages when the test // package is deployed. Until then, these tests won't deploy in CI. - class SettingsTests : public JsonTestClass + class SettingsTests { // Use a custom AppxManifest to ensure that we can activate winrt types // from our test. This property will tell taef to manually use this as @@ -40,52 +35,14 @@ namespace TerminalAppLocalTests END_TEST_CLASS() TEST_METHOD(TryCreateWinRTType); - TEST_METHOD(ValidateProfilesExist); - TEST_METHOD(ValidateDefaultProfileExists); - TEST_METHOD(ValidateDuplicateProfiles); - TEST_METHOD(ValidateManyWarnings); - TEST_METHOD(LayerGlobalProperties); - TEST_METHOD(ValidateProfileOrdering); - TEST_METHOD(ValidateHideProfiles); - TEST_METHOD(ValidateProfilesGenerateGuids); - TEST_METHOD(GeneratedGuidRoundtrips); - TEST_METHOD(TestAllValidationsWithNullGuids); - TEST_METHOD(TestReorderWithNullGuids); - TEST_METHOD(TestReorderingWithoutGuid); - TEST_METHOD(TestLayeringNameOnlyProfiles); - TEST_METHOD(TestExplodingNameOnlyProfiles); - TEST_METHOD(TestHideAllProfiles); - TEST_METHOD(TestInvalidColorSchemeName); - TEST_METHOD(TestHelperFunctions); - - TEST_METHOD(TestProfileIconWithEnvVar); - TEST_METHOD(TestProfileBackgroundImageWithEnvVar); - - TEST_METHOD(TestCloseOnExitParsing); - TEST_METHOD(TestCloseOnExitCompatibilityShim); - - TEST_METHOD(TestLayerUserDefaultsBeforeProfiles); - TEST_METHOD(TestDontLayerGuidFromUserDefaults); - TEST_METHOD(TestLayerUserDefaultsOnDynamics); TEST_METHOD(TestTerminalArgsForBinding); - TEST_METHOD(FindMissingProfile); TEST_METHOD(MakeSettingsForProfileThatDoesntExist); TEST_METHOD(MakeSettingsForDefaultProfileThatDoesntExist); TEST_METHOD(TestLayerProfileOnColorScheme); - TEST_METHOD(ValidateKeybindingsWarnings); - - TEST_METHOD(ValidateExecuteCommandlineWarning); - - TEST_METHOD(ValidateLegacyGlobalsWarning); - - TEST_METHOD(TestTrailingCommas); - - TEST_METHOD(TestCommandsAndKeybindings); - TEST_METHOD(TestIterateCommands); TEST_METHOD(TestIterateOnGeneratedNamedCommands); TEST_METHOD(TestIterateOnBadJson); @@ -94,20 +51,16 @@ namespace TerminalAppLocalTests TEST_METHOD(TestNestedInIterableCommand); TEST_METHOD(TestIterableInNestedCommand); TEST_METHOD(TestMixedNestedAndIterableCommand); - TEST_METHOD(TestNestedCommandWithoutName); - TEST_METHOD(TestUnbindNestedCommand); - TEST_METHOD(TestRebindNestedCommand); TEST_METHOD(TestIterableColorSchemeCommands); TEST_CLASS_SETUP(ClassSetup) { - InitializeJsonReader(); return true; } private: - void _logCommandNames(winrt::Windows::Foundation::Collections::IMapView commands, const int indentation = 1) + void _logCommandNames(winrt::Windows::Foundation::Collections::IMapView commands, const int indentation = 1) { if (indentation == 1) { @@ -122,11 +75,9 @@ namespace TerminalAppLocalTests nameAndCommand.Value().Name()) .c_str()); - winrt::com_ptr cmdImpl; - cmdImpl.copy_from(winrt::get_self(nameAndCommand.Value())); - if (cmdImpl->HasNestedCommands()) + if (nameAndCommand.Value().HasNestedCommands()) { - _logCommandNames(cmdImpl->_subcommands.GetView(), indentation + 2); + _logCommandNames(nameAndCommand.Value().NestedCommands(), indentation + 2); } } } @@ -142,2493 +93,476 @@ namespace TerminalAppLocalTests VERIFY_ARE_NOT_EQUAL(oldFontSize, newFontSize); } - void SettingsTests::ValidateProfilesExist() - { - const std::string settingsWithProfiles{ R"( - { - "profiles": [ - { - "name" : "profile0" - } - ] - })" }; - - const std::string settingsWithoutProfiles{ R"( - { - "defaultProfile": "{6239a42c-1de4-49a3-80bd-e8fdd045185c}" - })" }; - - const std::string settingsWithEmptyProfiles{ R"( - { - "profiles": [] - })" }; - - { - // Case 1: Good settings - const auto settingsObject = VerifyParseSucceeded(settingsWithProfiles); - auto settings = implementation::CascadiaSettings::FromJson(settingsObject); - settings->_ValidateProfilesExist(); - } - { - // Case 2: Bad settings - const auto settingsObject = VerifyParseSucceeded(settingsWithoutProfiles); - auto settings = implementation::CascadiaSettings::FromJson(settingsObject); - bool caughtExpectedException = false; - try - { - settings->_ValidateProfilesExist(); - } - catch (const winrt::TerminalApp::implementation::SettingsException& ex) - { - VERIFY_IS_TRUE(ex.Error() == winrt::TerminalApp::SettingsLoadErrors::NoProfiles); - caughtExpectedException = true; - } - VERIFY_IS_TRUE(caughtExpectedException); - } - { - // Case 3: Bad settings - const auto settingsObject = VerifyParseSucceeded(settingsWithEmptyProfiles); - auto settings = implementation::CascadiaSettings::FromJson(settingsObject); - bool caughtExpectedException = false; - try - { - settings->_ValidateProfilesExist(); - } - catch (const winrt::TerminalApp::implementation::SettingsException& ex) - { - VERIFY_IS_TRUE(ex.Error() == winrt::TerminalApp::SettingsLoadErrors::NoProfiles); - caughtExpectedException = true; - } - VERIFY_IS_TRUE(caughtExpectedException); - } - } - - void SettingsTests::ValidateDefaultProfileExists() - { - const std::string goodProfiles{ R"( - { - "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", - "profiles": [ - { - "name" : "profile0", - "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile0", - "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" - } - ] - })" }; - - const std::string badProfiles{ R"( - { - "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", - "profiles": [ - { - "name" : "profile0", - "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile1", - "guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}" - } - ] - })" }; - - const std::string noDefaultAtAll{ R"( - { - "alwaysShowTabs": true, - "profiles": [ - { - "name" : "profile0", - "guid": "{6239a42c-5555-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile1", - "guid": "{6239a42c-6666-49a3-80bd-e8fdd045185c}" - } - ] - })" }; - - const std::string goodProfilesSpecifiedByName{ R"( - { - "defaultProfile": "profile1", - "profiles": [ - { - "name" : "profile0", - "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile1", - "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" - } - ] - })" }; - - { - // Case 1: Good settings - Log::Comment(NoThrowString().Format( - L"Testing a pair of profiles with unique guids, and the defaultProfile is one of those guids")); - const auto settingsObject = VerifyParseSucceeded(goodProfiles); - auto settings = implementation::CascadiaSettings::FromJson(settingsObject); - settings->_ResolveDefaultProfile(); - settings->_ValidateDefaultProfileExists(); - VERIFY_ARE_EQUAL(static_cast(0), settings->_warnings.Size()); - VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size()); - VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(0).Guid()); - } - { - // Case 2: Bad settings - Log::Comment(NoThrowString().Format( - L"Testing a pair of profiles with unique guids, but the defaultProfile is NOT one of those guids")); - const auto settingsObject = VerifyParseSucceeded(badProfiles); - auto settings = implementation::CascadiaSettings::FromJson(settingsObject); - settings->_ResolveDefaultProfile(); - settings->_ValidateDefaultProfileExists(); - VERIFY_ARE_EQUAL(static_cast(1), settings->_warnings.Size()); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::MissingDefaultProfile, settings->_warnings.GetAt(0)); - - VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size()); - VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(0).Guid()); - } - { - // Case 2: Bad settings - Log::Comment(NoThrowString().Format( - L"Testing a pair of profiles with unique guids, and no defaultProfile at all")); - const auto settingsObject = VerifyParseSucceeded(badProfiles); - auto settings = implementation::CascadiaSettings::FromJson(settingsObject); - settings->_ResolveDefaultProfile(); - settings->_ValidateDefaultProfileExists(); - VERIFY_ARE_EQUAL(static_cast(1), settings->_warnings.Size()); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::MissingDefaultProfile, settings->_warnings.GetAt(0)); - - VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size()); - VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(0).Guid()); - } - { - // Case 4: Good settings, default profile is a string - Log::Comment(NoThrowString().Format( - L"Testing a pair of profiles with unique guids, and the defaultProfile is one of the profile names")); - const auto settingsObject = VerifyParseSucceeded(goodProfilesSpecifiedByName); - auto settings = implementation::CascadiaSettings::FromJson(settingsObject); - settings->_ResolveDefaultProfile(); - settings->_ValidateDefaultProfileExists(); - VERIFY_ARE_EQUAL(static_cast(0), settings->_warnings.Size()); - VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size()); - VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(1).Guid()); - } - } - - void SettingsTests::ValidateDuplicateProfiles() - { - const std::string goodProfiles{ R"( - { - "profiles": [ - { - "name" : "profile0", - "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile0", - "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" - } - ] - })" }; - - const std::string badProfiles{ R"( - { - "profiles": [ - { - "name" : "profile0", - "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile1", - "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}" - } - ] - })" }; - - const std::string veryBadProfiles{ R"( - { - "profiles": [ - { - "name" : "profile0", - "guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile1", - "guid": "{6239a42c-5555-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile2", - "guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile3", - "guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile4", - "guid": "{6239a42c-6666-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile5", - "guid": "{6239a42c-5555-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile6", - "guid": "{6239a42c-7777-49a3-80bd-e8fdd045185c}" - } - ] - })" }; - Profile profile0 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}")); - profile0.Name(L"profile0"); - Profile profile1 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-5555-49a3-80bd-e8fdd045185c}")); - profile1.Name(L"profile1"); - Profile profile2 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}")); - profile2.Name(L"profile2"); - Profile profile3 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}")); - profile3.Name(L"profile3"); - Profile profile4 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-6666-49a3-80bd-e8fdd045185c}")); - profile4.Name(L"profile4"); - Profile profile5 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-5555-49a3-80bd-e8fdd045185c}")); - profile5.Name(L"profile5"); - Profile profile6 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-7777-49a3-80bd-e8fdd045185c}")); - profile6.Name(L"profile6"); - - { - // Case 1: Good settings - Log::Comment(NoThrowString().Format( - L"Testing a pair of profiles with unique guids")); - - auto settings = winrt::make_self(); - settings->_profiles.Append(profile0); - settings->_profiles.Append(profile1); - - settings->_ValidateNoDuplicateProfiles(); - - VERIFY_ARE_EQUAL(static_cast(0), settings->_warnings.Size()); - VERIFY_ARE_EQUAL(static_cast(2), settings->_profiles.Size()); - } - { - // Case 2: Bad settings - Log::Comment(NoThrowString().Format( - L"Testing a pair of profiles with the same guid")); - - auto settings = winrt::make_self(); - settings->_profiles.Append(profile2); - settings->_profiles.Append(profile3); - - settings->_ValidateNoDuplicateProfiles(); - - VERIFY_ARE_EQUAL(static_cast(1), settings->_warnings.Size()); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::DuplicateProfile, settings->_warnings.GetAt(0)); - - VERIFY_ARE_EQUAL(static_cast(1), settings->_profiles.Size()); - VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name()); - } - { - // Case 3: Very bad settings - Log::Comment(NoThrowString().Format( - L"Testing a set of profiles, many of which with duplicated guids")); - - auto settings = winrt::make_self(); - settings->_profiles.Append(profile0); - settings->_profiles.Append(profile1); - settings->_profiles.Append(profile2); - settings->_profiles.Append(profile3); - settings->_profiles.Append(profile4); - settings->_profiles.Append(profile5); - settings->_profiles.Append(profile6); - - settings->_ValidateNoDuplicateProfiles(); - - VERIFY_ARE_EQUAL(static_cast(1), settings->_warnings.Size()); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::DuplicateProfile, settings->_warnings.GetAt(0)); - - VERIFY_ARE_EQUAL(static_cast(4), settings->_profiles.Size()); - VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(1).Name()); - VERIFY_ARE_EQUAL(L"profile4", settings->_profiles.GetAt(2).Name()); - VERIFY_ARE_EQUAL(L"profile6", settings->_profiles.GetAt(3).Name()); - } - } - - void SettingsTests::ValidateManyWarnings() + void SettingsTests::TestTerminalArgsForBinding() { - const std::string badProfiles{ R"( + const std::string settingsJson{ R"( { - "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "profiles": [ { - "name" : "profile0", - "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" + "name": "profile0", + "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", + "historySize": 1, + "commandline": "cmd.exe" }, { - "name" : "profile1", - "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}" + "name": "profile1", + "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "historySize": 2, + "commandline": "pwsh.exe" }, { - "name" : "profile2", - "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" + "name": "profile2", + "historySize": 3, + "commandline": "wsl.exe" } + ], + "keybindings": [ + { "keys": ["ctrl+a"], "command": { "action": "splitPane", "split": "vertical" } }, + { "keys": ["ctrl+b"], "command": { "action": "splitPane", "split": "vertical", "profile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" } }, + { "keys": ["ctrl+c"], "command": { "action": "splitPane", "split": "vertical", "profile": "profile1" } }, + { "keys": ["ctrl+d"], "command": { "action": "splitPane", "split": "vertical", "profile": "profile2" } }, + { "keys": ["ctrl+e"], "command": { "action": "splitPane", "split": "horizontal", "commandline": "foo.exe" } }, + { "keys": ["ctrl+f"], "command": { "action": "splitPane", "split": "horizontal", "profile": "profile1", "commandline": "foo.exe" } }, + { "keys": ["ctrl+g"], "command": { "action": "newTab" } }, + { "keys": ["ctrl+h"], "command": { "action": "newTab", "startingDirectory": "c:\\foo" } }, + { "keys": ["ctrl+i"], "command": { "action": "newTab", "profile": "profile2", "startingDirectory": "c:\\foo" } }, + { "keys": ["ctrl+j"], "command": { "action": "newTab", "tabTitle": "bar" } }, + { "keys": ["ctrl+k"], "command": { "action": "newTab", "profile": "profile2", "tabTitle": "bar" } }, + { "keys": ["ctrl+l"], "command": { "action": "newTab", "profile": "profile1", "tabTitle": "bar", "startingDirectory": "c:\\foo", "commandline":"foo.exe" } } ] })" }; - Profile profile4 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}")); - profile4.Name(L"profile4"); - Profile profile5 = winrt::make(::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}")); - profile5.Name(L"profile5"); - - // Case 2: Bad settings - Log::Comment(NoThrowString().Format( - L"Testing a pair of profiles with the same guid")); - const auto settingsObject = VerifyParseSucceeded(badProfiles); - auto settings = implementation::CascadiaSettings::FromJson(settingsObject); - - settings->_profiles.Append(profile4); - settings->_profiles.Append(profile5); - - settings->_ValidateSettings(); - - VERIFY_ARE_EQUAL(3u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::DuplicateProfile, settings->_warnings.GetAt(0)); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::MissingDefaultProfile, settings->_warnings.GetAt(1)); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::UnknownColorScheme, settings->_warnings.GetAt(2)); - - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); - VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(0).Guid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid()); - } - - void SettingsTests::LayerGlobalProperties() - { - const std::string settings0String{ R"( - { - "alwaysShowTabs": true, - "initialCols" : 120, - "initialRows" : 30 - })" }; - const std::string settings1String{ R"( - { - "showTabsInTitlebar": false, - "initialCols" : 240, - "initialRows" : 60 - })" }; - const auto settings0Json = VerifyParseSucceeded(settings0String); - const auto settings1Json = VerifyParseSucceeded(settings1String); - - auto settings = winrt::make_self(); - - settings->LayerJson(settings0Json); - VERIFY_ARE_EQUAL(true, settings->_globals->AlwaysShowTabs()); - VERIFY_ARE_EQUAL(120, settings->_globals->InitialCols()); - VERIFY_ARE_EQUAL(30, settings->_globals->InitialRows()); - VERIFY_ARE_EQUAL(true, settings->_globals->ShowTabsInTitlebar()); - - settings->LayerJson(settings1Json); - VERIFY_ARE_EQUAL(true, settings->_globals->AlwaysShowTabs()); - VERIFY_ARE_EQUAL(240, settings->_globals->InitialCols()); - VERIFY_ARE_EQUAL(60, settings->_globals->InitialRows()); - VERIFY_ARE_EQUAL(false, settings->_globals->ShowTabsInTitlebar()); - } - void SettingsTests::ValidateProfileOrdering() - { - const std::string userProfiles0String{ R"( - { - "profiles": [ - { - "name" : "profile0", - "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile1", - "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" - } - ] - })" }; + const winrt::guid guid0{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}") }; + const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}") }; - const std::string defaultProfilesString{ R"( - { - "profiles": [ - { - "name" : "profile2", - "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile3", - "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}" - } - ] - })" }; + CascadiaSettings settings{ til::u8u16(settingsJson) }; - const std::string userProfiles1String{ R"( - { - "profiles": [ - { - "name" : "profile4", - "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile5", - "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" - } - ] - })" }; + auto keymap = settings.GlobalSettings().KeyMap(); + VERIFY_ARE_EQUAL(3u, settings.Profiles().Size()); - const auto userProfiles0Json = VerifyParseSucceeded(userProfiles0String); - const auto userProfiles1Json = VerifyParseSucceeded(userProfiles1String); - const auto defaultProfilesJson = VerifyParseSucceeded(defaultProfilesString); + const auto profile2Guid = settings.Profiles().GetAt(2).Guid(); + VERIFY_ARE_NOT_EQUAL(winrt::guid{}, profile2Guid); - { - Log::Comment(NoThrowString().Format( - L"Case 1: Simple swapping of the ordering. The user has the " - L"default profiles in the opposite order of the default ordering.")); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(defaultProfilesString, true); - settings->LayerJson(settings->_defaultSettings); - VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); - VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"profile3", settings->_profiles.GetAt(1).Name()); - - settings->_ParseJsonString(userProfiles0String, false); - settings->LayerJson(settings->_userSettings); - VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); - VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(1).Name()); - - settings->_ReorderProfilesToMatchUserSettingsOrder(); - VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); - VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(1).Name()); - } + VERIFY_ARE_EQUAL(12u, keymap.Size()); { - Log::Comment(NoThrowString().Format( - L"Case 2: Make sure all the user's profiles appear before the defaults.")); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(defaultProfilesString, true); - settings->LayerJson(settings->_defaultSettings); - VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); - VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"profile3", settings->_profiles.GetAt(1).Name()); - - settings->_ParseJsonString(userProfiles1String, false); - settings->LayerJson(settings->_userSettings); - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); - VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"profile4", settings->_profiles.GetAt(1).Name()); - VERIFY_ARE_EQUAL(L"profile5", settings->_profiles.GetAt(2).Name()); - - settings->_ReorderProfilesToMatchUserSettingsOrder(); - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); - VERIFY_ARE_EQUAL(L"profile4", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"profile5", settings->_profiles.GetAt(1).Name()); - VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(2).Name()); - } - } - - void SettingsTests::ValidateHideProfiles() - { - const std::string defaultProfilesString{ R"( - { - "profiles": [ - { - "name" : "profile2", - "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile3", - "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}" - } - ] - })" }; - - const std::string userProfiles0String{ R"( - { - "profiles": [ - { - "name" : "profile0", - "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", - "hidden": true - }, - { - "name" : "profile1", - "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" - } - ] - })" }; - - const std::string userProfiles1String{ R"( - { - "profiles": [ - { - "name" : "profile4", - "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", - "hidden": true - }, - { - "name" : "profile5", - "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile6", - "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}", - "hidden": true - } - ] - })" }; - - const auto userProfiles0Json = VerifyParseSucceeded(userProfiles0String); - const auto userProfiles1Json = VerifyParseSucceeded(userProfiles1String); - const auto defaultProfilesJson = VerifyParseSucceeded(defaultProfilesString); - - { - auto settings = winrt::make_self(); - settings->_ParseJsonString(defaultProfilesString, true); - settings->LayerJson(settings->_defaultSettings); - VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); - VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"profile3", settings->_profiles.GetAt(1).Name()); - VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden()); - VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(1).Hidden()); - - settings->_ParseJsonString(userProfiles0String, false); - settings->LayerJson(settings->_userSettings); - VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); - VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(1).Name()); - VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden()); - VERIFY_ARE_EQUAL(true, settings->_profiles.GetAt(1).Hidden()); - - settings->_ReorderProfilesToMatchUserSettingsOrder(); - settings->_RemoveHiddenProfiles(); - VERIFY_ARE_EQUAL(1u, settings->_profiles.Size()); - VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden()); - } - - { - auto settings = winrt::make_self(); - settings->_ParseJsonString(defaultProfilesString, true); - settings->LayerJson(settings->_defaultSettings); - VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); - VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"profile3", settings->_profiles.GetAt(1).Name()); - VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden()); - VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(1).Hidden()); - - settings->_ParseJsonString(userProfiles1String, false); - settings->LayerJson(settings->_userSettings); - VERIFY_ARE_EQUAL(4u, settings->_profiles.Size()); - VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"profile4", settings->_profiles.GetAt(1).Name()); - VERIFY_ARE_EQUAL(L"profile5", settings->_profiles.GetAt(2).Name()); - VERIFY_ARE_EQUAL(L"profile6", settings->_profiles.GetAt(3).Name()); - VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden()); - VERIFY_ARE_EQUAL(true, settings->_profiles.GetAt(1).Hidden()); - VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(2).Hidden()); - VERIFY_ARE_EQUAL(true, settings->_profiles.GetAt(3).Hidden()); - - settings->_ReorderProfilesToMatchUserSettingsOrder(); - settings->_RemoveHiddenProfiles(); - VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); - VERIFY_ARE_EQUAL(L"profile5", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"profile2", settings->_profiles.GetAt(1).Name()); - VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(0).Hidden()); - VERIFY_ARE_EQUAL(false, settings->_profiles.GetAt(1).Hidden()); - } - } - - void SettingsTests::ValidateProfilesGenerateGuids() - { - const std::string profile0String{ R"( - { - "name" : "profile0" - })" }; - const std::string profile1String{ R"( - { - "name" : "profile1" - })" }; - const std::string profile2String{ R"( - { - "name" : "profile2", - "guid" : null - })" }; - const std::string profile3String{ R"( - { - "name" : "profile3", - "guid" : "{00000000-0000-0000-0000-000000000000}" - })" }; - const std::string profile4String{ R"( - { - "name" : "profile4", - "guid" : "{6239a42c-1de4-49a3-80bd-e8fdd045185c}" - })" }; - const std::string profile5String{ R"( - { - "name" : "profile2" - })" }; - - const auto profile0Json = VerifyParseSucceeded(profile0String); - const auto profile1Json = VerifyParseSucceeded(profile1String); - const auto profile2Json = VerifyParseSucceeded(profile2String); - const auto profile3Json = VerifyParseSucceeded(profile3String); - const auto profile4Json = VerifyParseSucceeded(profile4String); - const auto profile5Json = VerifyParseSucceeded(profile5String); - - const auto profile0 = implementation::Profile::FromJson(profile0Json); - const auto profile1 = implementation::Profile::FromJson(profile1Json); - const auto profile2 = implementation::Profile::FromJson(profile2Json); - const auto profile3 = implementation::Profile::FromJson(profile3Json); - const auto profile4 = implementation::Profile::FromJson(profile4Json); - const auto profile5 = implementation::Profile::FromJson(profile5Json); - - const winrt::guid cmdGuid{ Utils::GuidFromString(L"{6239a42c-1de4-49a3-80bd-e8fdd045185c}") }; - const winrt::guid nullGuid{}; - - VERIFY_IS_FALSE(profile0->HasGuid()); - VERIFY_IS_FALSE(profile1->HasGuid()); - VERIFY_IS_FALSE(profile2->HasGuid()); - VERIFY_IS_TRUE(profile3->HasGuid()); - VERIFY_IS_TRUE(profile4->HasGuid()); - VERIFY_IS_FALSE(profile5->HasGuid()); - - VERIFY_ARE_EQUAL(profile3->Guid(), nullGuid); - VERIFY_ARE_EQUAL(profile4->Guid(), cmdGuid); - - auto settings = winrt::make_self(); - settings->_profiles.Append(*profile0); - settings->_profiles.Append(*profile1); - settings->_profiles.Append(*profile2); - settings->_profiles.Append(*profile3); - settings->_profiles.Append(*profile4); - settings->_profiles.Append(*profile5); - - settings->_ValidateProfilesHaveGuid(); - VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(4).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(5).HasGuid()); - - VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(0).Guid(), nullGuid); - VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(1).Guid(), nullGuid); - VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(2).Guid(), nullGuid); - VERIFY_ARE_EQUAL(settings->_profiles.GetAt(3).Guid(), nullGuid); - VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(4).Guid(), nullGuid); - VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(5).Guid(), nullGuid); - - VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(0).Guid(), cmdGuid); - VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(1).Guid(), cmdGuid); - VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(2).Guid(), cmdGuid); - VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(3).Guid(), cmdGuid); - VERIFY_ARE_EQUAL(settings->_profiles.GetAt(4).Guid(), cmdGuid); - VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(5).Guid(), cmdGuid); - - VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(0).Guid(), settings->_profiles.GetAt(2).Guid()); - VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(1).Guid(), settings->_profiles.GetAt(2).Guid()); - VERIFY_ARE_EQUAL(settings->_profiles.GetAt(2).Guid(), settings->_profiles.GetAt(2).Guid()); - VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(3).Guid(), settings->_profiles.GetAt(2).Guid()); - VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(4).Guid(), settings->_profiles.GetAt(2).Guid()); - VERIFY_ARE_EQUAL(settings->_profiles.GetAt(5).Guid(), settings->_profiles.GetAt(2).Guid()); - } - - void SettingsTests::GeneratedGuidRoundtrips() - { - // Parse a profile without a guid. - // We should automatically generate a GUID for that profile. - // When that profile is serialized and deserialized again, the GUID we - // generated for it should persist. - const std::string profileWithoutGuid{ R"({ - "name" : "profile0" - })" }; - const auto profile0Json = VerifyParseSucceeded(profileWithoutGuid); - - const auto profile0 = implementation::Profile::FromJson(profile0Json); - const GUID nullGuid{ 0 }; - - VERIFY_IS_FALSE(profile0->HasGuid()); - - const auto serialized0Profile = profile0->GenerateStub(); - const auto profile1 = implementation::Profile::FromJson(serialized0Profile); - VERIFY_IS_FALSE(profile0->HasGuid()); - VERIFY_IS_FALSE(profile1->HasGuid()); - - auto settings = winrt::make_self(); - settings->_profiles.Append(*profile1); - settings->_ValidateProfilesHaveGuid(); - - VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); - - const auto profileImpl = winrt::get_self(settings->_profiles.GetAt(0)); - const auto serialized1Profile = profileImpl->GenerateStub(); - - const auto profile2 = implementation::Profile::FromJson(serialized1Profile); - VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); - VERIFY_IS_TRUE(profile2->HasGuid()); - VERIFY_ARE_EQUAL(settings->_profiles.GetAt(0).Guid(), profile2->Guid()); - } - - void SettingsTests::TestAllValidationsWithNullGuids() - { - const std::string settings0String{ R"( - { - "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", - "profiles": [ - { - "name" : "profile0", - "guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile1" - } - ], - "schemes": [ - { "name": "Campbell" } - ] - })" }; - - const auto settings0Json = VerifyParseSucceeded(settings0String); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(settings0String, false); - settings->LayerJson(settings->_userSettings); - - VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); - VERIFY_IS_FALSE(settings->_profiles.GetAt(1).HasGuid()); - - settings->_ValidateSettings(); - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); - } - - void SettingsTests::TestReorderWithNullGuids() - { - const std::string settings0String{ R"( - { - "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", - "profiles": [ - { - "name" : "profile0", - "guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile1" - }, - { - "name" : "cmdFromUserSettings", - "guid" : "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}" // from defaults.json - } - ] - })" }; - - const auto settings0Json = VerifyParseSucceeded(settings0String); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(DefaultJson, true); - settings->LayerJson(settings->_defaultSettings); - VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); - VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name()); - - settings->_ParseJsonString(settings0String, false); - settings->LayerJson(settings->_userSettings); - - VERIFY_ARE_EQUAL(4u, settings->_profiles.Size()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid()); - VERIFY_IS_FALSE(settings->_profiles.GetAt(3).HasGuid()); - VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"cmdFromUserSettings", settings->_profiles.GetAt(1).Name()); - VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(2).Name()); - VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(3).Name()); - - settings->_ValidateSettings(); - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(4u, settings->_profiles.Size()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid()); - VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"profile1", settings->_profiles.GetAt(1).Name()); - VERIFY_ARE_EQUAL(L"cmdFromUserSettings", settings->_profiles.GetAt(2).Name()); - VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(3).Name()); - } - - void SettingsTests::TestReorderingWithoutGuid() - { - Log::Comment(NoThrowString().Format( - L"During the GH#2515 PR, this set of settings was found to cause an" - L" exception, crashing the terminal. This test ensures that it doesn't.")); - - Log::Comment(NoThrowString().Format( - L"While similar to TestReorderWithNullGuids, there's something else" - L" about this scenario specifically that causes a crash, when " - L" TestReorderWithNullGuids did _not_.")); - - const std::string settings0String{ R"( - { - "defaultProfile" : "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}", - "profiles": [ - { - "guid" : "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}", - "acrylicOpacity" : 0.5, - "closeOnExit" : true, - "background" : "#8A00FF", - "foreground" : "#F2F2F2", - "commandline" : "cmd.exe", - "cursorColor" : "#FFFFFF", - "fontFace" : "Cascadia Code", - "fontSize" : 10, - "historySize" : 9001, - "padding" : "20", - "snapOnInput" : true, - "startingDirectory" : "%USERPROFILE%", - "useAcrylic" : true - }, - { - "name" : "ThisProfileShouldNotCrash", - "tabTitle" : "Ubuntu", - "acrylicOpacity" : 0.5, - "background" : "#2C001E", - "closeOnExit" : true, - "colorScheme" : "Campbell", - "commandline" : "wsl.exe", - "cursorColor" : "#FFFFFF", - "cursorShape" : "bar", - "fontSize" : 10, - "historySize" : 9001, - "padding" : "0, 0, 0, 0", - "snapOnInput" : true, - "useAcrylic" : true - }, - { - // This is the same profile that would be generated by the WSL profile generator. - "name" : "Ubuntu", - "guid" : "{2C4DE342-38B7-51CF-B940-2309A097F518}", - "acrylicOpacity" : 0.5, - "background" : "#2C001E", - "closeOnExit" : false, - "cursorColor" : "#FFFFFF", - "cursorShape" : "bar", - "fontSize" : 10, - "historySize" : 9001, - "snapOnInput" : true, - "useAcrylic" : true - } - ] - })" }; - - const auto settings0Json = VerifyParseSucceeded(settings0String); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(DefaultJson, true); - settings->LayerJson(settings->_defaultSettings); - VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); - VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name()); - - settings->_ParseJsonString(settings0String, false); - settings->LayerJson(settings->_userSettings); - - VERIFY_ARE_EQUAL(4u, settings->_profiles.Size()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); - VERIFY_IS_FALSE(settings->_profiles.GetAt(2).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid()); - VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name()); - VERIFY_ARE_EQUAL(L"ThisProfileShouldNotCrash", settings->_profiles.GetAt(2).Name()); - VERIFY_ARE_EQUAL(L"Ubuntu", settings->_profiles.GetAt(3).Name()); - - settings->_ValidateSettings(); - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(4u, settings->_profiles.Size()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid()); - VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"ThisProfileShouldNotCrash", settings->_profiles.GetAt(1).Name()); - VERIFY_ARE_EQUAL(L"Ubuntu", settings->_profiles.GetAt(2).Name()); - VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(3).Name()); - } - - void SettingsTests::TestLayeringNameOnlyProfiles() - { - // This is a test discovered during GH#2782. When we add a name-only - // profile, it should only layer with other name-only profiles with the - // _same name_ - - const std::string settings0String{ R"( - { - "defaultProfile" : "{00000000-0000-5f56-a8ff-afceeeaa6101}", - "profiles": [ - { - "guid" : "{00000000-0000-5f56-a8ff-afceeeaa6101}", - "name" : "ThisProfileIsGood" - - }, - { - "name" : "ThisProfileShouldNotLayer" - }, - { - "name" : "NeitherShouldThisOne" - } - ] - })" }; - - const auto settings0Json = VerifyParseSucceeded(settings0String); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(DefaultJson, true); - settings->LayerJson(settings->_defaultSettings); - VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); - VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name()); - - Log::Comment(NoThrowString().Format( - L"Parse the user settings")); - settings->_ParseJsonString(settings0String, false); - settings->LayerJson(settings->_userSettings); - - VERIFY_ARE_EQUAL(5u, settings->_profiles.Size()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid()); - VERIFY_IS_FALSE(settings->_profiles.GetAt(3).HasGuid()); - VERIFY_IS_FALSE(settings->_profiles.GetAt(4).HasGuid()); - VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name()); - VERIFY_ARE_EQUAL(L"ThisProfileIsGood", settings->_profiles.GetAt(2).Name()); - VERIFY_ARE_EQUAL(L"ThisProfileShouldNotLayer", settings->_profiles.GetAt(3).Name()); - VERIFY_ARE_EQUAL(L"NeitherShouldThisOne", settings->_profiles.GetAt(4).Name()); - } - - void SettingsTests::TestExplodingNameOnlyProfiles() - { - // This is a test for GH#2782. When we add a name-only profile, we'll - // generate a GUID for it. We should make sure that we don't re-append - // that profile to the list of profiles. - - const std::string settings0String{ R"( - { - "defaultProfile" : "{00000000-0000-5f56-a8ff-afceeeaa6101}", - "profiles": [ - { - "guid" : "{00000000-0000-5f56-a8ff-afceeeaa6101}", - "name" : "ThisProfileIsGood" - - }, - { - "name" : "ThisProfileShouldNotDuplicate" - }, - { - "name" : "NeitherShouldThisOne" - } - ] - })" }; - - const auto settings0Json = VerifyParseSucceeded(settings0String); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(DefaultJson, true); - settings->LayerJson(settings->_defaultSettings); - VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); - VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name()); - - Log::Comment(NoThrowString().Format( - L"Parse the user settings")); - settings->_ParseJsonString(settings0String, false); - settings->LayerJson(settings->_userSettings); - - VERIFY_ARE_EQUAL(5u, settings->_profiles.Size()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid()); - VERIFY_IS_FALSE(settings->_profiles.GetAt(3).HasGuid()); - VERIFY_IS_FALSE(settings->_profiles.GetAt(4).HasGuid()); - VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(1).Name()); - VERIFY_ARE_EQUAL(L"ThisProfileIsGood", settings->_profiles.GetAt(2).Name()); - VERIFY_ARE_EQUAL(L"ThisProfileShouldNotDuplicate", settings->_profiles.GetAt(3).Name()); - VERIFY_ARE_EQUAL(L"NeitherShouldThisOne", settings->_profiles.GetAt(4).Name()); - - Log::Comment(NoThrowString().Format( - L"Pretend like we're checking to append dynamic profiles to the " - L"user's settings file. We absolutely _shouldn't_ be adding anything here.")); - bool const needToWriteFile = settings->_AppendDynamicProfilesToUserSettings(); - VERIFY_IS_FALSE(needToWriteFile); - VERIFY_ARE_EQUAL(settings0String.size(), settings->_userSettingsString.size()); - - Log::Comment(NoThrowString().Format( - L"Re-parse the settings file. We should have the _same_ settings as before.")); - Log::Comment(NoThrowString().Format( - L"Do this to a _new_ settings object, to make sure it turns out the same.")); - { - auto settings2 = winrt::make_self(); - settings2->_ParseJsonString(DefaultJson, true); - settings2->LayerJson(settings2->_defaultSettings); - VERIFY_ARE_EQUAL(2u, settings2->_profiles.Size()); - // Initialize the second settings object from the first settings - // object's settings string, the one that we synthesized. - const auto firstSettingsString = settings->_userSettingsString; - settings2->_ParseJsonString(firstSettingsString, false); - settings2->LayerJson(settings2->_userSettings); - VERIFY_ARE_EQUAL(5u, settings2->_profiles.Size()); - VERIFY_IS_TRUE(settings2->_profiles.GetAt(0).HasGuid()); - VERIFY_IS_TRUE(settings2->_profiles.GetAt(1).HasGuid()); - VERIFY_IS_TRUE(settings2->_profiles.GetAt(2).HasGuid()); - VERIFY_IS_FALSE(settings2->_profiles.GetAt(3).HasGuid()); - VERIFY_IS_FALSE(settings2->_profiles.GetAt(4).HasGuid()); - VERIFY_ARE_EQUAL(L"Windows PowerShell", settings2->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"Command Prompt", settings2->_profiles.GetAt(1).Name()); - VERIFY_ARE_EQUAL(L"ThisProfileIsGood", settings2->_profiles.GetAt(2).Name()); - VERIFY_ARE_EQUAL(L"ThisProfileShouldNotDuplicate", settings2->_profiles.GetAt(3).Name()); - VERIFY_ARE_EQUAL(L"NeitherShouldThisOne", settings2->_profiles.GetAt(4).Name()); - } - - Log::Comment(NoThrowString().Format( - L"Validate the settings. All the profiles we have should be valid.")); - settings->_ValidateSettings(); - - VERIFY_ARE_EQUAL(5u, settings->_profiles.Size()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(3).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(4).HasGuid()); - VERIFY_ARE_EQUAL(L"ThisProfileIsGood", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"ThisProfileShouldNotDuplicate", settings->_profiles.GetAt(1).Name()); - VERIFY_ARE_EQUAL(L"NeitherShouldThisOne", settings->_profiles.GetAt(2).Name()); - VERIFY_ARE_EQUAL(L"Windows PowerShell", settings->_profiles.GetAt(3).Name()); - VERIFY_ARE_EQUAL(L"Command Prompt", settings->_profiles.GetAt(4).Name()); - } - - void SettingsTests::TestHideAllProfiles() - { - const std::string settingsWithProfiles{ R"( - { - "profiles": [ - { - "name" : "profile0", - "hidden": false - }, - { - "name" : "profile1", - "hidden": true - } - ] - })" }; - - const std::string settingsWithoutProfiles{ R"( - { - "profiles": [ - { - "name" : "profile0", - "hidden": true - }, - { - "name" : "profile1", - "hidden": true - } - ] - })" }; - - VerifyParseSucceeded(settingsWithProfiles); - VerifyParseSucceeded(settingsWithoutProfiles); - - { - // Case 1: Good settings - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsWithProfiles, false); - settings->LayerJson(settings->_userSettings); - - settings->_RemoveHiddenProfiles(); - Log::Comment(NoThrowString().Format( - L"settingsWithProfiles successfully parsed and validated")); - VERIFY_ARE_EQUAL(1u, settings->_profiles.Size()); - } - { - // Case 2: Bad settings - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsWithoutProfiles, false); - settings->LayerJson(settings->_userSettings); - - bool caughtExpectedException = false; - try - { - settings->_RemoveHiddenProfiles(); - } - catch (const winrt::TerminalApp::implementation::SettingsException& ex) - { - VERIFY_IS_TRUE(ex.Error() == winrt::TerminalApp::SettingsLoadErrors::AllProfilesHidden); - caughtExpectedException = true; - } - VERIFY_IS_TRUE(caughtExpectedException); - } - } - - void SettingsTests::TestInvalidColorSchemeName() - { - Log::Comment(NoThrowString().Format( - L"Ensure that setting a profile's scheme to a non-existent scheme causes a warning.")); - - const std::string settings0String{ R"( - { - "profiles": [ - { - "name" : "profile0", - "colorScheme": "schemeOne" - }, - { - "name" : "profile1", - "colorScheme": "InvalidSchemeName" - }, - { - "name" : "profile2" - // Will use the Profile default value, "Campbell" - } - ], - "schemes": [ - { - "name": "schemeOne", - "foreground": "#111111" - }, - { - "name": "schemeTwo", - "foreground": "#222222" - } - ] - })" }; - - VerifyParseSucceeded(settings0String); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(settings0String, false); - settings->LayerJson(settings->_userSettings); - - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); - VERIFY_ARE_EQUAL(2u, settings->_globals->ColorSchemes().Size()); - - VERIFY_ARE_EQUAL(L"schemeOne", settings->_profiles.GetAt(0).ColorSchemeName()); - VERIFY_ARE_EQUAL(L"InvalidSchemeName", settings->_profiles.GetAt(1).ColorSchemeName()); - VERIFY_ARE_EQUAL(L"Campbell", settings->_profiles.GetAt(2).ColorSchemeName()); - - settings->_ValidateAllSchemesExist(); - - VERIFY_ARE_EQUAL(1u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::UnknownColorScheme, settings->_warnings.GetAt(0)); - - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); - VERIFY_ARE_EQUAL(2u, settings->_globals->ColorSchemes().Size()); - - VERIFY_ARE_EQUAL(L"schemeOne", settings->_profiles.GetAt(0).ColorSchemeName()); - VERIFY_ARE_EQUAL(L"Campbell", settings->_profiles.GetAt(1).ColorSchemeName()); - VERIFY_ARE_EQUAL(L"Campbell", settings->_profiles.GetAt(2).ColorSchemeName()); - } - - void SettingsTests::TestHelperFunctions() - { - const std::string settings0String{ R"( - { - "defaultProfile" : "{2C4DE342-38B7-51CF-B940-2309A097F518}", - "profiles": [ - { - "name" : "profile0", - "guid": "{6239a42c-5555-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile1", - "guid": "{6239a42c-6666-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "ThisProfileShouldNotThrow" - }, - { - "name" : "Ubuntu", - "guid" : "{2C4DE342-38B7-51CF-B940-2309A097F518}" - } - ] - })" }; - - auto name0{ L"profile0" }; - auto name1{ L"profile1" }; - auto name2{ L"Ubuntu" }; - auto name3{ L"ThisProfileShouldNotThrow" }; - auto badName{ L"DoesNotExist" }; - - const winrt::guid guid0{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-5555-49a3-80bd-e8fdd045185c}") }; - const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-6666-49a3-80bd-e8fdd045185c}") }; - const winrt::guid guid2{ ::Microsoft::Console::Utils::GuidFromString(L"{2C4DE342-38B7-51CF-B940-2309A097F518}") }; - const winrt::guid fakeGuid{ ::Microsoft::Console::Utils::GuidFromString(L"{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}") }; - const std::optional badGuid{}; - - VerifyParseSucceeded(settings0String); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(settings0String, false); - settings->LayerJson(settings->_userSettings); - - VERIFY_ARE_EQUAL(guid0, settings->_GetProfileGuidByName(name0)); - VERIFY_ARE_EQUAL(guid1, settings->_GetProfileGuidByName(name1)); - VERIFY_ARE_EQUAL(guid2, settings->_GetProfileGuidByName(name2)); - VERIFY_ARE_EQUAL(badGuid, settings->_GetProfileGuidByName(name3)); - VERIFY_ARE_EQUAL(badGuid, settings->_GetProfileGuidByName(badName)); - - auto prof0{ settings->FindProfile(guid0) }; - auto prof1{ settings->FindProfile(guid1) }; - auto prof2{ settings->FindProfile(guid2) }; - - auto badProf{ settings->FindProfile(fakeGuid) }; - VERIFY_ARE_EQUAL(badProf, nullptr); - - VERIFY_ARE_EQUAL(name0, prof0.Name()); - VERIFY_ARE_EQUAL(name1, prof1.Name()); - VERIFY_ARE_EQUAL(name2, prof2.Name()); - } - - void SettingsTests::TestProfileIconWithEnvVar() - { - const auto expectedPath = wil::ExpandEnvironmentStringsW(L"%WINDIR%\\System32\\x_80.png"); - - const std::string settingsJson{ R"( - { - "profiles": [ - { - "name": "profile0", - "icon": "%WINDIR%\\System32\\x_80.png" - } - ] - })" }; - - VerifyParseSucceeded(settingsJson); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsJson, false); - settings->LayerJson(settings->_userSettings); - VERIFY_ARE_NOT_EQUAL(0u, settings->_profiles.Size()); - VERIFY_ARE_EQUAL(expectedPath, settings->_profiles.GetAt(0).ExpandedIconPath()); - } - void SettingsTests::TestProfileBackgroundImageWithEnvVar() - { - const auto expectedPath = wil::ExpandEnvironmentStringsW(L"%WINDIR%\\System32\\x_80.png"); - - const std::string settingsJson{ R"( - { - "profiles": [ - { - "name": "profile0", - "backgroundImage": "%WINDIR%\\System32\\x_80.png" - } - ] - })" }; - - VerifyParseSucceeded(settingsJson); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsJson, false); - settings->LayerJson(settings->_userSettings); - VERIFY_ARE_NOT_EQUAL(0u, settings->_profiles.Size()); - - const auto globalSettings{ winrt::make() }; - const auto profile = settings->_profiles.GetAt(0); - const auto terminalSettings{ winrt::make_self() }; - terminalSettings->_ApplyProfileSettings(profile, globalSettings.ColorSchemes()); - VERIFY_ARE_EQUAL(expectedPath, terminalSettings->BackgroundImage()); - } - void SettingsTests::TestCloseOnExitParsing() - { - const std::string settingsJson{ R"( - { - "profiles": [ - { - "name": "profile0", - "closeOnExit": "graceful" - }, - { - "name": "profile1", - "closeOnExit": "always" - }, - { - "name": "profile2", - "closeOnExit": "never" - }, - { - "name": "profile3", - "closeOnExit": null - } - ] - })" }; - - VerifyParseSucceeded(settingsJson); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsJson, false); - settings->LayerJson(settings->_userSettings); - VERIFY_ARE_EQUAL(CloseOnExitMode::Graceful, settings->_profiles.GetAt(0).CloseOnExit()); - VERIFY_ARE_EQUAL(CloseOnExitMode::Always, settings->_profiles.GetAt(1).CloseOnExit()); - VERIFY_ARE_EQUAL(CloseOnExitMode::Never, settings->_profiles.GetAt(2).CloseOnExit()); - - // Unknown modes parse as "Graceful" - VERIFY_ARE_EQUAL(CloseOnExitMode::Graceful, settings->_profiles.GetAt(3).CloseOnExit()); - } - void SettingsTests::TestCloseOnExitCompatibilityShim() - { - const std::string settingsJson{ R"( - { - "profiles": [ - { - "name": "profile0", - "closeOnExit": true - }, - { - "name": "profile1", - "closeOnExit": false - } - ] - })" }; - - VerifyParseSucceeded(settingsJson); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsJson, false); - settings->LayerJson(settings->_userSettings); - VERIFY_ARE_EQUAL(CloseOnExitMode::Graceful, settings->_profiles.GetAt(0).CloseOnExit()); - VERIFY_ARE_EQUAL(CloseOnExitMode::Never, settings->_profiles.GetAt(1).CloseOnExit()); - } - - void SettingsTests::TestLayerUserDefaultsBeforeProfiles() - { - // Test for microsoft/terminal#2325. For this test, we'll be setting the - // "historySize" in the "defaultSettings", so it should apply to all - // profiles, unless they override it. In one of the user's profiles, - // we'll override that value, and in the other, we'll leave it - // untouched. - - const std::string settings0String{ R"( - { - "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", - "profiles": { - "defaults": { - "historySize": 1234 - }, - "list": [ - { - "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", - "name": "profile0", - "historySize": 2345 - }, - { - "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}", - "name": "profile1" - } - ] - } - })" }; - VerifyParseSucceeded(settings0String); - - const auto guid1String = L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"; - - { - auto settings = winrt::make_self(false); - settings->_ParseJsonString(settings0String, false); - VERIFY_IS_TRUE(settings->_userDefaultProfileSettings == Json::Value::null); - settings->_ApplyDefaultsFromUserSettings(); - VERIFY_IS_FALSE(settings->_userDefaultProfileSettings == Json::Value::null); - settings->LayerJson(settings->_userSettings); - - VERIFY_ARE_EQUAL(guid1String, settings->_globals->UnparsedDefaultProfile()); - VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); - - VERIFY_ARE_EQUAL(2345, settings->_profiles.GetAt(0).HistorySize()); - VERIFY_ARE_EQUAL(1234, settings->_profiles.GetAt(1).HistorySize()); - } - } - - void SettingsTests::TestDontLayerGuidFromUserDefaults() - { - // Test for microsoft/terminal#2325. We don't want the user to put a - // "guid" in the "defaultSettings", and have that apply to all the other - // profiles - - const std::string settings0String{ R"( - { - "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", - "profiles": { - "defaults": { - "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" - }, - "list": [ - { - "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", - "name": "profile0", - "historySize": 2345 - }, - { - // Doesn't have a GUID, we'll auto-generate one - "name": "profile1" - } - ] - } - })" }; - VerifyParseSucceeded(settings0String); - - const auto guid1String = L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"; - const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(guid1String) }; - const winrt::guid guid2{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}") }; - - { - auto settings = winrt::make_self(false); - settings->_ParseJsonString(DefaultJson, true); - settings->LayerJson(settings->_defaultSettings); - VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); - - settings->_ParseJsonString(settings0String, false); - VERIFY_IS_TRUE(settings->_userDefaultProfileSettings == Json::Value::null); - settings->_ApplyDefaultsFromUserSettings(); - VERIFY_IS_FALSE(settings->_userDefaultProfileSettings == Json::Value::null); - - Log::Comment(NoThrowString().Format( - L"Ensure that cmd and powershell don't get their GUIDs overwritten")); - VERIFY_ARE_NOT_EQUAL(guid2, settings->_profiles.GetAt(0).Guid()); - VERIFY_ARE_NOT_EQUAL(guid2, settings->_profiles.GetAt(1).Guid()); - - settings->LayerJson(settings->_userSettings); - - VERIFY_ARE_EQUAL(guid1String, settings->_globals->UnparsedDefaultProfile()); - VERIFY_ARE_EQUAL(4u, settings->_profiles.Size()); - - VERIFY_ARE_EQUAL(guid1, settings->_profiles.GetAt(2).Guid()); - VERIFY_IS_FALSE(settings->_profiles.GetAt(3).HasGuid()); - } - } - - void SettingsTests::TestLayerUserDefaultsOnDynamics() - { - // Test for microsoft/terminal#2325. For this test, we'll be setting the - // "historySize" in the "defaultSettings", so it should apply to all - // profiles, unless they override it. The dynamic profiles will _also_ - // set this value, but from discussion in GH#2325, we decided that - // settings in defaultSettings should apply _on top_ of settings from - // dynamic profiles. - - const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}") }; - const winrt::guid guid2{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}") }; - const winrt::guid guid3{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-3333-49a3-80bd-e8fdd045185c}") }; - - const std::string userProfiles{ R"( - { - "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", - "profiles": { - "defaults": { - "historySize": 1234 - }, - "list": [ - { - "name" : "profile0FromUserSettings", // this is _profiles.GetAt(0) - "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", - "source": "Terminal.App.UnitTest.0" - }, - { - "name" : "profile1FromUserSettings", // this is _profiles.GetAt(2) - "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}", - "source": "Terminal.App.UnitTest.1", - "historySize": 4444 - }, - { - "name" : "profile2FromUserSettings", // this is _profiles.GetAt(3) - "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}", - "historySize": 5555 - } - ] - } - })" }; - - auto gen0 = std::make_unique(L"Terminal.App.UnitTest.0"); - gen0->pfnGenerate = [guid1, guid2]() { - std::vector profiles; - Profile p0 = winrt::make(guid1); - p0.Name(L"profile0"); // this is _profiles.GetAt(0) - p0.HistorySize(1111); - profiles.push_back(p0); - return profiles; - }; - auto gen1 = std::make_unique(L"Terminal.App.UnitTest.1"); - gen1->pfnGenerate = [guid1, guid2]() { - std::vector profiles; - Profile p0 = winrt::make(guid1); - Profile p1 = winrt::make(guid2); - p0.Name(L"profile0"); // this is _profiles.GetAt(1) - p1.Name(L"profile1"); // this is _profiles.GetAt(2) - p0.HistorySize(2222); - profiles.push_back(p0); - p1.HistorySize(3333); - profiles.push_back(p1); - return profiles; - }; - - auto settings = winrt::make_self(false); - settings->_profileGenerators.emplace_back(std::move(gen0)); - settings->_profileGenerators.emplace_back(std::move(gen1)); - - Log::Comment(NoThrowString().Format( - L"All profiles with the same name have the same GUID. However, they" - L" will not be layered, because they have different source's")); - - // parse userProfiles as the user settings - settings->_ParseJsonString(userProfiles, false); - VERIFY_ARE_EQUAL(0u, settings->_profiles.Size(), L"Just parsing the user settings doesn't actually layer them"); - settings->_LoadDynamicProfiles(); - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); - - VERIFY_ARE_EQUAL(1111, settings->_profiles.GetAt(0).HistorySize()); - VERIFY_ARE_EQUAL(2222, settings->_profiles.GetAt(1).HistorySize()); - VERIFY_ARE_EQUAL(3333, settings->_profiles.GetAt(2).HistorySize()); - - settings->_ApplyDefaultsFromUserSettings(); - - VERIFY_ARE_EQUAL(1234, settings->_profiles.GetAt(0).HistorySize()); - VERIFY_ARE_EQUAL(1234, settings->_profiles.GetAt(1).HistorySize()); - VERIFY_ARE_EQUAL(1234, settings->_profiles.GetAt(2).HistorySize()); - - settings->LayerJson(settings->_userSettings); - VERIFY_ARE_EQUAL(4u, settings->_profiles.Size()); - - VERIFY_IS_FALSE(settings->_profiles.GetAt(0).Source().empty()); - VERIFY_IS_FALSE(settings->_profiles.GetAt(1).Source().empty()); - VERIFY_IS_FALSE(settings->_profiles.GetAt(2).Source().empty()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(3).Source().empty()); - - VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.0", settings->_profiles.GetAt(0).Source()); - VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.1", settings->_profiles.GetAt(1).Source()); - VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.1", settings->_profiles.GetAt(2).Source()); - - VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid()); - VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid()); - - VERIFY_ARE_EQUAL(guid1, settings->_profiles.GetAt(0).Guid()); - VERIFY_ARE_EQUAL(guid1, settings->_profiles.GetAt(1).Guid()); - VERIFY_ARE_EQUAL(guid2, settings->_profiles.GetAt(2).Guid()); - - VERIFY_ARE_EQUAL(L"profile0FromUserSettings", settings->_profiles.GetAt(0).Name()); - VERIFY_ARE_EQUAL(L"profile0", settings->_profiles.GetAt(1).Name()); - VERIFY_ARE_EQUAL(L"profile1FromUserSettings", settings->_profiles.GetAt(2).Name()); - VERIFY_ARE_EQUAL(L"profile2FromUserSettings", settings->_profiles.GetAt(3).Name()); - - Log::Comment(NoThrowString().Format( - L"This is the real meat of the test: The two dynamic profiles that " - L"_didn't_ have historySize set in the userSettings should have " - L"1234 as their historySize(from the defaultSettings).The other two" - L" profiles should have their custom historySize value.")); - - VERIFY_ARE_EQUAL(1234, settings->_profiles.GetAt(0).HistorySize()); - VERIFY_ARE_EQUAL(1234, settings->_profiles.GetAt(1).HistorySize()); - VERIFY_ARE_EQUAL(4444, settings->_profiles.GetAt(2).HistorySize()); - VERIFY_ARE_EQUAL(5555, settings->_profiles.GetAt(3).HistorySize()); - } - - void SettingsTests::TestTerminalArgsForBinding() - { - 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" - } - ], - "keybindings": [ - { "keys": ["ctrl+a"], "command": { "action": "splitPane", "split": "vertical" } }, - { "keys": ["ctrl+b"], "command": { "action": "splitPane", "split": "vertical", "profile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" } }, - { "keys": ["ctrl+c"], "command": { "action": "splitPane", "split": "vertical", "profile": "profile1" } }, - { "keys": ["ctrl+d"], "command": { "action": "splitPane", "split": "vertical", "profile": "profile2" } }, - { "keys": ["ctrl+e"], "command": { "action": "splitPane", "split": "horizontal", "commandline": "foo.exe" } }, - { "keys": ["ctrl+f"], "command": { "action": "splitPane", "split": "horizontal", "profile": "profile1", "commandline": "foo.exe" } }, - { "keys": ["ctrl+g"], "command": { "action": "newTab" } }, - { "keys": ["ctrl+h"], "command": { "action": "newTab", "startingDirectory": "c:\\foo" } }, - { "keys": ["ctrl+i"], "command": { "action": "newTab", "profile": "profile2", "startingDirectory": "c:\\foo" } }, - { "keys": ["ctrl+j"], "command": { "action": "newTab", "tabTitle": "bar" } }, - { "keys": ["ctrl+k"], "command": { "action": "newTab", "profile": "profile2", "tabTitle": "bar" } }, - { "keys": ["ctrl+l"], "command": { "action": "newTab", "profile": "profile1", "tabTitle": "bar", "startingDirectory": "c:\\foo", "commandline":"foo.exe" } } - ] - })" }; - - const winrt::guid guid0{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}") }; - const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}") }; - - VerifyParseSucceeded(settingsJson); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsJson, false); - settings->LayerJson(settings->_userSettings); - settings->_ValidateSettings(); - - auto keymapProj = settings->_globals->KeyMap(); - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); - - const auto profile2Guid = settings->_profiles.GetAt(2).Guid(); - VERIFY_ARE_NOT_EQUAL(winrt::guid{}, profile2Guid); - - const auto keymap = winrt::get_self(keymapProj); - VERIFY_ARE_EQUAL(12u, keymap->_keyShortcuts.size()); - - { - KeyChord kc{ true, false, false, static_cast('A') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); - 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::Vertical, 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_TRUE(realArgs.TerminalArgs().Profile().empty()); - - const auto [guid, termSettings] = implementation::TerminalSettings::BuildSettings(*settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(guid0, guid); - VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); - VERIFY_ARE_EQUAL(1, termSettings.HistorySize()); - } - { - KeyChord kc{ true, false, false, static_cast('B') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); - 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::Vertical, 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"{6239a42c-1111-49a3-80bd-e8fdd045185c}", realArgs.TerminalArgs().Profile()); - - const auto [guid, termSettings] = implementation::TerminalSettings::BuildSettings(*settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(guid1, guid); - VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline()); - VERIFY_ARE_EQUAL(2, termSettings.HistorySize()); - } - { - KeyChord kc{ true, false, false, static_cast('C') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); - 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::Vertical, 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"profile1", realArgs.TerminalArgs().Profile()); - - const auto [guid, termSettings] = implementation::TerminalSettings::BuildSettings(*settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(guid1, guid); - VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline()); - VERIFY_ARE_EQUAL(2, termSettings.HistorySize()); - } - { - KeyChord kc{ true, false, false, static_cast('D') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); - 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::Vertical, 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"profile2", realArgs.TerminalArgs().Profile()); - - const auto [guid, termSettings] = implementation::TerminalSettings::BuildSettings(*settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(profile2Guid, guid); - VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline()); - VERIFY_ARE_EQUAL(3, termSettings.HistorySize()); - } - { - KeyChord kc{ true, false, false, static_cast('E') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); - 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::Horizontal, realArgs.SplitStyle()); - VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); - VERIFY_IS_FALSE(realArgs.TerminalArgs().Commandline().empty()); - VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); - VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); - VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); - VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline()); - - const auto [guid, termSettings] = implementation::TerminalSettings::BuildSettings(*settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(guid0, guid); - VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline()); - VERIFY_ARE_EQUAL(1, termSettings.HistorySize()); - } - { - KeyChord kc{ true, false, false, static_cast('F') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); - 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::Horizontal, realArgs.SplitStyle()); - VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); - VERIFY_IS_FALSE(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"profile1", realArgs.TerminalArgs().Profile()); - VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline()); - - const auto [guid, termSettings] = implementation::TerminalSettings::BuildSettings(*settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(guid1, guid); - VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline()); - VERIFY_ARE_EQUAL(2, termSettings.HistorySize()); - } - { - KeyChord kc{ true, false, false, static_cast('G') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); - VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); - const auto& realArgs = actionAndArgs.Args().try_as(); - VERIFY_IS_NOT_NULL(realArgs); - // Verify the args have the expected value - 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_TRUE(realArgs.TerminalArgs().Profile().empty()); - - const auto [guid, termSettings] = implementation::TerminalSettings::BuildSettings(*settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(guid0, guid); - VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); - VERIFY_ARE_EQUAL(1, termSettings.HistorySize()); - } - { - KeyChord kc{ true, false, false, static_cast('H') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); - VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); - const auto& realArgs = actionAndArgs.Args().try_as(); - VERIFY_IS_NOT_NULL(realArgs); - // Verify the args have the expected value - VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); - VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); - VERIFY_IS_FALSE(realArgs.TerminalArgs().StartingDirectory().empty()); - VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); - VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); - VERIFY_ARE_EQUAL(L"c:\\foo", realArgs.TerminalArgs().StartingDirectory()); - - const auto [guid, termSettings] = implementation::TerminalSettings::BuildSettings(*settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(guid0, guid); - VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); - VERIFY_ARE_EQUAL(L"c:\\foo", termSettings.StartingDirectory()); - VERIFY_ARE_EQUAL(1, termSettings.HistorySize()); - } - { - KeyChord kc{ true, false, false, static_cast('I') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); - VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); - const auto& realArgs = actionAndArgs.Args().try_as(); - VERIFY_IS_NOT_NULL(realArgs); - // Verify the args have the expected value - VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); - VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); - VERIFY_IS_FALSE(realArgs.TerminalArgs().StartingDirectory().empty()); - VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); - VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); - VERIFY_ARE_EQUAL(L"c:\\foo", realArgs.TerminalArgs().StartingDirectory()); - VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile()); - - const auto [guid, termSettings] = implementation::TerminalSettings::BuildSettings(*settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(profile2Guid, guid); - VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline()); - VERIFY_ARE_EQUAL(L"c:\\foo", termSettings.StartingDirectory()); - VERIFY_ARE_EQUAL(3, termSettings.HistorySize()); - } - { - KeyChord kc{ true, false, false, static_cast('J') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); - VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); - const auto& realArgs = actionAndArgs.Args().try_as(); - VERIFY_IS_NOT_NULL(realArgs); - // Verify the args have the expected value - VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); - VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); - VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); - VERIFY_IS_FALSE(realArgs.TerminalArgs().TabTitle().empty()); - VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); - VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle()); - - const auto [guid, termSettings] = implementation::TerminalSettings::BuildSettings(*settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(guid0, guid); - VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); - VERIFY_ARE_EQUAL(L"bar", termSettings.StartingTitle()); - VERIFY_ARE_EQUAL(1, termSettings.HistorySize()); - } - { - KeyChord kc{ true, false, false, static_cast('K') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); - VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); - const auto& realArgs = actionAndArgs.Args().try_as(); - VERIFY_IS_NOT_NULL(realArgs); - // Verify the args have the expected value - VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); - VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); - VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); - VERIFY_IS_FALSE(realArgs.TerminalArgs().TabTitle().empty()); - VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); - VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle()); - VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile()); - - const auto [guid, termSettings] = implementation::TerminalSettings::BuildSettings(*settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(profile2Guid, guid); - VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline()); - VERIFY_ARE_EQUAL(L"bar", termSettings.StartingTitle()); - VERIFY_ARE_EQUAL(3, termSettings.HistorySize()); - } - { - KeyChord kc{ true, false, false, static_cast('L') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); - VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); - const auto& realArgs = actionAndArgs.Args().try_as(); - VERIFY_IS_NOT_NULL(realArgs); - // Verify the args have the expected value - VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); - VERIFY_IS_FALSE(realArgs.TerminalArgs().Commandline().empty()); - VERIFY_IS_FALSE(realArgs.TerminalArgs().StartingDirectory().empty()); - VERIFY_IS_FALSE(realArgs.TerminalArgs().TabTitle().empty()); - VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); - VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline()); - VERIFY_ARE_EQUAL(L"c:\\foo", realArgs.TerminalArgs().StartingDirectory()); - VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle()); - VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile()); - - const auto [guid, termSettings] = implementation::TerminalSettings::BuildSettings(*settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(guid1, guid); - VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline()); - VERIFY_ARE_EQUAL(L"bar", termSettings.StartingTitle()); - VERIFY_ARE_EQUAL(L"c:\\foo", termSettings.StartingDirectory()); - VERIFY_ARE_EQUAL(2, termSettings.HistorySize()); - } - } - - void SettingsTests::FindMissingProfile() - { - // Test that CascadiaSettings::FindProfile returns null for a GUID that - // doesn't exist - const std::string settingsString{ R"( - { - "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", - "profiles": [ - { - "name" : "profile0", - "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile1", - "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" - } - ] - })" }; - const auto settingsJsonObj = VerifyParseSucceeded(settingsString); - auto settings = implementation::CascadiaSettings::FromJson(settingsJsonObj); - - const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"); - const auto guid2 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}"); - const auto guid3 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-3333-49a3-80bd-e8fdd045185c}"); - - const auto profile1 = settings->FindProfile(guid1); - const auto profile2 = settings->FindProfile(guid2); - const auto profile3 = settings->FindProfile(guid3); - - VERIFY_IS_NOT_NULL(profile1); - VERIFY_IS_NOT_NULL(profile2); - VERIFY_IS_NULL(profile3); - - VERIFY_ARE_EQUAL(L"profile0", profile1.Name()); - VERIFY_ARE_EQUAL(L"profile1", profile2.Name()); - } - - void SettingsTests::MakeSettingsForProfileThatDoesntExist() - { - // Test that MakeSettings throws when the GUID doesn't exist - const std::string settingsString{ R"( - { - "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", - "profiles": [ - { - "name" : "profile0", - "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", - "historySize": 1 - }, - { - "name" : "profile1", - "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}", - "historySize": 2 - } - ] - })" }; - const auto settingsJsonObj = VerifyParseSucceeded(settingsString); - auto settings = implementation::CascadiaSettings::FromJson(settingsJsonObj); - settings->_ResolveDefaultProfile(); - - const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"); - const auto guid2 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}"); - const auto guid3 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-3333-49a3-80bd-e8fdd045185c}"); - - try - { - auto terminalSettings = winrt::make(*settings, guid1, nullptr); - VERIFY_ARE_NOT_EQUAL(nullptr, terminalSettings); - VERIFY_ARE_EQUAL(1, terminalSettings.HistorySize()); - } - catch (...) - { - VERIFY_IS_TRUE(false, L"This call to BuildSettings should succeed"); - } - - try - { - auto terminalSettings = winrt::make(*settings, guid2, nullptr); - VERIFY_ARE_NOT_EQUAL(nullptr, terminalSettings); - VERIFY_ARE_EQUAL(2, terminalSettings.HistorySize()); - } - catch (...) - { - VERIFY_IS_TRUE(false, L"This call to BuildSettings should succeed"); - } - - VERIFY_THROWS(auto terminalSettings = winrt::make(*settings, guid3, nullptr), wil::ResultException, L"This call to BuildSettings should fail"); - - try - { - const auto [guid, termSettings] = implementation::TerminalSettings::BuildSettings(*settings, nullptr, nullptr); - VERIFY_ARE_NOT_EQUAL(nullptr, termSettings); - VERIFY_ARE_EQUAL(1, termSettings.HistorySize()); - } - catch (...) - { - VERIFY_IS_TRUE(false, L"This call to BuildSettings should succeed"); - } - } - - void SettingsTests::MakeSettingsForDefaultProfileThatDoesntExist() - { - // Test that MakeSettings _doesnt_ throw when we load settings with a - // defaultProfile that's not in the list, we validate the settings, and - // then call MakeSettings(nullopt). The validation should ensure that - // the default profile is something reasonable - const std::string settingsString{ R"( - { - "defaultProfile": "{6239a42c-3333-49a3-80bd-e8fdd045185c}", - "profiles": [ - { - "name" : "profile0", - "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", - "historySize": 1 - }, - { - "name" : "profile1", - "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}", - "historySize": 2 - } - ] - })" }; - const auto settingsJsonObj = VerifyParseSucceeded(settingsString); - auto settings = implementation::CascadiaSettings::FromJson(settingsJsonObj); - settings->_ValidateSettings(); - - VERIFY_ARE_EQUAL(2u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(2u, settings->_profiles.Size()); - VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), settings->_profiles.GetAt(0).Guid()); - try - { - const auto [guid, termSettings] = implementation::TerminalSettings::BuildSettings(*settings, nullptr, nullptr); - VERIFY_ARE_NOT_EQUAL(nullptr, termSettings); - VERIFY_ARE_EQUAL(1, termSettings.HistorySize()); - } - catch (...) - { - VERIFY_IS_TRUE(false, L"This call to BuildSettings should succeed"); - } - } - - void SettingsTests::TestLayerProfileOnColorScheme() - { - Log::Comment(NoThrowString().Format( - L"Ensure that setting (or not) a property in the profile that should override a property of the color scheme works correctly.")); - - const std::string settings0String{ R"( - { - "profiles": [ - { - "name" : "profile0", - "colorScheme": "schemeWithCursorColor" - }, - { - "name" : "profile1", - "colorScheme": "schemeWithoutCursorColor" - }, - { - "name" : "profile2", - "colorScheme": "schemeWithCursorColor", - "cursorColor": "#234567" - }, - { - "name" : "profile3", - "colorScheme": "schemeWithoutCursorColor", - "cursorColor": "#345678" - }, - { - "name" : "profile4", - "cursorColor": "#456789" - }, - { - "name" : "profile5" - } - ], - "schemes": [ - { - "name": "schemeWithCursorColor", - "cursorColor": "#123456" - }, - { - "name": "schemeWithoutCursorColor" - } - ] - })" }; - - VerifyParseSucceeded(settings0String); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(settings0String, false); - settings->LayerJson(settings->_userSettings); - - VERIFY_ARE_EQUAL(6u, settings->_profiles.Size()); - VERIFY_ARE_EQUAL(2u, settings->_globals->ColorSchemes().Size()); - - auto createTerminalSettings = [&](const auto& profile, const auto& schemes) { - auto terminalSettings{ winrt::make_self() }; - terminalSettings->_ApplyProfileSettings(profile, schemes); - return terminalSettings; - }; - - auto terminalSettings0 = createTerminalSettings(settings->_profiles.GetAt(0), settings->_globals->ColorSchemes()); - auto terminalSettings1 = createTerminalSettings(settings->_profiles.GetAt(1), settings->_globals->ColorSchemes()); - auto terminalSettings2 = createTerminalSettings(settings->_profiles.GetAt(2), settings->_globals->ColorSchemes()); - auto terminalSettings3 = createTerminalSettings(settings->_profiles.GetAt(3), settings->_globals->ColorSchemes()); - auto terminalSettings4 = createTerminalSettings(settings->_profiles.GetAt(4), settings->_globals->ColorSchemes()); - auto terminalSettings5 = createTerminalSettings(settings->_profiles.GetAt(5), settings->_globals->ColorSchemes()); - - VERIFY_ARE_EQUAL(ARGB(0, 0x12, 0x34, 0x56), terminalSettings0->CursorColor()); // from color scheme - VERIFY_ARE_EQUAL(DEFAULT_CURSOR_COLOR, terminalSettings1->CursorColor()); // default - VERIFY_ARE_EQUAL(ARGB(0, 0x23, 0x45, 0x67), terminalSettings2->CursorColor()); // from profile (trumps color scheme) - VERIFY_ARE_EQUAL(ARGB(0, 0x34, 0x56, 0x78), terminalSettings3->CursorColor()); // from profile (not set in color scheme) - VERIFY_ARE_EQUAL(ARGB(0, 0x45, 0x67, 0x89), terminalSettings4->CursorColor()); // from profile (no color scheme) - VERIFY_ARE_EQUAL(DEFAULT_CURSOR_COLOR, terminalSettings5->CursorColor()); // default - } - - void SettingsTests::ValidateKeybindingsWarnings() - { - const std::string badSettings{ R"( - { - "defaultProfile": "{6239a42c-2222-49a3-80bd-e8fdd045185c}", - "profiles": [ - { - "name" : "profile0", - "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile1", - "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}" - } - ], - "keybindings": [ - { "command": { "action": "splitPane", "split":"auto" }, "keys": [ "ctrl+alt+t", "ctrl+a" ] }, - { "command": { "action": "moveFocus" }, "keys": [ "ctrl+a" ] }, - { "command": { "action": "resizePane" }, "keys": [ "ctrl+b" ] } - ] - })" }; - - const auto settingsObject = VerifyParseSucceeded(badSettings); - auto settings = implementation::CascadiaSettings::FromJson(settingsObject); - - VERIFY_ARE_EQUAL(0u, settings->_globals->_keymap->_keyShortcuts.size()); - - VERIFY_ARE_EQUAL(3u, settings->_globals->_keybindingsWarnings.size()); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::TooManyKeysForChord, settings->_globals->_keybindingsWarnings.at(0)); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter, settings->_globals->_keybindingsWarnings.at(1)); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter, settings->_globals->_keybindingsWarnings.at(2)); - - settings->_ValidateKeybindings(); - - VERIFY_ARE_EQUAL(4u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::AtLeastOneKeybindingWarning, settings->_warnings.GetAt(0)); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::TooManyKeysForChord, settings->_warnings.GetAt(1)); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.GetAt(2)); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.GetAt(3)); - } - - void SettingsTests::ValidateExecuteCommandlineWarning() - { - const std::string badSettings{ R"( - { - "defaultProfile": "{6239a42c-2222-49a3-80bd-e8fdd045185c}", - "profiles": [ - { - "name" : "profile0", - "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile1", - "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}" - } - ], - "keybindings": [ - { "name":null, "command": { "action": "wt" }, "keys": [ "ctrl+a" ] }, - { "name":null, "command": { "action": "wt", "commandline":"" }, "keys": [ "ctrl+b" ] }, - { "name":null, "command": { "action": "wt", "commandline":null }, "keys": [ "ctrl+c" ] } - ] - })" }; - - const auto settingsObject = VerifyParseSucceeded(badSettings); - - auto settings = implementation::CascadiaSettings::FromJson(settingsObject); - - VERIFY_ARE_EQUAL(0u, settings->_globals->_keymap->_keyShortcuts.size()); - - for (const auto& warning : settings->_globals->_keybindingsWarnings) - { - Log::Comment(NoThrowString().Format( - L"warning:%d", warning)); - } - VERIFY_ARE_EQUAL(3u, settings->_globals->_keybindingsWarnings.size()); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter, settings->_globals->_keybindingsWarnings.at(0)); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter, settings->_globals->_keybindingsWarnings.at(1)); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter, settings->_globals->_keybindingsWarnings.at(2)); - - settings->_ValidateKeybindings(); - - VERIFY_ARE_EQUAL(4u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::AtLeastOneKeybindingWarning, settings->_warnings.GetAt(0)); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.GetAt(1)); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.GetAt(2)); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.GetAt(3)); - } - - void SettingsTests::ValidateLegacyGlobalsWarning() - { - const std::string badSettings{ R"( - { - "globals": {}, - "defaultProfile": "{6239a42c-2222-49a3-80bd-e8fdd045185c}", - "profiles": [ - { - "name" : "profile0", - "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile1", - "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}" - } - ], - "keybindings": [] - })" }; - - // Create the default settings - auto settings = winrt::make_self(); - settings->_ParseJsonString(DefaultJson, true); - settings->LayerJson(settings->_defaultSettings); - - settings->_ValidateNoGlobalsKey(); - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); - - // Now layer on the user's settings - settings->_ParseJsonString(badSettings, false); - settings->LayerJson(settings->_userSettings); - - settings->_ValidateNoGlobalsKey(); - VERIFY_ARE_EQUAL(1u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(winrt::TerminalApp::SettingsLoadWarnings::LegacyGlobalsProperty, settings->_warnings.GetAt(0)); - } - - void SettingsTests::TestTrailingCommas() - { - const std::string badSettings{ R"( - { - "defaultProfile": "{6239a42c-2222-49a3-80bd-e8fdd045185c}", - "profiles": [ - { - "name" : "profile0", - "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}" - }, - { - "name" : "profile1", - "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}" - }, - ], - "keybindings": [], - })" }; - - // Create the default settings - auto settings = winrt::make_self(); - settings->_ParseJsonString(DefaultJson, true); - settings->LayerJson(settings->_defaultSettings); - - // Now layer on the user's settings - try - { - settings->_ParseJsonString(badSettings, false); - settings->LayerJson(settings->_userSettings); - } - catch (...) - { - VERIFY_IS_TRUE(false, L"This call to LayerJson should succeed, even with the trailing comma"); - } - } - - void SettingsTests::TestCommandsAndKeybindings() - { - 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" - } - ], - "actions": [ - { "keys": "ctrl+a", "command": { "action": "splitPane", "split": "vertical" } }, - { "name": "ctrl+b", "command": { "action": "splitPane", "split": "vertical" } }, - { "keys": "ctrl+c", "name": "ctrl+c", "command": { "action": "splitPane", "split": "vertical" } }, - { "keys": "ctrl+d", "command": { "action": "splitPane", "split": "vertical" } }, - { "keys": "ctrl+e", "command": { "action": "splitPane", "split": "horizontal" } }, - { "keys": "ctrl+f", "name":null, "command": { "action": "splitPane", "split": "horizontal" } } - ] - })" }; - - const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}"); - const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"); - - VerifyParseSucceeded(settingsJson); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsJson, false); - settings->LayerJson(settings->_userSettings); - settings->_ValidateSettings(); - - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); - - const auto profile2Guid = settings->_profiles.GetAt(2).Guid(); - VERIFY_ARE_NOT_EQUAL(winrt::guid{}, profile2Guid); - - auto keymap = winrt::get_self(settings->_globals->KeyMap()); - VERIFY_ARE_EQUAL(5u, keymap->_keyShortcuts.size()); - - // A/D, B, C, E will be in the list of commands, for 4 total. - // * A and D share the same name, so they'll only generate a single action. - // * F's name is set manually to `null` - auto commands = settings->_globals->Commands(); - VERIFY_ARE_EQUAL(4u, commands.Size()); + KeyChord kc{ true, false, false, static_cast('A') }; + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); + 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(SplitState::Vertical, 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_TRUE(realArgs.TerminalArgs().Profile().empty()); + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(guid0, guid); + VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(1, termSettings.HistorySize()); + } { - KeyChord kc{ true, false, false, static_cast('A') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + KeyChord kc{ true, false, false, static_cast('B') }; + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); 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::Vertical, realArgs.SplitStyle()); + VERIFY_ARE_EQUAL(SplitState::Vertical, 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_TRUE(realArgs.TerminalArgs().Profile().empty()); - } - - Log::Comment(L"Note that we're skipping ctrl+B, since that doesn't have `keys` set."); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}", realArgs.TerminalArgs().Profile()); + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(guid1, guid); + VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(2, termSettings.HistorySize()); + } { KeyChord kc{ true, false, false, static_cast('C') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); 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::Vertical, realArgs.SplitStyle()); + VERIFY_ARE_EQUAL(SplitState::Vertical, 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_TRUE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile()); + + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(guid1, guid); + VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(2, termSettings.HistorySize()); } { KeyChord kc{ true, false, false, static_cast('D') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); 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::Vertical, realArgs.SplitStyle()); + VERIFY_ARE_EQUAL(SplitState::Vertical, 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_TRUE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile()); + + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(profile2Guid, guid); + VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(3, termSettings.HistorySize()); } { KeyChord kc{ true, false, false, static_cast('E') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); 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::Horizontal, realArgs.SplitStyle()); + VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); - VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline()); + + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(guid0, guid); + VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(1, termSettings.HistorySize()); } { KeyChord kc{ true, false, false, static_cast('F') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*keymap, kc); + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); 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::Horizontal, realArgs.SplitStyle()); + VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); - VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); - VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); - } + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile()); + VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline()); - Log::Comment(L"Now verify the commands"); - _logCommandNames(commands); + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(guid1, guid); + VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(2, termSettings.HistorySize()); + } { - auto command = commands.Lookup(L"Split pane, split: vertical"); - 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(); + KeyChord kc{ true, false, false, static_cast('G') }; + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); + VERIFY_ARE_EQUAL(ShortcutAction::NewTab, 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::Vertical, 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_TRUE(realArgs.TerminalArgs().Profile().empty()); + + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(guid0, guid); + VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(1, termSettings.HistorySize()); } { - auto command = commands.Lookup(L"ctrl+b"); - 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(); + KeyChord kc{ true, false, false, static_cast('H') }; + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); + VERIFY_ARE_EQUAL(ShortcutAction::NewTab, 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::Vertical, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); - VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().StartingDirectory().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"c:\\foo", realArgs.TerminalArgs().StartingDirectory()); + + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(guid0, guid); + VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(L"c:\\foo", termSettings.StartingDirectory()); + VERIFY_ARE_EQUAL(1, termSettings.HistorySize()); } { - auto command = commands.Lookup(L"ctrl+c"); - 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(); + KeyChord kc{ true, false, false, static_cast('I') }; + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); + VERIFY_ARE_EQUAL(ShortcutAction::NewTab, 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::Vertical, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); - VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().StartingDirectory().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); - VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"c:\\foo", realArgs.TerminalArgs().StartingDirectory()); + VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile()); + + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(profile2Guid, guid); + VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(L"c:\\foo", termSettings.StartingDirectory()); + VERIFY_ARE_EQUAL(3, termSettings.HistorySize()); } { - auto command = commands.Lookup(L"Split pane, split: horizontal"); - 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(); + KeyChord kc{ true, false, false, static_cast('J') }; + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); + VERIFY_ARE_EQUAL(ShortcutAction::NewTab, 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::Horizontal, 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().TabTitle().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle()); + + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(guid0, guid); + VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(L"bar", termSettings.StartingTitle()); + VERIFY_ARE_EQUAL(1, termSettings.HistorySize()); + } + { + KeyChord kc{ true, false, false, static_cast('K') }; + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); + VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); + const auto& realArgs = actionAndArgs.Args().try_as(); + VERIFY_IS_NOT_NULL(realArgs); + // Verify the args have the expected value + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().TabTitle().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle()); + VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile()); + + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(profile2Guid, guid); + VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(L"bar", termSettings.StartingTitle()); + VERIFY_ARE_EQUAL(3, termSettings.HistorySize()); } + { + KeyChord kc{ true, false, false, static_cast('L') }; + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); + VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); + const auto& realArgs = actionAndArgs.Args().try_as(); + VERIFY_IS_NOT_NULL(realArgs); + // Verify the args have the expected value + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Commandline().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().StartingDirectory().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().TabTitle().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline()); + VERIFY_ARE_EQUAL(L"c:\\foo", realArgs.TerminalArgs().StartingDirectory()); + VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle()); + VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile()); + + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(guid1, guid); + VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(L"bar", termSettings.StartingTitle()); + VERIFY_ARE_EQUAL(L"c:\\foo", termSettings.StartingDirectory()); + VERIFY_ARE_EQUAL(2, termSettings.HistorySize()); + } + } + + void SettingsTests::MakeSettingsForProfileThatDoesntExist() + { + // Test that MakeSettings throws when the GUID doesn't exist + const std::string settingsString{ R"( + { + "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "profiles": [ + { + "name" : "profile0", + "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "historySize": 1 + }, + { + "name" : "profile1", + "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}", + "historySize": 2 + } + ] + })" }; + CascadiaSettings settings{ til::u8u16(settingsString) }; + + const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"); + const auto guid2 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}"); + const auto guid3 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-3333-49a3-80bd-e8fdd045185c}"); + + try + { + auto terminalSettings = winrt::make(settings, guid1, nullptr); + VERIFY_ARE_NOT_EQUAL(nullptr, terminalSettings); + VERIFY_ARE_EQUAL(1, terminalSettings.HistorySize()); + } + catch (...) + { + VERIFY_IS_TRUE(false, L"This call to BuildSettings should succeed"); + } + + try + { + auto terminalSettings = winrt::make(settings, guid2, nullptr); + VERIFY_ARE_NOT_EQUAL(nullptr, terminalSettings); + VERIFY_ARE_EQUAL(2, terminalSettings.HistorySize()); + } + catch (...) + { + VERIFY_IS_TRUE(false, L"This call to BuildSettings should succeed"); + } + + VERIFY_THROWS(auto terminalSettings = winrt::make(settings, guid3, nullptr), wil::ResultException, L"This call to BuildSettings should fail"); + + try + { + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, nullptr, nullptr); + VERIFY_ARE_NOT_EQUAL(nullptr, termSettings); + VERIFY_ARE_EQUAL(1, termSettings.HistorySize()); + } + catch (...) + { + VERIFY_IS_TRUE(false, L"This call to BuildSettings should succeed"); + } + } + + void SettingsTests::MakeSettingsForDefaultProfileThatDoesntExist() + { + // Test that MakeSettings _doesnt_ throw when we load settings with a + // defaultProfile that's not in the list, we validate the settings, and + // then call MakeSettings(nullopt). The validation should ensure that + // the default profile is something reasonable + const std::string settingsString{ R"( + { + "defaultProfile": "{6239a42c-3333-49a3-80bd-e8fdd045185c}", + "profiles": [ + { + "name" : "profile0", + "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "historySize": 1 + }, + { + "name" : "profile1", + "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}", + "historySize": 2 + } + ] + })" }; + CascadiaSettings settings{ til::u8u16(settingsString) }; + + VERIFY_ARE_EQUAL(2u, settings.Warnings().Size()); + VERIFY_ARE_EQUAL(2u, settings.Profiles().Size()); + VERIFY_ARE_EQUAL(settings.GlobalSettings().DefaultProfile(), settings.Profiles().GetAt(0).Guid()); + try + { + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, nullptr, nullptr); + VERIFY_ARE_NOT_EQUAL(nullptr, termSettings); + VERIFY_ARE_EQUAL(1, termSettings.HistorySize()); + } + catch (...) + { + VERIFY_IS_TRUE(false, L"This call to BuildSettings should succeed"); + } + } + + void SettingsTests::TestLayerProfileOnColorScheme() + { + Log::Comment(NoThrowString().Format( + L"Ensure that setting (or not) a property in the profile that should override a property of the color scheme works correctly.")); + + const std::string settings0String{ R"( + { + "profiles": [ + { + "name" : "profile0", + "colorScheme": "schemeWithCursorColor" + }, + { + "name" : "profile1", + "colorScheme": "schemeWithoutCursorColor" + }, + { + "name" : "profile2", + "colorScheme": "schemeWithCursorColor", + "cursorColor": "#234567" + }, + { + "name" : "profile3", + "colorScheme": "schemeWithoutCursorColor", + "cursorColor": "#345678" + }, + { + "name" : "profile4", + "cursorColor": "#456789" + }, + { + "name" : "profile5" + } + ], + "schemes": [ + { + "name": "schemeWithCursorColor", + "cursorColor": "#123456" + }, + { + "name": "schemeWithoutCursorColor" + } + ] + })" }; + + CascadiaSettings settings{ til::u8u16(settings0String) }; + + VERIFY_ARE_EQUAL(6u, settings.Profiles().Size()); + VERIFY_ARE_EQUAL(2u, settings.GlobalSettings().ColorSchemes().Size()); + + auto createTerminalSettings = [&](const auto& profile, const auto& schemes) { + auto terminalSettings{ winrt::make_self() }; + terminalSettings->_ApplyProfileSettings(profile, schemes); + return terminalSettings; + }; + + auto terminalSettings0 = createTerminalSettings(settings.Profiles().GetAt(0), settings.GlobalSettings().ColorSchemes()); + auto terminalSettings1 = createTerminalSettings(settings.Profiles().GetAt(1), settings.GlobalSettings().ColorSchemes()); + auto terminalSettings2 = createTerminalSettings(settings.Profiles().GetAt(2), settings.GlobalSettings().ColorSchemes()); + auto terminalSettings3 = createTerminalSettings(settings.Profiles().GetAt(3), settings.GlobalSettings().ColorSchemes()); + auto terminalSettings4 = createTerminalSettings(settings.Profiles().GetAt(4), settings.GlobalSettings().ColorSchemes()); + auto terminalSettings5 = createTerminalSettings(settings.Profiles().GetAt(5), settings.GlobalSettings().ColorSchemes()); + + VERIFY_ARE_EQUAL(ARGB(0, 0x12, 0x34, 0x56), terminalSettings0->CursorColor()); // from color scheme + VERIFY_ARE_EQUAL(DEFAULT_CURSOR_COLOR, terminalSettings1->CursorColor()); // default + VERIFY_ARE_EQUAL(ARGB(0, 0x23, 0x45, 0x67), terminalSettings2->CursorColor()); // from profile (trumps color scheme) + VERIFY_ARE_EQUAL(ARGB(0, 0x34, 0x56, 0x78), terminalSettings3->CursorColor()); // from profile (not set in color scheme) + VERIFY_ARE_EQUAL(ARGB(0, 0x45, 0x67, 0x89), terminalSettings4->CursorColor()); // from profile (no color scheme) + VERIFY_ARE_EQUAL(DEFAULT_CURSOR_COLOR, terminalSettings5->CursorColor()); // default } + void SettingsTests::TestIterateCommands() { // For this test, put an iterable command with a given `name`, @@ -2670,17 +604,13 @@ namespace TerminalAppLocalTests const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}"); const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"); - VerifyParseSucceeded(settingsJson); + CascadiaSettings settings{ til::u8u16(settingsJson) }; - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsJson, false); - settings->LayerJson(settings->_userSettings); + VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(3u, settings.Profiles().Size()); - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); - - auto commands = settings->_globals->Commands(); + auto commands = settings.GlobalSettings().Commands(); VERIFY_ARE_EQUAL(1u, commands.Size()); { @@ -2692,7 +622,7 @@ namespace TerminalAppLocalTests 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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -2701,10 +631,10 @@ namespace TerminalAppLocalTests VERIFY_ARE_EQUAL(L"${profile.name}", realArgs.TerminalArgs().Profile()); } - auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands, settings->Profiles().GetView(), settings->_globals->ColorSchemes()); + auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(commands, settings.Profiles().GetView(), settings.GlobalSettings().ColorSchemes()); _logCommandNames(expandedCommands.GetView()); - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(3u, expandedCommands.Size()); { @@ -2716,7 +646,7 @@ namespace TerminalAppLocalTests 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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -2734,7 +664,7 @@ namespace TerminalAppLocalTests 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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -2752,7 +682,7 @@ namespace TerminalAppLocalTests 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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -2801,17 +731,13 @@ namespace TerminalAppLocalTests const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}"); const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"); - VerifyParseSucceeded(settingsJson); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsJson, false); - settings->LayerJson(settings->_userSettings); + CascadiaSettings settings{ til::u8u16(settingsJson) }; - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(3u, settings.Profiles().Size()); - auto commands = settings->_globals->Commands(); + auto commands = settings.GlobalSettings().Commands(); VERIFY_ARE_EQUAL(1u, commands.Size()); { @@ -2823,7 +749,7 @@ namespace TerminalAppLocalTests 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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -2832,10 +758,10 @@ namespace TerminalAppLocalTests VERIFY_ARE_EQUAL(L"${profile.name}", realArgs.TerminalArgs().Profile()); } - auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands, settings->Profiles().GetView(), settings->_globals->ColorSchemes()); + auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(commands, settings.Profiles().GetView(), settings.GlobalSettings().ColorSchemes()); _logCommandNames(expandedCommands.GetView()); - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(3u, expandedCommands.Size()); { @@ -2847,7 +773,7 @@ namespace TerminalAppLocalTests 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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -2865,7 +791,7 @@ namespace TerminalAppLocalTests 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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -2883,7 +809,7 @@ namespace TerminalAppLocalTests 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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -2934,17 +860,13 @@ namespace TerminalAppLocalTests const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}"); const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"); - VerifyParseSucceeded(settingsJson); + CascadiaSettings settings{ til::u8u16(settingsJson) }; - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsJson, false); - settings->LayerJson(settings->_userSettings); + VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(3u, settings.Profiles().Size()); - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); - - auto commands = settings->_globals->Commands(); + auto commands = settings.GlobalSettings().Commands(); VERIFY_ARE_EQUAL(1u, commands.Size()); { @@ -2956,7 +878,7 @@ namespace TerminalAppLocalTests 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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -2965,11 +887,10 @@ namespace TerminalAppLocalTests VERIFY_ARE_EQUAL(L"${profile.name}", realArgs.TerminalArgs().Profile()); } - settings->_ValidateSettings(); - auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands, settings->Profiles().GetView(), settings->_globals->ColorSchemes()); + auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(commands, settings.Profiles().GetView(), settings.GlobalSettings().ColorSchemes()); _logCommandNames(expandedCommands.GetView()); - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(3u, expandedCommands.Size()); { @@ -2981,7 +902,7 @@ namespace TerminalAppLocalTests 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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -2999,7 +920,7 @@ namespace TerminalAppLocalTests 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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -3017,7 +938,7 @@ namespace TerminalAppLocalTests 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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -3077,56 +998,42 @@ namespace TerminalAppLocalTests "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. })" }; - VerifyParseSucceeded(settingsJson); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsJson, false); - settings->LayerJson(settings->_userSettings); + CascadiaSettings settings{ til::u8u16(settingsJson) }; - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); + VERIFY_ARE_EQUAL(3u, settings.Profiles().Size()); - auto commands = settings->_globals->Commands(); - settings->_ValidateSettings(); - auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands, settings->Profiles().GetView(), settings->_globals->ColorSchemes()); + auto commands = settings.GlobalSettings().Commands(); + auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(commands, settings.Profiles().GetView(), settings.GlobalSettings().ColorSchemes()); _logCommandNames(expandedCommands.GetView()); - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(1u, expandedCommands.Size()); - auto rootCommandProj = expandedCommands.Lookup(L"Connect to ssh..."); - VERIFY_IS_NOT_NULL(rootCommandProj); - auto rootActionAndArgs = rootCommandProj.Action(); + auto rootCommand = expandedCommands.Lookup(L"Connect to ssh..."); + VERIFY_IS_NOT_NULL(rootCommand); + auto rootActionAndArgs = rootCommand.Action(); VERIFY_IS_NULL(rootActionAndArgs); - winrt::com_ptr rootCommandImpl; - rootCommandImpl.copy_from(winrt::get_self(rootCommandProj)); - - VERIFY_ARE_EQUAL(2u, rootCommandImpl->_subcommands.Size()); + VERIFY_ARE_EQUAL(2u, rootCommand.NestedCommands().Size()); { winrt::hstring commandName{ L"first.com" }; - auto commandProj = rootCommandImpl->_subcommands.Lookup(commandName); - VERIFY_IS_NOT_NULL(commandProj); - auto actionAndArgs = commandProj.Action(); + auto command = rootCommand.NestedCommands().Lookup(commandName); + VERIFY_IS_NOT_NULL(command); + auto actionAndArgs = command.Action(); VERIFY_IS_NOT_NULL(actionAndArgs); - winrt::com_ptr commandImpl; - commandImpl.copy_from(winrt::get_self(commandProj)); - - VERIFY_IS_FALSE(commandImpl->HasNestedCommands()); + VERIFY_IS_FALSE(command.HasNestedCommands()); } { winrt::hstring commandName{ L"second.com" }; - auto commandProj = rootCommandImpl->_subcommands.Lookup(commandName); - VERIFY_IS_NOT_NULL(commandProj); - auto actionAndArgs = commandProj.Action(); + auto command = rootCommand.NestedCommands().Lookup(commandName); + VERIFY_IS_NOT_NULL(command); + auto actionAndArgs = command.Action(); VERIFY_IS_NOT_NULL(actionAndArgs); - winrt::com_ptr commandImpl; - commandImpl.copy_from(winrt::get_self(commandProj)); - - VERIFY_IS_FALSE(commandImpl->HasNestedCommands()); + VERIFY_IS_FALSE(command.HasNestedCommands()); } } @@ -3186,48 +1093,37 @@ namespace TerminalAppLocalTests "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. })" }; - VerifyParseSucceeded(settingsJson); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsJson, false); - settings->LayerJson(settings->_userSettings); + CascadiaSettings settings{ til::u8u16(settingsJson) }; - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); + VERIFY_ARE_EQUAL(3u, settings.Profiles().Size()); - auto commands = settings->_globals->Commands(); - settings->_ValidateSettings(); - auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands, settings->Profiles().GetView(), settings->_globals->ColorSchemes()); + auto commands = settings.GlobalSettings().Commands(); + auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(commands, settings.Profiles().GetView(), settings.GlobalSettings().ColorSchemes()); _logCommandNames(expandedCommands.GetView()); - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(1u, expandedCommands.Size()); - auto grandparentCommandProj = expandedCommands.Lookup(L"grandparent"); - VERIFY_IS_NOT_NULL(grandparentCommandProj); - auto grandparentActionAndArgs = grandparentCommandProj.Action(); + auto grandparentCommand = expandedCommands.Lookup(L"grandparent"); + VERIFY_IS_NOT_NULL(grandparentCommand); + auto grandparentActionAndArgs = grandparentCommand.Action(); VERIFY_IS_NULL(grandparentActionAndArgs); - winrt::com_ptr grandparentCommandImpl; - grandparentCommandImpl.copy_from(winrt::get_self(grandparentCommandProj)); - - VERIFY_ARE_EQUAL(1u, grandparentCommandImpl->_subcommands.Size()); + VERIFY_ARE_EQUAL(1u, grandparentCommand.NestedCommands().Size()); winrt::hstring parentName{ L"parent" }; - auto parentProj = grandparentCommandImpl->_subcommands.Lookup(parentName); - VERIFY_IS_NOT_NULL(parentProj); - auto parentActionAndArgs = parentProj.Action(); + auto parent = grandparentCommand.NestedCommands().Lookup(parentName); + VERIFY_IS_NOT_NULL(parent); + auto parentActionAndArgs = parent.Action(); VERIFY_IS_NULL(parentActionAndArgs); - winrt::com_ptr parentImpl; - parentImpl.copy_from(winrt::get_self(parentProj)); - - VERIFY_ARE_EQUAL(2u, parentImpl->_subcommands.Size()); + VERIFY_ARE_EQUAL(2u, parent.NestedCommands().Size()); { winrt::hstring childName{ L"child1" }; - auto childProj = parentImpl->_subcommands.Lookup(childName); - VERIFY_IS_NOT_NULL(childProj); - auto childActionAndArgs = childProj.Action(); + auto child = parent.NestedCommands().Lookup(childName); + VERIFY_IS_NOT_NULL(child); + auto childActionAndArgs = child.Action(); VERIFY_IS_NOT_NULL(childActionAndArgs); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, childActionAndArgs.Action()); @@ -3241,16 +1137,13 @@ namespace TerminalAppLocalTests VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); VERIFY_ARE_EQUAL(L"ssh me@first.com", realArgs.TerminalArgs().Commandline()); - winrt::com_ptr childImpl; - childImpl.copy_from(winrt::get_self(childProj)); - - VERIFY_IS_FALSE(childImpl->HasNestedCommands()); + VERIFY_IS_FALSE(child.HasNestedCommands()); } { winrt::hstring childName{ L"child2" }; - auto childProj = parentImpl->_subcommands.Lookup(childName); - VERIFY_IS_NOT_NULL(childProj); - auto childActionAndArgs = childProj.Action(); + auto child = parent.NestedCommands().Lookup(childName); + VERIFY_IS_NOT_NULL(child); + auto childActionAndArgs = child.Action(); VERIFY_IS_NOT_NULL(childActionAndArgs); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, childActionAndArgs.Action()); @@ -3264,10 +1157,7 @@ namespace TerminalAppLocalTests VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); VERIFY_ARE_EQUAL(L"ssh me@second.com", realArgs.TerminalArgs().Commandline()); - winrt::com_ptr childImpl; - childImpl.copy_from(winrt::get_self(childProj)); - - VERIFY_IS_FALSE(childImpl->HasNestedCommands()); + VERIFY_IS_FALSE(child.HasNestedCommands()); } } @@ -3326,50 +1216,42 @@ namespace TerminalAppLocalTests "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. })" }; - VerifyParseSucceeded(settingsJson); + CascadiaSettings settings{ til::u8u16(settingsJson) }; - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsJson, false); - settings->LayerJson(settings->_userSettings); + VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); + VERIFY_ARE_EQUAL(3u, settings.Profiles().Size()); - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); - - auto commands = settings->_globals->Commands(); - settings->_ValidateSettings(); - auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands, settings->Profiles().GetView(), settings->_globals->ColorSchemes()); + auto commands = settings.GlobalSettings().Commands(); + auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(commands, settings.Profiles().GetView(), settings.GlobalSettings().ColorSchemes()); _logCommandNames(expandedCommands.GetView()); - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(3u, expandedCommands.Size()); for (auto name : std::vector({ L"profile0", L"profile1", L"profile2" })) { winrt::hstring commandName{ name + L"..." }; - auto commandProj = expandedCommands.Lookup(commandName); - VERIFY_IS_NOT_NULL(commandProj); - auto actionAndArgs = commandProj.Action(); + auto command = expandedCommands.Lookup(commandName); + VERIFY_IS_NOT_NULL(command); + auto actionAndArgs = command.Action(); VERIFY_IS_NULL(actionAndArgs); - winrt::com_ptr commandImpl; - commandImpl.copy_from(winrt::get_self(commandProj)); - - VERIFY_IS_TRUE(commandImpl->HasNestedCommands()); - VERIFY_ARE_EQUAL(3u, commandImpl->_subcommands.Size()); - _logCommandNames(commandImpl->_subcommands.GetView()); + VERIFY_IS_TRUE(command.HasNestedCommands()); + VERIFY_ARE_EQUAL(3u, command.NestedCommands().Size()); + _logCommandNames(command.NestedCommands()); { winrt::hstring childCommandName{ fmt::format(L"Split pane, profile: {}", name) }; - auto childCommandProj = commandImpl->_subcommands.Lookup(childCommandName); - VERIFY_IS_NOT_NULL(childCommandProj); - auto childActionAndArgs = childCommandProj.Action(); + auto childCommand = command.NestedCommands().Lookup(childCommandName); + VERIFY_IS_NOT_NULL(childCommand); + auto childActionAndArgs = childCommand.Action(); VERIFY_IS_NOT_NULL(childActionAndArgs); VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, childActionAndArgs.Action()); const auto& realArgs = childActionAndArgs.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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -3377,23 +1259,20 @@ namespace TerminalAppLocalTests VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); VERIFY_ARE_EQUAL(name, realArgs.TerminalArgs().Profile()); - winrt::com_ptr childCommandImpl; - childCommandImpl.copy_from(winrt::get_self(childCommandProj)); - - VERIFY_IS_FALSE(childCommandImpl->HasNestedCommands()); + VERIFY_IS_FALSE(childCommand.HasNestedCommands()); } { winrt::hstring childCommandName{ fmt::format(L"Split pane, split: horizontal, profile: {}", name) }; - auto childCommandProj = commandImpl->_subcommands.Lookup(childCommandName); - VERIFY_IS_NOT_NULL(childCommandProj); - auto childActionAndArgs = childCommandProj.Action(); + auto childCommand = command.NestedCommands().Lookup(childCommandName); + VERIFY_IS_NOT_NULL(childCommand); + auto childActionAndArgs = childCommand.Action(); VERIFY_IS_NOT_NULL(childActionAndArgs); VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, childActionAndArgs.Action()); const auto& realArgs = childActionAndArgs.Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); // Verify the args have the expected value - VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Horizontal, realArgs.SplitStyle()); + VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -3401,23 +1280,20 @@ namespace TerminalAppLocalTests VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); VERIFY_ARE_EQUAL(name, realArgs.TerminalArgs().Profile()); - winrt::com_ptr childCommandImpl; - childCommandImpl.copy_from(winrt::get_self(childCommandProj)); - - VERIFY_IS_FALSE(childCommandImpl->HasNestedCommands()); + VERIFY_IS_FALSE(childCommand.HasNestedCommands()); } { winrt::hstring childCommandName{ fmt::format(L"Split pane, split: vertical, profile: {}", name) }; - auto childCommandProj = commandImpl->_subcommands.Lookup(childCommandName); - VERIFY_IS_NOT_NULL(childCommandProj); - auto childActionAndArgs = childCommandProj.Action(); + auto childCommand = command.NestedCommands().Lookup(childCommandName); + VERIFY_IS_NOT_NULL(childCommand); + auto childActionAndArgs = childCommand.Action(); VERIFY_IS_NOT_NULL(childActionAndArgs); VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, childActionAndArgs.Action()); const auto& realArgs = childActionAndArgs.Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); // Verify the args have the expected value - VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Vertical, realArgs.SplitStyle()); + VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -3425,10 +1301,7 @@ namespace TerminalAppLocalTests VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); VERIFY_ARE_EQUAL(name, realArgs.TerminalArgs().Profile()); - winrt::com_ptr childCommandImpl; - childCommandImpl.copy_from(winrt::get_self(childCommandProj)); - - VERIFY_IS_FALSE(childCommandImpl->HasNestedCommands()); + VERIFY_IS_FALSE(childCommand.HasNestedCommands()); } } } @@ -3480,39 +1353,31 @@ namespace TerminalAppLocalTests "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. })" }; - VerifyParseSucceeded(settingsJson); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsJson, false); - settings->LayerJson(settings->_userSettings); + CascadiaSettings settings{ til::u8u16(settingsJson) }; - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); + VERIFY_ARE_EQUAL(3u, settings.Profiles().Size()); - auto commands = settings->_globals->Commands(); - settings->_ValidateSettings(); - auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands, settings->Profiles().GetView(), settings->_globals->ColorSchemes()); + auto commands = settings.GlobalSettings().Commands(); + auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(commands, settings.Profiles().GetView(), settings.GlobalSettings().ColorSchemes()); _logCommandNames(expandedCommands.GetView()); - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(1u, expandedCommands.Size()); - auto rootCommandProj = expandedCommands.Lookup(L"New Tab With Profile..."); - VERIFY_IS_NOT_NULL(rootCommandProj); - auto rootActionAndArgs = rootCommandProj.Action(); + auto rootCommand = expandedCommands.Lookup(L"New Tab With Profile..."); + VERIFY_IS_NOT_NULL(rootCommand); + auto rootActionAndArgs = rootCommand.Action(); VERIFY_IS_NULL(rootActionAndArgs); - winrt::com_ptr rootCommandImpl; - rootCommandImpl.copy_from(winrt::get_self(rootCommandProj)); - - VERIFY_ARE_EQUAL(3u, rootCommandImpl->_subcommands.Size()); + VERIFY_ARE_EQUAL(3u, rootCommand.NestedCommands().Size()); for (auto name : std::vector({ L"profile0", L"profile1", L"profile2" })) { winrt::hstring commandName{ fmt::format(L"New tab, profile: {}", name) }; - auto commandProj = rootCommandImpl->_subcommands.Lookup(commandName); - VERIFY_IS_NOT_NULL(commandProj); - auto actionAndArgs = commandProj.Action(); + auto command = rootCommand.NestedCommands().Lookup(commandName); + VERIFY_IS_NOT_NULL(command); + auto actionAndArgs = command.Action(); VERIFY_IS_NOT_NULL(actionAndArgs); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); @@ -3526,10 +1391,7 @@ namespace TerminalAppLocalTests VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); VERIFY_ARE_EQUAL(name, realArgs.TerminalArgs().Profile()); - winrt::com_ptr commandImpl; - commandImpl.copy_from(winrt::get_self(commandProj)); - - VERIFY_IS_FALSE(commandImpl->HasNestedCommands()); + VERIFY_IS_FALSE(command.HasNestedCommands()); } } void SettingsTests::TestMixedNestedAndIterableCommand() @@ -3594,60 +1456,49 @@ namespace TerminalAppLocalTests "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. })" }; - VerifyParseSucceeded(settingsJson); + CascadiaSettings settings{ til::u8u16(settingsJson) }; - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsJson, false); - settings->LayerJson(settings->_userSettings); + VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); + VERIFY_ARE_EQUAL(3u, settings.Profiles().Size()); - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); - - auto commands = settings->_globals->Commands(); - settings->_ValidateSettings(); - auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands, settings->Profiles().GetView(), settings->_globals->ColorSchemes()); + auto commands = settings.GlobalSettings().Commands(); + auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(commands, settings.Profiles().GetView(), settings.GlobalSettings().ColorSchemes()); _logCommandNames(expandedCommands.GetView()); - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(1u, expandedCommands.Size()); - auto rootCommandProj = expandedCommands.Lookup(L"New Pane..."); - VERIFY_IS_NOT_NULL(rootCommandProj); - auto rootActionAndArgs = rootCommandProj.Action(); + auto rootCommand = expandedCommands.Lookup(L"New Pane..."); + VERIFY_IS_NOT_NULL(rootCommand); + auto rootActionAndArgs = rootCommand.Action(); VERIFY_IS_NULL(rootActionAndArgs); - winrt::com_ptr rootCommandImpl; - rootCommandImpl.copy_from(winrt::get_self(rootCommandProj)); - - VERIFY_ARE_EQUAL(3u, rootCommandImpl->_subcommands.Size()); + VERIFY_ARE_EQUAL(3u, rootCommand.NestedCommands().Size()); for (auto name : std::vector({ L"profile0", L"profile1", L"profile2" })) { winrt::hstring commandName{ name + L"..." }; - auto commandProj = rootCommandImpl->_subcommands.Lookup(commandName); - VERIFY_IS_NOT_NULL(commandProj); - auto actionAndArgs = commandProj.Action(); + auto command = rootCommand.NestedCommands().Lookup(commandName); + VERIFY_IS_NOT_NULL(command); + auto actionAndArgs = command.Action(); VERIFY_IS_NULL(actionAndArgs); - winrt::com_ptr commandImpl; - commandImpl.copy_from(winrt::get_self(commandProj)); + VERIFY_IS_TRUE(command.HasNestedCommands()); + VERIFY_ARE_EQUAL(3u, command.NestedCommands().Size()); - VERIFY_IS_TRUE(commandImpl->HasNestedCommands()); - VERIFY_ARE_EQUAL(3u, commandImpl->_subcommands.Size()); - - _logCommandNames(commandImpl->_subcommands.GetView()); + _logCommandNames(command.NestedCommands()); { winrt::hstring childCommandName{ fmt::format(L"Split pane, profile: {}", name) }; - auto childCommandProj = commandImpl->_subcommands.Lookup(childCommandName); - VERIFY_IS_NOT_NULL(childCommandProj); - auto childActionAndArgs = childCommandProj.Action(); + auto childCommand = command.NestedCommands().Lookup(childCommandName); + VERIFY_IS_NOT_NULL(childCommand); + auto childActionAndArgs = childCommand.Action(); VERIFY_IS_NOT_NULL(childActionAndArgs); VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, childActionAndArgs.Action()); const auto& realArgs = childActionAndArgs.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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -3655,23 +1506,20 @@ namespace TerminalAppLocalTests VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); VERIFY_ARE_EQUAL(name, realArgs.TerminalArgs().Profile()); - winrt::com_ptr childCommandImpl; - childCommandImpl.copy_from(winrt::get_self(childCommandProj)); - - VERIFY_IS_FALSE(childCommandImpl->HasNestedCommands()); + VERIFY_IS_FALSE(childCommand.HasNestedCommands()); } { winrt::hstring childCommandName{ fmt::format(L"Split pane, split: horizontal, profile: {}", name) }; - auto childCommandProj = commandImpl->_subcommands.Lookup(childCommandName); - VERIFY_IS_NOT_NULL(childCommandProj); - auto childActionAndArgs = childCommandProj.Action(); + auto childCommand = command.NestedCommands().Lookup(childCommandName); + VERIFY_IS_NOT_NULL(childCommand); + auto childActionAndArgs = childCommand.Action(); VERIFY_IS_NOT_NULL(childActionAndArgs); VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, childActionAndArgs.Action()); const auto& realArgs = childActionAndArgs.Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); // Verify the args have the expected value - VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Horizontal, realArgs.SplitStyle()); + VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -3679,23 +1527,20 @@ namespace TerminalAppLocalTests VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); VERIFY_ARE_EQUAL(name, realArgs.TerminalArgs().Profile()); - winrt::com_ptr childCommandImpl; - childCommandImpl.copy_from(winrt::get_self(childCommandProj)); - - VERIFY_IS_FALSE(childCommandImpl->HasNestedCommands()); + VERIFY_IS_FALSE(childCommand.HasNestedCommands()); } { winrt::hstring childCommandName{ fmt::format(L"Split pane, split: vertical, profile: {}", name) }; - auto childCommandProj = commandImpl->_subcommands.Lookup(childCommandName); - VERIFY_IS_NOT_NULL(childCommandProj); - auto childActionAndArgs = childCommandProj.Action(); + auto childCommand = command.NestedCommands().Lookup(childCommandName); + VERIFY_IS_NOT_NULL(childCommand); + auto childActionAndArgs = childCommand.Action(); VERIFY_IS_NOT_NULL(childActionAndArgs); VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, childActionAndArgs.Action()); const auto& realArgs = childActionAndArgs.Args().try_as(); VERIFY_IS_NOT_NULL(realArgs); // Verify the args have the expected value - VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Vertical, realArgs.SplitStyle()); + VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -3703,273 +1548,11 @@ namespace TerminalAppLocalTests VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); VERIFY_ARE_EQUAL(name, realArgs.TerminalArgs().Profile()); - winrt::com_ptr childCommandImpl; - childCommandImpl.copy_from(winrt::get_self(childCommandProj)); - - VERIFY_IS_FALSE(childCommandImpl->HasNestedCommands()); + VERIFY_IS_FALSE(childCommand.HasNestedCommands()); } } } - void SettingsTests::TestNestedCommandWithoutName() - { - // This test tests a nested command without a name specified. This type - // of command should just be ignored, since we can't auto-generate names - // for nested commands, they _must_ have names specified. - - 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" - } - ], - "actions": [ - { - "commands": [ - { - "name": "child1", - "command": { "action": "newTab", "commandline": "ssh me@first.com" } - }, - { - "name": "child2", - "command": { "action": "newTab", "commandline": "ssh me@second.com" } - } - ] - }, - ], - "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. - })" }; - - VerifyParseSucceeded(settingsJson); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsJson, false); - settings->LayerJson(settings->_userSettings); - - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); - - auto commands = settings->_globals->Commands(); - settings->_ValidateSettings(); - _logCommandNames(commands); - - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); - - // Because the "parent" command didn't have a name, it couldn't be - // placed into the list of commands. It and it's children are just - // ignored. - VERIFY_ARE_EQUAL(0u, commands.Size()); - } - - void SettingsTests::TestUnbindNestedCommand() - { - // Test that layering a command with `"commands": null` set will unbind a command that already exists. - - 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" - } - ], - "actions": [ - { - "name": "parent", - "commands": [ - { - "name": "child1", - "command": { "action": "newTab", "commandline": "ssh me@first.com" } - }, - { - "name": "child2", - "command": { "action": "newTab", "commandline": "ssh me@second.com" } - } - ] - }, - ], - "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. - })" }; - - const std::string settings1Json{ R"( - { - "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", - "actions": [ - { - "name": "parent", - "commands": null - }, - ], - })" }; - - VerifyParseSucceeded(settingsJson); - VerifyParseSucceeded(settings1Json); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsJson, false); - settings->LayerJson(settings->_userSettings); - - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); - - auto commands = settings->_globals->Commands(); - settings->_ValidateSettings(); - _logCommandNames(commands); - - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(1u, commands.Size()); - - Log::Comment(L"Layer second bit of json, to unbind the original command."); - - settings->_ParseJsonString(settings1Json, false); - settings->LayerJson(settings->_userSettings); - settings->_ValidateSettings(); - _logCommandNames(commands); - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(0u, commands.Size()); - } - - void SettingsTests::TestRebindNestedCommand() - { - // Test that layering a command with an action set on top of a command - // with nested commands replaces the nested commands with an action. - - 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" - } - ], - "actions": [ - { - "name": "parent", - "commands": [ - { - "name": "child1", - "command": { "action": "newTab", "commandline": "ssh me@first.com" } - }, - { - "name": "child2", - "command": { "action": "newTab", "commandline": "ssh me@second.com" } - } - ] - }, - ], - "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. - })" }; - - const std::string settings1Json{ R"( - { - "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", - "actions": [ - { - "name": "parent", - "command": "newTab" - }, - ], - })" }; - - VerifyParseSucceeded(settingsJson); - VerifyParseSucceeded(settings1Json); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsJson, false); - settings->LayerJson(settings->_userSettings); - - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); - - auto commands = settings->_globals->Commands(); - settings->_ValidateSettings(); - _logCommandNames(commands); - - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(1u, commands.Size()); - - { - winrt::hstring commandName{ L"parent" }; - auto commandProj = commands.Lookup(commandName); - VERIFY_IS_NOT_NULL(commandProj); - - winrt::com_ptr commandImpl; - commandImpl.copy_from(winrt::get_self(commandProj)); - - VERIFY_IS_TRUE(commandImpl->HasNestedCommands()); - VERIFY_ARE_EQUAL(2u, commandImpl->_subcommands.Size()); - } - - Log::Comment(L"Layer second bit of json, to unbind the original command."); - settings->_ParseJsonString(settings1Json, false); - settings->LayerJson(settings->_userSettings); - settings->_ValidateSettings(); - _logCommandNames(commands); - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); - VERIFY_ARE_EQUAL(1u, commands.Size()); - - { - winrt::hstring commandName{ L"parent" }; - auto commandProj = commands.Lookup(commandName); - - VERIFY_IS_NOT_NULL(commandProj); - auto actionAndArgs = commandProj.Action(); - VERIFY_IS_NOT_NULL(actionAndArgs); - VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); - const auto& realArgs = actionAndArgs.Args().try_as(); - VERIFY_IS_NOT_NULL(realArgs); - - winrt::com_ptr commandImpl; - commandImpl.copy_from(winrt::get_self(commandProj)); - - VERIFY_IS_FALSE(commandImpl->HasNestedCommands()); - } - } - void SettingsTests::TestIterableColorSchemeCommands() { // For this test, put an iterable command with a given `name`, @@ -4012,17 +1595,15 @@ namespace TerminalAppLocalTests ] })" }; - VerifyParseSucceeded(settingsJson); - - auto settings = winrt::make_self(); - settings->_ParseJsonString(settingsJson, false); - settings->LayerJson(settings->_userSettings); + CascadiaSettings settings{ til::u8u16(settingsJson) }; - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + // Since at least one profile does not reference a color scheme, + // we add a warning saying "the color scheme is unknown" + VERIFY_ARE_EQUAL(1u, settings.Warnings().Size()); - VERIFY_ARE_EQUAL(3u, settings->_profiles.Size()); + VERIFY_ARE_EQUAL(3u, settings.Profiles().Size()); - auto commands = settings->_globals->Commands(); + auto commands = settings.GlobalSettings().Commands(); VERIFY_ARE_EQUAL(1u, commands.Size()); { @@ -4034,7 +1615,7 @@ namespace TerminalAppLocalTests 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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -4043,10 +1624,11 @@ namespace TerminalAppLocalTests VERIFY_ARE_EQUAL(L"${scheme.name}", realArgs.TerminalArgs().Profile()); } - auto expandedCommands = implementation::TerminalPage::_ExpandCommands(commands, settings->Profiles().GetView(), settings->_globals->ColorSchemes()); + auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(commands, settings.Profiles().GetView(), settings.GlobalSettings().ColorSchemes()); _logCommandNames(expandedCommands.GetView()); - VERIFY_ARE_EQUAL(0u, settings->_warnings.Size()); + // This is the same warning as above + VERIFY_ARE_EQUAL(1u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(3u, expandedCommands.Size()); // Yes, this test is testing splitPane with profiles named after each @@ -4062,7 +1644,7 @@ namespace TerminalAppLocalTests 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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -4080,7 +1662,7 @@ namespace TerminalAppLocalTests 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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); @@ -4098,7 +1680,7 @@ namespace TerminalAppLocalTests 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_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle()); VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); diff --git a/src/cascadia/LocalTests_TerminalApp/TabTests.cpp b/src/cascadia/LocalTests_TerminalApp/TabTests.cpp index 4b98b1a9552..e623c9cf055 100644 --- a/src/cascadia/LocalTests_TerminalApp/TabTests.cpp +++ b/src/cascadia/LocalTests_TerminalApp/TabTests.cpp @@ -9,11 +9,11 @@ #include "../TerminalApp/ShortcutActionDispatch.h" #include "../TerminalApp/Tab.h" #include "../CppWinrtTailored.h" -#include "JsonTestClass.h" using namespace Microsoft::Console; using namespace TerminalApp; using namespace winrt::TerminalApp; +using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace WEX::Logging; using namespace WEX::TestExecution; using namespace WEX::Common; @@ -26,7 +26,7 @@ namespace TerminalAppLocalTests // an updated TAEF that will let us install framework packages when the test // package is deployed. Until then, these tests won't deploy in CI. - class TabTests : public JsonTestClass + class TabTests { // For this set of tests, we need to activate some XAML content. For // release builds, the application runs as a centennial application, @@ -64,7 +64,6 @@ namespace TerminalAppLocalTests TEST_CLASS_SETUP(ClassSetup) { - InitializeJsonReader(); return true; } @@ -75,7 +74,7 @@ namespace TerminalAppLocalTests private: void _initializeTerminalPage(winrt::com_ptr& page, - winrt::com_ptr& initialSettings); + CascadiaSettings initialSettings); }; void TabTests::EnsureTestsActivate() @@ -190,7 +189,7 @@ namespace TerminalAppLocalTests // Return Value: // - void TabTests::_initializeTerminalPage(winrt::com_ptr& page, - winrt::com_ptr& initialSettings) + CascadiaSettings initialSettings) { // This is super wacky, but we can't just initialize the // com_ptr in the lambda and assign it back out of @@ -206,7 +205,7 @@ namespace TerminalAppLocalTests auto result = RunOnUIThread([&projectedPage, &page, initialSettings]() { projectedPage = winrt::TerminalApp::TerminalPage(); page.copy_from(winrt::get_self(projectedPage)); - page->_settings = *initialSettings; + page->_settings = initialSettings; }); VERIFY_SUCCEEDED(result); @@ -276,12 +275,8 @@ namespace TerminalAppLocalTests ] })" }; - VerifyParseSucceeded(settingsJson0); - auto settings0 = winrt::make_self(false); + CascadiaSettings settings0{ til::u8u16(settingsJson0) }; VERIFY_IS_NOT_NULL(settings0); - settings0->_ParseJsonString(settingsJson0, false); - settings0->LayerJson(settings0->_userSettings); - settings0->_ValidateSettings(); // This is super wacky, but we can't just initialize the // com_ptr in the lambda and assign it back out of @@ -338,19 +333,11 @@ namespace TerminalAppLocalTests ] })" }; - VerifyParseSucceeded(settingsJson0); - auto settings0 = winrt::make_self(false); + CascadiaSettings settings0{ til::u8u16(settingsJson0) }; VERIFY_IS_NOT_NULL(settings0); - settings0->_ParseJsonString(settingsJson0, false); - settings0->LayerJson(settings0->_userSettings); - settings0->_ValidateSettings(); - VerifyParseSucceeded(settingsJson1); - auto settings1 = winrt::make_self(false); + CascadiaSettings settings1{ til::u8u16(settingsJson1) }; VERIFY_IS_NOT_NULL(settings1); - settings1->_ParseJsonString(settingsJson1, false); - settings1->LayerJson(settings1->_userSettings); - settings1->_ValidateSettings(); const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"); const auto guid2 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}"); @@ -383,7 +370,7 @@ namespace TerminalAppLocalTests L"Change the settings of the TerminalPage so the first profile is " L"no longer in the list of profiles")); result = RunOnUIThread([&page, settings1]() { - page->_settings = *settings1; + page->_settings = settings1; }); VERIFY_SUCCEEDED(result); @@ -433,19 +420,11 @@ namespace TerminalAppLocalTests ] })" }; - VerifyParseSucceeded(settingsJson0); - auto settings0 = winrt::make_self(false); + CascadiaSettings settings0{ til::u8u16(settingsJson0) }; VERIFY_IS_NOT_NULL(settings0); - settings0->_ParseJsonString(settingsJson0, false); - settings0->LayerJson(settings0->_userSettings); - settings0->_ValidateSettings(); - VerifyParseSucceeded(settingsJson1); - auto settings1 = winrt::make_self(false); + CascadiaSettings settings1{ til::u8u16(settingsJson1) }; VERIFY_IS_NOT_NULL(settings1); - settings1->_ParseJsonString(settingsJson1, false); - settings1->LayerJson(settings1->_userSettings); - settings1->_ValidateSettings(); const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"); const auto guid2 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}"); @@ -488,7 +467,7 @@ namespace TerminalAppLocalTests L"Change the settings of the TerminalPage so the first profile is " L"no longer in the list of profiles")); result = RunOnUIThread([&page, settings1]() { - page->_settings = *settings1; + page->_settings = settings1; }); VERIFY_SUCCEEDED(result); diff --git a/src/cascadia/LocalTests_TerminalApp/TerminalApp.LocalTests.vcxproj b/src/cascadia/LocalTests_TerminalApp/TerminalApp.LocalTests.vcxproj index 67952867d7d..e0fc2b56ff4 100644 --- a/src/cascadia/LocalTests_TerminalApp/TerminalApp.LocalTests.vcxproj +++ b/src/cascadia/LocalTests_TerminalApp/TerminalApp.LocalTests.vcxproj @@ -49,7 +49,6 @@ - @@ -57,19 +56,10 @@ - - - - Create - - - NotUsing - @@ -81,7 +71,8 @@ _ConsoleGenerateAdditionalWinmdManifests step won't gather the winmd's --> - + + diff --git a/src/cascadia/LocalTests_TerminalApp/TestHostApp/TestHostApp.vcxproj b/src/cascadia/LocalTests_TerminalApp/TestHostApp/TestHostApp.vcxproj index b6d85e9ae04..289afc5dccc 100644 --- a/src/cascadia/LocalTests_TerminalApp/TestHostApp/TestHostApp.vcxproj +++ b/src/cascadia/LocalTests_TerminalApp/TestHostApp/TestHostApp.vcxproj @@ -100,6 +100,10 @@ {ca5cad1a-44bd-4ac7-ac72-f16e576fdd12} + + {CA5CAD1A-082C-4476-9F33-94B339494076} + + @@ -153,6 +157,10 @@ + + + #include +#include #include diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index 6d2e765c3a1..64e2a63985c 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -14,6 +14,7 @@ using namespace winrt::Windows::UI::Core; using namespace winrt::Windows::Foundation::Collections; using namespace winrt::Windows::System; using namespace winrt::Microsoft::Terminal; +using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::TerminalControl; using namespace winrt::Microsoft::Terminal::TerminalConnection; using namespace ::TerminalApp; @@ -27,76 +28,76 @@ namespace winrt namespace winrt::TerminalApp::implementation { void TerminalPage::_HandleOpenNewTabDropdown(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { _OpenNewTabDropdown(); args.Handled(true); } void TerminalPage::_HandleDuplicateTab(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { _DuplicateTabViewItem(); args.Handled(true); } void TerminalPage::_HandleCloseTab(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { _CloseFocusedTab(); args.Handled(true); } void TerminalPage::_HandleClosePane(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { _CloseFocusedPane(); args.Handled(true); } void TerminalPage::_HandleCloseWindow(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { CloseWindow(); args.Handled(true); } void TerminalPage::_HandleScrollUp(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { _Scroll(-1); args.Handled(true); } void TerminalPage::_HandleScrollDown(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { _Scroll(1); args.Handled(true); } void TerminalPage::_HandleNextTab(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { _SelectNextTab(true); args.Handled(true); } void TerminalPage::_HandlePrevTab(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { _SelectNextTab(false); args.Handled(true); } void TerminalPage::_HandleSendInput(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { if (args == nullptr) { args.Handled(false); } - else if (const auto& realArgs = args.ActionArgs().try_as()) + else if (const auto& realArgs = args.ActionArgs().try_as()) { const auto termControl = _GetActiveControl(); termControl.SendInput(realArgs.Input()); @@ -105,13 +106,13 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleSplitPane(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { if (args == nullptr) { args.Handled(false); } - else if (const auto& realArgs = args.ActionArgs().try_as()) + else if (const auto& realArgs = args.ActionArgs().try_as()) { _SplitPane(realArgs.SplitStyle(), realArgs.SplitMode(), realArgs.TerminalArgs()); args.Handled(true); @@ -119,7 +120,7 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleTogglePaneZoom(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { auto activeTab = _GetFocusedTab(); @@ -141,23 +142,23 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleScrollUpPage(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { _ScrollPage(-1); args.Handled(true); } void TerminalPage::_HandleScrollDownPage(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { _ScrollPage(1); args.Handled(true); } void TerminalPage::_HandleOpenSettings(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { - if (const auto& realArgs = args.ActionArgs().try_as()) + if (const auto& realArgs = args.ActionArgs().try_as()) { _LaunchSettings(realArgs.Target()); args.Handled(true); @@ -165,21 +166,21 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandlePasteText(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { _PasteText(); args.Handled(true); } void TerminalPage::_HandleNewTab(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { if (args == nullptr) { _OpenNewTab(nullptr); args.Handled(true); } - else if (const auto& realArgs = args.ActionArgs().try_as()) + else if (const auto& realArgs = args.ActionArgs().try_as()) { _OpenNewTab(realArgs.TerminalArgs()); args.Handled(true); @@ -187,9 +188,9 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleSwitchToTab(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { - if (const auto& realArgs = args.ActionArgs().try_as()) + if (const auto& realArgs = args.ActionArgs().try_as()) { const auto handled = _SelectTab({ realArgs.TabIndex() }); args.Handled(handled); @@ -197,11 +198,11 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleResizePane(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { - if (const auto& realArgs = args.ActionArgs().try_as()) + if (const auto& realArgs = args.ActionArgs().try_as()) { - if (realArgs.Direction() == TerminalApp::Direction::None) + if (realArgs.Direction() == Direction::None) { // Do nothing args.Handled(false); @@ -215,11 +216,11 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleMoveFocus(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { - if (const auto& realArgs = args.ActionArgs().try_as()) + if (const auto& realArgs = args.ActionArgs().try_as()) { - if (realArgs.Direction() == TerminalApp::Direction::None) + if (realArgs.Direction() == Direction::None) { // Do nothing args.Handled(false); @@ -233,9 +234,9 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleCopyText(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { - if (const auto& realArgs = args.ActionArgs().try_as()) + if (const auto& realArgs = args.ActionArgs().try_as()) { const auto handled = _CopyText(realArgs.SingleLine(), realArgs.CopyFormatting()); args.Handled(handled); @@ -243,9 +244,9 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleAdjustFontSize(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { - if (const auto& realArgs = args.ActionArgs().try_as()) + if (const auto& realArgs = args.ActionArgs().try_as()) { const auto termControl = _GetActiveControl(); termControl.AdjustFontSize(realArgs.Delta()); @@ -254,14 +255,14 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleFind(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { _Find(); args.Handled(true); } void TerminalPage::_HandleResetFontSize(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { const auto termControl = _GetActiveControl(); termControl.ResetFontSize(); @@ -269,7 +270,7 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleToggleRetroEffect(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { const auto termControl = _GetActiveControl(); termControl.ToggleRetroEffect(); @@ -277,28 +278,28 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleToggleFocusMode(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { ToggleFocusMode(); args.Handled(true); } void TerminalPage::_HandleToggleFullscreen(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { ToggleFullscreen(); args.Handled(true); } void TerminalPage::_HandleToggleAlwaysOnTop(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { ToggleAlwaysOnTop(); args.Handled(true); } void TerminalPage::_HandleToggleCommandPalette(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { // TODO GH#6677: When we add support for commandline mode, first set the // mode that the command palette should be in, before making it visible. @@ -310,10 +311,10 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleSetColorScheme(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { args.Handled(false); - if (const auto& realArgs = args.ActionArgs().try_as()) + if (const auto& realArgs = args.ActionArgs().try_as()) { if (auto activeTab = _GetFocusedTab()) { @@ -332,11 +333,11 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleSetTabColor(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { std::optional tabColor; - if (const auto& realArgs = args.ActionArgs().try_as()) + if (const auto& realArgs = args.ActionArgs().try_as()) { if (realArgs.TabColor() != nullptr) { @@ -360,7 +361,7 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleOpenTabColorPicker(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { auto activeTab = _GetFocusedTab(); if (activeTab) @@ -371,11 +372,11 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleRenameTab(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { std::optional title; - if (const auto& realArgs = args.ActionArgs().try_as()) + if (const auto& realArgs = args.ActionArgs().try_as()) { title = realArgs.Title(); } @@ -396,11 +397,11 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleExecuteCommandline(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& actionArgs) + const ActionEventArgs& actionArgs) { - if (const auto& realArgs = actionArgs.ActionArgs().try_as()) + if (const auto& realArgs = actionArgs.ActionArgs().try_as()) { - auto actions = winrt::single_threaded_vector(std::move( + auto actions = winrt::single_threaded_vector(std::move( TerminalPage::ConvertExecuteCommandlineToActions(realArgs))); if (_startupActions.Size() != 0) @@ -412,9 +413,9 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleCloseOtherTabs(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& actionArgs) + const ActionEventArgs& actionArgs) { - if (const auto& realArgs = actionArgs.ActionArgs().try_as()) + if (const auto& realArgs = actionArgs.ActionArgs().try_as()) { uint32_t index; if (realArgs.Index()) @@ -449,9 +450,9 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleCloseTabsAfter(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& actionArgs) + const ActionEventArgs& actionArgs) { - if (const auto& realArgs = actionArgs.ActionArgs().try_as()) + if (const auto& realArgs = actionArgs.ActionArgs().try_as()) { uint32_t index; if (realArgs.Index()) @@ -486,7 +487,7 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleOpenTabSearch(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + const ActionEventArgs& args) { auto opt = _GetFocusedTabIndex(); uint32_t startIdx = opt.value_or(0); diff --git a/src/cascadia/TerminalApp/AppCommandlineArgs.cpp b/src/cascadia/TerminalApp/AppCommandlineArgs.cpp index 70e6df6940b..5e077a99eeb 100644 --- a/src/cascadia/TerminalApp/AppCommandlineArgs.cpp +++ b/src/cascadia/TerminalApp/AppCommandlineArgs.cpp @@ -4,10 +4,10 @@ #include "pch.h" #include "AppLogic.h" #include "AppCommandlineArgs.h" -#include "ActionArgs.h" #include using namespace winrt::TerminalApp; +using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace TerminalApp; // Either a ; at the start of a line, or a ; preceded by any non-\ char. @@ -159,18 +159,15 @@ void AppCommandlineArgs::_buildParser() { // -v,--version: Displays version info auto versionCallback = [this](int64_t /*count*/) { - if (const auto appLogic{ winrt::TerminalApp::implementation::AppLogic::Current() }) - { - // Set our message to display the application name and the current version. - _exitMessage = fmt::format("{0}\n{1}", - til::u16u8(appLogic->ApplicationDisplayName()), - til::u16u8(appLogic->ApplicationVersion())); - // Theoretically, we don't need to exit now, since this isn't really - // an error case. However, in practice, it feels weird to have `wt - // -v` open a new tab, and makes enough sense that `wt -v ; - // split-pane` (or whatever) just displays the version and exits. - _shouldExitEarly = true; - } + // Set our message to display the application name and the current version. + _exitMessage = fmt::format("{0}\n{1}", + til::u16u8(CascadiaSettings::ApplicationDisplayName()), + til::u16u8(CascadiaSettings::ApplicationVersion())); + // Theoretically, we don't need to exit now, since this isn't really + // an error case. However, in practice, it feels weird to have `wt + // -v` open a new tab, and makes enough sense that `wt -v ; + // split-pane` (or whatever) just displays the version and exits. + _shouldExitEarly = true; }; _app.add_flag_function("-v,--version", versionCallback, RS_A(L"CmdVersionDesc")); @@ -178,10 +175,10 @@ void AppCommandlineArgs::_buildParser() // -M,--maximized: Maximizes the window on launch // -F,--fullscreen: Fullscreens the window on launch auto maximizedCallback = [this](int64_t /*count*/) { - _launchMode = winrt::TerminalApp::LaunchMode::MaximizedMode; + _launchMode = winrt::Microsoft::Terminal::Settings::Model::LaunchMode::MaximizedMode; }; auto fullscreenCallback = [this](int64_t /*count*/) { - _launchMode = winrt::TerminalApp::LaunchMode::FullscreenMode; + _launchMode = winrt::Microsoft::Terminal::Settings::Model::LaunchMode::FullscreenMode; }; auto maximized = _app.add_flag_function("-M,--maximized", maximizedCallback, RS_A(L"CmdMaximizedDesc")); auto fullscreen = _app.add_flag_function("-F,--fullscreen", fullscreenCallback, RS_A(L"CmdFullscreenDesc")); @@ -214,14 +211,13 @@ void AppCommandlineArgs::_buildNewTabParser() // command was parsed. subcommand.subcommand->callback([&, this]() { // Build the NewTab action from the values we've parsed on the commandline. - auto newTabAction = winrt::make_self(); - newTabAction->Action(ShortcutAction::NewTab); - auto args = winrt::make_self(); + ActionAndArgs newTabAction{}; + newTabAction.Action(ShortcutAction::NewTab); // _getNewTerminalArgs MUST be called before parsing any other options, // as it might clear those options while finding the commandline - args->TerminalArgs(_getNewTerminalArgs(subcommand)); - newTabAction->Args(*args); - _startupActions.push_back(*newTabAction); + NewTabArgs args{ _getNewTerminalArgs(subcommand) }; + newTabAction.Args(args); + _startupActions.push_back(newTabAction); }); }; @@ -257,29 +253,29 @@ void AppCommandlineArgs::_buildSplitPaneParser() // command was parsed. subcommand.subcommand->callback([&, this]() { // Build the SplitPane action from the values we've parsed on the commandline. - auto splitPaneActionAndArgs = winrt::make_self(); - splitPaneActionAndArgs->Action(ShortcutAction::SplitPane); - auto args = winrt::make_self(); + ActionAndArgs splitPaneActionAndArgs{}; + splitPaneActionAndArgs.Action(ShortcutAction::SplitPane); + // _getNewTerminalArgs MUST be called before parsing any other options, // as it might clear those options while finding the commandline - args->TerminalArgs(_getNewTerminalArgs(subcommand)); - args->SplitStyle(SplitState::Automatic); + auto terminalArgs{ _getNewTerminalArgs(subcommand) }; + auto style{ SplitState::Automatic }; // Make sure to use the `Option`s here to check if they were set - // _getNewTerminalArgs might reset them while parsing a commandline if ((*subcommand._horizontalOption || *subcommand._verticalOption)) { if (_splitHorizontal) { - args->SplitStyle(SplitState::Horizontal); + style = SplitState::Horizontal; } else if (_splitVertical) { - args->SplitStyle(SplitState::Vertical); + style = SplitState::Vertical; } } - - splitPaneActionAndArgs->Args(*args); - _startupActions.push_back(*splitPaneActionAndArgs); + SplitPaneArgs args{ style, terminalArgs }; + splitPaneActionAndArgs.Args(args); + _startupActions.push_back(splitPaneActionAndArgs); }); }; @@ -319,20 +315,19 @@ void AppCommandlineArgs::_buildFocusTabParser() // command was parsed. subcommand->callback([&, this]() { // Build the action from the values we've parsed on the commandline. - auto focusTabAction = winrt::make_self(); + ActionAndArgs focusTabAction{}; if (_focusTabIndex >= 0) { - focusTabAction->Action(ShortcutAction::SwitchToTab); - auto args = winrt::make_self(); - args->TabIndex(_focusTabIndex); - focusTabAction->Args(*args); - _startupActions.push_back(*focusTabAction); + focusTabAction.Action(ShortcutAction::SwitchToTab); + SwitchToTabArgs args{ static_cast(_focusTabIndex) }; + focusTabAction.Args(args); + _startupActions.push_back(focusTabAction); } else if (_focusNextTab || _focusPrevTab) { - focusTabAction->Action(_focusNextTab ? ShortcutAction::NextTab : ShortcutAction::PrevTab); - _startupActions.push_back(*focusTabAction); + focusTabAction.Action(_focusNextTab ? ShortcutAction::NextTab : ShortcutAction::PrevTab); + _startupActions.push_back(std::move(focusTabAction)); } }); }; @@ -379,7 +374,7 @@ void AppCommandlineArgs::_addNewTerminalArgs(AppCommandlineArgs::NewTerminalSubc // - A fully initialized NewTerminalArgs corresponding to values we've currently parsed. NewTerminalArgs AppCommandlineArgs::_getNewTerminalArgs(AppCommandlineArgs::NewTerminalSubcommand& subcommand) { - auto args = winrt::make_self(); + NewTerminalArgs args{}; if (!_commandline.empty()) { @@ -403,25 +398,25 @@ NewTerminalArgs AppCommandlineArgs::_getNewTerminalArgs(AppCommandlineArgs::NewT } } - args->Commandline(winrt::to_hstring(cmdlineBuffer.str())); + args.Commandline(winrt::to_hstring(cmdlineBuffer.str())); } if (*subcommand.profileNameOption) { - args->Profile(winrt::to_hstring(_profileName)); + args.Profile(winrt::to_hstring(_profileName)); } if (*subcommand.startingDirectoryOption) { - args->StartingDirectory(winrt::to_hstring(_startingDirectory)); + args.StartingDirectory(winrt::to_hstring(_startingDirectory)); } if (*subcommand.titleOption) { - args->TabTitle(winrt::to_hstring(_startingTitle)); + args.TabTitle(winrt::to_hstring(_startingTitle)); } - return *args; + return args; } // Method Description: @@ -599,7 +594,7 @@ void AppCommandlineArgs::_addCommandsForArg(std::vector& commands, // - // Return Value: // - the deque of actions we've buffered as a result of parsing commands. -std::vector& AppCommandlineArgs::GetStartupActions() +std::vector& AppCommandlineArgs::GetStartupActions() { return _startupActions; } @@ -652,18 +647,15 @@ void AppCommandlineArgs::ValidateStartupCommands() _startupActions.front().Action() != ShortcutAction::NewTab) { // Build the NewTab action from the values we've parsed on the commandline. - auto newTabAction = winrt::make_self(); - newTabAction->Action(ShortcutAction::NewTab); - auto args = winrt::make_self(); - auto newTerminalArgs = winrt::make_self(); - args->TerminalArgs(*newTerminalArgs); - newTabAction->Args(*args); + NewTerminalArgs newTerminalArgs{}; + NewTabArgs args{ newTerminalArgs }; + ActionAndArgs newTabAction{ ShortcutAction::NewTab, args }; // push the arg onto the front - _startupActions.insert(_startupActions.begin(), 1, *newTabAction); + _startupActions.insert(_startupActions.begin(), 1, newTabAction); } } -std::optional AppCommandlineArgs::GetLaunchMode() const noexcept +std::optional AppCommandlineArgs::GetLaunchMode() const noexcept { return _launchMode; } diff --git a/src/cascadia/TerminalApp/AppCommandlineArgs.h b/src/cascadia/TerminalApp/AppCommandlineArgs.h index a0d87ffc6b8..35f3c301cbf 100644 --- a/src/cascadia/TerminalApp/AppCommandlineArgs.h +++ b/src/cascadia/TerminalApp/AppCommandlineArgs.h @@ -2,8 +2,6 @@ // Licensed under the MIT license. #pragma once -#include "ActionAndArgs.h" - #include "Commandline.h" #ifdef UNIT_TESTING @@ -36,11 +34,11 @@ class TerminalApp::AppCommandlineArgs final static std::vector BuildCommands(winrt::array_view& args); void ValidateStartupCommands(); - std::vector& GetStartupActions(); + std::vector& GetStartupActions(); const std::string& GetExitMessage(); bool ShouldExitEarly() const noexcept; - std::optional GetLaunchMode() const noexcept; + std::optional GetLaunchMode() const noexcept; private: static const std::wregex _commandDelimiterRegex; @@ -89,14 +87,14 @@ class TerminalApp::AppCommandlineArgs final bool _focusNextTab{ false }; bool _focusPrevTab{ false }; - std::optional _launchMode{ std::nullopt }; + std::optional _launchMode{ std::nullopt }; // Are you adding more args here? Make sure to reset them in _resetStateToDefault - std::vector _startupActions; + std::vector _startupActions; std::string _exitMessage; bool _shouldExitEarly{ false }; - winrt::TerminalApp::NewTerminalArgs _getNewTerminalArgs(NewTerminalSubcommand& subcommand); + winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs _getNewTerminalArgs(NewTerminalSubcommand& subcommand); void _addNewTerminalArgs(NewTerminalSubcommand& subcommand); void _buildParser(); void _buildNewTabParser(); diff --git a/src/cascadia/TerminalApp/AppKeyBindings.cpp b/src/cascadia/TerminalApp/AppKeyBindings.cpp index 99f1852ab0e..d6940987449 100644 --- a/src/cascadia/TerminalApp/AppKeyBindings.cpp +++ b/src/cascadia/TerminalApp/AppKeyBindings.cpp @@ -27,7 +27,7 @@ namespace winrt::TerminalApp::implementation _dispatch = dispatch; } - void AppKeyBindings::SetKeyMapping(const winrt::TerminalApp::KeyMapping& keymap) + void AppKeyBindings::SetKeyMapping(const winrt::Microsoft::Terminal::Settings::Model::KeyMapping& keymap) { _keymap = keymap; } diff --git a/src/cascadia/TerminalApp/AppKeyBindings.h b/src/cascadia/TerminalApp/AppKeyBindings.h index 499b78107ab..19891d5ed66 100644 --- a/src/cascadia/TerminalApp/AppKeyBindings.h +++ b/src/cascadia/TerminalApp/AppKeyBindings.h @@ -4,7 +4,6 @@ #pragma once #include "AppKeyBindings.g.h" -#include "ActionArgs.h" #include "ShortcutActionDispatch.h" #include "..\inc\cppwinrt_utils.h" @@ -12,8 +11,6 @@ namespace TerminalAppLocalTests { class SettingsTests; - class KeyBindingsTests; - class TestUtils; } namespace winrt::TerminalApp::implementation @@ -25,16 +22,14 @@ namespace winrt::TerminalApp::implementation bool TryKeyChord(winrt::Microsoft::Terminal::TerminalControl::KeyChord const& kc); void SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch); - void SetKeyMapping(const winrt::TerminalApp::KeyMapping& keymap); + void SetKeyMapping(const Microsoft::Terminal::Settings::Model::KeyMapping& keymap); private: - winrt::TerminalApp::KeyMapping _keymap{ nullptr }; + winrt::Microsoft::Terminal::Settings::Model::KeyMapping _keymap{ nullptr }; winrt::TerminalApp::ShortcutActionDispatch _dispatch{ nullptr }; friend class TerminalAppLocalTests::SettingsTests; - friend class TerminalAppLocalTests::KeyBindingsTests; - friend class TerminalAppLocalTests::TestUtils; }; } diff --git a/src/cascadia/TerminalApp/AppKeyBindings.idl b/src/cascadia/TerminalApp/AppKeyBindings.idl index 7370d6491ab..b4b979670f9 100644 --- a/src/cascadia/TerminalApp/AppKeyBindings.idl +++ b/src/cascadia/TerminalApp/AppKeyBindings.idl @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. import "ShortcutActionDispatch.idl"; -import "KeyMapping.idl"; namespace TerminalApp { @@ -10,6 +9,6 @@ namespace TerminalApp AppKeyBindings(); void SetDispatch(ShortcutActionDispatch dispatch); - void SetKeyMapping(KeyMapping keymap); + void SetKeyMapping(Microsoft.Terminal.Settings.Model.KeyMapping keymap); } } diff --git a/src/cascadia/TerminalApp/AppLogic.cpp b/src/cascadia/TerminalApp/AppLogic.cpp index 73461c0d5a3..e49b0147b6a 100644 --- a/src/cascadia/TerminalApp/AppLogic.cpp +++ b/src/cascadia/TerminalApp/AppLogic.cpp @@ -16,6 +16,7 @@ using namespace winrt::Windows::UI::Core; using namespace winrt::Windows::System; using namespace winrt::Microsoft::Terminal; using namespace winrt::Microsoft::Terminal::TerminalControl; +using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace ::TerminalApp; namespace winrt @@ -29,7 +30,7 @@ static const winrt::hstring StartupTaskName = L"StartTerminalOnLoginTask"; // !!! IMPORTANT !!! // Make sure that these keys are in the same order as the // SettingsLoadWarnings/Errors enum is! -static const std::array(winrt::TerminalApp::SettingsLoadWarnings::WARNINGS_SIZE)> settingsLoadWarningsLabels { +static const std::array(SettingsLoadWarnings::WARNINGS_SIZE)> settingsLoadWarningsLabels { USES_RESOURCE(L"MissingDefaultProfileText"), USES_RESOURCE(L"DuplicateProfileText"), USES_RESOURCE(L"UnknownColorSchemeText"), @@ -41,7 +42,7 @@ static const std::array(winrt::Terminal USES_RESOURCE(L"LegacyGlobalsProperty"), USES_RESOURCE(L"FailedToParseCommandJson") }; -static const std::array(winrt::TerminalApp::SettingsLoadErrors::ERRORS_SIZE)> settingsLoadErrorsLabels { +static const std::array(SettingsLoadErrors::ERRORS_SIZE)> settingsLoadErrorsLabels { USES_RESOURCE(L"NoProfilesText"), USES_RESOURCE(L"AllProfilesHiddenText") }; @@ -76,7 +77,7 @@ static winrt::hstring _GetMessageText(uint32_t index, std::array(warning), settingsLoadWarningsLabels); } @@ -89,7 +90,7 @@ static winrt::hstring _GetWarningText(winrt::TerminalApp::SettingsLoadWarnings w // - error: the SettingsLoadErrors value to get the localized text for. // Return Value: // - localized text for the given error -static winrt::hstring _GetErrorText(winrt::TerminalApp::SettingsLoadErrors error) +static winrt::hstring _GetErrorText(SettingsLoadErrors error) { return _GetMessageText(static_cast(error), settingsLoadErrorsLabels); } @@ -169,7 +170,7 @@ namespace winrt::TerminalApp::implementation // - Returns the settings currently in use by the entire Terminal application. // Throws: // - HR E_INVALIDARG if the app isn't up and running. - const TerminalApp::CascadiaSettings AppLogic::CurrentAppSettings() + const CascadiaSettings AppLogic::CurrentAppSettings() { auto appLogic{ ::winrt::TerminalApp::implementation::AppLogic::Current() }; THROW_HR_IF_NULL(E_INVALIDARG, appLogic); @@ -718,7 +719,7 @@ namespace winrt::TerminalApp::implementation void AppLogic::_RegisterSettingsChange() { // Get the containing folder. - const auto settingsPath{ CascadiaSettings::GetSettingsPath() }; + const std::filesystem::path settingsPath{ std::wstring_view{ CascadiaSettings::SettingsPath() } }; const auto folder = settingsPath.parent_path(); _reader.create(folder.c_str(), @@ -870,7 +871,7 @@ namespace winrt::TerminalApp::implementation // Method Description: // - Returns a pointer to the global shared settings. - [[nodiscard]] TerminalApp::CascadiaSettings AppLogic::GetSettings() const noexcept + [[nodiscard]] CascadiaSettings AppLogic::GetSettings() const noexcept { return _settings; } @@ -1041,65 +1042,6 @@ namespace winrt::TerminalApp::implementation return _appArgs.ShouldExitEarly(); } - winrt::hstring AppLogic::ApplicationDisplayName() const - { - try - { - const auto package{ winrt::Windows::ApplicationModel::Package::Current() }; - return package.DisplayName(); - } - CATCH_LOG(); - - return RS_(L"ApplicationDisplayNameUnpackaged"); - } - - winrt::hstring AppLogic::ApplicationVersion() const - { - try - { - const auto package{ winrt::Windows::ApplicationModel::Package::Current() }; - const auto version{ package.Id().Version() }; - winrt::hstring formatted{ wil::str_printf(L"%u.%u.%u.%u", version.Major, version.Minor, version.Build, version.Revision) }; - return formatted; - } - CATCH_LOG(); - - // Try to get the version the old-fashioned way - try - { - struct LocalizationInfo - { - WORD language, codepage; - }; - // Use the current module instance handle for TerminalApp.dll, nullptr for WindowsTerminal.exe - auto filename{ wil::GetModuleFileNameW(wil::GetModuleInstanceHandle()) }; - auto size{ GetFileVersionInfoSizeExW(0, filename.c_str(), nullptr) }; - THROW_LAST_ERROR_IF(size == 0); - auto versionBuffer{ std::make_unique(size) }; - THROW_IF_WIN32_BOOL_FALSE(GetFileVersionInfoExW(0, filename.c_str(), 0, size, versionBuffer.get())); - - // Get the list of Version localizations - LocalizationInfo* pVarLocalization{ nullptr }; - UINT varLen{ 0 }; - THROW_IF_WIN32_BOOL_FALSE(VerQueryValueW(versionBuffer.get(), L"\\VarFileInfo\\Translation", reinterpret_cast(&pVarLocalization), &varLen)); - THROW_HR_IF(E_UNEXPECTED, varLen < sizeof(*pVarLocalization)); // there must be at least one translation - - // Get the product version from the localized version compartment - // We're using String/ProductVersion here because our build pipeline puts more rich information in it (like the branch name) - // than in the unlocalized numeric version fields. - WCHAR* pProductVersion{ nullptr }; - UINT versionLen{ 0 }; - const auto localizedVersionName{ wil::str_printf(L"\\StringFileInfo\\%04x%04x\\ProductVersion", - pVarLocalization->language ? pVarLocalization->language : 0x0409, // well-known en-US LCID - pVarLocalization->codepage) }; - THROW_IF_WIN32_BOOL_FALSE(VerQueryValueW(versionBuffer.get(), localizedVersionName.c_str(), reinterpret_cast(&pProductVersion), &versionLen)); - return { pProductVersion }; - } - CATCH_LOG(); - - return RS_(L"ApplicationVersionUnknown"); - } - bool AppLogic::FocusMode() const { return _root ? _root->FocusMode() : false; diff --git a/src/cascadia/TerminalApp/AppLogic.h b/src/cascadia/TerminalApp/AppLogic.h index 192f7330ce3..a6dfd3251cd 100644 --- a/src/cascadia/TerminalApp/AppLogic.h +++ b/src/cascadia/TerminalApp/AppLogic.h @@ -6,7 +6,6 @@ #include "AppLogic.g.h" #include "Tab.h" -#include "CascadiaSettings.h" #include "TerminalPage.h" #include "Jumplist.h" #include "../../cascadia/inc/cppwinrt_utils.h" @@ -17,7 +16,7 @@ namespace winrt::TerminalApp::implementation { public: static AppLogic* Current() noexcept; - static const TerminalApp::CascadiaSettings CurrentAppSettings(); + static const Microsoft::Terminal::Settings::Model::CascadiaSettings CurrentAppSettings(); AppLogic(); ~AppLogic() = default; @@ -27,14 +26,12 @@ namespace winrt::TerminalApp::implementation void RunAsUwp(); bool IsElevated() const noexcept; void LoadSettings(); - [[nodiscard]] TerminalApp::CascadiaSettings GetSettings() const noexcept; + [[nodiscard]] Microsoft::Terminal::Settings::Model::CascadiaSettings GetSettings() const noexcept; int32_t SetStartupCommandline(array_view actions); winrt::hstring ParseCommandlineMessage(); bool ShouldExitEarly(); - winrt::hstring ApplicationDisplayName() const; - winrt::hstring ApplicationVersion() const; bool FocusMode() const; bool Fullscreen() const; bool AlwaysOnTop() const; @@ -42,7 +39,7 @@ namespace winrt::TerminalApp::implementation Windows::Foundation::Size GetLaunchDimensions(uint32_t dpi); TerminalApp::InitialPosition GetInitialPosition(int64_t defaultInitialX, int64_t defaultInitialY); winrt::Windows::UI::Xaml::ElementTheme GetRequestedTheme(); - LaunchMode GetLaunchMode(); + Microsoft::Terminal::Settings::Model::LaunchMode GetLaunchMode(); bool GetShowTabsInTitlebar(); float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const; @@ -70,7 +67,7 @@ namespace winrt::TerminalApp::implementation // updated in _ApplyTheme. The root currently is _root. winrt::com_ptr _root{ nullptr }; - TerminalApp::CascadiaSettings _settings{ nullptr }; + Microsoft::Terminal::Settings::Model::CascadiaSettings _settings{ nullptr }; HRESULT _settingsLoadedResult; winrt::hstring _settingsLoadExceptionText{}; diff --git a/src/cascadia/TerminalApp/AppLogic.idl b/src/cascadia/TerminalApp/AppLogic.idl index 838b40e1a67..683a038bbd9 100644 --- a/src/cascadia/TerminalApp/AppLogic.idl +++ b/src/cascadia/TerminalApp/AppLogic.idl @@ -13,13 +13,6 @@ namespace TerminalApp Int64 Y; }; - enum LaunchMode - { - DefaultMode, - MaximizedMode, - FullscreenMode, - }; - [default_interface] runtimeclass AppLogic : IDirectKeyListener, IDialogPresenter { AppLogic(); @@ -44,9 +37,6 @@ namespace TerminalApp String Title { get; }; - String ApplicationDisplayName { get; }; - String ApplicationVersion { get; }; - Boolean FocusMode { get; }; Boolean Fullscreen { get; }; Boolean AlwaysOnTop { get; }; @@ -55,7 +45,7 @@ namespace TerminalApp InitialPosition GetInitialPosition(Int64 defaultInitialX, Int64 defaultInitialY); Windows.UI.Xaml.ElementTheme GetRequestedTheme(); - LaunchMode GetLaunchMode(); + Microsoft.Terminal.Settings.Model.LaunchMode GetLaunchMode(); Boolean GetShowTabsInTitlebar(); Single CalcSnappedDimension(Boolean widthOrHeight, Single dimension); void TitlebarClicked(); diff --git a/src/cascadia/TerminalApp/Command.h b/src/cascadia/TerminalApp/Command.h deleted file mode 100644 index a89f10ed78b..00000000000 --- a/src/cascadia/TerminalApp/Command.h +++ /dev/null @@ -1,83 +0,0 @@ -/*++ -Copyright (c) Microsoft Corporation -Licensed under the MIT license. - -Module Name: -- Command.h - -Abstract: -- A command represents a single entry in the Command Palette. This is an object - that has a user facing "name" to display to the user, and an associated action - which can be dispatched. - -- For more information, see GH#2046, #5400, #5674, and #6635 - -Author(s): -- Mike Griese - June 2020 - ---*/ -#pragma once - -#include "Command.g.h" -#include "TerminalWarnings.h" -#include "Profile.h" -#include "..\inc\cppwinrt_utils.h" -#include "SettingsTypes.h" - -// fwdecl unittest classes -namespace TerminalAppLocalTests -{ - class SettingsTests; - class CommandTests; -}; - -namespace winrt::TerminalApp::implementation -{ - struct Command : CommandT - { - Command(); - - static winrt::com_ptr FromJson(const Json::Value& json, - std::vector& warnings); - - static void ExpandCommands(Windows::Foundation::Collections::IMap& commands, - Windows::Foundation::Collections::IVectorView profiles, - gsl::span schemes, - std::vector& warnings); - - static std::vector LayerJson(Windows::Foundation::Collections::IMap& commands, - const Json::Value& json); - bool HasNestedCommands(); - Windows::Foundation::Collections::IMapView NestedCommands(); - - void RefreshIcon(); - - winrt::Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker propertyChangedRevoker; - - WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler); - OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Name, _PropertyChangedHandlers); - OBSERVABLE_GETSET_PROPERTY(winrt::TerminalApp::ActionAndArgs, Action, _PropertyChangedHandlers); - 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); - - private: - Json::Value _originalJson; - Windows::Foundation::Collections::IMap _subcommands{ nullptr }; - - winrt::hstring _lastIconPath{}; - - static std::vector _expandCommand(Command* const expandable, - Windows::Foundation::Collections::IVectorView profiles, - gsl::span schemes, - std::vector& warnings); - friend class TerminalAppLocalTests::SettingsTests; - friend class TerminalAppLocalTests::CommandTests; - }; -} - -namespace winrt::TerminalApp::factory_implementation -{ - BASIC_FACTORY(Command); -} diff --git a/src/cascadia/TerminalApp/Command.idl b/src/cascadia/TerminalApp/Command.idl deleted file mode 100644 index d60287890b5..00000000000 --- a/src/cascadia/TerminalApp/Command.idl +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import "ShortcutActionDispatch.idl"; - -namespace TerminalApp -{ - [default_interface] runtimeclass Command : Windows.UI.Xaml.Data.INotifyPropertyChanged - { - Command(); - - String Name; - ActionAndArgs Action; - String KeyChordText; - - Windows.UI.Xaml.Controls.IconSource IconSource; - void RefreshIcon(); - - Boolean HasNestedCommands { get; }; - Windows.Foundation.Collections.IMapView NestedCommands { get; }; - } -} diff --git a/src/cascadia/TerminalApp/CommandPalette.cpp b/src/cascadia/TerminalApp/CommandPalette.cpp index 82fb48ed9a7..5b0e0307bd3 100644 --- a/src/cascadia/TerminalApp/CommandPalette.cpp +++ b/src/cascadia/TerminalApp/CommandPalette.cpp @@ -3,9 +3,6 @@ #include "pch.h" #include "CommandPalette.h" -#include "ActionAndArgs.h" -#include "ActionArgs.h" -#include "Command.h" #include @@ -18,6 +15,7 @@ using namespace winrt::Windows::UI::Xaml; using namespace winrt::Windows::System; using namespace winrt::Windows::Foundation; using namespace winrt::Windows::Foundation::Collections; +using namespace winrt::Microsoft::Terminal::Settings::Model; namespace winrt::TerminalApp::implementation { @@ -26,11 +24,11 @@ namespace winrt::TerminalApp::implementation { InitializeComponent(); - _filteredActions = winrt::single_threaded_observable_vector(); - _nestedActionStack = winrt::single_threaded_vector(); - _currentNestedCommands = winrt::single_threaded_vector(); - _allCommands = winrt::single_threaded_vector(); - _allTabActions = winrt::single_threaded_vector(); + _filteredActions = winrt::single_threaded_observable_vector(); + _nestedActionStack = winrt::single_threaded_vector(); + _currentNestedCommands = winrt::single_threaded_vector(); + _allCommands = winrt::single_threaded_vector(); + _allTabActions = winrt::single_threaded_vector(); _switchToMode(CommandPaletteMode::ActionMode); @@ -177,7 +175,7 @@ namespace winrt::TerminalApp::implementation { if (const auto selectedItem = _filteredActionsView().SelectedItem()) { - _dispatchCommand(selectedItem.try_as()); + _dispatchCommand(selectedItem.try_as()); } } // Commandline Mode: Use the input to synthesize an ExecuteCommandline action @@ -300,7 +298,7 @@ namespace winrt::TerminalApp::implementation { if (const auto selectedItem = _filteredActionsView().SelectedItem()) { - if (const auto data = selectedItem.try_as()) + if (const auto data = selectedItem.try_as()) { _dispatchCommand(data); } @@ -347,7 +345,7 @@ namespace winrt::TerminalApp::implementation void CommandPalette::_listItemClicked(Windows::Foundation::IInspectable const& /*sender*/, Windows::UI::Xaml::Controls::ItemClickEventArgs const& e) { - _dispatchCommand(e.ClickedItem().try_as()); + _dispatchCommand(e.ClickedItem().try_as()); } // Method Description: @@ -382,7 +380,7 @@ namespace winrt::TerminalApp::implementation // - // Return Value: // - A list of Commands to filter. - Collections::IVector CommandPalette::_commandsToFilter() + Collections::IVector CommandPalette::_commandsToFilter() { switch (_currentMode) { @@ -397,7 +395,7 @@ namespace winrt::TerminalApp::implementation case CommandPaletteMode::TabSwitchMode: return _allTabActions; case CommandPaletteMode::CommandlineMode: - return winrt::single_threaded_vector(); + return winrt::single_threaded_vector(); default: return _allCommands; } @@ -412,7 +410,7 @@ namespace winrt::TerminalApp::implementation // - command: the Command to dispatch. This might be null. // Return Value: // - - void CommandPalette::_dispatchCommand(const TerminalApp::Command& command) + void CommandPalette::_dispatchCommand(const Command& command) { if (command) { @@ -505,11 +503,8 @@ namespace winrt::TerminalApp::implementation winrt::hstring cmdline{ input }; // Build the ExecuteCommandline action from the values we've parsed on the commandline. - auto executeActionAndArgs = winrt::make_self(); - executeActionAndArgs->Action(ShortcutAction::ExecuteCommandline); - auto args = winrt::make_self(); - args->Commandline(cmdline); - executeActionAndArgs->Args(*args); + ExecuteCommandlineArgs args{ cmdline }; + ActionAndArgs executeActionAndArgs{ ShortcutAction::ExecuteCommandline, args }; TraceLoggingWrite( g_hTerminalAppProvider, // handle to TerminalApp tracelogging provider @@ -518,7 +513,7 @@ namespace winrt::TerminalApp::implementation TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance)); - if (_dispatch.DoAction(*executeActionAndArgs)) + if (_dispatch.DoAction(executeActionAndArgs)) { _close(); } @@ -584,7 +579,7 @@ namespace winrt::TerminalApp::implementation } } - Collections::IObservableVector CommandPalette::FilteredActions() + Collections::IObservableVector CommandPalette::FilteredActions() { return _filteredActions; } @@ -594,7 +589,7 @@ namespace winrt::TerminalApp::implementation _bindings = bindings; } - void CommandPalette::SetCommands(Collections::IVector const& actions) + void CommandPalette::SetCommands(Collections::IVector const& actions) { _allCommands = actions; _updateFilteredActions(); @@ -651,7 +646,7 @@ namespace winrt::TerminalApp::implementation } // This is a helper to aid in sorting commands by their `Name`s, alphabetically. - static bool _compareCommandNames(const TerminalApp::Command& lhs, const TerminalApp::Command& rhs) + static bool _compareCommandNames(const Command& lhs, const Command& rhs) { std::wstring_view leftName{ lhs.Name() }; std::wstring_view rightName{ rhs.Name() }; @@ -661,7 +656,7 @@ namespace winrt::TerminalApp::implementation // This is a helper struct to aid in sorting Commands by a given weighting. struct WeightedCommand { - TerminalApp::Command command; + Command command; int weight; int inOrderCounter; @@ -693,9 +688,9 @@ namespace winrt::TerminalApp::implementation // - A collection that will receive the filtered actions // Return Value: // - - std::vector CommandPalette::_collectFilteredActions() + std::vector CommandPalette::_collectFilteredActions() { - std::vector actions; + std::vector actions; auto searchText = _searchBox().Text(); const bool addAll = searchText.empty(); @@ -720,7 +715,7 @@ namespace winrt::TerminalApp::implementation } // Add all the commands, but make sure they're sorted alphabetically. - std::vector sortedCommands; + std::vector sortedCommands; sortedCommands.reserve(commandsToFilter.Size()); for (auto action : commandsToFilter) diff --git a/src/cascadia/TerminalApp/CommandPalette.h b/src/cascadia/TerminalApp/CommandPalette.h index c1e1830dda7..81b49e81b87 100644 --- a/src/cascadia/TerminalApp/CommandPalette.h +++ b/src/cascadia/TerminalApp/CommandPalette.h @@ -20,9 +20,9 @@ namespace winrt::TerminalApp::implementation { CommandPalette(); - Windows::Foundation::Collections::IObservableVector FilteredActions(); + Windows::Foundation::Collections::IObservableVector FilteredActions(); - void SetCommands(Windows::Foundation::Collections::IVector const& actions); + void SetCommands(Windows::Foundation::Collections::IVector const& actions); void SetKeyBindings(Microsoft::Terminal::TerminalControl::IKeyBindings bindings); void EnableCommandPaletteMode(); @@ -46,14 +46,14 @@ namespace winrt::TerminalApp::implementation private: friend struct CommandPaletteT; // for Xaml to bind events - Windows::Foundation::Collections::IVector _allCommands{ nullptr }; - Windows::Foundation::Collections::IVector _currentNestedCommands{ nullptr }; - Windows::Foundation::Collections::IObservableVector _filteredActions{ nullptr }; - Windows::Foundation::Collections::IVector _nestedActionStack{ nullptr }; + Windows::Foundation::Collections::IVector _allCommands{ nullptr }; + Windows::Foundation::Collections::IVector _currentNestedCommands{ nullptr }; + Windows::Foundation::Collections::IObservableVector _filteredActions{ nullptr }; + Windows::Foundation::Collections::IVector _nestedActionStack{ nullptr }; winrt::TerminalApp::ShortcutActionDispatch _dispatch; - Windows::Foundation::Collections::IVector _commandsToFilter(); + Windows::Foundation::Collections::IVector _commandsToFilter(); void _filterTextChanged(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args); @@ -73,7 +73,7 @@ namespace winrt::TerminalApp::implementation void _updateFilteredActions(); - std::vector _collectFilteredActions(); + std::vector _collectFilteredActions(); static int _getWeight(const winrt::hstring& searchText, const winrt::hstring& name); void _close(); @@ -87,13 +87,13 @@ namespace winrt::TerminalApp::implementation Microsoft::Terminal::TerminalControl::IKeyBindings _bindings; // Tab Switcher - Windows::Foundation::Collections::IVector _allTabActions{ nullptr }; + Windows::Foundation::Collections::IVector _allTabActions{ nullptr }; uint32_t _switcherStartIdx; void _anchorKeyUpHandler(); winrt::Windows::UI::Xaml::Controls::ListView::SizeChanged_revoker _sizeChangedRevoker; - void _dispatchCommand(const TerminalApp::Command& command); + void _dispatchCommand(const Microsoft::Terminal::Settings::Model::Command& command); void _dispatchCommandline(); void _dismissPalette(); }; diff --git a/src/cascadia/TerminalApp/CommandPalette.idl b/src/cascadia/TerminalApp/CommandPalette.idl index 10cfe967fa9..f938515354f 100644 --- a/src/cascadia/TerminalApp/CommandPalette.idl +++ b/src/cascadia/TerminalApp/CommandPalette.idl @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import "Command.idl"; import "IDirectKeyListener.idl"; +import "ShortcutActionDispatch.idl"; namespace TerminalApp { @@ -15,9 +15,9 @@ namespace TerminalApp String ControlName { get; }; String ParentCommandName { get; }; - Windows.Foundation.Collections.IObservableVector FilteredActions { get; }; + Windows.Foundation.Collections.IObservableVector FilteredActions { get; }; - void SetCommands(Windows.Foundation.Collections.IVector actions); + void SetCommands(Windows.Foundation.Collections.IVector actions); void SetKeyBindings(Microsoft.Terminal.TerminalControl.IKeyBindings bindings); void EnableCommandPaletteMode(); diff --git a/src/cascadia/TerminalApp/CommandPalette.xaml b/src/cascadia/TerminalApp/CommandPalette.xaml index a7ce2822c6f..212270878da 100644 --- a/src/cascadia/TerminalApp/CommandPalette.xaml +++ b/src/cascadia/TerminalApp/CommandPalette.xaml @@ -8,7 +8,8 @@ the MIT License. See LICENSE in the project root for license information. --> xmlns:mux="using:Microsoft.UI.Xaml.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:Windows10version1903="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract, 8)" + xmlns:Windows10version1903="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract, 8)" + xmlns:SettingsModel="using:Microsoft.Terminal.Settings.Model" TabNavigation="Cycle" IsTabStop="True" AllowFocusOnInteraction="True" @@ -205,7 +206,7 @@ the MIT License. See LICENSE in the project root for license information. --> ItemsSource="{x:Bind FilteredActions}"> - + diff --git a/src/cascadia/TerminalApp/DebugTapConnection.cpp b/src/cascadia/TerminalApp/DebugTapConnection.cpp index d149ad46213..0a71c8bff56 100644 --- a/src/cascadia/TerminalApp/DebugTapConnection.cpp +++ b/src/cascadia/TerminalApp/DebugTapConnection.cpp @@ -3,7 +3,6 @@ #include "pch.h" #include "DebugTapConnection.h" -#include "Utils.h" using namespace ::winrt::Microsoft::Terminal::TerminalConnection; using namespace ::winrt::Windows::Foundation; @@ -94,13 +93,13 @@ namespace winrt::Microsoft::TerminalApp::implementation void DebugTapConnection::_OutputHandler(const hstring str) { - _TerminalOutputHandlers(VisualizeControlCodes(str)); + _TerminalOutputHandlers(til::visualize_control_codes(str)); } // Called by the DebugInputTapConnection to print user input void DebugTapConnection::_PrintInput(const hstring& str) { - auto clean{ VisualizeControlCodes(str) }; + auto clean{ til::visualize_control_codes(str) }; auto formatted{ wil::str_printf(L"\x1b[91m%ls\x1b[m", clean.data()) }; _TerminalOutputHandlers(formatted); } diff --git a/src/cascadia/TerminalApp/Jumplist.cpp b/src/cascadia/TerminalApp/Jumplist.cpp index 4d108efc720..291e71b6bae 100644 --- a/src/cascadia/TerminalApp/Jumplist.cpp +++ b/src/cascadia/TerminalApp/Jumplist.cpp @@ -7,7 +7,7 @@ #include #include -using namespace winrt::TerminalApp; +using namespace winrt::Microsoft::Terminal::Settings::Model; // This property key isn't already defined in propkey.h, but is used by UWP Jumplist to determine the icon of the jumplist item. // IShellLink's SetIconLocation isn't going to read "ms-appx://" icon paths, so we'll need to use this to set the icon. @@ -157,7 +157,7 @@ HRESULT Jumplist::UpdateJumplist(const CascadiaSettings& settings) noexcept // - profiles - The profiles to add to the jumplist // Return Value: // - S_OK or HRESULT failure code. -[[nodiscard]] HRESULT Jumplist::_updateProfiles(IObjectCollection* jumplistItems, winrt::Windows::Foundation::Collections::IVectorView profiles) noexcept +[[nodiscard]] HRESULT Jumplist::_updateProfiles(IObjectCollection* jumplistItems, winrt::Windows::Foundation::Collections::IVectorView profiles) noexcept { try { diff --git a/src/cascadia/TerminalApp/Jumplist.h b/src/cascadia/TerminalApp/Jumplist.h index 5bd024f49b9..3f9baa6cd3b 100644 --- a/src/cascadia/TerminalApp/Jumplist.h +++ b/src/cascadia/TerminalApp/Jumplist.h @@ -12,17 +12,15 @@ #pragma once -#include "CascadiaSettings.h" - struct IObjectCollection; struct IShellLinkW; class Jumplist { public: - static HRESULT UpdateJumplist(const winrt::TerminalApp::CascadiaSettings& settings) noexcept; + static HRESULT UpdateJumplist(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings) noexcept; private: - [[nodiscard]] static HRESULT _updateProfiles(IObjectCollection* jumplistItems, winrt::Windows::Foundation::Collections::IVectorView profiles) noexcept; + [[nodiscard]] static HRESULT _updateProfiles(IObjectCollection* jumplistItems, winrt::Windows::Foundation::Collections::IVectorView profiles) noexcept; [[nodiscard]] static HRESULT _createShellLink(const std::wstring_view name, const std::wstring_view path, const std::wstring_view args, IShellLinkW** shLink) noexcept; }; diff --git a/src/cascadia/TerminalApp/KeyChordSerialization.h b/src/cascadia/TerminalApp/KeyChordSerialization.h deleted file mode 100644 index 4da2f0020a7..00000000000 --- a/src/cascadia/TerminalApp/KeyChordSerialization.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -#pragma once -#include - -class KeyChordSerialization final -{ -public: - static winrt::Microsoft::Terminal::TerminalControl::KeyChord FromString(const winrt::hstring& str); - static winrt::hstring ToString(const winrt::Microsoft::Terminal::TerminalControl::KeyChord& chord); -}; diff --git a/src/cascadia/TerminalApp/KeyMapping.h b/src/cascadia/TerminalApp/KeyMapping.h deleted file mode 100644 index 0ed882bf09d..00000000000 --- a/src/cascadia/TerminalApp/KeyMapping.h +++ /dev/null @@ -1,77 +0,0 @@ -/*++ -Copyright (c) Microsoft Corporation -Licensed under the MIT license. - -Module Name: -- KeyMapping.h - -Abstract: -- A mapping of key chords to actions. Includes (de)serialization logic. - -Author(s): -- Carlos Zamora - September 2020 - ---*/ - -#pragma once - -#include "KeyMapping.g.h" -#include "ActionArgs.h" -#include "..\inc\cppwinrt_utils.h" - -// fwdecl unittest classes -namespace TerminalAppLocalTests -{ - class SettingsTests; - class KeyBindingsTests; - class TestUtils; -} - -namespace winrt::TerminalApp::implementation -{ - struct KeyChordHash - { - std::size_t operator()(const winrt::Microsoft::Terminal::TerminalControl::KeyChord& key) const - { - std::hash keyHash; - std::hash modifiersHash; - std::size_t hashedKey = keyHash(key.Vkey()); - std::size_t hashedMods = modifiersHash(key.Modifiers()); - return hashedKey ^ hashedMods; - } - }; - - struct KeyChordEquality - { - bool operator()(const winrt::Microsoft::Terminal::TerminalControl::KeyChord& lhs, const winrt::Microsoft::Terminal::TerminalControl::KeyChord& rhs) const - { - return lhs.Modifiers() == rhs.Modifiers() && lhs.Vkey() == rhs.Vkey(); - } - }; - - struct KeyMapping : KeyMappingT - { - KeyMapping() = default; - - TerminalApp::ActionAndArgs TryLookup(winrt::Microsoft::Terminal::TerminalControl::KeyChord const& chord) const; - - void SetKeyBinding(TerminalApp::ActionAndArgs const& actionAndArgs, - winrt::Microsoft::Terminal::TerminalControl::KeyChord const& chord); - void ClearKeyBinding(winrt::Microsoft::Terminal::TerminalControl::KeyChord const& chord); - Microsoft::Terminal::TerminalControl::KeyChord GetKeyBindingForAction(TerminalApp::ShortcutAction const& action); - Microsoft::Terminal::TerminalControl::KeyChord GetKeyBindingForActionWithArgs(TerminalApp::ActionAndArgs const& actionAndArgs); - - static Windows::System::VirtualKeyModifiers ConvertVKModifiers(winrt::Microsoft::Terminal::TerminalControl::KeyModifiers modifiers); - - // Defined in KeyMappingSerialization.cpp - std::vector LayerJson(const Json::Value& json); - Json::Value ToJson(); - - private: - std::unordered_map _keyShortcuts; - - friend class TerminalAppLocalTests::SettingsTests; - friend class TerminalAppLocalTests::KeyBindingsTests; - friend class TerminalAppLocalTests::TestUtils; - }; -} diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index c58de58b59d..c785e80f22d 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -3,7 +3,6 @@ #include "pch.h" #include "Pane.h" -#include "Profile.h" #include "AppLogic.h" using namespace winrt::Windows::Foundation; @@ -12,6 +11,7 @@ using namespace winrt::Windows::UI; using namespace winrt::Windows::UI::Xaml; using namespace winrt::Windows::UI::Core; using namespace winrt::Windows::UI::Xaml::Media; +using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::TerminalControl; using namespace winrt::Microsoft::Terminal::TerminalConnection; using namespace winrt::TerminalApp; @@ -324,8 +324,8 @@ void Pane::_ControlConnectionStateChangedHandler(const TermControl& /*sender*/, if (paneProfile) { auto mode = paneProfile.CloseOnExit(); - if ((mode == winrt::TerminalApp::CloseOnExitMode::Always) || - (mode == winrt::TerminalApp::CloseOnExitMode::Graceful && newConnectionState == ConnectionState::Closed)) + if ((mode == CloseOnExitMode::Always) || + (mode == CloseOnExitMode::Graceful && newConnectionState == ConnectionState::Closed)) { _ClosedHandlers(nullptr, nullptr); } @@ -1712,8 +1712,8 @@ int Pane::GetLeafPaneCount() const noexcept // - nullopt if `target` is not this pane or a child of this pane, otherwise the // SplitState that `target` would use for an `Automatic` split given // `availableSpace` -std::optional Pane::PreCalculateAutoSplit(const std::shared_ptr target, - const winrt::Windows::Foundation::Size availableSpace) const +std::optional Pane::PreCalculateAutoSplit(const std::shared_ptr target, + const winrt::Windows::Foundation::Size availableSpace) const { if (_IsLeaf()) { diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index 6d1ffa133f1..0bd34be6420 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -55,17 +55,17 @@ class Pane : public std::enable_shared_from_this const GUID& profile); void ResizeContent(const winrt::Windows::Foundation::Size& newSize); void Relayout(); - bool ResizePane(const winrt::TerminalApp::Direction& direction); - bool NavigateFocus(const winrt::TerminalApp::Direction& direction); + bool ResizePane(const winrt::Microsoft::Terminal::Settings::Model::Direction& direction); + bool NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::Direction& direction); - bool CanSplit(winrt::TerminalApp::SplitState splitType); - std::pair, std::shared_ptr> Split(winrt::TerminalApp::SplitState splitType, + bool CanSplit(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType); + std::pair, std::shared_ptr> Split(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType, const GUID& profile, const winrt::Microsoft::Terminal::TerminalControl::TermControl& control); float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const; - std::optional PreCalculateAutoSplit(const std::shared_ptr target, const winrt::Windows::Foundation::Size parentSize) const; + std::optional PreCalculateAutoSplit(const std::shared_ptr target, const winrt::Windows::Foundation::Size parentSize) const; std::optional PreCalculateCanSplit(const std::shared_ptr target, - winrt::TerminalApp::SplitState splitType, + winrt::Microsoft::Terminal::Settings::Model::SplitState splitType, const winrt::Windows::Foundation::Size availableSpace) const; void Shutdown(); void Close(); @@ -91,7 +91,7 @@ class Pane : public std::enable_shared_from_this std::shared_ptr _firstChild{ nullptr }; std::shared_ptr _secondChild{ nullptr }; - winrt::TerminalApp::SplitState _splitState{ winrt::TerminalApp::SplitState::None }; + winrt::Microsoft::Terminal::Settings::Model::SplitState _splitState{ winrt::Microsoft::Terminal::Settings::Model::SplitState::None }; float _desiredSplitPosition; bool _lastActive{ false }; @@ -112,8 +112,8 @@ class Pane : public std::enable_shared_from_this bool _HasFocusedChild() const noexcept; void _SetupChildCloseHandlers(); - bool _CanSplit(winrt::TerminalApp::SplitState splitType); - std::pair, std::shared_ptr> _Split(winrt::TerminalApp::SplitState splitType, + bool _CanSplit(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType); + std::pair, std::shared_ptr> _Split(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType, const GUID& profile, const winrt::Microsoft::Terminal::TerminalControl::TermControl& control); @@ -121,8 +121,8 @@ class Pane : public std::enable_shared_from_this void _ApplySplitDefinitions(); void _UpdateBorders(); - bool _Resize(const winrt::TerminalApp::Direction& direction); - bool _NavigateFocus(const winrt::TerminalApp::Direction& direction); + bool _Resize(const winrt::Microsoft::Terminal::Settings::Model::Direction& direction); + bool _NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::Direction& direction); void _CloseChild(const bool closeFirst); winrt::fire_and_forget _CloseChildRoutine(const bool closeFirst); @@ -141,9 +141,9 @@ class Pane : public std::enable_shared_from_this LayoutSizeNode _CreateMinSizeTree(const bool widthOrHeight) const; float _ClampSplitPosition(const bool widthOrHeight, const float requestedValue, const float totalSize) const; - winrt::TerminalApp::SplitState _convertAutomaticSplitState(const winrt::TerminalApp::SplitState& splitType) const; + winrt::Microsoft::Terminal::Settings::Model::SplitState _convertAutomaticSplitState(const winrt::Microsoft::Terminal::Settings::Model::SplitState& splitType) const; - std::optional _preCalculateAutoSplit(const std::shared_ptr target, const winrt::Windows::Foundation::Size parentSize) const; + std::optional _preCalculateAutoSplit(const std::shared_ptr target, const winrt::Windows::Foundation::Size parentSize) const; // Function Description: // - Returns true if the given direction can be used with the given split @@ -159,22 +159,22 @@ class Pane : public std::enable_shared_from_this // Return Value: // - true iff the direction is perpendicular to the splitType. False for // winrt::TerminalApp::SplitState::None. - static constexpr bool DirectionMatchesSplit(const winrt::TerminalApp::Direction& direction, - const winrt::TerminalApp::SplitState& splitType) + static constexpr bool DirectionMatchesSplit(const winrt::Microsoft::Terminal::Settings::Model::Direction& direction, + const winrt::Microsoft::Terminal::Settings::Model::SplitState& splitType) { - if (splitType == winrt::TerminalApp::SplitState::None) + if (splitType == winrt::Microsoft::Terminal::Settings::Model::SplitState::None) { return false; } - else if (splitType == winrt::TerminalApp::SplitState::Horizontal) + else if (splitType == winrt::Microsoft::Terminal::Settings::Model::SplitState::Horizontal) { - return direction == winrt::TerminalApp::Direction::Up || - direction == winrt::TerminalApp::Direction::Down; + return direction == winrt::Microsoft::Terminal::Settings::Model::Direction::Up || + direction == winrt::Microsoft::Terminal::Settings::Model::Direction::Down; } - else if (splitType == winrt::TerminalApp::SplitState::Vertical) + else if (splitType == winrt::Microsoft::Terminal::Settings::Model::SplitState::Vertical) { - return direction == winrt::TerminalApp::Direction::Left || - direction == winrt::TerminalApp::Direction::Right; + return direction == winrt::Microsoft::Terminal::Settings::Model::Direction::Left || + direction == winrt::Microsoft::Terminal::Settings::Model::Direction::Right; } return false; } diff --git a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw index 15f42ebb3f6..7ab24f60555 100644 --- a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw @@ -342,14 +342,6 @@ Third-Party Notices A hyperlink name for the Terminal's third-party notices - - Windows Terminal (Unpackaged) - This display name is used when the application's name cannot be determined - - - Unknown - This is displayed when the version of the application cannot be determined - Cancel @@ -359,10 +351,6 @@ Do you want to close all tabs? - - Command Prompt - This is the name of "Command Prompt", as localized in Windows. The localization here should match the one in the Windows product for "Command Prompt" - Cancel @@ -393,198 +381,9 @@ No matching commands - - Close window - - - Toggle focus mode - "Focus mode" is a mode with minimal UI elements, for a distraction-free experience - - - Toggle fullscreen - - - Toggle always on top mode - - - Open new tab dropdown - - - Open settings file - - - Open default settings file - - - Open both settings and default settings files - - - Find - - - Resize pane - - - Move focus - - - Move focus {0} - {0} will be replaced with one of the four directions "DirectionLeft", "DirectionRight", "DirectionUp", or "DirectionDown" - - - Resize pane {0} - {0} will be replaced with one of the four directions "DirectionLeft", "DirectionRight", "DirectionUp", or "DirectionDown" - - - left - - - right - - - up - - - down - - - Switch to tab - - - New tab - - - Send Input: "{0}" - {0} will be replaced with a string of input as defined by the user - - - Split pane - - - Toggle pane zoom - - - New window - - - Duplicate tab - - - Duplicate pane - - - Next tab - - - Previous tab - - - Close pane - - - Close tab - - - Split pane horizontally - - - Split pane vertically - - - Copy text - - - Copy text as a single line - - - Paste - - - Scroll down one line - - - Scroll down one page - - - Scroll up one line - - - Scroll up one page - - - Adjust font size - - - Increase font size - - - Decrease font size - - - Increase font size, amount: {0} - {0} will be replaced with a positive number - - - Decrease font size, amount: {0} - {0} will be replaced with a positive number - - - Reset font size - - - Toggle retro terminal effect - - - Toggle command palette - Command Palette - - Set color scheme to {0} - {0} will be replaced with the name of a color scheme as defined by the user. - - - Set tab color to {0} - {0} will be replaced with a color, displayed in hexadecimal (#RRGGBB) notation. - - - Reset tab color - - - Set the tab color... - - - Rename tab to "{0}" - {0} will be replaced with a user-defined string - - - Reset tab title - - - Run commandline "{0}" in this window - {0} will be replaced with a user-defined commandline - - - Close tabs other than index {0} - {0} will be replaced with a number - - - Close tabs after index {0} - {0} will be replaced with a number - - - Select color scheme... - - - Search for tab... - - - New Tab... - - - Split Pane... - Tab Switcher @@ -646,12 +445,6 @@ Dark Gray - - Close all other tabs - - - Close all tabs after the current tab - This link is invalid: diff --git a/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp b/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp index cce86db1988..0e1940efd0e 100644 --- a/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp +++ b/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp @@ -7,6 +7,7 @@ #include "ShortcutActionDispatch.g.cpp" using namespace winrt::Microsoft::Terminal; +using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace winrt::TerminalApp; namespace winrt::TerminalApp::implementation @@ -23,99 +24,99 @@ namespace winrt::TerminalApp::implementation { const auto& action = actionAndArgs.Action(); const auto& args = actionAndArgs.Args(); - auto eventArgs = args ? winrt::make_self(args) : - winrt::make_self(); + auto eventArgs = args ? ActionEventArgs{ args } : + ActionEventArgs{}; switch (action) { case ShortcutAction::CopyText: { - _CopyTextHandlers(*this, *eventArgs); + _CopyTextHandlers(*this, eventArgs); break; } case ShortcutAction::PasteText: { - _PasteTextHandlers(*this, *eventArgs); + _PasteTextHandlers(*this, eventArgs); break; } case ShortcutAction::OpenNewTabDropdown: { - _OpenNewTabDropdownHandlers(*this, *eventArgs); + _OpenNewTabDropdownHandlers(*this, eventArgs); break; } case ShortcutAction::DuplicateTab: { - _DuplicateTabHandlers(*this, *eventArgs); + _DuplicateTabHandlers(*this, eventArgs); break; } case ShortcutAction::OpenSettings: { - _OpenSettingsHandlers(*this, *eventArgs); + _OpenSettingsHandlers(*this, eventArgs); break; } case ShortcutAction::NewTab: { - _NewTabHandlers(*this, *eventArgs); + _NewTabHandlers(*this, eventArgs); break; } case ShortcutAction::NewWindow: { - _NewWindowHandlers(*this, *eventArgs); + _NewWindowHandlers(*this, eventArgs); break; } case ShortcutAction::CloseWindow: { - _CloseWindowHandlers(*this, *eventArgs); + _CloseWindowHandlers(*this, eventArgs); break; } case ShortcutAction::CloseTab: { - _CloseTabHandlers(*this, *eventArgs); + _CloseTabHandlers(*this, eventArgs); break; } case ShortcutAction::ClosePane: { - _ClosePaneHandlers(*this, *eventArgs); + _ClosePaneHandlers(*this, eventArgs); break; } case ShortcutAction::ScrollUp: { - _ScrollUpHandlers(*this, *eventArgs); + _ScrollUpHandlers(*this, eventArgs); break; } case ShortcutAction::ScrollDown: { - _ScrollDownHandlers(*this, *eventArgs); + _ScrollDownHandlers(*this, eventArgs); break; } case ShortcutAction::ScrollUpPage: { - _ScrollUpPageHandlers(*this, *eventArgs); + _ScrollUpPageHandlers(*this, eventArgs); break; } case ShortcutAction::ScrollDownPage: { - _ScrollDownPageHandlers(*this, *eventArgs); + _ScrollDownPageHandlers(*this, eventArgs); break; } case ShortcutAction::NextTab: { - _NextTabHandlers(*this, *eventArgs); + _NextTabHandlers(*this, eventArgs); break; } case ShortcutAction::PrevTab: { - _PrevTabHandlers(*this, *eventArgs); + _PrevTabHandlers(*this, eventArgs); break; } case ShortcutAction::SendInput: { - _SendInputHandlers(*this, *eventArgs); + _SendInputHandlers(*this, eventArgs); break; } @@ -123,118 +124,118 @@ namespace winrt::TerminalApp::implementation case ShortcutAction::SplitHorizontal: case ShortcutAction::SplitPane: { - _SplitPaneHandlers(*this, *eventArgs); + _SplitPaneHandlers(*this, eventArgs); break; } case ShortcutAction::TogglePaneZoom: { - _TogglePaneZoomHandlers(*this, *eventArgs); + _TogglePaneZoomHandlers(*this, eventArgs); break; } case ShortcutAction::SwitchToTab: { - _SwitchToTabHandlers(*this, *eventArgs); + _SwitchToTabHandlers(*this, eventArgs); break; } case ShortcutAction::ResizePane: { - _ResizePaneHandlers(*this, *eventArgs); + _ResizePaneHandlers(*this, eventArgs); break; } case ShortcutAction::MoveFocus: { - _MoveFocusHandlers(*this, *eventArgs); + _MoveFocusHandlers(*this, eventArgs); break; } case ShortcutAction::AdjustFontSize: { - _AdjustFontSizeHandlers(*this, *eventArgs); + _AdjustFontSizeHandlers(*this, eventArgs); break; } case ShortcutAction::Find: { - _FindHandlers(*this, *eventArgs); + _FindHandlers(*this, eventArgs); break; } case ShortcutAction::ResetFontSize: { - _ResetFontSizeHandlers(*this, *eventArgs); + _ResetFontSizeHandlers(*this, eventArgs); break; } case ShortcutAction::ToggleRetroEffect: { - _ToggleRetroEffectHandlers(*this, *eventArgs); + _ToggleRetroEffectHandlers(*this, eventArgs); break; } case ShortcutAction::ToggleFocusMode: { - _ToggleFocusModeHandlers(*this, *eventArgs); + _ToggleFocusModeHandlers(*this, eventArgs); break; } case ShortcutAction::ToggleFullscreen: { - _ToggleFullscreenHandlers(*this, *eventArgs); + _ToggleFullscreenHandlers(*this, eventArgs); break; } case ShortcutAction::ToggleAlwaysOnTop: { - _ToggleAlwaysOnTopHandlers(*this, *eventArgs); + _ToggleAlwaysOnTopHandlers(*this, eventArgs); break; } case ShortcutAction::ToggleCommandPalette: { - _ToggleCommandPaletteHandlers(*this, *eventArgs); + _ToggleCommandPaletteHandlers(*this, eventArgs); break; } case ShortcutAction::SetColorScheme: { - _SetColorSchemeHandlers(*this, *eventArgs); + _SetColorSchemeHandlers(*this, eventArgs); break; } case ShortcutAction::SetTabColor: { - _SetTabColorHandlers(*this, *eventArgs); + _SetTabColorHandlers(*this, eventArgs); break; } case ShortcutAction::OpenTabColorPicker: { - _OpenTabColorPickerHandlers(*this, *eventArgs); + _OpenTabColorPickerHandlers(*this, eventArgs); break; } case ShortcutAction::RenameTab: { - _RenameTabHandlers(*this, *eventArgs); + _RenameTabHandlers(*this, eventArgs); break; } case ShortcutAction::ExecuteCommandline: { - _ExecuteCommandlineHandlers(*this, *eventArgs); + _ExecuteCommandlineHandlers(*this, eventArgs); break; } case ShortcutAction::CloseOtherTabs: { - _CloseOtherTabsHandlers(*this, *eventArgs); + _CloseOtherTabsHandlers(*this, eventArgs); break; } case ShortcutAction::CloseTabsAfter: { - _CloseTabsAfterHandlers(*this, *eventArgs); + _CloseTabsAfterHandlers(*this, eventArgs); break; } case ShortcutAction::TabSearch: { - _TabSearchHandlers(*this, *eventArgs); + _TabSearchHandlers(*this, eventArgs); break; } default: return false; } - return eventArgs->Handled(); + return eventArgs.Handled(); } } diff --git a/src/cascadia/TerminalApp/ShortcutActionDispatch.h b/src/cascadia/TerminalApp/ShortcutActionDispatch.h index caecb41ef77..a42a2191ca1 100644 --- a/src/cascadia/TerminalApp/ShortcutActionDispatch.h +++ b/src/cascadia/TerminalApp/ShortcutActionDispatch.h @@ -4,7 +4,6 @@ #pragma once #include "ShortcutActionDispatch.g.h" -#include "ActionArgs.h" #include "..\inc\cppwinrt_utils.h" // fwdecl unittest classes @@ -20,47 +19,47 @@ namespace winrt::TerminalApp::implementation { ShortcutActionDispatch() = default; - bool DoAction(const ActionAndArgs& actionAndArgs); + bool DoAction(const Microsoft::Terminal::Settings::Model::ActionAndArgs& actionAndArgs); // clang-format off - TYPED_EVENT(CopyText, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(PasteText, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(OpenNewTabDropdown, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(DuplicateTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(NewTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(NewWindow, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(CloseWindow, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(CloseTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(ClosePane, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(SwitchToTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(NextTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(PrevTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(SendInput, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(SplitPane, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(TogglePaneZoom, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(AdjustFontSize, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(ResetFontSize, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(ScrollUp, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(ScrollDown, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(ScrollUpPage, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(ScrollDownPage, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(OpenSettings, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(ResizePane, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(Find, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(MoveFocus, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(ToggleRetroEffect, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(ToggleFocusMode, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(ToggleFullscreen, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(ToggleAlwaysOnTop, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(ToggleCommandPalette, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(SetColorScheme, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(SetTabColor, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(OpenTabColorPicker, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(RenameTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(ExecuteCommandline, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(CloseOtherTabs, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(CloseTabsAfter, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(TabSearch, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); + TYPED_EVENT(CopyText, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(PasteText, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(OpenNewTabDropdown, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(DuplicateTab, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(NewTab, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(NewWindow, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(CloseWindow, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(CloseTab, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(ClosePane, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(SwitchToTab, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(NextTab, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(PrevTab, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(SendInput, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(SplitPane, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(TogglePaneZoom, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(AdjustFontSize, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(ResetFontSize, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(ScrollUp, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(ScrollDown, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(ScrollUpPage, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(ScrollDownPage, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(OpenSettings, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(ResizePane, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(Find, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(MoveFocus, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(ToggleRetroEffect, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(ToggleFocusMode, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(ToggleFullscreen, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(ToggleAlwaysOnTop, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(ToggleCommandPalette, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(SetColorScheme, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(SetTabColor, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(OpenTabColorPicker, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(RenameTab, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(ExecuteCommandline, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(CloseOtherTabs, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(CloseTabsAfter, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); + TYPED_EVENT(TabSearch, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs); // clang-format on private: diff --git a/src/cascadia/TerminalApp/ShortcutActionDispatch.idl b/src/cascadia/TerminalApp/ShortcutActionDispatch.idl index d84f662e31f..91d1bea8189 100644 --- a/src/cascadia/TerminalApp/ShortcutActionDispatch.idl +++ b/src/cascadia/TerminalApp/ShortcutActionDispatch.idl @@ -1,51 +1,50 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import "KeyMapping.idl"; namespace TerminalApp { [default_interface] runtimeclass ShortcutActionDispatch { ShortcutActionDispatch(); - Boolean DoAction(ActionAndArgs actionAndArgs); + Boolean DoAction(Microsoft.Terminal.Settings.Model.ActionAndArgs actionAndArgs); - event Windows.Foundation.TypedEventHandler CopyText; - event Windows.Foundation.TypedEventHandler PasteText; - event Windows.Foundation.TypedEventHandler NewTab; - event Windows.Foundation.TypedEventHandler OpenNewTabDropdown; - event Windows.Foundation.TypedEventHandler DuplicateTab; - event Windows.Foundation.TypedEventHandler NewWindow; - event Windows.Foundation.TypedEventHandler CloseWindow; - event Windows.Foundation.TypedEventHandler CloseTab; - event Windows.Foundation.TypedEventHandler ClosePane; - event Windows.Foundation.TypedEventHandler SwitchToTab; - event Windows.Foundation.TypedEventHandler NextTab; - event Windows.Foundation.TypedEventHandler PrevTab; - event Windows.Foundation.TypedEventHandler SendInput; - event Windows.Foundation.TypedEventHandler SplitPane; - event Windows.Foundation.TypedEventHandler TogglePaneZoom; - event Windows.Foundation.TypedEventHandler AdjustFontSize; - event Windows.Foundation.TypedEventHandler ResetFontSize; - event Windows.Foundation.TypedEventHandler ScrollUp; - event Windows.Foundation.TypedEventHandler ScrollDown; - event Windows.Foundation.TypedEventHandler ScrollUpPage; - event Windows.Foundation.TypedEventHandler ScrollDownPage; - event Windows.Foundation.TypedEventHandler OpenSettings; - event Windows.Foundation.TypedEventHandler ResizePane; - event Windows.Foundation.TypedEventHandler Find; - event Windows.Foundation.TypedEventHandler MoveFocus; - event Windows.Foundation.TypedEventHandler ToggleRetroEffect; - event Windows.Foundation.TypedEventHandler ToggleFocusMode; - event Windows.Foundation.TypedEventHandler ToggleFullscreen; - event Windows.Foundation.TypedEventHandler ToggleAlwaysOnTop; - event Windows.Foundation.TypedEventHandler ToggleCommandPalette; - event Windows.Foundation.TypedEventHandler SetColorScheme; - event Windows.Foundation.TypedEventHandler SetTabColor; - event Windows.Foundation.TypedEventHandler OpenTabColorPicker; - event Windows.Foundation.TypedEventHandler RenameTab; - event Windows.Foundation.TypedEventHandler ExecuteCommandline; - event Windows.Foundation.TypedEventHandler CloseOtherTabs; - event Windows.Foundation.TypedEventHandler CloseTabsAfter; - event Windows.Foundation.TypedEventHandler TabSearch; + event Windows.Foundation.TypedEventHandler CopyText; + event Windows.Foundation.TypedEventHandler PasteText; + event Windows.Foundation.TypedEventHandler NewTab; + event Windows.Foundation.TypedEventHandler OpenNewTabDropdown; + event Windows.Foundation.TypedEventHandler DuplicateTab; + event Windows.Foundation.TypedEventHandler NewWindow; + event Windows.Foundation.TypedEventHandler CloseWindow; + event Windows.Foundation.TypedEventHandler CloseTab; + event Windows.Foundation.TypedEventHandler ClosePane; + event Windows.Foundation.TypedEventHandler SwitchToTab; + event Windows.Foundation.TypedEventHandler NextTab; + event Windows.Foundation.TypedEventHandler PrevTab; + event Windows.Foundation.TypedEventHandler SendInput; + event Windows.Foundation.TypedEventHandler SplitPane; + event Windows.Foundation.TypedEventHandler TogglePaneZoom; + event Windows.Foundation.TypedEventHandler AdjustFontSize; + event Windows.Foundation.TypedEventHandler ResetFontSize; + event Windows.Foundation.TypedEventHandler ScrollUp; + event Windows.Foundation.TypedEventHandler ScrollDown; + event Windows.Foundation.TypedEventHandler ScrollUpPage; + event Windows.Foundation.TypedEventHandler ScrollDownPage; + event Windows.Foundation.TypedEventHandler OpenSettings; + event Windows.Foundation.TypedEventHandler ResizePane; + event Windows.Foundation.TypedEventHandler Find; + event Windows.Foundation.TypedEventHandler MoveFocus; + event Windows.Foundation.TypedEventHandler ToggleRetroEffect; + event Windows.Foundation.TypedEventHandler ToggleFocusMode; + event Windows.Foundation.TypedEventHandler ToggleFullscreen; + event Windows.Foundation.TypedEventHandler ToggleAlwaysOnTop; + event Windows.Foundation.TypedEventHandler ToggleCommandPalette; + event Windows.Foundation.TypedEventHandler SetColorScheme; + event Windows.Foundation.TypedEventHandler SetTabColor; + event Windows.Foundation.TypedEventHandler OpenTabColorPicker; + event Windows.Foundation.TypedEventHandler RenameTab; + event Windows.Foundation.TypedEventHandler ExecuteCommandline; + event Windows.Foundation.TypedEventHandler CloseOtherTabs; + event Windows.Foundation.TypedEventHandler CloseTabsAfter; + event Windows.Foundation.TypedEventHandler TabSearch; } } diff --git a/src/cascadia/TerminalApp/Tab.cpp b/src/cascadia/TerminalApp/Tab.cpp index f7d33efd754..cd494049f38 100644 --- a/src/cascadia/TerminalApp/Tab.cpp +++ b/src/cascadia/TerminalApp/Tab.cpp @@ -8,13 +8,12 @@ #include "Tab.g.cpp" #include "Utils.h" #include "ColorHelper.h" -#include "ActionAndArgs.h" -#include "ActionArgs.h" using namespace winrt; using namespace winrt::Windows::UI::Xaml; using namespace winrt::Windows::UI::Core; using namespace winrt::Microsoft::Terminal::TerminalControl; +using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace winrt::Windows::System; namespace winrt @@ -304,7 +303,7 @@ namespace winrt::TerminalApp::implementation // - splitType: The type of split we want to create. // Return Value: // - True if the focused pane can be split. False otherwise. - bool Tab::CanSplitPane(winrt::TerminalApp::SplitState splitType) + bool Tab::CanSplitPane(SplitState splitType) { return _activePane->CanSplit(splitType); } @@ -318,7 +317,7 @@ namespace winrt::TerminalApp::implementation // - control: A TermControl to use in the new pane. // Return Value: // - - void Tab::SplitPane(winrt::TerminalApp::SplitState splitType, const GUID& profile, TermControl& control) + void Tab::SplitPane(SplitState splitType, const GUID& profile, TermControl& control) { auto [first, second] = _activePane->Split(splitType, profile, control); _activePane = first; @@ -364,7 +363,7 @@ namespace winrt::TerminalApp::implementation // - direction: The direction to move the separator in. // Return Value: // - - void Tab::ResizePane(const winrt::TerminalApp::Direction& direction) + void Tab::ResizePane(const Direction& direction) { // NOTE: This _must_ be called on the root pane, so that it can propagate // throughout the entire tree. @@ -378,7 +377,7 @@ namespace winrt::TerminalApp::implementation // - direction: The direction to move the focus in. // Return Value: // - - void Tab::NavigateFocus(const winrt::TerminalApp::Direction& direction) + void Tab::NavigateFocus(const Direction& direction) { // NOTE: This _must_ be called on the root pane, so that it can propagate // throughout the entire tree. @@ -1043,15 +1042,11 @@ namespace winrt::TerminalApp::implementation // - void Tab::_MakeSwitchToTabCommand() { - auto focusTabAction = winrt::make_self(); - auto args = winrt::make_self(); - args->TabIndex(_TabViewIndex); + SwitchToTabArgs args{ _TabViewIndex }; + ActionAndArgs focusTabAction{ ShortcutAction::SwitchToTab, args }; - focusTabAction->Action(ShortcutAction::SwitchToTab); - focusTabAction->Args(*args); - - winrt::TerminalApp::Command command; - command.Action(*focusTabAction); + Command command; + command.Action(focusTabAction); command.Name(Title()); command.IconSource(IconSource()); @@ -1061,7 +1056,7 @@ namespace winrt::TerminalApp::implementation void Tab::UpdateTabViewIndex(const uint32_t idx) { TabViewIndex(idx); - SwitchToTabCommand().Action().Args().as()->TabIndex(idx); + SwitchToTabCommand().Action().Args().as().TabIndex(idx); } DEFINE_EVENT(Tab, ActivePaneChanged, _ActivePaneChangedHandlers, winrt::delegate<>); diff --git a/src/cascadia/TerminalApp/Tab.h b/src/cascadia/TerminalApp/Tab.h index 3b52488f5d0..02ce977d874 100644 --- a/src/cascadia/TerminalApp/Tab.h +++ b/src/cascadia/TerminalApp/Tab.h @@ -33,18 +33,18 @@ namespace winrt::TerminalApp::implementation winrt::fire_and_forget Scroll(const int delta); - bool CanSplitPane(winrt::TerminalApp::SplitState splitType); - void SplitPane(winrt::TerminalApp::SplitState splitType, const GUID& profile, winrt::Microsoft::Terminal::TerminalControl::TermControl& control); + bool CanSplitPane(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType); + void SplitPane(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType, const GUID& profile, winrt::Microsoft::Terminal::TerminalControl::TermControl& control); winrt::fire_and_forget UpdateIcon(const winrt::hstring iconPath); float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const; - SplitState PreCalculateAutoSplit(winrt::Windows::Foundation::Size rootSize) const; - bool PreCalculateCanSplit(SplitState splitType, winrt::Windows::Foundation::Size availableSpace) const; + winrt::Microsoft::Terminal::Settings::Model::SplitState PreCalculateAutoSplit(winrt::Windows::Foundation::Size rootSize) const; + bool PreCalculateCanSplit(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType, winrt::Windows::Foundation::Size availableSpace) const; void ResizeContent(const winrt::Windows::Foundation::Size& newSize); - void ResizePane(const winrt::TerminalApp::Direction& direction); - void NavigateFocus(const winrt::TerminalApp::Direction& direction); + void ResizePane(const winrt::Microsoft::Terminal::Settings::Model::Direction& direction); + void NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::Direction& direction); void UpdateSettings(const winrt::TerminalApp::TerminalSettings& settings, const GUID& profile); winrt::hstring GetActiveTitle() const; @@ -78,7 +78,7 @@ namespace winrt::TerminalApp::implementation OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Title, _PropertyChangedHandlers); OBSERVABLE_GETSET_PROPERTY(winrt::Windows::UI::Xaml::Controls::IconSource, IconSource, _PropertyChangedHandlers, nullptr); - OBSERVABLE_GETSET_PROPERTY(winrt::TerminalApp::Command, SwitchToTabCommand, _PropertyChangedHandlers, nullptr); + OBSERVABLE_GETSET_PROPERTY(winrt::Microsoft::Terminal::Settings::Model::Command, SwitchToTabCommand, _PropertyChangedHandlers, nullptr); // The TabViewIndex is the index this Tab object resides in TerminalPage's _tabs vector. // This is needed since Tab is going to be managing its own SwitchToTab command. diff --git a/src/cascadia/TerminalApp/Tab.idl b/src/cascadia/TerminalApp/Tab.idl index ceb52a55f8f..b02e4da0f4b 100644 --- a/src/cascadia/TerminalApp/Tab.idl +++ b/src/cascadia/TerminalApp/Tab.idl @@ -1,15 +1,13 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import "Command.idl"; - namespace TerminalApp { [default_interface] runtimeclass Tab : Windows.UI.Xaml.Data.INotifyPropertyChanged { String Title { get; }; Windows.UI.Xaml.Controls.IconSource IconSource { get; }; - Command SwitchToTabCommand { get; }; + Microsoft.Terminal.Settings.Model.Command SwitchToTabCommand { get; }; UInt32 TabViewIndex { get; }; } } diff --git a/src/cascadia/TerminalApp/TelnetGenerator.h b/src/cascadia/TerminalApp/TelnetGenerator.h deleted file mode 100644 index c7356b65fd9..00000000000 --- a/src/cascadia/TerminalApp/TelnetGenerator.h +++ /dev/null @@ -1,19 +0,0 @@ -/*++ -Copyright (c) Microsoft Corporation -Licensed under the MIT license. - -Module Name: -- TelnetGenerator - -Abstract: -- Information needed to detect a Telnet connection type. - -Author(s): -- Michael Niksa - 2019-12-05 - ---*/ - -#pragma once - -// {311153fb-d3f0-4ac6-b920-038de7cf5289} -static constexpr winrt::guid TelnetConnectionType = { 0x311153fb, 0xd3f0, 0x4ac6, { 0xb9, 0x20, 0x03, 0x8d, 0xe7, 0xcf, 0x52, 0x89 } }; diff --git a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj index 9a799688d8f..af7afce7e3b 100644 --- a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj +++ b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj @@ -92,9 +92,6 @@ CommandPalette.xaml - - Command.idl - EmptyStringVisibilityConverter.idl @@ -105,31 +102,7 @@ Tab.idl - - ColorScheme.idl - - - GlobalAppSettings.idl - - - Profile.idl - - - CascadiaSettings.idl - - - - - - - TerminalWarnings.idl - - - - - - TerminalSettings.idl @@ -138,19 +111,10 @@ ShortcutActionDispatch.idl - - ActionArgs.idl - - - ActionArgs.idl - AppKeyBindings.idl - - KeyMapping.idl - App.xaml @@ -183,9 +147,6 @@ CommandPalette.xaml - - Command.idl - EmptyStringVisibilityConverter.idl @@ -196,33 +157,9 @@ Tab.idl - - ColorScheme.idl - - - GlobalAppSettings.idl - - - Profile.idl - - - CascadiaSettings.idl - - - CascadiaSettings.idl - - - KeyMapping.idl - - - - - - - TerminalSettings.idl @@ -232,18 +169,9 @@ AppKeyBindings.idl - - KeyMapping.idl - ShortcutActionDispatch.idl - - ActionArgs.idl - - - ActionArgs.idl - App.xaml @@ -253,11 +181,6 @@ AppLogic.idl - - - NotUsing - @@ -270,9 +193,7 @@ - - MinMaxCloseControl.xaml Code @@ -297,16 +218,10 @@ CommandPalette.xaml Code - - - - - - @@ -358,12 +273,18 @@ false false + + $(_BinRoot)Microsoft.Terminal.Settings.Model\Microsoft.Terminal.Settings.Model.winmd + true + false + false + pch.h - ..;$(OpenConsoleDir)\dep\jsoncpp\json;%(AdditionalIncludeDirectories); + ..;%(AdditionalIncludeDirectories); 4702;%(DisableSpecificWarnings) @@ -403,20 +324,6 @@ - - - - - - - - - - - - diff --git a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj.filters b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj.filters index e8949cbdfe6..8fe72119571 100644 --- a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj.filters +++ b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj.filters @@ -10,45 +10,9 @@ - - profileGeneration - - - profileGeneration - - - profileGeneration - - - settings - - - settings - - - settings - - - settings - - - settings - - - settings - - - settings - pane - - profileGeneration - - - json - tab @@ -71,45 +35,9 @@ app - - profileGeneration - - - profileGeneration - - - profileGeneration - - - profileGeneration - - - settings - - - settings - - - settings - - - settings - - - settings - - - settings - pane - - profileGeneration - - - json - tab @@ -134,32 +62,17 @@ settings - - settings - settings tab - - commandPalette - settings - - settings - - - settings - - - settings - @@ -188,9 +101,6 @@ {21588d0a-fa81-4306-828d-c095af895b9e} - - {c81be61b-0d58-4277-8fd1-fcc888c3da9c} - {27ff86d8-2a62-4787-b55a-2ec1db32abec} @@ -200,9 +110,6 @@ {2455d67b-17ef-4cdd-ad9e-eb8ec4412e03} - - {81a6314f-aa5b-4533-a499-13bc3a5c4af0} - {6d40e12f-b83f-462e-8f93-fa421f87b27e} diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 8dc7142a3f0..2db068d8b1e 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -3,7 +3,6 @@ #include "pch.h" #include "TerminalPage.h" -#include "ActionAndArgs.h" #include "Utils.h" #include "AppLogic.h" #include "../../types/inc/utils.hpp" @@ -14,9 +13,6 @@ #include #include -#include "KeyChordSerialization.h" -#include "AzureCloudShellGenerator.h" // For AzureConnectionType -#include "TelnetGenerator.h" // For TelnetConnectionType #include "TabRowControl.h" #include "ColorHelper.h" #include "DebugTapConnection.h" @@ -32,6 +28,7 @@ using namespace winrt::Windows::UI::Text; using namespace winrt::Microsoft::Terminal; using namespace winrt::Microsoft::Terminal::TerminalControl; using namespace winrt::Microsoft::Terminal::TerminalConnection; +using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace ::TerminalApp; using namespace ::Microsoft::Console; @@ -46,7 +43,7 @@ namespace winrt::TerminalApp::implementation { TerminalPage::TerminalPage() : _tabs{ winrt::single_threaded_observable_vector() }, - _startupActions{ winrt::single_threaded_vector() } + _startupActions{ winrt::single_threaded_vector() } { InitializeComponent(); } @@ -59,8 +56,8 @@ namespace winrt::TerminalApp::implementation // Arguments: // - settings: The settings who's keybindings we should use to look up the key chords from // - commands: The list of commands to label. - static void _recursiveUpdateCommandKeybindingLabels(TerminalApp::CascadiaSettings settings, - IMapView commands) + static void _recursiveUpdateCommandKeybindingLabels(CascadiaSettings settings, + IMapView commands) { for (const auto& nameAndCmd : commands) { @@ -83,7 +80,71 @@ namespace winrt::TerminalApp::implementation } } - static void _recursiveUpdateCommandIcons(IMapView commands) + // Method Description: + // - Set the command's IconSource. Supports a variety of icons: + // * If the icon is a path to an image, we'll use that. + // * If it isn't, then we'll try and use the text as a FontIcon. If the + // character is in the range of symbols reserved for the Segoe MDL2 + // Asserts, well treat it as such. Otherwise, we'll default to a Sego + // UI icon, so things like emoji will work. + // - MUST BE CALLED ON THE UI THREAD. + // Arguments: + // - cmd - the command that we're updating IconSource for + // Return Value: + // - + static void _refreshIcon(const Command& cmd) + { + if (cmd.IconPath().size() != 0) + { + cmd.IconSource(GetColoredIcon(cmd.IconPath())); + + // If we fail to set the icon source using the "icon" as a path, + // let's try it as a symbol/emoji. + // + // Anything longer that 2 wchar_t's _isn't_ an emoji or symbol, so + // don't do this if it's just an invalid path. + if (cmd.IconSource() == nullptr && cmd.IconPath().size() <= 2) + { + try + { + WUX::Controls::FontIconSource icon; + const wchar_t ch = cmd.IconPath()[0]; + + // The range of MDL2 Icons isn't explicitly defined, but + // we're using this based off the table on: + // https://docs.microsoft.com/en-us/windows/uwp/design/style/segoe-ui-symbol-font + const bool isMDL2Icon = ch >= L'\uE700' && ch <= L'\uF8FF'; + if (isMDL2Icon) + { + icon.FontFamily(WUX::Media::FontFamily{ L"Segoe MDL2 Assets" }); + } + else + { + // Note: you _do_ need to manually set the font here. + icon.FontFamily(WUX::Media::FontFamily{ L"Segoe UI" }); + } + icon.FontSize(12); + icon.Glyph(cmd.IconPath()); + cmd.IconSource(icon); + } + CATCH_LOG(); + } + } + if (cmd.IconSource() == nullptr) + { + // Set the default IconSource to a BitmapIconSource with a null source + // (instead of just nullptr) because there's a really weird crash when swapping + // data bound IconSourceElements in a ListViewTemplate (i.e. CommandPalette). + // Swapping between nullptr IconSources and non-null IconSources causes a crash + // to occur, but swapping between IconSources with a null source and non-null IconSources + // work perfectly fine :shrug:. + winrt::Windows::UI::Xaml::Controls::BitmapIconSource icon; + icon.UriSource(nullptr); + cmd.IconSource(icon); + } + } + + static void _recursiveUpdateCommandIcons(IMapView commands) { for (const auto& nameAndCmd : commands) { @@ -92,7 +153,7 @@ namespace winrt::TerminalApp::implementation // !!! LOAD-BEARING !!! If this is never called, then Commands will // have a nullptr icon. If they do, a really weird crash can occur. // MAKE SURE this is called once after a settings load. - command.RefreshIcon(); + _refreshIcon(command); if (command.HasNestedCommands()) { @@ -101,7 +162,7 @@ namespace winrt::TerminalApp::implementation } } - winrt::fire_and_forget TerminalPage::SetSettings(TerminalApp::CascadiaSettings settings, bool needRefreshUI) + winrt::fire_and_forget TerminalPage::SetSettings(CascadiaSettings settings, bool needRefreshUI) { _settings = settings; if (needRefreshUI) @@ -213,8 +274,8 @@ namespace winrt::TerminalApp::implementation if (altPressed && !debugTap) { - page->_SplitPane(TerminalApp::SplitState::Automatic, - TerminalApp::SplitType::Manual, + page->_SplitPane(SplitState::Automatic, + SplitType::Manual, nullptr); } else @@ -308,7 +369,7 @@ namespace winrt::TerminalApp::implementation // should fire an Initialized event. // Return Value: // - - winrt::fire_and_forget TerminalPage::_ProcessStartupActions(Windows::Foundation::Collections::IVector actions, + winrt::fire_and_forget TerminalPage::_ProcessStartupActions(Windows::Foundation::Collections::IVector actions, const bool initial) { // If there are no actions left, do nothing. @@ -330,7 +391,7 @@ namespace winrt::TerminalApp::implementation } else { - return; + co_return; } } } @@ -368,22 +429,12 @@ namespace winrt::TerminalApp::implementation winrt::hstring TerminalPage::ApplicationDisplayName() { - if (const auto appLogic{ implementation::AppLogic::Current() }) - { - return appLogic->ApplicationDisplayName(); - } - - return RS_(L"ApplicationDisplayNameUnpackaged"); + return CascadiaSettings::ApplicationDisplayName(); } winrt::hstring TerminalPage::ApplicationVersion() { - if (const auto appLogic{ implementation::AppLogic::Current() }) - { - return appLogic->ApplicationVersion(); - } - - return RS_(L"ApplicationVersionUnknown"); + return CascadiaSettings::ApplicationVersion(); } void TerminalPage::_ThirdPartyNoticesOnClick(const IInspectable& /*sender*/, const Windows::UI::Xaml::RoutedEventArgs& /*eventArgs*/) @@ -462,14 +513,10 @@ namespace winrt::TerminalApp::implementation // Add the keyboard shortcuts based on the number of profiles defined // Look for a keychord that is bound to the equivalent // NewTab(ProfileIndex=N) action - auto actionAndArgs = winrt::make_self(); - actionAndArgs->Action(ShortcutAction::NewTab); - auto newTabArgs = winrt::make_self(); - auto newTerminalArgs = winrt::make_self(); - newTerminalArgs->ProfileIndex(profileIndex); - newTabArgs->TerminalArgs(*newTerminalArgs); - actionAndArgs->Args(*newTabArgs); - auto profileKeyChord{ keyBindings.GetKeyBindingForActionWithArgs(*actionAndArgs) }; + NewTerminalArgs newTerminalArgs{ profileIndex }; + NewTabArgs newTabArgs{ newTerminalArgs }; + ActionAndArgs actionAndArgs{ ShortcutAction::NewTab, newTabArgs }; + auto profileKeyChord{ keyBindings.GetKeyBindingForActionWithArgs(actionAndArgs) }; // make sure we find one to display if (profileKeyChord) @@ -501,8 +548,7 @@ namespace winrt::TerminalApp::implementation profileMenuItem.Click([profileIndex, weakThis{ get_weak() }](auto&&, auto&&) { if (auto page{ weakThis.get() }) { - auto newTerminalArgs = winrt::make_self(); - newTerminalArgs->ProfileIndex(profileIndex); + NewTerminalArgs newTerminalArgs{ profileIndex }; // if alt is pressed, open a pane const CoreWindow window = CoreWindow::GetForCurrentThread(); @@ -518,13 +564,13 @@ namespace winrt::TerminalApp::implementation if (altPressed && !debugTap) { - page->_SplitPane(TerminalApp::SplitState::Automatic, - TerminalApp::SplitType::Manual, - *newTerminalArgs); + page->_SplitPane(SplitState::Automatic, + SplitType::Manual, + newTerminalArgs); } else { - page->_OpenNewTab(*newTerminalArgs); + page->_OpenNewTab(newTerminalArgs); } } }); @@ -614,7 +660,7 @@ namespace winrt::TerminalApp::implementation // - newTerminalArgs: An object that may contain a blob of parameters to // control which profile is created and with possible other // configurations. See TerminalSettings::BuildSettings for more details. - void TerminalPage::_OpenNewTab(const winrt::TerminalApp::NewTerminalArgs& newTerminalArgs) + void TerminalPage::_OpenNewTab(const NewTerminalArgs& newTerminalArgs) try { auto [profileGuid, settings] = TerminalSettings::BuildSettings(_settings, newTerminalArgs, *_bindings); @@ -781,7 +827,7 @@ namespace winrt::TerminalApp::implementation } if (hasConnectionType && - connectionType == AzureConnectionType && + connectionType == TerminalConnection::AzureConnection::ConnectionType() && TerminalConnection::AzureConnection::IsAzureConnectionAvailable()) { // TODO GH#4661: Replace this with directly using the AzCon when our VT is better @@ -797,7 +843,7 @@ namespace winrt::TerminalApp::implementation } else if (hasConnectionType && - connectionType == TelnetConnectionType) + connectionType == TerminalConnection::TelnetConnection::ConnectionType()) { connection = TerminalConnection::TelnetConnection(settings.Commandline()); } @@ -885,7 +931,7 @@ namespace winrt::TerminalApp::implementation // as the object to handle dispatching ShortcutAction events. // Arguments: // - bindings: A AppKeyBindings object to wire up with our event handlers - void TerminalPage::_HookupKeyBindings(const TerminalApp::KeyMapping& keymap) noexcept + void TerminalPage::_HookupKeyBindings(const KeyMapping& keymap) noexcept { _bindings->SetDispatch(*_actionDispatch); _bindings->SetKeyMapping(keymap); @@ -1439,12 +1485,12 @@ namespace winrt::TerminalApp::implementation // - newTerminalArgs: An object that may contain a blob of parameters to // control which profile is created and with possible other // configurations. See CascadiaSettings::BuildSettings for more details. - void TerminalPage::_SplitPane(const TerminalApp::SplitState splitType, - const TerminalApp::SplitType splitMode, - const winrt::TerminalApp::NewTerminalArgs& newTerminalArgs) + void TerminalPage::_SplitPane(const SplitState splitType, + const SplitType splitMode, + const NewTerminalArgs& newTerminalArgs) { // Do nothing if we're requesting no split. - if (splitType == TerminalApp::SplitState::None) + if (splitType == SplitState::None) { return; } @@ -1464,7 +1510,7 @@ namespace winrt::TerminalApp::implementation GUID realGuid; bool profileFound = false; - if (splitMode == TerminalApp::SplitType::Duplicate) + if (splitMode == SplitType::Duplicate) { std::optional current_guid = focusedTab->GetFocusedProfile(); if (current_guid) @@ -1887,14 +1933,14 @@ namespace winrt::TerminalApp::implementation switch (target) { case SettingsTarget::DefaultsFile: - openFile(CascadiaSettings::GetDefaultSettingsPath()); + openFile(CascadiaSettings::DefaultSettingsPath()); break; case SettingsTarget::SettingsFile: - openFile(CascadiaSettings::GetSettingsPath()); + openFile(CascadiaSettings::SettingsPath()); break; case SettingsTarget::AllFiles: - openFile(CascadiaSettings::GetDefaultSettingsPath()); - openFile(CascadiaSettings::GetSettingsPath()); + openFile(CascadiaSettings::DefaultSettingsPath()); + openFile(CascadiaSettings::SettingsPath()); break; } } @@ -2104,7 +2150,7 @@ namespace winrt::TerminalApp::implementation } // 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) + static bool _compareSchemeNames(const ColorScheme& lhs, const ColorScheme& rhs) { std::wstring leftName{ lhs.Name() }; std::wstring rightName{ rhs.Name() }; @@ -2117,13 +2163,13 @@ namespace winrt::TerminalApp::implementation // - // Return Value: // - - IMap TerminalPage::_ExpandCommands(IMapView commandsToExpand, - IVectorView profiles, - IMapView schemes) + IMap TerminalPage::_ExpandCommands(IMapView commandsToExpand, + IVectorView profiles, + IMapView schemes) { - std::vector warnings; + IVector warnings; - std::vector sortedSchemes; + std::vector sortedSchemes; sortedSchemes.reserve(schemes.Size()); for (const auto& nameAndScheme : schemes) @@ -2134,7 +2180,7 @@ namespace winrt::TerminalApp::implementation sortedSchemes.end(), _compareSchemeNames); - IMap copyOfCommands = winrt::single_threaded_map(); + IMap copyOfCommands = winrt::single_threaded_map(); for (const auto& nameAndCommand : commandsToExpand) { copyOfCommands.Insert(nameAndCommand.Key(), nameAndCommand.Value()); @@ -2142,7 +2188,7 @@ namespace winrt::TerminalApp::implementation Command::ExpandCommands(copyOfCommands, profiles, - sortedSchemes, + { sortedSchemes }, warnings); return copyOfCommands; @@ -2157,15 +2203,15 @@ namespace winrt::TerminalApp::implementation // - void TerminalPage::_UpdateCommandsForPalette() { - IMap copyOfCommands = _ExpandCommands(_settings.GlobalSettings().Commands(), - _settings.Profiles().GetView(), - _settings.GlobalSettings().ColorSchemes()); + IMap copyOfCommands = _ExpandCommands(_settings.GlobalSettings().Commands(), + _settings.Profiles().GetView(), + _settings.GlobalSettings().ColorSchemes()); _recursiveUpdateCommandKeybindingLabels(_settings, copyOfCommands.GetView()); _recursiveUpdateCommandIcons(copyOfCommands.GetView()); // Update the command palette when settings reload - auto commandsCollection = winrt::single_threaded_vector(); + auto commandsCollection = winrt::single_threaded_vector(); for (const auto& nameAndCommand : copyOfCommands) { commandsCollection.Append(nameAndCommand.Value()); @@ -2182,13 +2228,13 @@ namespace winrt::TerminalApp::implementation // - actions: a list of Actions to process on startup. // Return Value: // - - void TerminalPage::SetStartupActions(std::vector& actions) + void TerminalPage::SetStartupActions(std::vector& actions) { // The fastest way to copy all the actions out of the std::vector and // put them into a winrt::IVector is by making a copy, then moving the // copy into the winrt vector ctor. auto listCopy = actions; - _startupActions = winrt::single_threaded_vector(std::move(listCopy)); + _startupActions = winrt::single_threaded_vector(std::move(listCopy)); } winrt::TerminalApp::IDialogPresenter TerminalPage::DialogPresenter() const @@ -2457,7 +2503,7 @@ namespace winrt::TerminalApp::implementation // - args: the ExecuteCommandlineArgs to synthesize a list of startup actions for. // Return Value: // - an empty list if we failed to parse, otherwise a list of actions to execute. - std::vector TerminalPage::ConvertExecuteCommandlineToActions(const TerminalApp::ExecuteCommandlineArgs& args) + std::vector TerminalPage::ConvertExecuteCommandlineToActions(const ExecuteCommandlineArgs& args) { if (!args || args.Commandline().empty()) { diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 540921c0c23..13d4a3341e0 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -5,8 +5,6 @@ #include "TerminalPage.g.h" #include "Tab.h" -#include "CascadiaSettings.h" -#include "Profile.h" #include "AppKeyBindings.h" #include "TerminalSettings.h" @@ -35,7 +33,7 @@ namespace winrt::TerminalApp::implementation public: TerminalPage(); - winrt::fire_and_forget SetSettings(TerminalApp::CascadiaSettings settings, bool needRefreshUI); + winrt::fire_and_forget SetSettings(Microsoft::Terminal::Settings::Model::CascadiaSettings settings, bool needRefreshUI); void Create(); @@ -59,8 +57,8 @@ namespace winrt::TerminalApp::implementation bool Fullscreen() const; bool AlwaysOnTop() const; - void SetStartupActions(std::vector& actions); - static std::vector ConvertExecuteCommandlineToActions(const TerminalApp::ExecuteCommandlineArgs& args); + void SetStartupActions(std::vector& actions); + static std::vector ConvertExecuteCommandlineToActions(const Microsoft::Terminal::Settings::Model::ExecuteCommandlineArgs& args); winrt::TerminalApp::IDialogPresenter DialogPresenter() const; void DialogPresenter(winrt::TerminalApp::IDialogPresenter dialogPresenter); @@ -88,7 +86,7 @@ namespace winrt::TerminalApp::implementation Windows::UI::Xaml::Controls::Grid _tabContent{ nullptr }; Microsoft::UI::Xaml::Controls::SplitButton _newTabButton{ nullptr }; - TerminalApp::CascadiaSettings _settings{ nullptr }; + Microsoft::Terminal::Settings::Model::CascadiaSettings _settings{ nullptr }; Windows::Foundation::Collections::IObservableVector _tabs; winrt::com_ptr _GetStrongTabImpl(const uint32_t index) const; @@ -112,8 +110,8 @@ namespace winrt::TerminalApp::implementation winrt::Windows::UI::Xaml::Controls::Grid::LayoutUpdated_revoker _layoutUpdatedRevoker; StartupState _startupState{ StartupState::NotInitialized }; - Windows::Foundation::Collections::IVector _startupActions; - winrt::fire_and_forget _ProcessStartupActions(Windows::Foundation::Collections::IVector actions, const bool initial); + Windows::Foundation::Collections::IVector _startupActions; + winrt::fire_and_forget _ProcessStartupActions(Windows::Foundation::Collections::IVector actions, const bool initial); void _ShowAboutDialog(); void _ShowCloseWarningDialog(); @@ -122,7 +120,7 @@ namespace winrt::TerminalApp::implementation void _CreateNewTabFlyout(); void _OpenNewTabDropdown(); - void _OpenNewTab(const winrt::TerminalApp::NewTerminalArgs& newTerminalArgs); + void _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs); void _CreateNewTabFromSettings(GUID profileGuid, TerminalApp::TerminalSettings settings); winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _CreateConnectionFromSettings(GUID profileGuid, TerminalApp::TerminalSettings settings); @@ -132,7 +130,7 @@ namespace winrt::TerminalApp::implementation void _CloseWarningPrimaryButtonOnClick(Windows::UI::Xaml::Controls::ContentDialog sender, Windows::UI::Xaml::Controls::ContentDialogButtonClickEventArgs eventArgs); void _ThirdPartyNoticesOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs); - void _HookupKeyBindings(const TerminalApp::KeyMapping& keymap) noexcept; + void _HookupKeyBindings(const Microsoft::Terminal::Settings::Model::KeyMapping& keymap) noexcept; void _RegisterActionCallbacks(); void _UpdateTitle(const Tab& tab); @@ -140,9 +138,9 @@ namespace winrt::TerminalApp::implementation void _UpdateTabView(); void _UpdateTabWidthMode(); void _UpdateCommandsForPalette(); - static winrt::Windows::Foundation::Collections::IMap _ExpandCommands(Windows::Foundation::Collections::IMapView commandsToExpand, - Windows::Foundation::Collections::IVectorView profiles, - Windows::Foundation::Collections::IMapView schemes); + static winrt::Windows::Foundation::Collections::IMap _ExpandCommands(Windows::Foundation::Collections::IMapView commandsToExpand, + Windows::Foundation::Collections::IVectorView profiles, + Windows::Foundation::Collections::IMapView schemes); void _DuplicateTabViewItem(); void _RemoveTabViewItem(const Microsoft::UI::Xaml::Controls::TabViewItem& tabViewItem); @@ -152,7 +150,7 @@ namespace winrt::TerminalApp::implementation void _SelectNextTab(const bool bMoveRight); bool _SelectTab(const uint32_t tabIndex); - void _MoveFocus(const Direction& direction); + void _MoveFocus(const Microsoft::Terminal::Settings::Model::Direction& direction); winrt::Microsoft::Terminal::TerminalControl::TermControl _GetActiveControl(); std::optional _GetFocusedTabIndex() const noexcept; @@ -167,8 +165,8 @@ namespace winrt::TerminalApp::implementation // Todo: add more event implementations here // MSFT:20641986: Add keybindings for New Window void _Scroll(int delta); - void _SplitPane(const winrt::TerminalApp::SplitState splitType, const winrt::TerminalApp::SplitType splitMode = winrt::TerminalApp::SplitType::Manual, const winrt::TerminalApp::NewTerminalArgs& newTerminalArgs = nullptr); - void _ResizePane(const Direction& direction); + void _SplitPane(const Microsoft::Terminal::Settings::Model::SplitState splitType, const Microsoft::Terminal::Settings::Model::SplitType splitMode = Microsoft::Terminal::Settings::Model::SplitType::Manual, const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr); + void _ResizePane(const Microsoft::Terminal::Settings::Model::Direction& direction); void _ScrollPage(int delta); void _SetAcceleratorForMenuItem(Windows::UI::Xaml::Controls::MenuFlyoutItem& menuItem, const winrt::Microsoft::Terminal::TerminalControl::KeyChord& keyChord); @@ -182,7 +180,7 @@ namespace winrt::TerminalApp::implementation void _PasteText(); - fire_and_forget _LaunchSettings(const winrt::TerminalApp::SettingsTarget target); + fire_and_forget _LaunchSettings(const Microsoft::Terminal::Settings::Model::SettingsTarget target); void _OnTabClick(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs); void _OnTabSelectionChanged(const IInspectable& sender, const Windows::UI::Xaml::Controls::SelectionChangedEventArgs& eventArgs); @@ -209,43 +207,43 @@ namespace winrt::TerminalApp::implementation #pragma region ActionHandlers // These are all defined in AppActionHandlers.cpp - void _HandleOpenNewTabDropdown(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleDuplicateTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleCloseTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleClosePane(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleScrollUp(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleScrollDown(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleNextTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandlePrevTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleSendInput(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleSplitPane(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleTogglePaneZoom(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleScrollUpPage(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleScrollDownPage(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleOpenSettings(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandlePasteText(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleNewTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleSwitchToTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleResizePane(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleMoveFocus(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleCopyText(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleCloseWindow(const IInspectable&, const TerminalApp::ActionEventArgs& args); - void _HandleAdjustFontSize(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleFind(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleResetFontSize(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleToggleRetroEffect(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleToggleFocusMode(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleToggleFullscreen(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleToggleAlwaysOnTop(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleSetColorScheme(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleSetTabColor(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleOpenTabColorPicker(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleRenameTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleExecuteCommandline(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleToggleCommandPalette(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleCloseOtherTabs(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleCloseTabsAfter(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleOpenTabSearch(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); + void _HandleOpenNewTabDropdown(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleDuplicateTab(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleCloseTab(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleClosePane(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleScrollUp(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleScrollDown(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleNextTab(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandlePrevTab(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleSendInput(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleSplitPane(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleTogglePaneZoom(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleScrollUpPage(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleScrollDownPage(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleOpenSettings(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandlePasteText(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleNewTab(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleSwitchToTab(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleResizePane(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleMoveFocus(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleCopyText(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleCloseWindow(const IInspectable&, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleAdjustFontSize(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleFind(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleResetFontSize(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleToggleRetroEffect(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleToggleFocusMode(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleToggleFullscreen(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleToggleAlwaysOnTop(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleSetColorScheme(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleSetTabColor(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleOpenTabColorPicker(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleRenameTab(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleExecuteCommandline(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleToggleCommandPalette(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleCloseOtherTabs(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleCloseTabsAfter(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); + void _HandleOpenTabSearch(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args); // Make sure to hook new actions up in _RegisterActionCallbacks! #pragma endregion diff --git a/src/cascadia/TerminalApp/TerminalSettings.cpp b/src/cascadia/TerminalApp/TerminalSettings.cpp index 1a92ed5c880..cee6b82d041 100644 --- a/src/cascadia/TerminalApp/TerminalSettings.cpp +++ b/src/cascadia/TerminalApp/TerminalSettings.cpp @@ -7,10 +7,11 @@ #include "TerminalSettings.g.cpp" using namespace winrt::Microsoft::Terminal::TerminalControl; +using namespace winrt::Microsoft::Terminal::Settings::Model; namespace winrt::TerminalApp::implementation { - TerminalSettings::TerminalSettings(const TerminalApp::CascadiaSettings& appSettings, winrt::guid profileGuid, const IKeyBindings& keybindings) : + TerminalSettings::TerminalSettings(const CascadiaSettings& appSettings, winrt::guid profileGuid, const IKeyBindings& keybindings) : _KeyBindings{ keybindings } { const auto profile = appSettings.FindProfile(profileGuid); @@ -38,8 +39,8 @@ namespace winrt::TerminalApp::implementation // - keybindings: the keybinding handler // Return Value: // - the GUID of the created profile, and a fully initialized TerminalSettings object - std::tuple TerminalSettings::BuildSettings(const TerminalApp::CascadiaSettings& appSettings, - const TerminalApp::NewTerminalArgs& newTerminalArgs, + std::tuple TerminalSettings::BuildSettings(const CascadiaSettings& appSettings, + const NewTerminalArgs& newTerminalArgs, const IKeyBindings& keybindings) { const guid profileGuid = appSettings.GetProfileForArgs(newTerminalArgs); @@ -72,7 +73,7 @@ namespace winrt::TerminalApp::implementation // - schemes: a map of schemes to look for our color scheme in, if we have one. // Return Value: // - - void TerminalSettings::_ApplyProfileSettings(const TerminalApp::Profile& profile, const Windows::Foundation::Collections::IMapView& schemes) + void TerminalSettings::_ApplyProfileSettings(const Profile& profile, const Windows::Foundation::Collections::IMapView& schemes) { // Fill in the Terminal Setting's CoreSettings from the profile _HistorySize = profile.HistorySize(); @@ -161,7 +162,7 @@ namespace winrt::TerminalApp::implementation // - globalSettings: the global property values we're applying. // Return Value: // - - void TerminalSettings::_ApplyGlobalSettings(const TerminalApp::GlobalAppSettings& globalSettings) noexcept + void TerminalSettings::_ApplyGlobalSettings(const GlobalAppSettings& globalSettings) noexcept { _InitialRows = globalSettings.InitialRows(); _InitialCols = globalSettings.InitialCols(); @@ -180,7 +181,7 @@ namespace winrt::TerminalApp::implementation // - scheme: the ColorScheme we are applying to the TerminalSettings object // Return Value: // - - void TerminalSettings::ApplyColorScheme(const TerminalApp::ColorScheme& scheme) + void TerminalSettings::ApplyColorScheme(const ColorScheme& scheme) { _DefaultForeground = til::color{ scheme.Foreground() }; _DefaultBackground = til::color{ scheme.Background() }; diff --git a/src/cascadia/TerminalApp/TerminalSettings.h b/src/cascadia/TerminalApp/TerminalSettings.h index 0e4beddbb8d..41c65e0c48d 100644 --- a/src/cascadia/TerminalApp/TerminalSettings.h +++ b/src/cascadia/TerminalApp/TerminalSettings.h @@ -19,8 +19,6 @@ Author(s): #include #include -#include "CascadiaSettings.h" - // fwdecl unittest classes namespace TerminalAppLocalTests { @@ -32,15 +30,15 @@ namespace winrt::TerminalApp::implementation struct TerminalSettings : TerminalSettingsT { TerminalSettings() = default; - TerminalSettings(const TerminalApp::CascadiaSettings& appSettings, + TerminalSettings(const Microsoft::Terminal::Settings::Model::CascadiaSettings& appSettings, guid profileGuid, const Microsoft::Terminal::TerminalControl::IKeyBindings& keybindings); - static std::tuple BuildSettings(const TerminalApp::CascadiaSettings& appSettings, - const TerminalApp::NewTerminalArgs& newTerminalArgs, + static std::tuple BuildSettings(const Microsoft::Terminal::Settings::Model::CascadiaSettings& appSettings, + const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs, const Microsoft::Terminal::TerminalControl::IKeyBindings& keybindings); - void ApplyColorScheme(const TerminalApp::ColorScheme& scheme); + void ApplyColorScheme(const Microsoft::Terminal::Settings::Model::ColorScheme& scheme); // TECHNICALLY, the hstring copy assignment can throw, but the GETSET_PROPERTY // macro defines the operator as `noexcept`. We're not really worried about it, @@ -118,8 +116,8 @@ namespace winrt::TerminalApp::implementation private: std::array _colorTable{}; - void _ApplyProfileSettings(const TerminalApp::Profile& profile, const Windows::Foundation::Collections::IMapView& schemes); - void _ApplyGlobalSettings(const TerminalApp::GlobalAppSettings& globalSettings) noexcept; + void _ApplyProfileSettings(const Microsoft::Terminal::Settings::Model::Profile& profile, const Windows::Foundation::Collections::IMapView& schemes); + void _ApplyGlobalSettings(const Microsoft::Terminal::Settings::Model::GlobalAppSettings& globalSettings) noexcept; friend class TerminalAppLocalTests::SettingsTests; }; diff --git a/src/cascadia/TerminalApp/Utils.cpp b/src/cascadia/TerminalApp/Utils.cpp deleted file mode 100644 index 46f07b9bd93..00000000000 --- a/src/cascadia/TerminalApp/Utils.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation -// Licensed under the MIT license. - -#include "pch.h" -#include "Utils.h" - -std::wstring VisualizeControlCodes(std::wstring str) noexcept -{ - for (auto& ch : str) - { - if (ch < 0x20) - { - ch += 0x2400; - } - else if (ch == 0x20) - { - ch = 0x2423; // replace space with ␣ - } - else if (ch == 0x7f) - { - ch = 0x2421; // replace del with ␡ - } - } - return str; -} diff --git a/src/cascadia/TerminalApp/Utils.h b/src/cascadia/TerminalApp/Utils.h index 91915804139..dee4e659673 100644 --- a/src/cascadia/TerminalApp/Utils.h +++ b/src/cascadia/TerminalApp/Utils.h @@ -13,43 +13,6 @@ Author(s): --*/ #pragma once -// Method Description: -// - Create a std::string from a string_view. We do this because we can't look -// up a key in a Json::Value with a string_view directly, so instead we'll use -// this helper. Should a string_view lookup ever be added to jsoncpp, we can -// remove this entirely. -// Arguments: -// - key: the string_view to build a string from -// Return Value: -// - a std::string to use for looking up a value from a Json::Value -inline std::string JsonKey(const std::string_view key) -{ - return static_cast(key); -} - -// This is a pair of helpers for determining if a pair of guids are equal, and -// establishing an ordering on GUIDs (via std::less). -namespace std -{ - template<> - struct less - { - bool operator()(const GUID& lhs, const GUID& rhs) const - { - return memcmp(&lhs, &rhs, sizeof(rhs)) < 0; - } - }; - - template<> - struct equal_to - { - bool operator()(const GUID& lhs, const GUID& rhs) const - { - return memcmp(&lhs, &rhs, sizeof(rhs)) == 0; - } - }; -} - namespace winrt::Microsoft::UI::Xaml::Controls { struct IconSource; @@ -115,10 +78,3 @@ TIconSource GetColoredIcon(const winrt::hstring& path) return nullptr; } - -std::wstring VisualizeControlCodes(std::wstring str) noexcept; - -inline std::wstring VisualizeControlCodes(std::wstring_view str) noexcept -{ - return VisualizeControlCodes(std::wstring{ str }); -} diff --git a/src/cascadia/TerminalApp/dll/TerminalApp.vcxproj b/src/cascadia/TerminalApp/dll/TerminalApp.vcxproj index 8d8962cca79..4fe164c4e2b 100644 --- a/src/cascadia/TerminalApp/dll/TerminalApp.vcxproj +++ b/src/cascadia/TerminalApp/dll/TerminalApp.vcxproj @@ -69,6 +69,7 @@ include Settings and Connection, since Control will include them for us) --> + diff --git a/src/cascadia/TerminalApp/pch.h b/src/cascadia/TerminalApp/pch.h index dcac6c4e1ab..d2691b5b817 100644 --- a/src/cascadia/TerminalApp/pch.h +++ b/src/cascadia/TerminalApp/pch.h @@ -61,12 +61,11 @@ TRACELOGGING_DECLARE_PROVIDER(g_hTerminalAppProvider); #include #include -// JsonCpp -#include - #include +#include #include +#include #include #include diff --git a/src/cascadia/TerminalConnection/AzureConnection.cpp b/src/cascadia/TerminalConnection/AzureConnection.cpp index ae7b3a5601e..4a1eeb97522 100644 --- a/src/cascadia/TerminalConnection/AzureConnection.cpp +++ b/src/cascadia/TerminalConnection/AzureConnection.cpp @@ -35,6 +35,8 @@ static constexpr auto HttpUserAgent = L"Terminal/0.0"; static constexpr int USER_INPUT_COLOR = 93; // yellow - the color of something the user can type static constexpr int USER_INFO_COLOR = 97; // white - the color of clarifying information +static constexpr winrt::guid AzureConnectionType = { 0xd9fcfdfa, 0xa479, 0x412c, { 0x83, 0xb7, 0xc5, 0x64, 0xe, 0x61, 0xcd, 0x62 } }; + static inline std::wstring _colorize(const unsigned int colorCode, const std::wstring_view text) { return fmt::format(L"\x1b[{0}m{1}\x1b[m", colorCode, text); @@ -60,6 +62,11 @@ static inline std::wstring _formatTenant(int tenantNumber, const Tenant& tenant) namespace winrt::Microsoft::Terminal::TerminalConnection::implementation { + winrt::guid AzureConnection::ConnectionType() noexcept + { + return AzureConnectionType; + } + // This function exists because the clientID only gets added by the release pipelines // and is not available on local builds, so we want to be able to make sure we don't // try to make an Azure connection if its a local build diff --git a/src/cascadia/TerminalConnection/AzureConnection.h b/src/cascadia/TerminalConnection/AzureConnection.h index 162dad5f717..4db0a9619b4 100644 --- a/src/cascadia/TerminalConnection/AzureConnection.h +++ b/src/cascadia/TerminalConnection/AzureConnection.h @@ -19,6 +19,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation { struct AzureConnection : AzureConnectionT, ConnectionStateHolder { + static winrt::guid ConnectionType() noexcept; static bool IsAzureConnectionAvailable() noexcept; AzureConnection(const uint32_t rows, const uint32_t cols); diff --git a/src/cascadia/TerminalConnection/AzureConnection.idl b/src/cascadia/TerminalConnection/AzureConnection.idl index f925706c5d9..6bd6e4930f1 100644 --- a/src/cascadia/TerminalConnection/AzureConnection.idl +++ b/src/cascadia/TerminalConnection/AzureConnection.idl @@ -7,6 +7,7 @@ namespace Microsoft.Terminal.TerminalConnection { [default_interface] runtimeclass AzureConnection : ITerminalConnection { + static Guid ConnectionType { get; }; static Boolean IsAzureConnectionAvailable(); AzureConnection(UInt32 rows, UInt32 columns); diff --git a/src/cascadia/TerminalConnection/TelnetConnection.cpp b/src/cascadia/TerminalConnection/TelnetConnection.cpp index d7753349588..91daa142cf9 100644 --- a/src/cascadia/TerminalConnection/TelnetConnection.cpp +++ b/src/cascadia/TerminalConnection/TelnetConnection.cpp @@ -14,8 +14,16 @@ using namespace ::Microsoft::Console; constexpr std::wstring_view telnetScheme = L"telnet"; constexpr std::wstring_view msTelnetLoopbackScheme = L"ms-telnet-loop"; +// {311153fb-d3f0-4ac6-b920-038de7cf5289} +static constexpr winrt::guid TelnetConnectionType = { 0x311153fb, 0xd3f0, 0x4ac6, { 0xb9, 0x20, 0x03, 0x8d, 0xe7, 0xcf, 0x52, 0x89 } }; + namespace winrt::Microsoft::Terminal::TerminalConnection::implementation { + winrt::guid TelnetConnection::ConnectionType() noexcept + { + return TelnetConnectionType; + } + TelnetConnection::TelnetConnection(const hstring& uri) : _reader{ nullptr }, _writer{ nullptr }, diff --git a/src/cascadia/TerminalConnection/TelnetConnection.h b/src/cascadia/TerminalConnection/TelnetConnection.h index ca632c4366f..c8ba6bf1781 100644 --- a/src/cascadia/TerminalConnection/TelnetConnection.h +++ b/src/cascadia/TerminalConnection/TelnetConnection.h @@ -26,6 +26,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation { struct TelnetConnection : TelnetConnectionT, ConnectionStateHolder { + static winrt::guid ConnectionType() noexcept; + TelnetConnection(const hstring& uri); void Start(); diff --git a/src/cascadia/TerminalConnection/TelnetConnection.idl b/src/cascadia/TerminalConnection/TelnetConnection.idl index ac250b39ca6..2fd8b63b1da 100644 --- a/src/cascadia/TerminalConnection/TelnetConnection.idl +++ b/src/cascadia/TerminalConnection/TelnetConnection.idl @@ -8,6 +8,7 @@ namespace Microsoft.Terminal.TerminalConnection [default_interface] runtimeclass TelnetConnection : ITerminalConnection { + static Guid ConnectionType { get; }; TelnetConnection(String uri); }; diff --git a/src/cascadia/TerminalApp/ActionAndArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp similarity index 97% rename from src/cascadia/TerminalApp/ActionAndArgs.cpp rename to src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp index 8f7048f9dc0..91b1c29dd4d 100644 --- a/src/cascadia/TerminalApp/ActionAndArgs.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp @@ -51,9 +51,9 @@ static constexpr std::string_view ActionKey{ "action" }; // This key is reserved to remove a keybinding, instead of mapping it to an action. static constexpr std::string_view UnboundKey{ "unbound" }; -namespace winrt::TerminalApp::implementation +namespace winrt::Microsoft::Terminal::Settings::Model::implementation { - using namespace ::TerminalApp; + using namespace ::Microsoft::Terminal::Settings::Model; // Specifically use a map here over an unordered_map. We want to be able to // iterate over these entries in-order when we're serializing the keybindings. @@ -105,7 +105,7 @@ namespace winrt::TerminalApp::implementation { UnboundKey, ShortcutAction::Invalid }, }; - using ParseResult = std::tuple>; + using ParseResult = std::tuple>; using ParseActionFunction = std::function; // This is a map of ShortcutAction->function. It holds @@ -169,7 +169,7 @@ namespace winrt::TerminalApp::implementation // - a deserialized ActionAndArgs corresponding to the values in json, or // null if we failed to deserialize an action. winrt::com_ptr ActionAndArgs::FromJson(const Json::Value& json, - std::vector& warnings) + std::vector& warnings) { // Invalid is our placeholder that the action was not parsed. ShortcutAction action = ShortcutAction::Invalid; @@ -208,7 +208,7 @@ namespace winrt::TerminalApp::implementation // does, we'll try to deserialize any "args" that were provided with // the binding. IActionArgs args{ nullptr }; - std::vector parseWarnings; + std::vector parseWarnings; const auto deserializersIter = argParsers.find(action); if (deserializersIter != argParsers.end()) { diff --git a/src/cascadia/TerminalApp/ActionAndArgs.h b/src/cascadia/TerminalSettingsModel/ActionAndArgs.h similarity index 56% rename from src/cascadia/TerminalApp/ActionAndArgs.h rename to src/cascadia/TerminalSettingsModel/ActionAndArgs.h index a0e26fc8957..a23879c6183 100644 --- a/src/cascadia/TerminalApp/ActionAndArgs.h +++ b/src/cascadia/TerminalSettingsModel/ActionAndArgs.h @@ -1,25 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + #pragma once + #include "ActionAndArgs.g.h" #include "TerminalWarnings.h" #include "..\inc\cppwinrt_utils.h" -namespace winrt::TerminalApp::implementation +namespace winrt::Microsoft::Terminal::Settings::Model::implementation { struct ActionAndArgs : public ActionAndArgsT { static const std::map> ActionKeyNamesMap; static winrt::com_ptr FromJson(const Json::Value& json, - std::vector& warnings); + std::vector& warnings); ActionAndArgs() = default; + ActionAndArgs(ShortcutAction action, IActionArgs args) : + _Action{ action }, + _Args{ args } {}; + hstring GenerateName() const; - GETSET_PROPERTY(TerminalApp::ShortcutAction, Action, TerminalApp::ShortcutAction::Invalid); + GETSET_PROPERTY(ShortcutAction, Action, ShortcutAction::Invalid); GETSET_PROPERTY(IActionArgs, Args, nullptr); }; } -namespace winrt::TerminalApp::factory_implementation +namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation { BASIC_FACTORY(ActionAndArgs); } diff --git a/src/cascadia/TerminalApp/ActionArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionArgs.cpp similarity index 95% rename from src/cascadia/TerminalApp/ActionArgs.cpp rename to src/cascadia/TerminalSettingsModel/ActionArgs.cpp index 6cc367634c5..1ce89a1dc6c 100644 --- a/src/cascadia/TerminalApp/ActionArgs.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.cpp @@ -21,13 +21,11 @@ #include "RenameTabArgs.g.cpp" #include "ExecuteCommandlineArgs.g.cpp" -#include "Utils.h" - #include using namespace winrt::Microsoft::Terminal::TerminalControl; -namespace winrt::TerminalApp::implementation +namespace winrt::Microsoft::Terminal::Settings::Model::implementation { winrt::hstring NewTerminalArgs::GenerateName() const { @@ -212,7 +210,7 @@ namespace winrt::TerminalApp::implementation // The string will be similar to the following: // * "Send Input: ...input..." - auto escapedInput = VisualizeControlCodes(_Input); + auto escapedInput = til::visualize_control_codes(_Input); auto name = fmt::format(std::wstring_view(RS_(L"SendInputCommandKey")), escapedInput); return winrt::hstring{ name }; } diff --git a/src/cascadia/TerminalApp/ActionArgs.h b/src/cascadia/TerminalSettingsModel/ActionArgs.h similarity index 85% rename from src/cascadia/TerminalApp/ActionArgs.h rename to src/cascadia/TerminalSettingsModel/ActionArgs.h index 3f7e829cd04..209fef24c24 100644 --- a/src/cascadia/TerminalApp/ActionArgs.h +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.h @@ -24,7 +24,6 @@ #include "CloseTabsAfterArgs.g.h" #include "../../cascadia/inc/cppwinrt_utils.h" -#include "Utils.h" #include "JsonUtils.h" #include "TerminalWarnings.h" @@ -36,16 +35,16 @@ // * ActionEventArgs holds a single IActionArgs. For events that don't need // additional args, this can be nullptr. -namespace winrt::TerminalApp::implementation +namespace winrt::Microsoft::Terminal::Settings::Model::implementation { - using namespace ::TerminalApp; - using FromJsonResult = std::tuple>; + using namespace ::Microsoft::Terminal::Settings::Model; + using FromJsonResult = std::tuple>; struct ActionEventArgs : public ActionEventArgsT { ActionEventArgs() = default; - explicit ActionEventArgs(const TerminalApp::IActionArgs& args) : + explicit ActionEventArgs(const Model::IActionArgs& args) : _ActionArgs{ args } {}; GETSET_PROPERTY(IActionArgs, ActionArgs, nullptr); GETSET_PROPERTY(bool, Handled, false); @@ -54,6 +53,8 @@ namespace winrt::TerminalApp::implementation struct NewTerminalArgs : public NewTerminalArgsT { NewTerminalArgs() = default; + NewTerminalArgs(int32_t& profileIndex) : + _ProfileIndex{ profileIndex } {}; GETSET_PROPERTY(winrt::hstring, Commandline, L""); GETSET_PROPERTY(winrt::hstring, StartingDirectory, L""); GETSET_PROPERTY(winrt::hstring, TabTitle, L""); @@ -69,7 +70,7 @@ namespace winrt::TerminalApp::implementation public: hstring GenerateName() const; - bool Equals(const winrt::TerminalApp::NewTerminalArgs& other) + bool Equals(const Model::NewTerminalArgs& other) { return other.Commandline() == _Commandline && other.StartingDirectory() == _StartingDirectory && @@ -77,7 +78,7 @@ namespace winrt::TerminalApp::implementation other.ProfileIndex() == _ProfileIndex && other.Profile() == _Profile; }; - static winrt::TerminalApp::NewTerminalArgs FromJson(const Json::Value& json) + static Model::NewTerminalArgs FromJson(const Json::Value& json) { // LOAD BEARING: Not using make_self here _will_ break you in the future! auto args = winrt::make_self(); @@ -94,7 +95,7 @@ namespace winrt::TerminalApp::implementation { CopyTextArgs() = default; GETSET_PROPERTY(bool, SingleLine, false); - GETSET_PROPERTY(Windows::Foundation::IReference, CopyFormatting, nullptr); + GETSET_PROPERTY(Windows::Foundation::IReference, CopyFormatting, nullptr); static constexpr std::string_view SingleLineKey{ "singleLine" }; static constexpr std::string_view CopyFormattingKey{ "copyFormatting" }; @@ -125,7 +126,9 @@ namespace winrt::TerminalApp::implementation struct NewTabArgs : public NewTabArgsT { NewTabArgs() = default; - GETSET_PROPERTY(winrt::TerminalApp::NewTerminalArgs, TerminalArgs, nullptr); + NewTabArgs(const Model::NewTerminalArgs& terminalArgs) : + _TerminalArgs{ terminalArgs } {}; + GETSET_PROPERTY(Model::NewTerminalArgs, TerminalArgs, nullptr); public: hstring GenerateName() const; @@ -151,6 +154,8 @@ namespace winrt::TerminalApp::implementation struct SwitchToTabArgs : public SwitchToTabArgsT { SwitchToTabArgs() = default; + SwitchToTabArgs(uint32_t& tabIndex) : + _TabIndex{ tabIndex } {}; GETSET_PROPERTY(uint32_t, TabIndex, 0); static constexpr std::string_view TabIndexKey{ "index" }; @@ -179,7 +184,7 @@ namespace winrt::TerminalApp::implementation struct ResizePaneArgs : public ResizePaneArgsT { ResizePaneArgs() = default; - GETSET_PROPERTY(TerminalApp::Direction, Direction, TerminalApp::Direction::None); + GETSET_PROPERTY(Model::Direction, Direction, Direction::None); static constexpr std::string_view DirectionKey{ "direction" }; @@ -200,9 +205,9 @@ namespace winrt::TerminalApp::implementation // LOAD BEARING: Not using make_self here _will_ break you in the future! auto args = winrt::make_self(); JsonUtils::GetValueForKey(json, DirectionKey, args->_Direction); - if (args->_Direction == TerminalApp::Direction::None) + if (args->_Direction == Direction::None) { - return { nullptr, { TerminalApp::SettingsLoadWarnings::MissingRequiredParameter } }; + return { nullptr, { SettingsLoadWarnings::MissingRequiredParameter } }; } else { @@ -214,7 +219,7 @@ namespace winrt::TerminalApp::implementation struct MoveFocusArgs : public MoveFocusArgsT { MoveFocusArgs() = default; - GETSET_PROPERTY(TerminalApp::Direction, Direction, TerminalApp::Direction::None); + GETSET_PROPERTY(Model::Direction, Direction, Direction::None); static constexpr std::string_view DirectionKey{ "direction" }; @@ -235,9 +240,9 @@ namespace winrt::TerminalApp::implementation // LOAD BEARING: Not using make_self here _will_ break you in the future! auto args = winrt::make_self(); JsonUtils::GetValueForKey(json, DirectionKey, args->_Direction); - if (args->_Direction == TerminalApp::Direction::None) + if (args->_Direction == Direction::None) { - return { nullptr, { TerminalApp::SettingsLoadWarnings::MissingRequiredParameter } }; + return { nullptr, { SettingsLoadWarnings::MissingRequiredParameter } }; } else { @@ -299,7 +304,7 @@ namespace winrt::TerminalApp::implementation JsonUtils::GetValueForKey(json, InputKey, args->_Input); if (args->_Input.empty()) { - return { nullptr, { TerminalApp::SettingsLoadWarnings::MissingRequiredParameter } }; + return { nullptr, { SettingsLoadWarnings::MissingRequiredParameter } }; } return { *args, {} }; } @@ -308,9 +313,12 @@ namespace winrt::TerminalApp::implementation struct SplitPaneArgs : public SplitPaneArgsT { SplitPaneArgs() = default; - GETSET_PROPERTY(winrt::TerminalApp::SplitState, SplitStyle, winrt::TerminalApp::SplitState::Automatic); - GETSET_PROPERTY(winrt::TerminalApp::NewTerminalArgs, TerminalArgs, nullptr); - GETSET_PROPERTY(winrt::TerminalApp::SplitType, SplitMode, winrt::TerminalApp::SplitType::Manual); + SplitPaneArgs(SplitState style, const Model::NewTerminalArgs& terminalArgs) : + _SplitStyle{ style }, + _TerminalArgs{ terminalArgs } {}; + GETSET_PROPERTY(SplitState, SplitStyle, SplitState::Automatic); + GETSET_PROPERTY(Model::NewTerminalArgs, TerminalArgs, nullptr); + GETSET_PROPERTY(SplitType, SplitMode, SplitType::Manual); static constexpr std::string_view SplitKey{ "split" }; static constexpr std::string_view SplitModeKey{ "splitMode" }; @@ -344,7 +352,7 @@ namespace winrt::TerminalApp::implementation struct OpenSettingsArgs : public OpenSettingsArgsT { OpenSettingsArgs() = default; - GETSET_PROPERTY(TerminalApp::SettingsTarget, Target, TerminalApp::SettingsTarget::SettingsFile); + GETSET_PROPERTY(SettingsTarget, Target, SettingsTarget::SettingsFile); static constexpr std::string_view TargetKey{ "target" }; @@ -395,7 +403,7 @@ namespace winrt::TerminalApp::implementation JsonUtils::GetValueForKey(json, NameKey, args->_SchemeName); if (args->_SchemeName.empty()) { - return { nullptr, { TerminalApp::SettingsLoadWarnings::MissingRequiredParameter } }; + return { nullptr, { SettingsLoadWarnings::MissingRequiredParameter } }; } return { *args, {} }; } @@ -463,6 +471,8 @@ namespace winrt::TerminalApp::implementation struct ExecuteCommandlineArgs : public ExecuteCommandlineArgsT { ExecuteCommandlineArgs() = default; + ExecuteCommandlineArgs(winrt::hstring commandline) : + _Commandline{ commandline } {}; GETSET_PROPERTY(winrt::hstring, Commandline, L""); static constexpr std::string_view CommandlineKey{ "commandline" }; @@ -486,7 +496,7 @@ namespace winrt::TerminalApp::implementation JsonUtils::GetValueForKey(json, CommandlineKey, args->_Commandline); if (args->_Commandline.empty()) { - return { nullptr, { TerminalApp::SettingsLoadWarnings::MissingRequiredParameter } }; + return { nullptr, { SettingsLoadWarnings::MissingRequiredParameter } }; } return { *args, {} }; } @@ -495,7 +505,7 @@ namespace winrt::TerminalApp::implementation struct CloseOtherTabsArgs : public CloseOtherTabsArgsT { CloseOtherTabsArgs() = default; - GETSET_PROPERTY(winrt::Windows::Foundation::IReference, Index, nullptr); + GETSET_PROPERTY(Windows::Foundation::IReference, Index, nullptr); static constexpr std::string_view IndexKey{ "index" }; @@ -523,7 +533,7 @@ namespace winrt::TerminalApp::implementation struct CloseTabsAfterArgs : public CloseTabsAfterArgsT { CloseTabsAfterArgs() = default; - GETSET_PROPERTY(winrt::Windows::Foundation::IReference, Index, nullptr); + GETSET_PROPERTY(Windows::Foundation::IReference, Index, nullptr); static constexpr std::string_view IndexKey{ "index" }; @@ -549,8 +559,12 @@ namespace winrt::TerminalApp::implementation }; } -namespace winrt::TerminalApp::factory_implementation +namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation { BASIC_FACTORY(ActionEventArgs); + BASIC_FACTORY(SwitchToTabArgs); BASIC_FACTORY(NewTerminalArgs); + BASIC_FACTORY(NewTabArgs); + BASIC_FACTORY(SplitPaneArgs); + BASIC_FACTORY(ExecuteCommandlineArgs); } diff --git a/src/cascadia/TerminalApp/ActionArgs.idl b/src/cascadia/TerminalSettingsModel/ActionArgs.idl similarity index 86% rename from src/cascadia/TerminalApp/ActionArgs.idl rename to src/cascadia/TerminalSettingsModel/ActionArgs.idl index 51ecf282941..407dbd6d4cb 100644 --- a/src/cascadia/TerminalApp/ActionArgs.idl +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.idl @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -namespace TerminalApp +namespace Microsoft.Terminal.Settings.Model { interface IActionArgs { @@ -47,6 +47,8 @@ namespace TerminalApp [default_interface] runtimeclass NewTerminalArgs { NewTerminalArgs(); + NewTerminalArgs(Int32 profileIndex); + String Commandline; String StartingDirectory; String TabTitle; @@ -61,6 +63,7 @@ namespace TerminalApp [default_interface] runtimeclass ActionEventArgs : IActionEventArgs { + ActionEventArgs(); ActionEventArgs(IActionArgs args); }; @@ -72,12 +75,14 @@ namespace TerminalApp [default_interface] runtimeclass NewTabArgs : IActionArgs { + NewTabArgs(NewTerminalArgs terminalArgs); NewTerminalArgs TerminalArgs { get; }; }; [default_interface] runtimeclass SwitchToTabArgs : IActionArgs { - UInt32 TabIndex { get; }; + SwitchToTabArgs(UInt32 tabIndex); + UInt32 TabIndex; }; [default_interface] runtimeclass ResizePaneArgs : IActionArgs @@ -102,6 +107,7 @@ namespace TerminalApp [default_interface] runtimeclass SplitPaneArgs : IActionArgs { + SplitPaneArgs(SplitState style, NewTerminalArgs terminalArgs); SplitState SplitStyle { get; }; NewTerminalArgs TerminalArgs { get; }; SplitType SplitMode { get; }; @@ -129,6 +135,7 @@ namespace TerminalApp [default_interface] runtimeclass ExecuteCommandlineArgs : IActionArgs { + ExecuteCommandlineArgs(String commandline); String Commandline; }; diff --git a/src/cascadia/TerminalApp/AzureCloudShellGenerator.cpp b/src/cascadia/TerminalSettingsModel/AzureCloudShellGenerator.cpp similarity index 76% rename from src/cascadia/TerminalApp/AzureCloudShellGenerator.cpp rename to src/cascadia/TerminalSettingsModel/AzureCloudShellGenerator.cpp index 1c962370b44..3435d795591 100644 --- a/src/cascadia/TerminalApp/AzureCloudShellGenerator.cpp +++ b/src/cascadia/TerminalSettingsModel/AzureCloudShellGenerator.cpp @@ -3,8 +3,6 @@ #include "pch.h" -#include - #include "AzureCloudShellGenerator.h" #include "LegacyProfileGeneratorNamespaces.h" @@ -13,8 +11,9 @@ #include "Utils.h" #include "DefaultProfileUtils.h" -using namespace ::TerminalApp; -using namespace winrt::TerminalApp; +using namespace ::Microsoft::Terminal::Settings::Model; +using namespace winrt::Microsoft::Terminal::Settings::Model; +using namespace winrt::Microsoft::Terminal::TerminalConnection; std::wstring_view AzureCloudShellGenerator::GetNamespace() { @@ -32,13 +31,13 @@ std::vector AzureCloudShellGenerator::GenerateProfiles() { std::vector profiles; - if (winrt::Microsoft::Terminal::TerminalConnection::AzureConnection::IsAzureConnectionAvailable()) + if (AzureConnection::IsAzureConnectionAvailable()) { auto azureCloudShellProfile{ CreateDefaultProfile(L"Azure Cloud Shell") }; azureCloudShellProfile.Commandline(L"Azure"); azureCloudShellProfile.StartingDirectory(DEFAULT_STARTING_DIRECTORY); azureCloudShellProfile.ColorSchemeName(L"Vintage"); - azureCloudShellProfile.ConnectionType(AzureConnectionType); + azureCloudShellProfile.ConnectionType(AzureConnection::ConnectionType()); profiles.emplace_back(azureCloudShellProfile); } diff --git a/src/cascadia/TerminalApp/AzureCloudShellGenerator.h b/src/cascadia/TerminalSettingsModel/AzureCloudShellGenerator.h similarity index 63% rename from src/cascadia/TerminalApp/AzureCloudShellGenerator.h rename to src/cascadia/TerminalSettingsModel/AzureCloudShellGenerator.h index d624c856b47..79ad05a31e2 100644 --- a/src/cascadia/TerminalApp/AzureCloudShellGenerator.h +++ b/src/cascadia/TerminalSettingsModel/AzureCloudShellGenerator.h @@ -18,17 +18,15 @@ Author(s): #pragma once #include "IDynamicProfileGenerator.h" -static constexpr winrt::guid AzureConnectionType = { 0xd9fcfdfa, 0xa479, 0x412c, { 0x83, 0xb7, 0xc5, 0x64, 0xe, 0x61, 0xcd, 0x62 } }; - -namespace TerminalApp +namespace Microsoft::Terminal::Settings::Model { - class AzureCloudShellGenerator : public TerminalApp::IDynamicProfileGenerator + class AzureCloudShellGenerator : public IDynamicProfileGenerator { public: AzureCloudShellGenerator() = default; ~AzureCloudShellGenerator() = default; std::wstring_view GetNamespace() override; - std::vector GenerateProfiles() override; + std::vector GenerateProfiles() override; }; }; diff --git a/src/cascadia/TerminalApp/CascadiaSettings.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp similarity index 79% rename from src/cascadia/TerminalApp/CascadiaSettings.cpp rename to src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp index 64c387732c4..c8d1364b9f1 100644 --- a/src/cascadia/TerminalApp/CascadiaSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp @@ -9,7 +9,6 @@ #include "CascadiaSettings.h" #include "../../types/inc/utils.hpp" #include "../../inc/DefaultSettings.h" -#include "AppLogic.h" #include "Utils.h" #include "LibraryResources.h" @@ -19,9 +18,9 @@ #include "CascadiaSettings.g.cpp" -using namespace ::TerminalApp; +using namespace ::Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::TerminalControl; -using namespace winrt::TerminalApp::implementation; +using namespace winrt::Microsoft::Terminal::Settings::Model::implementation; using namespace winrt::Windows::Foundation::Collections; using namespace Microsoft::Console; @@ -46,7 +45,7 @@ CascadiaSettings::CascadiaSettings() : // - addDynamicProfiles: if true, we'll add the built-in DPGs. CascadiaSettings::CascadiaSettings(const bool addDynamicProfiles) : _globals{ winrt::make_self() }, - _profiles{ winrt::single_threaded_observable_vector() }, + _profiles{ winrt::single_threaded_observable_vector() }, _warnings{ winrt::single_threaded_vector() }, _deserializationErrorMessage{ L"" } { @@ -58,6 +57,15 @@ CascadiaSettings::CascadiaSettings(const bool addDynamicProfiles) : } } +CascadiaSettings::CascadiaSettings(winrt::hstring json) : + CascadiaSettings(false) +{ + const auto jsonString{ til::u16u8(json) }; + _ParseJsonString(jsonString, false); + LayerJson(_userSettings); + _ValidateSettings(); +} + // Method Description: // - Finds a profile that matches the given GUID. If there is no profile in this // settings object that matches, returns nullptr. @@ -66,7 +74,7 @@ CascadiaSettings::CascadiaSettings(const bool addDynamicProfiles) : // Return Value: // - a non-ownership pointer to the profile matching the given guid, or nullptr // if there is no match. -winrt::TerminalApp::Profile CascadiaSettings::FindProfile(winrt::guid profileGuid) const noexcept +winrt::Microsoft::Terminal::Settings::Model::Profile CascadiaSettings::FindProfile(winrt::guid profileGuid) const noexcept { const winrt::guid guid{ profileGuid }; for (auto profile : _profiles) @@ -89,7 +97,7 @@ winrt::TerminalApp::Profile CascadiaSettings::FindProfile(winrt::guid profileGui // - // Return Value: // - an iterable collection of all of our Profiles. -IObservableVector CascadiaSettings::Profiles() const noexcept +IObservableVector CascadiaSettings::Profiles() const noexcept { return _profiles; } @@ -100,7 +108,7 @@ IObservableVector CascadiaSettings::Profiles() cons // - // Return Value: // - the globally configured keybindings -winrt::TerminalApp::KeyMapping CascadiaSettings::KeyMap() const noexcept +winrt::Microsoft::Terminal::Settings::Model::KeyMapping CascadiaSettings::KeyMap() const noexcept { return _globals->KeyMap(); } @@ -111,7 +119,7 @@ winrt::TerminalApp::KeyMapping CascadiaSettings::KeyMap() const noexcept // - // Return Value: // - a reference to our global settings -winrt::TerminalApp::GlobalAppSettings CascadiaSettings::GlobalSettings() const +winrt::Microsoft::Terminal::Settings::Model::GlobalAppSettings CascadiaSettings::GlobalSettings() const { return *_globals; } @@ -121,12 +129,12 @@ winrt::TerminalApp::GlobalAppSettings CascadiaSettings::GlobalSettings() const // knew were bad when we called `_ValidateSettings` last. // Return Value: // - a reference to our list of warnings. -IVectorView CascadiaSettings::Warnings() +IVectorView CascadiaSettings::Warnings() { return _warnings.GetView(); } -winrt::Windows::Foundation::IReference CascadiaSettings::GetLoadingError() +winrt::Windows::Foundation::IReference CascadiaSettings::GetLoadingError() { return _loadError; } @@ -210,7 +218,7 @@ void CascadiaSettings::_ValidateProfilesExist() // We can't add the warning to the list of warnings here, because this // object is not going to be returned at any point. - throw SettingsException(TerminalApp::SettingsLoadErrors::NoProfiles); + throw SettingsException(Microsoft::Terminal::Settings::Model::SettingsLoadErrors::NoProfiles); } } @@ -264,7 +272,7 @@ void CascadiaSettings::_ValidateDefaultProfileExists() if (nullDefaultProfile || defaultProfileNotInProfiles) { - _warnings.Append(TerminalApp::SettingsLoadWarnings::MissingDefaultProfile); + _warnings.Append(Microsoft::Terminal::Settings::Model::SettingsLoadWarnings::MissingDefaultProfile); // Use the first profile as the new default // _temporarily_ set the default profile to the first profile. Because @@ -307,7 +315,7 @@ void CascadiaSettings::_ValidateNoDuplicateProfiles() if (foundDupe) { - _warnings.Append(TerminalApp::SettingsLoadWarnings::DuplicateProfile); + _warnings.Append(Microsoft::Terminal::Settings::Model::SettingsLoadWarnings::DuplicateProfile); } } @@ -396,7 +404,7 @@ void CascadiaSettings::_RemoveHiddenProfiles() { // Throw an exception. This is an invalid state, and we want the app to // be able to gracefully use the default settings. - throw SettingsException(TerminalApp::SettingsLoadErrors::AllProfilesHidden); + throw SettingsException(SettingsLoadErrors::AllProfilesHidden); } } @@ -480,12 +488,12 @@ void CascadiaSettings::_ValidateMediaResources() if (invalidBackground) { - _warnings.Append(TerminalApp::SettingsLoadWarnings::InvalidBackgroundImage); + _warnings.Append(SettingsLoadWarnings::InvalidBackgroundImage); } if (invalidIcon) { - _warnings.Append(TerminalApp::SettingsLoadWarnings::InvalidIcon); + _warnings.Append(SettingsLoadWarnings::InvalidIcon); } } @@ -505,7 +513,7 @@ void CascadiaSettings::_ValidateMediaResources() // and attempt to look the profile up by name instead. // Return Value: // - the GUID of the profile corresponding to this combination of index and NewTerminalArgs -winrt::guid CascadiaSettings::GetProfileForArgs(const winrt::TerminalApp::NewTerminalArgs& newTerminalArgs) const +winrt::guid CascadiaSettings::GetProfileForArgs(const Model::NewTerminalArgs& newTerminalArgs) const { std::optional profileByIndex, profileByName; if (newTerminalArgs) @@ -609,7 +617,7 @@ void CascadiaSettings::_ValidateKeybindings() if (!keybindingWarnings.empty()) { - _warnings.Append(TerminalApp::SettingsLoadWarnings::AtLeastOneKeybindingWarning); + _warnings.Append(SettingsLoadWarnings::AtLeastOneKeybindingWarning); for (auto warning : keybindingWarnings) { _warnings.Append(warning); @@ -632,7 +640,7 @@ void CascadiaSettings::_ValidateNoGlobalsKey() { if (auto oldGlobalsProperty{ _userSettings["globals"] }) { - _warnings.Append(TerminalApp::SettingsLoadWarnings::LegacyGlobalsProperty); + _warnings.Append(SettingsLoadWarnings::LegacyGlobalsProperty); } } @@ -661,15 +669,13 @@ std::string CascadiaSettings::_ApplyFirstRunChangesToSettingsTemplate(std::strin til::replace_needle_in_haystack_inplace(finalSettings, "%DEFAULT_PROFILE%", til::u16u8(defaultProfileGuid)); - if (const auto appLogic{ winrt::TerminalApp::implementation::AppLogic::Current() }) - { - til::replace_needle_in_haystack_inplace(finalSettings, - "%VERSION%", - til::u16u8(appLogic->ApplicationVersion())); - til::replace_needle_in_haystack_inplace(finalSettings, - "%PRODUCT%", - til::u16u8(appLogic->ApplicationDisplayName())); - } + + til::replace_needle_in_haystack_inplace(finalSettings, + "%VERSION%", + til::u16u8(ApplicationVersion())); + til::replace_needle_in_haystack_inplace(finalSettings, + "%PRODUCT%", + til::u16u8(ApplicationDisplayName())); til::replace_needle_in_haystack_inplace(finalSettings, "%COMMAND_PROMPT_LOCALIZED_NAME%", @@ -686,7 +692,7 @@ std::string CascadiaSettings::_ApplyFirstRunChangesToSettingsTemplate(std::strin // - profileGuid: the GUID of the profile to find the scheme for. // Return Value: // - a non-owning pointer to the scheme. -winrt::TerminalApp::ColorScheme CascadiaSettings::GetColorSchemeForProfile(const winrt::guid profileGuid) const +winrt::Microsoft::Terminal::Settings::Model::ColorScheme CascadiaSettings::GetColorSchemeForProfile(const winrt::guid profileGuid) const { auto profile = FindProfile(profileGuid); if (!profile) @@ -696,3 +702,62 @@ winrt::TerminalApp::ColorScheme CascadiaSettings::GetColorSchemeForProfile(const const auto schemeName = profile.ColorSchemeName(); return _globals->ColorSchemes().TryLookup(schemeName); } + +winrt::hstring CascadiaSettings::ApplicationDisplayName() +{ + try + { + const auto package{ winrt::Windows::ApplicationModel::Package::Current() }; + return package.DisplayName(); + } + CATCH_LOG(); + + return RS_(L"ApplicationDisplayNameUnpackaged"); +} + +winrt::hstring CascadiaSettings::ApplicationVersion() +{ + try + { + const auto package{ winrt::Windows::ApplicationModel::Package::Current() }; + const auto version{ package.Id().Version() }; + winrt::hstring formatted{ wil::str_printf(L"%u.%u.%u.%u", version.Major, version.Minor, version.Build, version.Revision) }; + return formatted; + } + CATCH_LOG(); + + // Try to get the version the old-fashioned way + try + { + struct LocalizationInfo + { + WORD language, codepage; + }; + // Use the current module instance handle for TerminalApp.dll, nullptr for WindowsTerminal.exe + auto filename{ wil::GetModuleFileNameW(wil::GetModuleInstanceHandle()) }; + auto size{ GetFileVersionInfoSizeExW(0, filename.c_str(), nullptr) }; + THROW_LAST_ERROR_IF(size == 0); + auto versionBuffer{ std::make_unique(size) }; + THROW_IF_WIN32_BOOL_FALSE(GetFileVersionInfoExW(0, filename.c_str(), 0, size, versionBuffer.get())); + + // Get the list of Version localizations + LocalizationInfo* pVarLocalization{ nullptr }; + UINT varLen{ 0 }; + THROW_IF_WIN32_BOOL_FALSE(VerQueryValueW(versionBuffer.get(), L"\\VarFileInfo\\Translation", reinterpret_cast(&pVarLocalization), &varLen)); + THROW_HR_IF(E_UNEXPECTED, varLen < sizeof(*pVarLocalization)); // there must be at least one translation + + // Get the product version from the localized version compartment + // We're using String/ProductVersion here because our build pipeline puts more rich information in it (like the branch name) + // than in the unlocalized numeric version fields. + WCHAR* pProductVersion{ nullptr }; + UINT versionLen{ 0 }; + const auto localizedVersionName{ wil::str_printf(L"\\StringFileInfo\\%04x%04x\\ProductVersion", + pVarLocalization->language ? pVarLocalization->language : 0x0409, // well-known en-US LCID + pVarLocalization->codepage) }; + THROW_IF_WIN32_BOOL_FALSE(VerQueryValueW(versionBuffer.get(), localizedVersionName.c_str(), reinterpret_cast(&pProductVersion), &versionLen)); + return { pProductVersion }; + } + CATCH_LOG(); + + return RS_(L"ApplicationVersionUnknown"); +} diff --git a/src/cascadia/TerminalApp/CascadiaSettings.h b/src/cascadia/TerminalSettingsModel/CascadiaSettings.h similarity index 61% rename from src/cascadia/TerminalApp/CascadiaSettings.h rename to src/cascadia/TerminalSettingsModel/CascadiaSettings.h index 909028ca956..410710b90b4 100644 --- a/src/cascadia/TerminalApp/CascadiaSettings.h +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.h @@ -19,7 +19,6 @@ Author(s): #include "CascadiaSettings.g.h" -#include #include "GlobalAppSettings.h" #include "TerminalWarnings.h" #include "IDynamicProfileGenerator.h" @@ -28,13 +27,12 @@ Author(s): #include "ColorScheme.h" // fwdecl unittest classes -namespace TerminalAppLocalTests +namespace SettingsModelLocalTests { - class SettingsTests; + class DeserializationTests; class ProfileTests; class ColorSchemeTests; class KeyBindingsTests; - class TabTests; }; namespace TerminalAppUnitTests { @@ -42,59 +40,63 @@ namespace TerminalAppUnitTests class JsonTests; }; -namespace TerminalApp +namespace Microsoft::Terminal::Settings::Model { class SettingsTypedDeserializationException; }; -class TerminalApp::SettingsTypedDeserializationException final : public std::runtime_error +class Microsoft::Terminal::Settings::Model::SettingsTypedDeserializationException final : public std::runtime_error { public: SettingsTypedDeserializationException(const std::string_view description) : runtime_error(description.data()) {} }; -namespace winrt::TerminalApp::implementation +namespace winrt::Microsoft::Terminal::Settings::Model::implementation { struct CascadiaSettings : CascadiaSettingsT { public: CascadiaSettings(); explicit CascadiaSettings(const bool addDynamicProfiles); + CascadiaSettings(hstring json); - static TerminalApp::CascadiaSettings LoadDefaults(); - static TerminalApp::CascadiaSettings LoadAll(); - static TerminalApp::CascadiaSettings LoadUniversal(); + static Model::CascadiaSettings LoadDefaults(); + static Model::CascadiaSettings LoadAll(); + static Model::CascadiaSettings LoadUniversal(); - TerminalApp::GlobalAppSettings GlobalSettings() const; + Model::GlobalAppSettings GlobalSettings() const; - Windows::Foundation::Collections::IObservableVector Profiles() const noexcept; + Windows::Foundation::Collections::IObservableVector Profiles() const noexcept; - TerminalApp::KeyMapping KeyMap() const noexcept; + Model::KeyMapping KeyMap() const noexcept; - static std::unique_ptr FromJson(const Json::Value& json); + static com_ptr FromJson(const Json::Value& json); void LayerJson(const Json::Value& json); - static std::filesystem::path GetSettingsPath(); - static std::filesystem::path GetDefaultSettingsPath(); + static hstring SettingsPath(); + static hstring DefaultSettingsPath(); - TerminalApp::Profile FindProfile(guid profileGuid) const noexcept; - TerminalApp::ColorScheme GetColorSchemeForProfile(const guid profileGuid) const; + static winrt::hstring ApplicationDisplayName(); + static winrt::hstring ApplicationVersion(); + + Model::Profile FindProfile(guid profileGuid) const noexcept; + Model::ColorScheme GetColorSchemeForProfile(const guid profileGuid) const; Windows::Foundation::Collections::IVectorView Warnings(); Windows::Foundation::IReference GetLoadingError(); hstring GetSerializationErrorMessage(); - winrt::guid GetProfileForArgs(const winrt::TerminalApp::NewTerminalArgs& newTerminalArgs) const; + winrt::guid GetProfileForArgs(const Model::NewTerminalArgs& newTerminalArgs) const; private: com_ptr _globals; - Windows::Foundation::Collections::IObservableVector _profiles; - Windows::Foundation::Collections::IVector _warnings; + Windows::Foundation::Collections::IObservableVector _profiles; + Windows::Foundation::Collections::IVector _warnings; Windows::Foundation::IReference _loadError; hstring _deserializationErrorMessage; - std::vector> _profileGenerators; + std::vector> _profileGenerators; std::string _userSettingsString; Json::Value _userSettings; @@ -102,9 +104,9 @@ namespace winrt::TerminalApp::implementation Json::Value _userDefaultProfileSettings{ Json::Value::null }; void _LayerOrCreateProfile(const Json::Value& profileJson); - winrt::com_ptr _FindMatchingProfile(const Json::Value& profileJson); + winrt::com_ptr _FindMatchingProfile(const Json::Value& profileJson); void _LayerOrCreateColorScheme(const Json::Value& schemeJson); - winrt::com_ptr _FindMatchingColorScheme(const Json::Value& schemeJson); + winrt::com_ptr _FindMatchingColorScheme(const Json::Value& schemeJson); void _ParseJsonString(std::string_view fileData, const bool isDefaultSettings); static const Json::Value& _GetProfilesJsonObject(const Json::Value& json); static const Json::Value& _GetDisabledProfileSourcesJsonObject(const Json::Value& json); @@ -137,17 +139,16 @@ namespace winrt::TerminalApp::implementation void _ValidateKeybindings(); void _ValidateNoGlobalsKey(); - friend class TerminalAppLocalTests::SettingsTests; - friend class TerminalAppLocalTests::ProfileTests; - friend class TerminalAppLocalTests::ColorSchemeTests; - friend class TerminalAppLocalTests::KeyBindingsTests; - friend class TerminalAppLocalTests::TabTests; + friend class SettingsModelLocalTests::DeserializationTests; + friend class SettingsModelLocalTests::ProfileTests; + friend class SettingsModelLocalTests::ColorSchemeTests; + friend class SettingsModelLocalTests::KeyBindingsTests; friend class TerminalAppUnitTests::DynamicProfileTests; friend class TerminalAppUnitTests::JsonTests; }; } -namespace winrt::TerminalApp::factory_implementation +namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation { BASIC_FACTORY(CascadiaSettings); } diff --git a/src/cascadia/TerminalApp/CascadiaSettings.idl b/src/cascadia/TerminalSettingsModel/CascadiaSettings.idl similarity index 74% rename from src/cascadia/TerminalApp/CascadiaSettings.idl rename to src/cascadia/TerminalSettingsModel/CascadiaSettings.idl index 08976a4b414..09779be7700 100644 --- a/src/cascadia/TerminalApp/CascadiaSettings.idl +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.idl @@ -5,13 +5,21 @@ import "GlobalAppSettings.idl"; import "Profile.idl"; import "TerminalWarnings.idl"; -namespace TerminalApp +namespace Microsoft.Terminal.Settings.Model { [default_interface] runtimeclass CascadiaSettings { + CascadiaSettings(String json); + static CascadiaSettings LoadDefaults(); static CascadiaSettings LoadAll(); static CascadiaSettings LoadUniversal(); + static String SettingsPath { get; }; + static String DefaultSettingsPath { get; }; + + static String ApplicationDisplayName { get; }; + static String ApplicationVersion { get; }; + GlobalAppSettings GlobalSettings { get; }; Windows.Foundation.Collections.IObservableVector Profiles { get; }; diff --git a/src/cascadia/TerminalApp/CascadiaSettingsSerialization.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp similarity index 94% rename from src/cascadia/TerminalApp/CascadiaSettingsSerialization.cpp rename to src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp index 6099cd2ee87..a3fa1c6fc3e 100644 --- a/src/cascadia/TerminalApp/CascadiaSettingsSerialization.cpp +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp @@ -5,7 +5,7 @@ #include #include "CascadiaSettings.h" #include "../../types/inc/utils.hpp" -#include "utils.h" +#include "Utils.h" #include "JsonUtils.h" #include #include @@ -18,7 +18,7 @@ // Both defaults.h and userDefaults.h are generated at build time into the // "Generated Files" directory. -using namespace winrt::TerminalApp::implementation; +using namespace winrt::Microsoft::Terminal::Settings::Model::implementation; using namespace ::Microsoft::Console; static constexpr std::wstring_view SettingsFilename{ L"settings.json" }; @@ -100,7 +100,7 @@ static void _CatchRethrowSerializationExceptionWithLocationInfo(std::string_view // profiles inserted into their list of profiles. // Return Value: // - a unique_ptr containing a new CascadiaSettings object. -winrt::TerminalApp::CascadiaSettings CascadiaSettings::LoadAll() +winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings CascadiaSettings::LoadAll() { try { @@ -195,7 +195,7 @@ winrt::TerminalApp::CascadiaSettings CascadiaSettings::LoadAll() // Do it after everything else so it won't happen unless validation passed. // Also, avoid processing unless someone's listening for measures. The keybindings work, at least, // is a lot of computation we can skip if no one cares. - if (TraceLoggingProviderEnabled(g_hTerminalAppProvider, 0, MICROSOFT_KEYWORD_MEASURES)) + if (TraceLoggingProviderEnabled(g_hSettingsModelProvider, 0, MICROSOFT_KEYWORD_MEASURES)) { const auto guid = resultPtr->GlobalSettings().DefaultProfile(); @@ -204,7 +204,7 @@ winrt::TerminalApp::CascadiaSettings CascadiaSettings::LoadAll() if (hardcodedDefaultGuid != guid) { TraceLoggingWrite( - g_hTerminalAppProvider, // handle to TerminalApp tracelogging provider + g_hSettingsModelProvider, // handle to TerminalApp tracelogging provider "CustomDefaultProfile", TraceLoggingDescription("Event emitted when user has chosen a different default profile than hardcoded one on load/reload"), TraceLoggingGuid(guid, "DefaultProfile", "ID of user-chosen default profile"), @@ -233,7 +233,7 @@ winrt::TerminalApp::CascadiaSettings CascadiaSettings::LoadAll() const auto keybindingsString = Json::writeString(wbuilder, value); TraceLoggingWrite( - g_hTerminalAppProvider, // handle to TerminalApp tracelogging provider + g_hSettingsModelProvider, // handle to TerminalApp tracelogging provider "CustomKeybindings", TraceLoggingDescription("Event emitted when custom keybindings are identified on load/reload"), TraceLoggingUtf8String(keybindingsString.c_str(), "Keybindings", "Keybindings as JSON"), @@ -265,7 +265,7 @@ winrt::TerminalApp::CascadiaSettings CascadiaSettings::LoadAll() // - // Return Value: // - a unique_ptr to a CascadiaSettings with the connection types and settings for Universal terminal -winrt::TerminalApp::CascadiaSettings CascadiaSettings::LoadUniversal() +winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings CascadiaSettings::LoadUniversal() { // We're going to do this ourselves because we want to exclude almost everything // from the special Universal-for-developers configuration @@ -305,7 +305,7 @@ winrt::TerminalApp::CascadiaSettings CascadiaSettings::LoadUniversal() // - // Return Value: // - a unique_ptr to a CascadiaSettings with the settings from defaults.json -winrt::TerminalApp::CascadiaSettings CascadiaSettings::LoadDefaults() +winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings CascadiaSettings::LoadDefaults() { auto resultPtr{ winrt::make_self() }; @@ -472,8 +472,6 @@ bool CascadiaSettings::_AppendDynamicProfilesToUserSettings() // * Serialize that diff // * Insert that diff to the end of the list of profiles. - const Profile defaultProfile; - Json::StreamWriterBuilder wbuilder; // Use 4 spaces to indent instead of \t wbuilder.settings_["indentation"] = " "; @@ -484,7 +482,7 @@ bool CascadiaSettings::_AppendDynamicProfilesToUserSettings() { if (profileJson.isObject()) { - const auto profileImpl = winrt::get_self(profile); + const auto profileImpl = winrt::get_self(profile); if (profileImpl->ShouldBeLayered(profileJson)) { return true; @@ -535,7 +533,7 @@ bool CascadiaSettings::_AppendDynamicProfilesToUserSettings() // Generate a diff for the profile, that contains the minimal set of // changes to re-create this profile. - const auto profileImpl = winrt::get_self(profile); + const auto profileImpl = winrt::get_self(profile); const auto diff = profileImpl->GenerateStub(); auto profileSerialization = Json::writeString(wbuilder, diff); @@ -573,9 +571,9 @@ bool CascadiaSettings::_AppendDynamicProfilesToUserSettings() // - json: an object which should be a serialization of a CascadiaSettings object. // Return Value: // - a new CascadiaSettings instance created from the values in `json` -std::unique_ptr CascadiaSettings::FromJson(const Json::Value& json) +winrt::com_ptr CascadiaSettings::FromJson(const Json::Value& json) { - auto resultPtr = std::make_unique(); + auto resultPtr = winrt::make_self(); resultPtr->LayerJson(json); return resultPtr; } @@ -793,7 +791,7 @@ bool CascadiaSettings::_IsPackaged() // fail to write the file void CascadiaSettings::_WriteSettings(const std::string_view content) { - auto pathToSettingsFile{ CascadiaSettings::GetSettingsPath() }; + auto pathToSettingsFile{ CascadiaSettings::SettingsPath() }; wil::unique_hfile hOut{ CreateFileW(pathToSettingsFile.c_str(), GENERIC_WRITE, @@ -820,7 +818,7 @@ void CascadiaSettings::_WriteSettings(const std::string_view content) // from reading the file std::optional CascadiaSettings::_ReadUserSettings() { - const auto pathToSettingsFile{ CascadiaSettings::GetSettingsPath() }; + const auto pathToSettingsFile{ CascadiaSettings::SettingsPath() }; wil::unique_hfile hFile{ CreateFileW(pathToSettingsFile.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, @@ -834,7 +832,7 @@ std::optional CascadiaSettings::_ReadUserSettings() // GH#5186 - We moved from profiles.json to settings.json; we want to // migrate any file we find. We're using MoveFile in case their settings.json // is a symbolic link. - auto pathToLegacySettingsFile{ pathToSettingsFile }; + std::filesystem::path pathToLegacySettingsFile{ std::wstring_view{ pathToSettingsFile } }; pathToLegacySettingsFile.replace_filename(LegacySettingsFilename); wil::unique_hfile hLegacyFile{ CreateFileW(pathToLegacySettingsFile.c_str(), @@ -918,7 +916,7 @@ std::optional CascadiaSettings::_ReadFile(HANDLE hFile) // - // Return Value: // - the full path to the settings file -std::filesystem::path CascadiaSettings::GetSettingsPath() +winrt::hstring CascadiaSettings::SettingsPath() { wil::unique_cotaskmem_string localAppDataFolder; // KF_FLAG_FORCE_APP_DATA_REDIRECTION, when engaged, causes SHGet... to return @@ -936,10 +934,10 @@ std::filesystem::path CascadiaSettings::GetSettingsPath() // Create the directory if it doesn't exist std::filesystem::create_directories(parentDirectoryForSettingsFile); - return parentDirectoryForSettingsFile / SettingsFilename; + return winrt::hstring{ (parentDirectoryForSettingsFile / SettingsFilename).wstring() }; } -std::filesystem::path CascadiaSettings::GetDefaultSettingsPath() +winrt::hstring CascadiaSettings::DefaultSettingsPath() { // Both of these posts suggest getting the path to the exe, then removing // the exe's name to get the package root: @@ -959,7 +957,7 @@ std::filesystem::path CascadiaSettings::GetDefaultSettingsPath() const std::filesystem::path exePath{ exePathString }; const std::filesystem::path rootDir = exePath.parent_path(); - return rootDir / DefaultsFilename; + return winrt::hstring{ (rootDir / DefaultsFilename).wstring() }; } // Function Description: diff --git a/src/cascadia/TerminalApp/ColorScheme.cpp b/src/cascadia/TerminalSettingsModel/ColorScheme.cpp similarity index 94% rename from src/cascadia/TerminalApp/ColorScheme.cpp rename to src/cascadia/TerminalSettingsModel/ColorScheme.cpp index 4c4ee9cca42..78c2da9e0b4 100644 --- a/src/cascadia/TerminalApp/ColorScheme.cpp +++ b/src/cascadia/TerminalSettingsModel/ColorScheme.cpp @@ -11,8 +11,8 @@ #include "ColorScheme.g.cpp" using namespace ::Microsoft::Console; -using namespace TerminalApp; -using namespace winrt::TerminalApp::implementation; +using namespace Microsoft::Terminal::Settings::Model; +using namespace winrt::Microsoft::Terminal::Settings::Model::implementation; using namespace winrt::Windows::UI; static constexpr std::string_view NameKey{ "name" }; diff --git a/src/cascadia/TerminalApp/ColorScheme.h b/src/cascadia/TerminalSettingsModel/ColorScheme.h similarity index 82% rename from src/cascadia/TerminalApp/ColorScheme.h rename to src/cascadia/TerminalSettingsModel/ColorScheme.h index 68456dc15b3..87c69c9fba4 100644 --- a/src/cascadia/TerminalApp/ColorScheme.h +++ b/src/cascadia/TerminalSettingsModel/ColorScheme.h @@ -21,13 +21,13 @@ Author(s): #include "ColorScheme.g.h" // fwdecl unittest classes -namespace TerminalAppLocalTests +namespace SettingsModelLocalTests { class SettingsTests; class ColorSchemeTests; }; -namespace winrt::TerminalApp::implementation +namespace winrt::Microsoft::Terminal::Settings::Model::implementation { struct ColorScheme : ColorSchemeT { @@ -55,12 +55,7 @@ namespace winrt::TerminalApp::implementation private: std::array _table; - friend class TerminalAppLocalTests::SettingsTests; - friend class TerminalAppLocalTests::ColorSchemeTests; + friend class SettingsModelLocalTests::SettingsTests; + friend class SettingsModelLocalTests::ColorSchemeTests; }; } - -namespace winrt::TerminalApp::factory_implementation -{ - BASIC_FACTORY(ColorScheme); -} diff --git a/src/cascadia/TerminalApp/ColorScheme.idl b/src/cascadia/TerminalSettingsModel/ColorScheme.idl similarity index 86% rename from src/cascadia/TerminalApp/ColorScheme.idl rename to src/cascadia/TerminalSettingsModel/ColorScheme.idl index f1603f8a309..02aaf514bce 100644 --- a/src/cascadia/TerminalApp/ColorScheme.idl +++ b/src/cascadia/TerminalSettingsModel/ColorScheme.idl @@ -1,11 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -namespace TerminalApp +namespace Microsoft.Terminal.Settings.Model { [default_interface] runtimeclass ColorScheme { - ColorScheme(); - String Name; Windows.UI.Color Foreground; diff --git a/src/cascadia/TerminalApp/Command.cpp b/src/cascadia/TerminalSettingsModel/Command.cpp similarity index 77% rename from src/cascadia/TerminalApp/Command.cpp rename to src/cascadia/TerminalSettingsModel/Command.cpp index b5ae9c0f5f8..e0cc54672fa 100644 --- a/src/cascadia/TerminalApp/Command.cpp +++ b/src/cascadia/TerminalSettingsModel/Command.cpp @@ -5,15 +5,14 @@ #include "Command.h" #include "Command.g.cpp" -#include "Utils.h" #include "ActionAndArgs.h" #include "JsonUtils.h" #include #include "TerminalSettingsSerializationHelpers.h" -using namespace winrt::TerminalApp; -using namespace winrt::Windows::Foundation; -using namespace ::TerminalApp; +using namespace winrt::Microsoft::Terminal::Settings::Model; +using namespace winrt::Windows::Foundation::Collections; +using namespace ::Microsoft::Terminal::Settings::Model; namespace winrt { @@ -32,14 +31,14 @@ static constexpr std::string_view ProfileNameToken{ "${profile.name}" }; static constexpr std::string_view ProfileIconToken{ "${profile.icon}" }; static constexpr std::string_view SchemeNameToken{ "${scheme.name}" }; -namespace winrt::TerminalApp::implementation +namespace winrt::Microsoft::Terminal::Settings::Model::implementation { Command::Command() { _setAction(nullptr); } - Collections::IMapView Command::NestedCommands() + IMapView Command::NestedCommands() { return _subcommands ? _subcommands.GetView() : nullptr; } @@ -107,70 +106,6 @@ namespace winrt::TerminalApp::implementation return actionAndArgs->GenerateName(); } - // Method Description: - // - Actually initialize our IconSource for our _lastIconPath. Supports a variety of icons: - // * If the icon is a path to an image, we'll use that. - // * If it isn't, then we'll try and use the text as a FontIcon. If the - // character is in the range of symbols reserved for the Segoe MDL2 - // Asserts, well treat it as such. Otherwise, we'll default to a Sego - // UI icon, so things like emoji will work. - // - MUST BE CALLED ON THE UI THREAD. - // Arguments: - // - - // Return Value: - // - - void Command::RefreshIcon() - { - if (!_lastIconPath.empty()) - { - _setIconSource(GetColoredIcon(_lastIconPath)); - - // If we fail to set the icon source using the "icon" as a path, - // let's try it as a symbol/emoji. - // - // Anything longer that 2 wchar_t's _isn't_ an emoji or symbol, so - // don't do this if it's just an invalid path. - if (IconSource() == nullptr && _lastIconPath.size() <= 2) - { - try - { - WUX::Controls::FontIconSource icon; - const wchar_t ch = _lastIconPath[0]; - - // The range of MDL2 Icons isn't explicitly defined, but - // we're using this based off the table on: - // https://docs.microsoft.com/en-us/windows/uwp/design/style/segoe-ui-symbol-font - const bool isMDL2Icon = ch >= L'\uE700' && ch <= L'\uF8FF'; - if (isMDL2Icon) - { - icon.FontFamily(WUX::Media::FontFamily{ L"Segoe MDL2 Assets" }); - } - else - { - // Note: you _do_ need to manually set the font here. - icon.FontFamily(WUX::Media::FontFamily{ L"Segoe UI" }); - } - icon.FontSize(12); - icon.Glyph(_lastIconPath); - _setIconSource(icon); - } - CATCH_LOG(); - } - } - if (IconSource() == nullptr) - { - // Set the default IconSource to a BitmapIconSource with a null source - // (instead of just nullptr) because there's a really weird crash when swapping - // data bound IconSourceElements in a ListViewTemplate (i.e. CommandPalette). - // Swapping between nullptr IconSources and non-null IconSources causes a crash - // to occur, but swapping between IconSources with a null source and non-null IconSources - // work perfectly fine :shrug:. - winrt::Windows::UI::Xaml::Controls::BitmapIconSource icon; - icon.UriSource(nullptr); - _setIconSource(icon); - } - } - // Method Description: // - Deserialize a Command from the `json` object. The json object should // contain a "name" and "action", and optionally an "icon". @@ -200,7 +135,7 @@ namespace winrt::TerminalApp::implementation if (const auto nestedCommandsJson{ json[JsonKey(CommandsKey)] }) { // Initialize our list of subcommands. - result->_subcommands = winrt::single_threaded_map(); + result->_subcommands = winrt::single_threaded_map(); auto nestedWarnings = Command::LayerJson(result->_subcommands, nestedCommandsJson); // It's possible that the nested commands have some warnings warnings.insert(warnings.end(), nestedWarnings.begin(), nestedWarnings.end()); @@ -216,7 +151,7 @@ namespace winrt::TerminalApp::implementation // Only get the icon path right now. The icon needs to be resolved into // an IconSource on the UI thread, which will be done by RefreshIcon. - JsonUtils::GetValueForKey(json, IconKey, result->_lastIconPath); + JsonUtils::GetValueForKey(json, IconKey, result->_IconPath); // If we're a nested command, we can ignore the current action. if (!nested) @@ -280,7 +215,7 @@ namespace winrt::TerminalApp::implementation // - json: A Json::Value containing an array of serialized commands // Return Value: // - A vector containing any warnings detected while parsing - std::vector Command::LayerJson(Windows::Foundation::Collections::IMap& commands, + std::vector Command::LayerJson(IMap& commands, const Json::Value& json) { std::vector warnings; @@ -352,13 +287,13 @@ namespace winrt::TerminalApp::implementation // appended to this vector. // Return Value: // - - void Command::ExpandCommands(Windows::Foundation::Collections::IMap& commands, - Windows::Foundation::Collections::IVectorView profiles, - gsl::span schemes, - std::vector& warnings) + void Command::ExpandCommands(IMap commands, + IVectorView profiles, + IVectorView schemes, + IVector warnings) { std::vector commandsToRemove; - std::vector commandsToAdd; + std::vector commandsToAdd; // First, collect up all the commands that need replacing. for (const auto& nameAndCmd : commands) @@ -408,12 +343,12 @@ namespace winrt::TerminalApp::implementation // Return Value: // - and empty vector if the command wasn't expandable, otherwise a list of // the newly-created commands. - std::vector Command::_expandCommand(Command* const expandable, - Windows::Foundation::Collections::IVectorView profiles, - gsl::span schemes, - std::vector& warnings) + std::vector Command::_expandCommand(Command* const expandable, + IVectorView profiles, + IVectorView schemes, + IVector& warnings) { - std::vector newCommands; + std::vector newCommands; if (expandable->HasNestedCommands()) { @@ -438,16 +373,18 @@ namespace winrt::TerminalApp::implementation const auto actualDataEnd = newJsonString.data() + newJsonString.size(); if (!reader->parse(actualDataStart, actualDataEnd, &newJsonValue, &errs)) { - warnings.push_back(SettingsLoadWarnings::FailedToParseCommandJson); + warnings.Append(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) }) + std::vector newWarnings; + if (auto newCmd{ Command::FromJson(newJsonValue, newWarnings) }) { newCommands.push_back(*newCmd); } + std::for_each(newWarnings.begin(), newWarnings.end(), [warnings](auto& warn) { warnings.Append(warn); }); return true; }; diff --git a/src/cascadia/TerminalSettingsModel/Command.h b/src/cascadia/TerminalSettingsModel/Command.h new file mode 100644 index 00000000000..d73058cc6db --- /dev/null +++ b/src/cascadia/TerminalSettingsModel/Command.h @@ -0,0 +1,80 @@ +/*++ +Copyright (c) Microsoft Corporation +Licensed under the MIT license. + +Module Name: +- Command.h + +Abstract: +- A command represents a single entry in the Command Palette. This is an object + that has a user facing "name" to display to the user, and an associated action + which can be dispatched. + +- For more information, see GH#2046, #5400, #5674, and #6635 + +Author(s): +- Mike Griese - June 2020 + +--*/ +#pragma once + +#include "Command.g.h" +#include "TerminalWarnings.h" +#include "Profile.h" +#include "..\inc\cppwinrt_utils.h" +#include "SettingsTypes.h" + +// fwdecl unittest classes +namespace SettingsModelLocalTests +{ + class DeserializationTests; + class CommandTests; +}; + +namespace winrt::Microsoft::Terminal::Settings::Model::implementation +{ + struct Command : CommandT + { + Command(); + + static winrt::com_ptr FromJson(const Json::Value& json, + std::vector& warnings); + + static void ExpandCommands(Windows::Foundation::Collections::IMap commands, + Windows::Foundation::Collections::IVectorView profiles, + Windows::Foundation::Collections::IVectorView schemes, + Windows::Foundation::Collections::IVector warnings); + + static std::vector LayerJson(Windows::Foundation::Collections::IMap& commands, + const Json::Value& json); + bool HasNestedCommands(); + Windows::Foundation::Collections::IMapView NestedCommands(); + + winrt::Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker propertyChangedRevoker; + + WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler); + OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Name, _PropertyChangedHandlers); + OBSERVABLE_GETSET_PROPERTY(Model::ActionAndArgs, Action, _PropertyChangedHandlers); + OBSERVABLE_GETSET_PROPERTY(winrt::hstring, KeyChordText, _PropertyChangedHandlers); + OBSERVABLE_GETSET_PROPERTY(winrt::Windows::UI::Xaml::Controls::IconSource, IconSource, _PropertyChangedHandlers, nullptr); + GETSET_PROPERTY(winrt::hstring, IconPath); + + GETSET_PROPERTY(ExpandCommandType, IterateOn, ExpandCommandType::None); + + private: + Json::Value _originalJson; + Windows::Foundation::Collections::IMap _subcommands{ nullptr }; + + static std::vector _expandCommand(Command* const expandable, + Windows::Foundation::Collections::IVectorView profiles, + Windows::Foundation::Collections::IVectorView schemes, + Windows::Foundation::Collections::IVector& warnings); + friend class SettingsModelLocalTests::DeserializationTests; + friend class SettingsModelLocalTests::CommandTests; + }; +} + +namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation +{ + BASIC_FACTORY(Command); +} diff --git a/src/cascadia/TerminalSettingsModel/Command.idl b/src/cascadia/TerminalSettingsModel/Command.idl new file mode 100644 index 00000000000..98d3bc27aa8 --- /dev/null +++ b/src/cascadia/TerminalSettingsModel/Command.idl @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import "KeyMapping.idl"; +import "Profile.idl"; +import "ColorScheme.idl"; +import "TerminalWarnings.idl"; + +namespace Microsoft.Terminal.Settings.Model +{ + [default_interface] runtimeclass Command : Windows.UI.Xaml.Data.INotifyPropertyChanged + { + Command(); + + String Name; + ActionAndArgs Action; + String KeyChordText; + + Windows.UI.Xaml.Controls.IconSource IconSource; + String IconPath { get; }; + + Boolean HasNestedCommands { get; }; + Windows.Foundation.Collections.IMapView NestedCommands { get; }; + + static void ExpandCommands(Windows.Foundation.Collections.IMap commands, + Windows.Foundation.Collections.IVectorView profiles, + Windows.Foundation.Collections.IVectorView schemes, + Windows.Foundation.Collections.IVector warnings); + } +} diff --git a/src/cascadia/TerminalApp/DefaultProfileUtils.cpp b/src/cascadia/TerminalSettingsModel/DefaultProfileUtils.cpp similarity index 80% rename from src/cascadia/TerminalApp/DefaultProfileUtils.cpp rename to src/cascadia/TerminalSettingsModel/DefaultProfileUtils.cpp index 18c59ef6e88..57b3701145d 100644 --- a/src/cascadia/TerminalApp/DefaultProfileUtils.cpp +++ b/src/cascadia/TerminalSettingsModel/DefaultProfileUtils.cpp @@ -15,11 +15,11 @@ static constexpr std::wstring_view PACKAGED_PROFILE_ICON_EXTENSION{ L".png" }; // - name: the name of the new profile. // Return Value: // - A Profile, ready to be filled in -winrt::TerminalApp::Profile CreateDefaultProfile(const std::wstring_view name) +winrt::Microsoft::Terminal::Settings::Model::Profile CreateDefaultProfile(const std::wstring_view name) { const winrt::guid profileGuid{ Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID, gsl::as_bytes(gsl::make_span(name))) }; - auto newProfile = winrt::make(profileGuid); + auto newProfile = winrt::make(profileGuid); newProfile.Name(name); std::wstring iconPath{ PACKAGED_PROFILE_ICON_PATH }; diff --git a/src/cascadia/TerminalApp/DefaultProfileUtils.h b/src/cascadia/TerminalSettingsModel/DefaultProfileUtils.h similarity index 85% rename from src/cascadia/TerminalApp/DefaultProfileUtils.h rename to src/cascadia/TerminalSettingsModel/DefaultProfileUtils.h index c12b7169cf0..28b6c53cd7e 100644 --- a/src/cascadia/TerminalApp/DefaultProfileUtils.h +++ b/src/cascadia/TerminalSettingsModel/DefaultProfileUtils.h @@ -20,4 +20,4 @@ Author(s): // uuidv5 properties: name format is UTF-16LE bytes static constexpr GUID TERMINAL_PROFILE_NAMESPACE_GUID = { 0x2bde4a90, 0xd05f, 0x401c, { 0x94, 0x92, 0xe4, 0x8, 0x84, 0xea, 0xd1, 0xd8 } }; -winrt::TerminalApp::Profile CreateDefaultProfile(const std::wstring_view name); +winrt::Microsoft::Terminal::Settings::Model::Profile CreateDefaultProfile(const std::wstring_view name); diff --git a/src/cascadia/TerminalApp/GlobalAppSettings.cpp b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.cpp similarity index 87% rename from src/cascadia/TerminalApp/GlobalAppSettings.cpp rename to src/cascadia/TerminalSettingsModel/GlobalAppSettings.cpp index 4ce7ba31530..224b279ce43 100644 --- a/src/cascadia/TerminalApp/GlobalAppSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.cpp @@ -5,14 +5,13 @@ #include "GlobalAppSettings.h" #include "../../types/inc/Utils.hpp" #include "../../inc/DefaultSettings.h" -#include "Utils.h" #include "JsonUtils.h" #include "TerminalSettingsSerializationHelpers.h" #include "GlobalAppSettings.g.cpp" -using namespace TerminalApp; -using namespace winrt::TerminalApp::implementation; +using namespace Microsoft::Terminal::Settings::Model; +using namespace winrt::Microsoft::Terminal::Settings::Model::implementation; using namespace winrt::Windows::UI::Xaml; using namespace ::Microsoft::Console; using namespace winrt::Microsoft::UI::Xaml::Controls; @@ -59,11 +58,11 @@ GlobalAppSettings::GlobalAppSettings() : _defaultProfile{}, _DebugFeaturesEnabled{ debugFeaturesDefault } { - _commands = winrt::single_threaded_map(); - _colorSchemes = winrt::single_threaded_map(); + _commands = winrt::single_threaded_map(); + _colorSchemes = winrt::single_threaded_map(); } -winrt::Windows::Foundation::Collections::IMapView GlobalAppSettings::ColorSchemes() noexcept +winrt::Windows::Foundation::Collections::IMapView GlobalAppSettings::ColorSchemes() noexcept { return _colorSchemes.GetView(); } @@ -86,7 +85,7 @@ winrt::hstring GlobalAppSettings::UnparsedDefaultProfile() const return _unparsedDefaultProfile; } -winrt::TerminalApp::KeyMapping GlobalAppSettings::KeyMap() const noexcept +winrt::Microsoft::Terminal::Settings::Model::KeyMapping GlobalAppSettings::KeyMap() const noexcept { return *_keymap; } @@ -170,7 +169,7 @@ void GlobalAppSettings::LayerJson(const Json::Value& json) _keybindingsWarnings.insert(_keybindingsWarnings.end(), warnings.begin(), warnings.end()); // Now parse the array again, but this time as a list of commands. - warnings = winrt::TerminalApp::implementation::Command::LayerJson(_commands, bindings); + warnings = implementation::Command::LayerJson(_commands, bindings); } }; parseBindings(LegacyKeybindingsKey); @@ -183,7 +182,7 @@ void GlobalAppSettings::LayerJson(const Json::Value& json) // - scheme: the color scheme to add // Return Value: // - -void GlobalAppSettings::AddColorScheme(const winrt::TerminalApp::ColorScheme& scheme) +void GlobalAppSettings::AddColorScheme(const Model::ColorScheme& scheme) { _colorSchemes.Insert(scheme.Name(), scheme); } @@ -197,12 +196,12 @@ void GlobalAppSettings::AddColorScheme(const winrt::TerminalApp::ColorScheme& sc // - // Return Value: // - -std::vector GlobalAppSettings::KeybindingsWarnings() const +std::vector GlobalAppSettings::KeybindingsWarnings() const { return _keybindingsWarnings; } -winrt::Windows::Foundation::Collections::IMapView GlobalAppSettings::Commands() noexcept +winrt::Windows::Foundation::Collections::IMapView GlobalAppSettings::Commands() noexcept { return _commands.GetView(); } diff --git a/src/cascadia/TerminalApp/GlobalAppSettings.h b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.h similarity index 67% rename from src/cascadia/TerminalApp/GlobalAppSettings.h rename to src/cascadia/TerminalSettingsModel/GlobalAppSettings.h index b5d8a2d8a15..600fb255c54 100644 --- a/src/cascadia/TerminalApp/GlobalAppSettings.h +++ b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.h @@ -22,30 +22,30 @@ Author(s): #include "ColorScheme.h" // fwdecl unittest classes -namespace TerminalAppLocalTests +namespace SettingsModelLocalTests { - class SettingsTests; + class DeserializationTests; class ColorSchemeTests; }; -namespace winrt::TerminalApp::implementation +namespace winrt::Microsoft::Terminal::Settings::Model::implementation { struct GlobalAppSettings : GlobalAppSettingsT { public: GlobalAppSettings(); - Windows::Foundation::Collections::IMapView ColorSchemes() noexcept; - void AddColorScheme(const TerminalApp::ColorScheme& scheme); + Windows::Foundation::Collections::IMapView ColorSchemes() noexcept; + void AddColorScheme(const Model::ColorScheme& scheme); - TerminalApp::KeyMapping KeyMap() const noexcept; + Model::KeyMapping KeyMap() const noexcept; static com_ptr FromJson(const Json::Value& json); void LayerJson(const Json::Value& json); - std::vector KeybindingsWarnings() const; + std::vector KeybindingsWarnings() const; - Windows::Foundation::Collections::IMapView Commands() noexcept; + Windows::Foundation::Collections::IMapView Commands() noexcept; // These are implemented manually to handle the string/GUID exchange // by higher layers in the app. @@ -66,8 +66,8 @@ namespace winrt::TerminalApp::implementation GETSET_PROPERTY(winrt::Microsoft::Terminal::TerminalControl::CopyFormat, CopyFormatting, 0); GETSET_PROPERTY(bool, WarnAboutLargePaste, true); GETSET_PROPERTY(bool, WarnAboutMultiLinePaste, true); - GETSET_PROPERTY(winrt::TerminalApp::LaunchPosition, InitialPosition, nullptr, nullptr); - GETSET_PROPERTY(winrt::TerminalApp::LaunchMode, LaunchMode, winrt::TerminalApp::LaunchMode::DefaultMode); + GETSET_PROPERTY(Model::LaunchPosition, InitialPosition, nullptr, nullptr); + GETSET_PROPERTY(Model::LaunchMode, LaunchMode, LaunchMode::DefaultMode); GETSET_PROPERTY(bool, SnapToGridOnResize, true); GETSET_PROPERTY(bool, ForceFullRepaintRendering, false); GETSET_PROPERTY(bool, SoftwareRendering, false); @@ -82,12 +82,12 @@ namespace winrt::TerminalApp::implementation guid _defaultProfile; com_ptr _keymap; - std::vector _keybindingsWarnings; + std::vector _keybindingsWarnings; - Windows::Foundation::Collections::IMap _colorSchemes; - Windows::Foundation::Collections::IMap _commands; + Windows::Foundation::Collections::IMap _colorSchemes; + Windows::Foundation::Collections::IMap _commands; - friend class TerminalAppLocalTests::SettingsTests; - friend class TerminalAppLocalTests::ColorSchemeTests; + friend class SettingsModelLocalTests::DeserializationTests; + friend class SettingsModelLocalTests::ColorSchemeTests; }; } diff --git a/src/cascadia/TerminalApp/GlobalAppSettings.idl b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl similarity index 89% rename from src/cascadia/TerminalApp/GlobalAppSettings.idl rename to src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl index 8bcf0a44e68..5a748738719 100644 --- a/src/cascadia/TerminalApp/GlobalAppSettings.idl +++ b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl @@ -1,12 +1,11 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import "AppLogic.idl"; import "ColorScheme.idl"; import "KeyMapping.idl"; import "Command.idl"; -namespace TerminalApp +namespace Microsoft.Terminal.Settings.Model { // MIDL 3 allows for structs to hold nullable types // Though IReference is a WinRT object, MIDL 3 @@ -18,6 +17,13 @@ namespace TerminalApp Windows.Foundation.IReference Y; }; + enum LaunchMode + { + DefaultMode, + MaximizedMode, + FullscreenMode, + }; + [default_interface] runtimeclass GlobalAppSettings { Guid DefaultProfile; String UnparsedDefaultProfile(); diff --git a/src/cascadia/TerminalApp/IDynamicProfileGenerator.h b/src/cascadia/TerminalSettingsModel/IDynamicProfileGenerator.h similarity index 70% rename from src/cascadia/TerminalApp/IDynamicProfileGenerator.h rename to src/cascadia/TerminalSettingsModel/IDynamicProfileGenerator.h index 22940364a26..2b55049650b 100644 --- a/src/cascadia/TerminalApp/IDynamicProfileGenerator.h +++ b/src/cascadia/TerminalSettingsModel/IDynamicProfileGenerator.h @@ -22,16 +22,16 @@ Author(s): #pragma once #include "Profile.h" -namespace TerminalApp +namespace Microsoft::Terminal::Settings::Model { class IDynamicProfileGenerator; }; -class TerminalApp::IDynamicProfileGenerator +class Microsoft::Terminal::Settings::Model::IDynamicProfileGenerator { public: virtual ~IDynamicProfileGenerator() = 0; virtual std::wstring_view GetNamespace() = 0; - virtual std::vector GenerateProfiles() = 0; + virtual std::vector GenerateProfiles() = 0; }; -inline TerminalApp::IDynamicProfileGenerator::~IDynamicProfileGenerator() {} +inline Microsoft::Terminal::Settings::Model::IDynamicProfileGenerator::~IDynamicProfileGenerator() {} diff --git a/src/cascadia/TerminalApp/JsonUtils.h b/src/cascadia/TerminalSettingsModel/JsonUtils.h similarity index 90% rename from src/cascadia/TerminalApp/JsonUtils.h rename to src/cascadia/TerminalSettingsModel/JsonUtils.h index 11c1a40d1d3..2ed3f1bde9e 100644 --- a/src/cascadia/TerminalApp/JsonUtils.h +++ b/src/cascadia/TerminalSettingsModel/JsonUtils.h @@ -6,7 +6,7 @@ Module Name: - JsonUtils.h Abstract: -- Helpers for the TerminalApp project +- Helpers for the Terminal Settings Model project Author(s): - Mike Griese - August 2019 - Dustin Howett - January 2020 @@ -31,7 +31,21 @@ namespace winrt } } -namespace TerminalApp::JsonUtils +// Method Description: +// - Create a std::string from a string_view. We do this because we can't look +// up a key in a Json::Value with a string_view directly, so instead we'll use +// this helper. Should a string_view lookup ever be added to jsoncpp, we can +// remove this entirely. +// Arguments: +// - key: the string_view to build a string from +// Return Value: +// - a std::string to use for looking up a value from a Json::Value +inline std::string JsonKey(const std::string_view key) +{ + return static_cast(key); +} + +namespace Microsoft::Terminal::Settings::Model::JsonUtils { namespace Detail { @@ -694,15 +708,15 @@ namespace TerminalApp::JsonUtils } }; -#define JSON_ENUM_MAPPER(...) \ - template<> \ - struct ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__> : \ - public ::TerminalApp::JsonUtils::EnumMapper<__VA_ARGS__, ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__>> +#define JSON_ENUM_MAPPER(...) \ + template<> \ + struct ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait<__VA_ARGS__> : \ + public ::Microsoft::Terminal::Settings::Model::JsonUtils::EnumMapper<__VA_ARGS__, ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait<__VA_ARGS__>> -#define JSON_FLAG_MAPPER(...) \ - template<> \ - struct ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__> : \ - public ::TerminalApp::JsonUtils::FlagMapper<__VA_ARGS__, ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__>> +#define JSON_FLAG_MAPPER(...) \ + template<> \ + struct ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait<__VA_ARGS__> : \ + public ::Microsoft::Terminal::Settings::Model::JsonUtils::FlagMapper<__VA_ARGS__, ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait<__VA_ARGS__>> #define JSON_MAPPINGS(Count) \ static constexpr std::array mappings diff --git a/src/cascadia/TerminalApp/KeyChordSerialization.cpp b/src/cascadia/TerminalSettingsModel/KeyChordSerialization.cpp similarity index 96% rename from src/cascadia/TerminalApp/KeyChordSerialization.cpp rename to src/cascadia/TerminalSettingsModel/KeyChordSerialization.cpp index 16e9732a57f..b57fdc5207c 100644 --- a/src/cascadia/TerminalApp/KeyChordSerialization.cpp +++ b/src/cascadia/TerminalSettingsModel/KeyChordSerialization.cpp @@ -3,8 +3,10 @@ #include "pch.h" #include "KeyChordSerialization.h" +#include "KeyChordSerialization.g.cpp" using namespace winrt::Microsoft::Terminal::TerminalControl; +using namespace winrt::Microsoft::Terminal::Settings::Model::implementation; static constexpr std::wstring_view CTRL_KEY{ L"ctrl" }; static constexpr std::wstring_view SHIFT_KEY{ L"shift" }; diff --git a/src/cascadia/TerminalSettingsModel/KeyChordSerialization.h b/src/cascadia/TerminalSettingsModel/KeyChordSerialization.h new file mode 100644 index 00000000000..53304420ba4 --- /dev/null +++ b/src/cascadia/TerminalSettingsModel/KeyChordSerialization.h @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +#include "KeyChordSerialization.g.h" +#include "../inc/cppwinrt_utils.h" + +namespace winrt::Microsoft::Terminal::Settings::Model::implementation +{ + struct KeyChordSerialization + { + KeyChordSerialization() = default; + + static winrt::Microsoft::Terminal::TerminalControl::KeyChord FromString(const winrt::hstring& str); + static winrt::hstring ToString(const winrt::Microsoft::Terminal::TerminalControl::KeyChord& chord); + }; +} + +namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation +{ + // C++/WinRT generates a constructor even though one is not specified in the IDL + BASIC_FACTORY(KeyChordSerialization); +} diff --git a/src/cascadia/TerminalSettingsModel/KeyChordSerialization.idl b/src/cascadia/TerminalSettingsModel/KeyChordSerialization.idl new file mode 100644 index 00000000000..966d10f23ec --- /dev/null +++ b/src/cascadia/TerminalSettingsModel/KeyChordSerialization.idl @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +namespace Microsoft.Terminal.Settings.Model +{ + static runtimeclass KeyChordSerialization + { + static Microsoft.Terminal.TerminalControl.KeyChord FromString(String str); + static String ToString(Microsoft.Terminal.TerminalControl.KeyChord chord); + } +} diff --git a/src/cascadia/TerminalApp/KeyMapping.cpp b/src/cascadia/TerminalSettingsModel/KeyMapping.cpp similarity index 79% rename from src/cascadia/TerminalApp/KeyMapping.cpp rename to src/cascadia/TerminalSettingsModel/KeyMapping.cpp index 495feaab57d..91838eab09f 100644 --- a/src/cascadia/TerminalApp/KeyMapping.cpp +++ b/src/cascadia/TerminalSettingsModel/KeyMapping.cpp @@ -7,12 +7,12 @@ #include "KeyMapping.g.cpp" -using namespace winrt::TerminalApp; +using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::TerminalControl; -namespace winrt::TerminalApp::implementation +namespace winrt::Microsoft::Terminal::Settings::Model::implementation { - TerminalApp::ActionAndArgs KeyMapping::TryLookup(KeyChord const& chord) const + Microsoft::Terminal::Settings::Model::ActionAndArgs KeyMapping::TryLookup(KeyChord const& chord) const { const auto result = _keyShortcuts.find(chord); if (result != _keyShortcuts.end()) @@ -22,7 +22,12 @@ namespace winrt::TerminalApp::implementation return nullptr; } - void KeyMapping::SetKeyBinding(const TerminalApp::ActionAndArgs& actionAndArgs, + uint64_t KeyMapping::Size() const + { + return _keyShortcuts.size(); + } + + void KeyMapping::SetKeyBinding(const Microsoft::Terminal::Settings::Model::ActionAndArgs& actionAndArgs, const KeyChord& chord) { _keyShortcuts[chord] = actionAndArgs; @@ -39,7 +44,7 @@ namespace winrt::TerminalApp::implementation _keyShortcuts.erase(chord); } - KeyChord KeyMapping::GetKeyBindingForAction(TerminalApp::ShortcutAction const& action) + KeyChord KeyMapping::GetKeyBindingForAction(Microsoft::Terminal::Settings::Model::ShortcutAction const& action) { for (auto& kv : _keyShortcuts) { @@ -60,7 +65,7 @@ namespace winrt::TerminalApp::implementation // - actionAndArgs: The ActionAndArgs to lookup the keybinding for. // Return Value: // - The bound keychord, if this ActionAndArgs is bound to a key, otherwise nullptr. - KeyChord KeyMapping::GetKeyBindingForActionWithArgs(TerminalApp::ActionAndArgs const& actionAndArgs) + KeyChord KeyMapping::GetKeyBindingForActionWithArgs(Microsoft::Terminal::Settings::Model::ActionAndArgs const& actionAndArgs) { if (actionAndArgs == nullptr) { diff --git a/src/cascadia/TerminalSettingsModel/KeyMapping.h b/src/cascadia/TerminalSettingsModel/KeyMapping.h new file mode 100644 index 00000000000..5918b8b9686 --- /dev/null +++ b/src/cascadia/TerminalSettingsModel/KeyMapping.h @@ -0,0 +1,78 @@ +/*++ +Copyright (c) Microsoft Corporation +Licensed under the MIT license. + +Module Name: +- KeyMapping.h + +Abstract: +- A mapping of key chords to actions. Includes (de)serialization logic. + +Author(s): +- Carlos Zamora - September 2020 + +--*/ + +#pragma once + +#include "KeyMapping.g.h" +#include "ActionArgs.h" +#include "..\inc\cppwinrt_utils.h" + +// fwdecl unittest classes +namespace SettingsModelLocalTests +{ + class DeserializationTests; + class KeyBindingsTests; + class TestUtils; +} + +namespace winrt::Microsoft::Terminal::Settings::Model::implementation +{ + struct KeyChordHash + { + std::size_t operator()(const TerminalControl::KeyChord& key) const + { + std::hash keyHash; + std::hash modifiersHash; + std::size_t hashedKey = keyHash(key.Vkey()); + std::size_t hashedMods = modifiersHash(key.Modifiers()); + return hashedKey ^ hashedMods; + } + }; + + struct KeyChordEquality + { + bool operator()(const TerminalControl::KeyChord& lhs, const TerminalControl::KeyChord& rhs) const + { + return lhs.Modifiers() == rhs.Modifiers() && lhs.Vkey() == rhs.Vkey(); + } + }; + + struct KeyMapping : KeyMappingT + { + KeyMapping() = default; + + Model::ActionAndArgs TryLookup(TerminalControl::KeyChord const& chord) const; + uint64_t Size() const; + + void SetKeyBinding(Model::ActionAndArgs const& actionAndArgs, + TerminalControl::KeyChord const& chord); + void ClearKeyBinding(TerminalControl::KeyChord const& chord); + TerminalControl::KeyChord GetKeyBindingForAction(Model::ShortcutAction const& action); + TerminalControl::KeyChord GetKeyBindingForActionWithArgs(Model::ActionAndArgs const& actionAndArgs); + + static Windows::System::VirtualKeyModifiers ConvertVKModifiers(TerminalControl::KeyModifiers modifiers); + + // Defined in KeyMappingSerialization.cpp + std::vector LayerJson(const Json::Value& json); + Json::Value ToJson(); + + private: + std::unordered_map _keyShortcuts; + + friend class SettingsModelLocalTests::DeserializationTests; + friend class SettingsModelLocalTests::KeyBindingsTests; + friend class SettingsModelLocalTests::TestUtils; + }; +} diff --git a/src/cascadia/TerminalApp/KeyMapping.idl b/src/cascadia/TerminalSettingsModel/KeyMapping.idl similarity index 89% rename from src/cascadia/TerminalApp/KeyMapping.idl rename to src/cascadia/TerminalSettingsModel/KeyMapping.idl index ebaddb1cc55..4901285e739 100644 --- a/src/cascadia/TerminalApp/KeyMapping.idl +++ b/src/cascadia/TerminalSettingsModel/KeyMapping.idl @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. + import "ActionArgs.idl"; -namespace TerminalApp +namespace Microsoft.Terminal.Settings.Model { enum ShortcutAction { @@ -51,6 +52,8 @@ namespace TerminalApp [default_interface] runtimeclass ActionAndArgs { ActionAndArgs(); + ActionAndArgs(ShortcutAction action, IActionArgs args); + IActionArgs Args; ShortcutAction Action; }; @@ -58,6 +61,7 @@ namespace TerminalApp [default_interface] runtimeclass KeyMapping { ActionAndArgs TryLookup(Microsoft.Terminal.TerminalControl.KeyChord chord); + UInt64 Size(); void SetKeyBinding(ActionAndArgs actionAndArgs, Microsoft.Terminal.TerminalControl.KeyChord chord); void ClearKeyBinding(Microsoft.Terminal.TerminalControl.KeyChord chord); diff --git a/src/cascadia/TerminalApp/KeyMappingSerialization.cpp b/src/cascadia/TerminalSettingsModel/KeyMappingSerialization.cpp similarity index 92% rename from src/cascadia/TerminalApp/KeyMappingSerialization.cpp rename to src/cascadia/TerminalSettingsModel/KeyMappingSerialization.cpp index 4ddde130e91..665c938f591 100644 --- a/src/cascadia/TerminalApp/KeyMappingSerialization.cpp +++ b/src/cascadia/TerminalSettingsModel/KeyMappingSerialization.cpp @@ -10,11 +10,10 @@ #include "KeyMapping.h" #include "ActionAndArgs.h" #include "KeyChordSerialization.h" -#include "Utils.h" #include "JsonUtils.h" using namespace winrt::Microsoft::Terminal::TerminalControl; -using namespace winrt::TerminalApp; +using namespace winrt::Microsoft::Terminal::Settings::Model; static constexpr std::string_view KeysKey{ "keys" }; static constexpr std::string_view CommandKey{ "command" }; @@ -57,7 +56,7 @@ static Json::Value _ShortcutAsJsonObject(const KeyChord& chord, // ShortcutAction. // Return Value: // - a Json::Value which is an equivalent serialization of this object. -Json::Value winrt::TerminalApp::implementation::KeyMapping::ToJson() +Json::Value winrt::Microsoft::Terminal::Settings::Model::implementation::KeyMapping::ToJson() { Json::Value bindingsArray; @@ -93,7 +92,7 @@ Json::Value winrt::TerminalApp::implementation::KeyMapping::ToJson() // `"unbound"`, then we'll clear the keybinding from the existing keybindings. // Arguments: // - json: an array of Json::Value's to deserialize into our _keyShortcuts mapping. -std::vector winrt::TerminalApp::implementation::KeyMapping::LayerJson(const Json::Value& json) +std::vector winrt::Microsoft::Terminal::Settings::Model::implementation::KeyMapping::LayerJson(const Json::Value& json) { // It's possible that the user provided keybindings have some warnings in // them - problems that we should alert the user to, but we can recover diff --git a/src/cascadia/TerminalApp/LegacyProfileGeneratorNamespaces.h b/src/cascadia/TerminalSettingsModel/LegacyProfileGeneratorNamespaces.h similarity index 100% rename from src/cascadia/TerminalApp/LegacyProfileGeneratorNamespaces.h rename to src/cascadia/TerminalSettingsModel/LegacyProfileGeneratorNamespaces.h diff --git a/src/cascadia/TerminalSettingsModel/Microsoft.Terminal.Settings.ModelLib.vcxproj b/src/cascadia/TerminalSettingsModel/Microsoft.Terminal.Settings.ModelLib.vcxproj new file mode 100644 index 00000000000..37f928fdf3f --- /dev/null +++ b/src/cascadia/TerminalSettingsModel/Microsoft.Terminal.Settings.ModelLib.vcxproj @@ -0,0 +1,211 @@ + + + + {CA5CAD1A-d7ec-4107-b7c6-79cb77ae2907} + Win32Proj + Microsoft.Terminal.Settings.Model.Lib + Microsoft.Terminal.Settings.Model + Microsoft.Terminal.Settings.Model.Lib + 10.0.17763.0 + StaticLibrary + Console + true + + true + + + + + + + + + ActionArgs.idl + + + ActionArgs.idl + + + + CascadiaSettings.idl + + + ColorScheme.idl + + + Command.idl + + + + GlobalAppSettings.idl + + + + + KeyChordSerialization.idl + + + KeyMapping.idl + + + + Profile.idl + + + + + TerminalWarnings.idl + + + + + + + + Create + + + ActionArgs.idl + + + ActionArgs.idl + + + + CascadiaSettings.idl + + + CascadiaSettings.idl + + + ColorScheme.idl + + + Command.idl + + + + GlobalAppSettings.idl + + + KeyChordSerialization.idl + + + KeyMapping.idl + + + KeyMapping.idl + + + + Profile.idl + + + + + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + {CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE} + false + + + + + + <_BinRoot Condition="'$(Platform)' != 'Win32'">$(OpenConsoleDir)$(Platform)\$(Configuration)\ + <_BinRoot Condition="'$(Platform)' == 'Win32'">$(OpenConsoleDir)$(Configuration)\ + + + + + $(_BinRoot)TerminalConnection\Microsoft.Terminal.TerminalConnection.winmd + true + false + false + + + $(_BinRoot)TerminalControl\Microsoft.Terminal.TerminalControl.winmd + true + false + false + + + + + + pch.h + ..;$(OpenConsoleDir)\dep\jsoncpp\json;%(AdditionalIncludeDirectories); + + 4702;%(DisableSpecificWarnings) + + + WindowsApp.lib;user32.lib;shell32.lib;%(AdditionalDependencies) + + + false + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + + + + + + diff --git a/src/cascadia/TerminalSettingsModel/Microsoft.Terminal.Settings.ModelLib.vcxproj.filters b/src/cascadia/TerminalSettingsModel/Microsoft.Terminal.Settings.ModelLib.vcxproj.filters new file mode 100644 index 00000000000..485f96e896c --- /dev/null +++ b/src/cascadia/TerminalSettingsModel/Microsoft.Terminal.Settings.ModelLib.vcxproj.filters @@ -0,0 +1,89 @@ + + + + + + + + + + + + + profileGeneration + + + profileGeneration + + + profileGeneration + + + + + + + + + + profileGeneration + + + + json + + + + + + + profileGeneration + + + profileGeneration + + + profileGeneration + + + profileGeneration + + + + + + + + + + + + profileGeneration + + + json + + + + + + + + + + + + + + + + + + + {c81be61b-0d58-4277-8fd1-fcc888c3da9c} + + + {81a6314f-aa5b-4533-a499-13bc3a5c4af0} + + + diff --git a/src/cascadia/TerminalApp/PowershellCoreProfileGenerator.cpp b/src/cascadia/TerminalSettingsModel/PowershellCoreProfileGenerator.cpp similarity index 96% rename from src/cascadia/TerminalApp/PowershellCoreProfileGenerator.cpp rename to src/cascadia/TerminalSettingsModel/PowershellCoreProfileGenerator.cpp index 364a42e0c19..a6bc2d50d8a 100644 --- a/src/cascadia/TerminalApp/PowershellCoreProfileGenerator.cpp +++ b/src/cascadia/TerminalSettingsModel/PowershellCoreProfileGenerator.cpp @@ -135,8 +135,8 @@ namespace }; } -using namespace ::TerminalApp; -using namespace winrt::TerminalApp; +using namespace ::Microsoft::Terminal::Settings::Model; +using namespace winrt::Microsoft::Terminal::Settings::Model; // Function Description: // - Finds all powershell instances with the traditional layout under a directory. diff --git a/src/cascadia/TerminalApp/PowershellCoreProfileGenerator.h b/src/cascadia/TerminalSettingsModel/PowershellCoreProfileGenerator.h similarity index 68% rename from src/cascadia/TerminalApp/PowershellCoreProfileGenerator.h rename to src/cascadia/TerminalSettingsModel/PowershellCoreProfileGenerator.h index c32c9410c92..d6bb846355e 100644 --- a/src/cascadia/TerminalApp/PowershellCoreProfileGenerator.h +++ b/src/cascadia/TerminalSettingsModel/PowershellCoreProfileGenerator.h @@ -18,9 +18,9 @@ Author(s): #include "IDynamicProfileGenerator.h" -namespace TerminalApp +namespace Microsoft::Terminal::Settings::Model { - class PowershellCoreProfileGenerator : public TerminalApp::IDynamicProfileGenerator + class PowershellCoreProfileGenerator : public Microsoft::Terminal::Settings::Model::IDynamicProfileGenerator { public: static const std::wstring_view GetPreferredPowershellProfileName(); @@ -29,6 +29,6 @@ namespace TerminalApp ~PowershellCoreProfileGenerator() = default; std::wstring_view GetNamespace() override; - std::vector GenerateProfiles() override; + std::vector GenerateProfiles() override; }; }; diff --git a/src/cascadia/TerminalApp/Profile.cpp b/src/cascadia/TerminalSettingsModel/Profile.cpp similarity index 95% rename from src/cascadia/TerminalApp/Profile.cpp rename to src/cascadia/TerminalSettingsModel/Profile.cpp index 5e53c60702a..249a3bc46bd 100644 --- a/src/cascadia/TerminalApp/Profile.cpp +++ b/src/cascadia/TerminalSettingsModel/Profile.cpp @@ -3,7 +3,6 @@ #include "pch.h" #include "Profile.h" -#include "Utils.h" #include "JsonUtils.h" #include "../../types/inc/Utils.hpp" #include @@ -13,8 +12,8 @@ #include "Profile.g.cpp" -using namespace TerminalApp; -using namespace winrt::TerminalApp::implementation; +using namespace Microsoft::Terminal::Settings::Model; +using namespace winrt::Microsoft::Terminal::Settings::Model::implementation; using namespace winrt::Microsoft::Terminal::TerminalControl; using namespace winrt::Windows::UI; using namespace winrt::Windows::UI::Xaml; @@ -107,7 +106,7 @@ Json::Value Profile::GenerateStub() const // - json: an object which should be a serialization of a Profile object. // Return Value: // - a new Profile instance created from the values in `json` -winrt::com_ptr Profile::FromJson(const Json::Value& json) +winrt::com_ptr Profile::FromJson(const Json::Value& json) { auto result = winrt::make_self(); result->LayerJson(json); @@ -323,7 +322,7 @@ void Profile::GenerateGuidIfNecessary() noexcept _Guid = Profile::_GenerateGuidForProfile(_Name, _Source); TraceLoggingWrite( - g_hTerminalAppProvider, + g_hSettingsModelProvider, "SynthesizedGuidForProfile", TraceLoggingDescription("Event emitted when a profile is deserialized without a GUID"), TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), diff --git a/src/cascadia/TerminalApp/Profile.h b/src/cascadia/TerminalSettingsModel/Profile.h similarity index 95% rename from src/cascadia/TerminalApp/Profile.h rename to src/cascadia/TerminalSettingsModel/Profile.h index 93fb675881c..7fac38028e8 100644 --- a/src/cascadia/TerminalApp/Profile.h +++ b/src/cascadia/TerminalSettingsModel/Profile.h @@ -37,7 +37,7 @@ namespace TerminalAppUnitTests // GUID specified manually. constexpr GUID RUNTIME_GENERATED_PROFILE_NAMESPACE_GUID = { 0xf65ddb7e, 0x706b, 0x4499, { 0x8a, 0x50, 0x40, 0x31, 0x3c, 0xaf, 0x51, 0x0a } }; -namespace winrt::TerminalApp::implementation +namespace winrt::Microsoft::Terminal::Settings::Model::implementation { struct Profile : ProfileT { @@ -135,7 +135,7 @@ namespace winrt::TerminalApp::implementation }; } -namespace winrt::TerminalApp::factory_implementation +namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation { BASIC_FACTORY(Profile); } diff --git a/src/cascadia/TerminalApp/Profile.idl b/src/cascadia/TerminalSettingsModel/Profile.idl similarity index 94% rename from src/cascadia/TerminalApp/Profile.idl rename to src/cascadia/TerminalSettingsModel/Profile.idl index 916929b576f..2391a162f80 100644 --- a/src/cascadia/TerminalApp/Profile.idl +++ b/src/cascadia/TerminalSettingsModel/Profile.idl @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -namespace TerminalApp +namespace Microsoft.Terminal.Settings.Model { enum CloseOnExitMode { diff --git a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw new file mode 100644 index 00000000000..bf902d54a6d --- /dev/null +++ b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw @@ -0,0 +1,327 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Select color scheme... + + + New Tab... + + + Split Pane... + + + Windows Terminal (Unpackaged) + This display name is used when the application's name cannot be determined + + + Unknown + This is displayed when the version of the application cannot be determined + + + Adjust font size + + + Close tabs other than index {0} + {0} will be replaced with a number + + + Close all other tabs + + + Close pane + + + Close tab + + + Close tabs after index {0} + {0} will be replaced with a number + + + Close all tabs after the current tab + + + Close window + + + Command Prompt + This is the name of "Command Prompt", as localized in Windows. The localization here should match the one in the Windows product for "Command Prompt" + + + Copy text as a single line + + + Copy text + + + Decrease font size + + + Decrease font size, amount: {0} + {0} will be replaced with a positive number + + + down + + + left + + + right + + + up + + + Duplicate pane + + + Duplicate tab + + + Run commandline "{0}" in this window + {0} will be replaced with a user-defined commandline + + + Find + + + Increase font size + + + Increase font size, amount: {0} + {0} will be replaced with a positive number + + + Move focus + + + Move focus {0} + {0} will be replaced with one of the four directions "DirectionLeft", "DirectionRight", "DirectionUp", or "DirectionDown" + + + New tab + + + New window + + + Next tab + + + Open both settings and default settings files + + + Open default settings file + + + Open new tab dropdown + + + Open settings file + + + Set the tab color... + + + Paste + + + Previous tab + + + Rename tab to "{0}" + {0} will be replaced with a user-defined string + + + Reset font size + + + Reset tab color + + + Reset tab title + + + Resize pane + + + Resize pane {0} + {0} will be replaced with one of the four directions "DirectionLeft", "DirectionRight", "DirectionUp", or "DirectionDown" + + + Scroll down one line + + + Scroll down one page + + + Scroll up one line + + + Scroll up one page + + + Send Input: "{0}" + {0} will be replaced with a string of input as defined by the user + + + Set color scheme to {0} + {0} will be replaced with the name of a color scheme as defined by the user. + + + Set tab color to {0} + {0} will be replaced with a color, displayed in hexadecimal (#RRGGBB) notation. + + + Split pane horizontally + + + Split pane + + + Split pane vertically + + + Switch to tab + + + Search for tab... + + + Toggle always on top mode + + + Toggle command palette + + + Toggle focus mode + "Focus mode" is a mode with minimal UI elements, for a distraction-free experience + + + Toggle fullscreen + + + Toggle pane zoom + + + Toggle retro terminal effect + + \ No newline at end of file diff --git a/src/cascadia/TerminalApp/SettingsTypes.h b/src/cascadia/TerminalSettingsModel/SettingsTypes.h similarity index 80% rename from src/cascadia/TerminalApp/SettingsTypes.h rename to src/cascadia/TerminalSettingsModel/SettingsTypes.h index 0fc1fa0bb6a..b8ff66c15e0 100644 --- a/src/cascadia/TerminalApp/SettingsTypes.h +++ b/src/cascadia/TerminalSettingsModel/SettingsTypes.h @@ -11,7 +11,7 @@ Module Name: #pragma once -namespace winrt::TerminalApp +namespace winrt::Microsoft::Terminal::Settings::Model { enum class ExpandCommandType : uint32_t { diff --git a/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h b/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h similarity index 84% rename from src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h rename to src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h index 3a3eb4f5ffb..8f28dbfcfc4 100644 --- a/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h +++ b/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h @@ -18,9 +18,6 @@ Module Name: #include "JsonUtils.h" #include "SettingsTypes.h" -#include -#include - JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::TerminalControl::CursorStyle) { static constexpr std::array mappings = { @@ -79,7 +76,7 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::TerminalControl::TextAntialiasing // Type Description: // - Helper for converting a user-specified closeOnExit value to its corresponding enum -JSON_ENUM_MAPPER(::winrt::TerminalApp::CloseOnExitMode) +JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::CloseOnExitMode) { JSON_MAPPINGS(3) = { pair_type{ "always", ValueType::Always }, @@ -88,7 +85,7 @@ JSON_ENUM_MAPPER(::winrt::TerminalApp::CloseOnExitMode) }; // Override mapping parser to add boolean parsing - ::winrt::TerminalApp::CloseOnExitMode FromJson(const Json::Value& json) + ::winrt::Microsoft::Terminal::Settings::Model::CloseOnExitMode FromJson(const Json::Value& json) { if (json.isBool()) { @@ -109,10 +106,10 @@ JSON_ENUM_MAPPER(::winrt::TerminalApp::CloseOnExitMode) // value type (unsinged int) and return type (FontWeight struct). JSON_ENUM_MAPPER // expects that the value type _is_ the return type. template<> -struct ::TerminalApp::JsonUtils::ConversionTrait<::winrt::Windows::UI::Text::FontWeight> : - public ::TerminalApp::JsonUtils::EnumMapper< +struct ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait<::winrt::Windows::UI::Text::FontWeight> : + public ::Microsoft::Terminal::Settings::Model::JsonUtils::EnumMapper< unsigned int, - ::TerminalApp::JsonUtils::ConversionTrait<::winrt::Windows::UI::Text::FontWeight>> + ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait<::winrt::Windows::UI::Text::FontWeight>> { // The original parser used the font weight getters Bold(), Normal(), etc. // They were both cumbersome and *not constant expressions* @@ -166,7 +163,7 @@ JSON_ENUM_MAPPER(::winrt::Windows::UI::Xaml::ElementTheme) }; }; -JSON_ENUM_MAPPER(::winrt::TerminalApp::LaunchMode) +JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::LaunchMode) { JSON_MAPPINGS(3) = { pair_type{ "default", ValueType::DefaultMode }, @@ -184,7 +181,7 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode) }; }; -JSON_ENUM_MAPPER(winrt::TerminalApp::ExpandCommandType) +JSON_ENUM_MAPPER(winrt::Microsoft::Terminal::Settings::Model::ExpandCommandType) { JSON_MAPPINGS(2) = { pair_type{ "profiles", ValueType::Profiles }, @@ -226,11 +223,11 @@ JSON_FLAG_MAPPER(::winrt::Microsoft::Terminal::TerminalControl::CopyFormat) // (abc, 100): if a value is not valid, we treat it as default // (100, 100, 100): we only read the first two values, this is equivalent to (100, 100) template<> -struct ::TerminalApp::JsonUtils::ConversionTrait<::winrt::TerminalApp::LaunchPosition> +struct ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait<::winrt::Microsoft::Terminal::Settings::Model::LaunchPosition> { - ::winrt::TerminalApp::LaunchPosition FromJson(const Json::Value& json) + ::winrt::Microsoft::Terminal::Settings::Model::LaunchPosition FromJson(const Json::Value& json) { - ::winrt::TerminalApp::LaunchPosition ret; + ::winrt::Microsoft::Terminal::Settings::Model::LaunchPosition ret; std::string initialPosition{ json.asString() }; static constexpr char singleCharDelim = ','; std::stringstream tokenStream(initialPosition); @@ -268,7 +265,7 @@ struct ::TerminalApp::JsonUtils::ConversionTrait<::winrt::TerminalApp::LaunchPos return json.isString(); } - Json::Value ToJson(const ::winrt::TerminalApp::LaunchPosition& val) + Json::Value ToJson(const ::winrt::Microsoft::Terminal::Settings::Model::LaunchPosition& val) { std::stringstream ss; if (val.X) @@ -290,7 +287,7 @@ struct ::TerminalApp::JsonUtils::ConversionTrait<::winrt::TerminalApp::LaunchPos }; // Possible Direction values -JSON_ENUM_MAPPER(::winrt::TerminalApp::Direction) +JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::Direction) { JSON_MAPPINGS(4) = { pair_type{ "left", ValueType::Left }, @@ -301,7 +298,7 @@ JSON_ENUM_MAPPER(::winrt::TerminalApp::Direction) }; // Possible SplitState values -JSON_ENUM_MAPPER(::winrt::TerminalApp::SplitState) +JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::SplitState) { JSON_MAPPINGS(3) = { pair_type{ "vertical", ValueType::Vertical }, @@ -311,14 +308,14 @@ JSON_ENUM_MAPPER(::winrt::TerminalApp::SplitState) }; // Possible SplitType values -JSON_ENUM_MAPPER(::winrt::TerminalApp::SplitType) +JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::SplitType) { JSON_MAPPINGS(1) = { pair_type{ "duplicate", ValueType::Duplicate }, }; }; -JSON_ENUM_MAPPER(::winrt::TerminalApp::SettingsTarget) +JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::SettingsTarget) { JSON_MAPPINGS(3) = { pair_type{ "settingsFile", ValueType::SettingsFile }, diff --git a/src/cascadia/TerminalApp/TerminalWarnings.h b/src/cascadia/TerminalSettingsModel/TerminalWarnings.h similarity index 90% rename from src/cascadia/TerminalApp/TerminalWarnings.h rename to src/cascadia/TerminalSettingsModel/TerminalWarnings.h index 57250be7d8a..c0e8bc9f579 100644 --- a/src/cascadia/TerminalApp/TerminalWarnings.h +++ b/src/cascadia/TerminalSettingsModel/TerminalWarnings.h @@ -15,7 +15,7 @@ Author(s): --*/ #pragma once -namespace winrt::TerminalApp::implementation +namespace winrt::Microsoft::Terminal::Settings::Model::implementation { // This is a helper class to wrap up a SettingsLoadErrors into a proper // exception type. diff --git a/src/cascadia/TerminalApp/TerminalWarnings.idl b/src/cascadia/TerminalSettingsModel/TerminalWarnings.idl similarity index 93% rename from src/cascadia/TerminalApp/TerminalWarnings.idl rename to src/cascadia/TerminalSettingsModel/TerminalWarnings.idl index fd4558ad6cb..f6010952124 100644 --- a/src/cascadia/TerminalApp/TerminalWarnings.idl +++ b/src/cascadia/TerminalSettingsModel/TerminalWarnings.idl @@ -1,8 +1,7 @@ // Copyright (c) Microsoft Corporation // Licensed under the MIT license. -#pragma once -namespace TerminalApp +namespace Microsoft.Terminal.Settings.Model { // SettingsLoadWarnings are scenarios where the settings contained // information we knew was invalid, but we could recover from. diff --git a/src/cascadia/TerminalApp/WslDistroGenerator.cpp b/src/cascadia/TerminalSettingsModel/WslDistroGenerator.cpp similarity index 95% rename from src/cascadia/TerminalApp/WslDistroGenerator.cpp rename to src/cascadia/TerminalSettingsModel/WslDistroGenerator.cpp index 3f2c655fecb..1aae9375461 100644 --- a/src/cascadia/TerminalApp/WslDistroGenerator.cpp +++ b/src/cascadia/TerminalSettingsModel/WslDistroGenerator.cpp @@ -15,8 +15,8 @@ static constexpr std::wstring_view DockerDistributionPrefix{ L"docker-desktop" }; -using namespace ::TerminalApp; -using namespace winrt::TerminalApp; +using namespace ::Microsoft::Terminal::Settings::Model; +using namespace winrt::Microsoft::Terminal::Settings::Model; // Legacy GUIDs: // - Debian 58ad8b0c-3ef8-5f4d-bc6f-13e4c00f2530 diff --git a/src/cascadia/TerminalApp/WslDistroGenerator.h b/src/cascadia/TerminalSettingsModel/WslDistroGenerator.h similarity index 64% rename from src/cascadia/TerminalApp/WslDistroGenerator.h rename to src/cascadia/TerminalSettingsModel/WslDistroGenerator.h index 323ecaaadad..4d85debb424 100644 --- a/src/cascadia/TerminalApp/WslDistroGenerator.h +++ b/src/cascadia/TerminalSettingsModel/WslDistroGenerator.h @@ -17,14 +17,14 @@ Author(s): #pragma once #include "IDynamicProfileGenerator.h" -namespace TerminalApp +namespace Microsoft::Terminal::Settings::Model { - class WslDistroGenerator : public TerminalApp::IDynamicProfileGenerator + class WslDistroGenerator : public Microsoft::Terminal::Settings::Model::IDynamicProfileGenerator { public: WslDistroGenerator() = default; ~WslDistroGenerator() = default; std::wstring_view GetNamespace() override; - std::vector GenerateProfiles() override; + std::vector GenerateProfiles() override; }; }; diff --git a/src/cascadia/TerminalApp/defaults-universal.json b/src/cascadia/TerminalSettingsModel/defaults-universal.json similarity index 100% rename from src/cascadia/TerminalApp/defaults-universal.json rename to src/cascadia/TerminalSettingsModel/defaults-universal.json diff --git a/src/cascadia/TerminalApp/defaults.json b/src/cascadia/TerminalSettingsModel/defaults.json similarity index 100% rename from src/cascadia/TerminalApp/defaults.json rename to src/cascadia/TerminalSettingsModel/defaults.json diff --git a/src/cascadia/TerminalSettingsModel/dll/Microsoft.Terminal.Settings.Model.def b/src/cascadia/TerminalSettingsModel/dll/Microsoft.Terminal.Settings.Model.def new file mode 100644 index 00000000000..8c1a02932d0 --- /dev/null +++ b/src/cascadia/TerminalSettingsModel/dll/Microsoft.Terminal.Settings.Model.def @@ -0,0 +1,3 @@ +EXPORTS +DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE +DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE diff --git a/src/cascadia/TerminalSettingsModel/dll/Microsoft.Terminal.Settings.Model.vcxproj b/src/cascadia/TerminalSettingsModel/dll/Microsoft.Terminal.Settings.Model.vcxproj new file mode 100644 index 00000000000..8e57af5325f --- /dev/null +++ b/src/cascadia/TerminalSettingsModel/dll/Microsoft.Terminal.Settings.Model.vcxproj @@ -0,0 +1,103 @@ + + + + {CA5CAD1A-082C-4476-9F33-94B339494076} + Microsoft.Terminal.Settings.Model + Microsoft.Terminal.Settings.Model + + + DynamicLibrary + Console + + true + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {18D09A24-8240-42D6-8CB6-236EEE820263} + + + + false + + + false + + + + true + true + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + $(OpenConsoleDir)\dep\jsoncpp\json;%(AdditionalIncludeDirectories); + + + User32.lib;WindowsApp.lib;shell32.lib;%(AdditionalDependencies) + + /INCLUDE:_DllMain@12 + /INCLUDE:DllMain + + + + false + + + + diff --git a/src/cascadia/TerminalSettingsModel/init.cpp b/src/cascadia/TerminalSettingsModel/init.cpp new file mode 100644 index 00000000000..85421fd7f2b --- /dev/null +++ b/src/cascadia/TerminalSettingsModel/init.cpp @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation +// Licensed under the MIT license. + +#include "pch.h" +#include + +// Note: Generate GUID using TlgGuid.exe tool +TRACELOGGING_DEFINE_PROVIDER( + g_hSettingsModelProvider, + "Microsoft.Windows.Terminal.Setting.Model", + // {be579944-4d33-5202-e5d6-a7a57f1935cb} + (0xbe579944, 0x4d33, 0x5202, 0xe5, 0xd6, 0xa7, 0xa5, 0x7f, 0x19, 0x35, 0xcb), + TraceLoggingOptionMicrosoftTelemetry()); + +BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD reason, LPVOID /*reserved*/) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hInstDll); + TraceLoggingRegister(g_hSettingsModelProvider); + break; + case DLL_PROCESS_DETACH: + if (g_hSettingsModelProvider) + { + TraceLoggingUnregister(g_hSettingsModelProvider); + } + break; + } + + return TRUE; +} + +UTILS_DEFINE_LIBRARY_RESOURCE_SCOPE(L"Microsoft.Terminal.Settings.Model/Resources") diff --git a/src/cascadia/TerminalSettingsModel/packages.config b/src/cascadia/TerminalSettingsModel/packages.config new file mode 100644 index 00000000000..8db4233e6a9 --- /dev/null +++ b/src/cascadia/TerminalSettingsModel/packages.config @@ -0,0 +1,4 @@ + + + + diff --git a/src/cascadia/TerminalSettingsModel/pch.cpp b/src/cascadia/TerminalSettingsModel/pch.cpp new file mode 100644 index 00000000000..3c27d44d570 --- /dev/null +++ b/src/cascadia/TerminalSettingsModel/pch.cpp @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "pch.h" diff --git a/src/cascadia/TerminalSettingsModel/pch.h b/src/cascadia/TerminalSettingsModel/pch.h new file mode 100644 index 00000000000..d658fdf7d58 --- /dev/null +++ b/src/cascadia/TerminalSettingsModel/pch.h @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// +// pch.h +// Header for platform projection include files +// + +#pragma once + +#define WIN32_LEAN_AND_MEAN + +// Manually include til after we include Windows.Foundation to give it winrt superpowers +#define BLOCK_TIL +#include +// This is inexplicable, but for whatever reason, cppwinrt conflicts with the +// SDK definition of this function, so the only fix is to undef it. +// from WinBase.h +// Windows::UI::Xaml::Media::Animation::IStoryboard::GetCurrentTime +#ifdef GetCurrentTime +#undef GetCurrentTime +#endif + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +// Including TraceLogging essentials for the binary +#include +#include +TRACELOGGING_DECLARE_PROVIDER(g_hSettingsModelProvider); +#include +#include + +// JsonCpp +#include + +#include + +#include +#include + +// Manually include til after we include Windows.Foundation to give it winrt superpowers +#include "til.h" diff --git a/src/cascadia/TerminalApp/userDefaults.json b/src/cascadia/TerminalSettingsModel/userDefaults.json similarity index 100% rename from src/cascadia/TerminalApp/userDefaults.json rename to src/cascadia/TerminalSettingsModel/userDefaults.json diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp index d7896b6aa32..d0b6a3aa734 100644 --- a/src/cascadia/WindowsTerminal/AppHost.cpp +++ b/src/cascadia/WindowsTerminal/AppHost.cpp @@ -15,6 +15,7 @@ using namespace winrt::Windows::UI::Composition; using namespace winrt::Windows::UI::Xaml; using namespace winrt::Windows::UI::Xaml::Hosting; using namespace winrt::Windows::Foundation::Numerics; +using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace ::Microsoft::Console; using namespace ::Microsoft::Console::Types; @@ -236,7 +237,7 @@ void AppHost::LastTabClosed(const winrt::Windows::Foundation::IInspectable& /*se // - launchMode: A LaunchMode enum reference that indicates the launch mode // Return Value: // - None -void AppHost::_HandleCreateWindow(const HWND hwnd, RECT proposedRect, winrt::TerminalApp::LaunchMode& launchMode) +void AppHost::_HandleCreateWindow(const HWND hwnd, RECT proposedRect, LaunchMode& launchMode) { launchMode = _logic.GetLaunchMode(); diff --git a/src/cascadia/WindowsTerminal/AppHost.h b/src/cascadia/WindowsTerminal/AppHost.h index d99fddadb92..4bdc45c5d29 100644 --- a/src/cascadia/WindowsTerminal/AppHost.h +++ b/src/cascadia/WindowsTerminal/AppHost.h @@ -4,6 +4,7 @@ #include "pch.h" #include +#include #include "NonClientIslandWindow.h" @@ -27,7 +28,7 @@ class AppHost void _HandleCommandlineArgs(); - void _HandleCreateWindow(const HWND hwnd, RECT proposedRect, winrt::TerminalApp::LaunchMode& launchMode); + void _HandleCreateWindow(const HWND hwnd, RECT proposedRect, winrt::Microsoft::Terminal::Settings::Model::LaunchMode& launchMode); void _UpdateTitleBarContent(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::UIElement& arg); void _UpdateTheme(const winrt::Windows::Foundation::IInspectable&, diff --git a/src/cascadia/WindowsTerminal/IslandWindow.cpp b/src/cascadia/WindowsTerminal/IslandWindow.cpp index e6497d1d48b..4312fb59df8 100644 --- a/src/cascadia/WindowsTerminal/IslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/IslandWindow.cpp @@ -13,6 +13,7 @@ using namespace winrt::Windows::UI::Composition; using namespace winrt::Windows::UI::Xaml; using namespace winrt::Windows::UI::Xaml::Hosting; using namespace winrt::Windows::Foundation::Numerics; +using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace ::Microsoft::Console::Types; #define XAML_HOSTING_WINDOW_CLASS_NAME L"CASCADIA_HOSTING_WINDOW_CLASS" @@ -89,7 +90,7 @@ void IslandWindow::Close() // window. // Return Value: // - -void IslandWindow::SetCreateCallback(std::function pfn) noexcept +void IslandWindow::SetCreateCallback(std::function pfn) noexcept { _pfnCreateCallback = pfn; } @@ -131,14 +132,14 @@ void IslandWindow::_HandleCreateWindow(const WPARAM, const LPARAM lParam) noexce rc.right = rc.left + pcs->cx; rc.bottom = rc.top + pcs->cy; - winrt::TerminalApp::LaunchMode launchMode = winrt::TerminalApp::LaunchMode::DefaultMode; + LaunchMode launchMode = LaunchMode::DefaultMode; if (_pfnCreateCallback) { _pfnCreateCallback(_window.get(), rc, launchMode); } int nCmdShow = SW_SHOW; - if (launchMode == winrt::TerminalApp::LaunchMode::MaximizedMode) + if (launchMode == LaunchMode::MaximizedMode) { nCmdShow = SW_MAXIMIZE; } diff --git a/src/cascadia/WindowsTerminal/IslandWindow.h b/src/cascadia/WindowsTerminal/IslandWindow.h index 29d24156f55..8e6a4fcc943 100644 --- a/src/cascadia/WindowsTerminal/IslandWindow.h +++ b/src/cascadia/WindowsTerminal/IslandWindow.h @@ -28,7 +28,7 @@ class IslandWindow : virtual void Initialize(); - void SetCreateCallback(std::function pfn) noexcept; + void SetCreateCallback(std::function pfn) noexcept; void SetSnapDimensionCallback(std::function pfn) noexcept; void FocusModeChanged(const bool focusMode); @@ -55,7 +55,7 @@ class IslandWindow : winrt::Windows::UI::Xaml::Controls::Grid _rootGrid; - std::function _pfnCreateCallback; + std::function _pfnCreateCallback; std::function _pfnSnapDimensionCallback; void _HandleCreateWindow(const WPARAM wParam, const LPARAM lParam) noexcept; diff --git a/src/cascadia/WindowsTerminal/WindowsTerminal.vcxproj b/src/cascadia/WindowsTerminal/WindowsTerminal.vcxproj index 395c76d9e8e..6e204c63f12 100644 --- a/src/cascadia/WindowsTerminal/WindowsTerminal.vcxproj +++ b/src/cascadia/WindowsTerminal/WindowsTerminal.vcxproj @@ -74,6 +74,7 @@ so that the AppX Manifest contains their activatable classes. --> + diff --git a/src/cascadia/WindowsTerminalUniversal/WindowsTerminalUniversal.vcxproj b/src/cascadia/WindowsTerminalUniversal/WindowsTerminalUniversal.vcxproj index 0a749357a56..e3422b000e1 100644 --- a/src/cascadia/WindowsTerminalUniversal/WindowsTerminalUniversal.vcxproj +++ b/src/cascadia/WindowsTerminalUniversal/WindowsTerminalUniversal.vcxproj @@ -145,6 +145,7 @@ + {ca5cad1a-44bd-4ac7-ac72-f16e576fdd12} diff --git a/src/cascadia/ut_app/ColorHelperTests.cpp b/src/cascadia/ut_app/ColorHelperTests.cpp index dd686f59fd4..3f6166ee188 100644 --- a/src/cascadia/ut_app/ColorHelperTests.cpp +++ b/src/cascadia/ut_app/ColorHelperTests.cpp @@ -3,7 +3,7 @@ #include "precomp.h" -#include "../TerminalApp/Profile.h" +#include "../TerminalSettingsModel/Profile.h" #include "../TerminalApp/ColorHelper.h" using namespace Microsoft::Console; diff --git a/src/cascadia/ut_app/DynamicProfileTests.cpp b/src/cascadia/ut_app/DynamicProfileTests.cpp index 65c877dced4..3dee2785714 100644 --- a/src/cascadia/ut_app/DynamicProfileTests.cpp +++ b/src/cascadia/ut_app/DynamicProfileTests.cpp @@ -3,18 +3,17 @@ #include "precomp.h" -#include "../TerminalApp/ColorScheme.h" -#include "../TerminalApp/Profile.h" -#include "../TerminalApp/CascadiaSettings.h" -#include "../TerminalApp/LegacyProfileGeneratorNamespaces.h" +#include "../TerminalSettingsModel/ColorScheme.h" +#include "../TerminalSettingsModel/Profile.h" +#include "../TerminalSettingsModel/CascadiaSettings.h" +#include "../TerminalSettingsModel/LegacyProfileGeneratorNamespaces.h" -#include "../LocalTests_TerminalApp/JsonTestClass.h" +#include "../LocalTests_SettingsModel/JsonTestClass.h" #include "TestDynamicProfileGenerator.h" using namespace Microsoft::Console; -using namespace TerminalApp; -using namespace winrt::TerminalApp; +using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace WEX::Logging; using namespace WEX::TestExecution; using namespace WEX::Common; diff --git a/src/cascadia/ut_app/JsonTests.cpp b/src/cascadia/ut_app/JsonTests.cpp index 178ccd8cffb..0ff4fd37964 100644 --- a/src/cascadia/ut_app/JsonTests.cpp +++ b/src/cascadia/ut_app/JsonTests.cpp @@ -3,17 +3,16 @@ #include "precomp.h" -#include "../TerminalApp/ColorScheme.h" -#include "../TerminalApp/Profile.h" -#include "../TerminalApp/CascadiaSettings.h" -#include "../LocalTests_TerminalApp/JsonTestClass.h" +#include "../TerminalSettingsModel/ColorScheme.h" +#include "../TerminalSettingsModel/Profile.h" +#include "../TerminalSettingsModel/CascadiaSettings.h" +#include "../LocalTests_SettingsModel/JsonTestClass.h" using namespace Microsoft::Console; -using namespace TerminalApp; using namespace WEX::Logging; using namespace WEX::TestExecution; using namespace WEX::Common; -using namespace winrt::TerminalApp; +using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::TerminalControl; namespace TerminalAppUnitTests diff --git a/src/cascadia/ut_app/JsonUtilsTests.cpp b/src/cascadia/ut_app/JsonUtilsTests.cpp index b9bc020eca4..efaac0da068 100644 --- a/src/cascadia/ut_app/JsonUtilsTests.cpp +++ b/src/cascadia/ut_app/JsonUtilsTests.cpp @@ -3,13 +3,13 @@ #include "precomp.h" -#include "../TerminalApp/JsonUtils.h" +#include "../TerminalSettingsModel/JsonUtils.h" using namespace Microsoft::Console; using namespace WEX::Logging; using namespace WEX::TestExecution; using namespace WEX::Common; -using namespace TerminalApp::JsonUtils; +using namespace Microsoft::Terminal::Settings::Model::JsonUtils; struct StructWithConverterSpecialization { diff --git a/src/cascadia/ut_app/TerminalApp.UnitTests.vcxproj b/src/cascadia/ut_app/TerminalApp.UnitTests.vcxproj index 868002a5fd2..fd16efd8ccf 100644 --- a/src/cascadia/ut_app/TerminalApp.UnitTests.vcxproj +++ b/src/cascadia/ut_app/TerminalApp.UnitTests.vcxproj @@ -62,6 +62,7 @@ + @@ -70,7 +71,7 @@ - ..;$(OpenConsoleDir)\dep\jsoncpp\json;$(OpenConsoleDir)src\inc;$(OpenConsoleDir)src\inc\test;$(WinRT_IncludePath)\..\cppwinrt\winrt;"$(OpenConsoleDir)\src\cascadia\TerminalApp\Generated Files";%(AdditionalIncludeDirectories) + ..;$(OpenConsoleDir)\dep\jsoncpp\json;$(OpenConsoleDir)src\inc;$(OpenConsoleDir)src\inc\test;$(WinRT_IncludePath)\..\cppwinrt\winrt;"$(OpenConsoleDir)\src\cascadia\TerminalApp\Generated Files";"$(OpenConsoleDir)\src\cascadia\TerminalSettingsModel\Generated Files";%(AdditionalIncludeDirectories) precomp.h diff --git a/src/cascadia/ut_app/TestDynamicProfileGenerator.h b/src/cascadia/ut_app/TestDynamicProfileGenerator.h index 698af689edd..7c30dd732cb 100644 --- a/src/cascadia/ut_app/TestDynamicProfileGenerator.h +++ b/src/cascadia/ut_app/TestDynamicProfileGenerator.h @@ -13,7 +13,7 @@ Author(s): - Mike Griese - August 2019 --*/ -#include "../TerminalApp/IDynamicProfileGenerator.h" +#include "../TerminalSettingsModel/IDynamicProfileGenerator.h" namespace TerminalAppUnitTests { @@ -21,7 +21,7 @@ namespace TerminalAppUnitTests }; class TerminalAppUnitTests::TestDynamicProfileGenerator final : - public TerminalApp::IDynamicProfileGenerator + public Microsoft::Terminal::Settings::Model::IDynamicProfileGenerator { public: TestDynamicProfileGenerator(std::wstring_view ns) : @@ -29,16 +29,16 @@ class TerminalAppUnitTests::TestDynamicProfileGenerator final : std::wstring_view GetNamespace() override { return _namespace; }; - std::vector GenerateProfiles() override + std::vector GenerateProfiles() override { if (pfnGenerate) { return pfnGenerate(); } - return std::vector{}; + return std::vector{}; } std::wstring _namespace; - std::function()> pfnGenerate{ nullptr }; + std::function()> pfnGenerate{ nullptr }; }; diff --git a/src/inc/til.h b/src/inc/til.h index 1816d2e0736..1462c93f762 100644 --- a/src/inc/til.h +++ b/src/inc/til.h @@ -18,6 +18,7 @@ #include "til/spsc.h" #include "til/coalesce.h" #include "til/replace.h" +#include "til/visualize_control_codes.h" namespace til // Terminal Implementation Library. Also: "Today I Learned" { diff --git a/src/inc/til/visualize_control_codes.h b/src/inc/til/visualize_control_codes.h new file mode 100644 index 00000000000..db5ae73d51c --- /dev/null +++ b/src/inc/til/visualize_control_codes.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +namespace til // Terminal Implementation Library. Also: "Today I Learned" +{ + _TIL_INLINEPREFIX std::wstring visualize_control_codes(std::wstring str) noexcept + { + for (auto& ch : str) + { + if (ch < 0x20) + { + ch += 0x2400; + } + else if (ch == 0x20) + { + ch = 0x2423; // replace space with ␣ + } + else if (ch == 0x7f) + { + ch = 0x2421; // replace del with ␡ + } + } + return str; + } + + _TIL_INLINEPREFIX std::wstring visualize_control_codes(std::wstring_view str) + { + return visualize_control_codes(std::wstring{ str }); + } +} diff --git a/src/til/ut_til/VisualizeControlCodesTests.cpp b/src/til/ut_til/VisualizeControlCodesTests.cpp new file mode 100644 index 00000000000..4d492e9244b --- /dev/null +++ b/src/til/ut_til/VisualizeControlCodesTests.cpp @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "precomp.h" + +#include "til/operators.h" + +using namespace WEX::Common; +using namespace WEX::Logging; +using namespace WEX::TestExecution; + +class VisualizeControlCodesTests +{ + TEST_CLASS(VisualizeControlCodesTests); + + TEST_METHOD(EscapeSequence) + { + const std::wstring_view expected{ L"\u241b[A\u2423\u241b[B" }; + + const std::wstring_view input{ L"\u001b[A \u001b[B" }; + VERIFY_ARE_EQUAL(expected, til::visualize_control_codes(input)); + } +}; diff --git a/src/til/ut_til/til.unit.tests.vcxproj b/src/til/ut_til/til.unit.tests.vcxproj index 1b9975ec83b..083d365e18e 100644 --- a/src/til/ut_til/til.unit.tests.vcxproj +++ b/src/til/ut_til/til.unit.tests.vcxproj @@ -22,6 +22,7 @@ + Create