Reduce usage of Json::Value throughout Terminal.Settings.Model (#11184)

This commit reduces the code surface that interacts with raw JSON data,
reducing code complexity and improving maintainability.
Files that needed to be changed drastically were additionally
cleaned up to remove any code cruft that has accrued over time.

In order to facility this the following changes were made:
* Move JSON handling from `CascadiaSettings` into `SettingsLoader`
  This allows us to use STL containers for data model instances.
  For instance profiles are now added to a hashmap for O(1) lookup.
* JSON parsing within `SettingsLoader` doesn't differentiate between user,
  inbox and fragment JSON data, reducing code complexity and size.
  It also centralizes common concerns, like profile deduplication and
  ensuring that all profiles are assigned a GUID.
* Direct JSON modification, like the insertion of dynamic profiles into
  settings.json were removed. This vastly reduces code complexity,
  but unfortunately removes support for comments in JSON on first start.
* `ColorScheme`s cannot be layered. As such its `LayerJson` API was replaced
  with `FromJson`, allowing us to remove JSON-based color scheme validation.
* `Profile`s used to test their wish to layer using `ShouldBeLayered`, which
  was replaced with a GUID-based hashmap lookup on previously parsed profiles.

Further changes were made as improvements upon the previous changes:
* Compact the JSON files embedded binary, saving 28kB
* Prevent double-initialization of the color table in `ColorScheme`
* Making `til::color` getters `constexpr`, allow better optimizations

The result is a reduction of:
* 48kB binary size for the Settings.Model.dll
* 5-10% startup duration
* 26% code for the `CascadiaSettings` class
* 1% overall code in this project

Furthermore this results in the following breaking changes:
* The long deprecated "globals" settings object will not be detected and no
  warning will be created during load.
* The initial creation of a new settings.json will not produce helpful comments.

Both cases are caused by the removal of manual JSON handling and the
move to representing the settings file with model objects instead

## PR Checklist
* [x] Closes #5276
* [x] Closes #7421
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed

* Out-of-box-experience is identical to before ✔️
  (Except for the settings.json file lacking comments.)
* Existing user settings load correctly ✔️
* New WSL instances are added to user settings ✔️
* New fragments are added to user settings ✔️
* All profiles are assigned GUIDs ✔️
This commit is contained in:
Leonard Hecker 2021-09-22 18:27:31 +02:00 committed by GitHub
parent 591a67111e
commit 168d28b036
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 2335 additions and 5540 deletions

View File

@ -557,6 +557,7 @@ DECSTR
DECSWL DECSWL
DECTCEM DECTCEM
Dedupe Dedupe
deduplicate
deduplicated deduplicated
DEFAPP DEFAPP
DEFAULTBACKGROUND DEFAULTBACKGROUND
@ -784,6 +785,7 @@ FINDSTRINGEXACT
FINDUP FINDUP
FIter FIter
FIXEDCONVERTED FIXEDCONVERTED
FIXEDFILEINFO
Flg Flg
flyout flyout
fmodern fmodern
@ -1992,6 +1994,7 @@ resx
retval retval
rfa rfa
rfc rfc
rfid
rftp rftp
rgb rgb
rgba rgba

View File

@ -289,6 +289,7 @@ If you would like to ask a question that you feel doesn't warrant an issue
* You must [enable Developer Mode in the Windows Settings * You must [enable Developer Mode in the Windows Settings
app](https://docs.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development) app](https://docs.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development)
to locally install and run Windows Terminal to locally install and run Windows Terminal
* You must have [PowerShell 7 or later](https://github.com/PowerShell/PowerShell/releases/latest) installed
* You must have the [Windows 10 1903 * You must have the [Windows 10 1903
SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk) SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk)
installed installed

View File

@ -5,9 +5,11 @@
#include "../TerminalSettingsModel/ColorScheme.h" #include "../TerminalSettingsModel/ColorScheme.h"
#include "../TerminalSettingsModel/CascadiaSettings.h" #include "../TerminalSettingsModel/CascadiaSettings.h"
#include "../types/inc/colorTable.hpp"
#include "JsonTestClass.h" #include "JsonTestClass.h"
using namespace Microsoft::Console; using namespace Microsoft::Console;
using namespace winrt::Microsoft::Terminal;
using namespace winrt::Microsoft::Terminal::Settings::Model::implementation; using namespace winrt::Microsoft::Terminal::Settings::Model::implementation;
using namespace WEX::Logging; using namespace WEX::Logging;
using namespace WEX::TestExecution; using namespace WEX::TestExecution;
@ -32,339 +34,293 @@ namespace SettingsModelLocalTests
TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml") TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml")
END_TEST_CLASS() END_TEST_CLASS()
TEST_METHOD(CanLayerColorScheme); TEST_METHOD(ParseSimpleColorScheme);
TEST_METHOD(LayerColorSchemeProperties);
TEST_METHOD(LayerColorSchemesOnArray); TEST_METHOD(LayerColorSchemesOnArray);
TEST_METHOD(UpdateSchemeReferences); TEST_METHOD(UpdateSchemeReferences);
TEST_CLASS_SETUP(ClassSetup) static Core::Color rgb(uint8_t r, uint8_t g, uint8_t b) noexcept
{ {
InitializeJsonReader(); return Core::Color{ r, g, b, 255 };
return true;
} }
}; };
void ColorSchemeTests::CanLayerColorScheme() void ColorSchemeTests::ParseSimpleColorScheme()
{ {
const std::string scheme0String{ R"({ const std::string campbellScheme{ "{"
"name": "scheme0", "\"background\" : \"#0C0C0C\","
"foreground": "#000000", "\"black\" : \"#0C0C0C\","
"background": "#010101" "\"blue\" : \"#0037DA\","
})" }; "\"brightBlack\" : \"#767676\","
const std::string scheme1String{ R"({ "\"brightBlue\" : \"#3B78FF\","
"name": "scheme1", "\"brightCyan\" : \"#61D6D6\","
"foreground": "#020202", "\"brightGreen\" : \"#16C60C\","
"background": "#030303" "\"brightPurple\" : \"#B4009E\","
})" }; "\"brightRed\" : \"#E74856\","
const std::string scheme2String{ R"({ "\"brightWhite\" : \"#F2F2F2\","
"name": "scheme0", "\"brightYellow\" : \"#F9F1A5\","
"foreground": "#040404", "\"cursorColor\" : \"#FFFFFF\","
"background": "#050505" "\"cyan\" : \"#3A96DD\","
})" }; "\"foreground\" : \"#F2F2F2\","
const std::string scheme3String{ R"({ "\"green\" : \"#13A10E\","
// "name": "scheme3", "\"name\" : \"Campbell\","
"foreground": "#060606", "\"purple\" : \"#881798\","
"background": "#070707" "\"red\" : \"#C50F1F\","
})" }; "\"selectionBackground\" : \"#131313\","
"\"white\" : \"#CCCCCC\","
"\"yellow\" : \"#C19C00\""
"}" };
const auto scheme0Json = VerifyParseSucceeded(scheme0String); const auto schemeObject = VerifyParseSucceeded(campbellScheme);
const auto scheme1Json = VerifyParseSucceeded(scheme1String); auto scheme = ColorScheme::FromJson(schemeObject);
const auto scheme2Json = VerifyParseSucceeded(scheme2String); VERIFY_ARE_EQUAL(L"Campbell", scheme->Name());
const auto scheme3Json = VerifyParseSucceeded(scheme3String); VERIFY_ARE_EQUAL(til::color(0xf2, 0xf2, 0xf2, 255), til::color{ scheme->Foreground() });
VERIFY_ARE_EQUAL(til::color(0x0c, 0x0c, 0x0c, 255), til::color{ scheme->Background() });
VERIFY_ARE_EQUAL(til::color(0x13, 0x13, 0x13, 255), til::color{ scheme->SelectionBackground() });
VERIFY_ARE_EQUAL(til::color(0xFF, 0xFF, 0xFF, 255), til::color{ scheme->CursorColor() });
const auto scheme0 = ColorScheme::FromJson(scheme0Json); std::array<COLORREF, COLOR_TABLE_SIZE> expectedCampbellTable;
const auto campbellSpan = gsl::make_span(expectedCampbellTable);
Utils::InitializeCampbellColorTable(campbellSpan);
Utils::SetColorTableAlpha(campbellSpan, 0);
VERIFY_IS_TRUE(scheme0->ShouldBeLayered(scheme0Json)); for (size_t i = 0; i < expectedCampbellTable.size(); i++)
VERIFY_IS_FALSE(scheme0->ShouldBeLayered(scheme1Json)); {
VERIFY_IS_TRUE(scheme0->ShouldBeLayered(scheme2Json)); const auto& expected = expectedCampbellTable.at(i);
VERIFY_IS_FALSE(scheme0->ShouldBeLayered(scheme3Json)); const til::color actual{ scheme->Table().at(static_cast<uint32_t>(i)) };
VERIFY_ARE_EQUAL(expected, actual);
}
const auto scheme1 = ColorScheme::FromJson(scheme1Json); Log::Comment(L"Roundtrip Test for Color Scheme");
Json::Value outJson{ scheme->ToJson() };
VERIFY_IS_FALSE(scheme1->ShouldBeLayered(scheme0Json)); VERIFY_ARE_EQUAL(schemeObject, outJson);
VERIFY_IS_TRUE(scheme1->ShouldBeLayered(scheme1Json));
VERIFY_IS_FALSE(scheme1->ShouldBeLayered(scheme2Json));
VERIFY_IS_FALSE(scheme1->ShouldBeLayered(scheme3Json));
const auto scheme3 = ColorScheme::FromJson(scheme3Json);
VERIFY_IS_FALSE(scheme3->ShouldBeLayered(scheme0Json));
VERIFY_IS_FALSE(scheme3->ShouldBeLayered(scheme1Json));
VERIFY_IS_FALSE(scheme3->ShouldBeLayered(scheme2Json));
VERIFY_IS_FALSE(scheme3->ShouldBeLayered(scheme3Json));
}
void ColorSchemeTests::LayerColorSchemeProperties()
{
const std::string scheme0String{ R"({
"name": "scheme0",
"foreground": "#000000",
"background": "#010101",
"selectionBackground": "#010100",
"cursorColor": "#010001",
"red": "#010000",
"green": "#000100",
"blue": "#000001"
})" };
const std::string scheme1String{ R"({
"name": "scheme1",
"foreground": "#020202",
"background": "#030303",
"selectionBackground": "#020200",
"cursorColor": "#040004",
"red": "#020000",
"blue": "#000002"
})" };
const std::string scheme2String{ R"({
"name": "scheme0",
"foreground": "#040404",
"background": "#050505",
"selectionBackground": "#030300",
"cursorColor": "#060006",
"red": "#030000",
"green": "#000300"
})" };
const auto scheme0Json = VerifyParseSucceeded(scheme0String);
const auto scheme1Json = VerifyParseSucceeded(scheme1String);
const auto scheme2Json = VerifyParseSucceeded(scheme2String);
auto scheme0 = ColorScheme::FromJson(scheme0Json);
VERIFY_ARE_EQUAL(L"scheme0", scheme0->_Name);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 0), scheme0->_SelectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 0, 1), scheme0->_CursorColor);
VERIFY_ARE_EQUAL(ARGB(0, 1, 0, 0), scheme0->_table[XTERM_RED_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 1, 0), scheme0->_table[XTERM_GREEN_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 1), scheme0->_table[XTERM_BLUE_ATTR]);
Log::Comment(NoThrowString().Format(
L"Layering scheme1 on top of scheme0"));
scheme0->LayerJson(scheme1Json);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 0), scheme0->_SelectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 4, 0, 4), scheme0->_CursorColor);
VERIFY_ARE_EQUAL(ARGB(0, 2, 0, 0), scheme0->_table[XTERM_RED_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 1, 0), scheme0->_table[XTERM_GREEN_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 2), scheme0->_table[XTERM_BLUE_ATTR]);
Log::Comment(NoThrowString().Format(
L"Layering scheme2Json on top of (scheme0+scheme1)"));
scheme0->LayerJson(scheme2Json);
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 0), scheme0->_SelectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 6, 0, 6), scheme0->_CursorColor);
VERIFY_ARE_EQUAL(ARGB(0, 3, 0, 0), scheme0->_table[XTERM_RED_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 3, 0), scheme0->_table[XTERM_GREEN_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 2), scheme0->_table[XTERM_BLUE_ATTR]);
} }
void ColorSchemeTests::LayerColorSchemesOnArray() void ColorSchemeTests::LayerColorSchemesOnArray()
{ {
const std::string scheme0String{ R"({ static constexpr std::string_view inboxSettings{ R"({
"name": "scheme0", "schemes": [
"foreground": "#000000", {
"background": "#010101" "background": "#0C0C0C",
"black": "#0C0C0C",
"blue": "#0037DA",
"brightBlack": "#767676",
"brightBlue": "#3B78FF",
"brightCyan": "#61D6D6",
"brightGreen": "#16C60C",
"brightPurple": "#B4009E",
"brightRed": "#E74856",
"brightWhite": "#F2F2F2",
"brightYellow": "#F9F1A5",
"cursorColor": "#FFFFFF",
"cyan": "#3A96DD",
"foreground": "#CCCCCC",
"green": "#13A10E",
"name": "Campbell",
"purple": "#881798",
"red": "#C50F1F",
"selectionBackground": "#FFFFFF",
"white": "#CCCCCC",
"yellow": "#C19C00"
}
]
})" }; })" };
const std::string scheme1String{ R"({ static constexpr std::string_view userSettings{ R"({
"name": "scheme1", "profiles": [
"foreground": "#020202", {
"background": "#030303" "name" : "profile0"
})" }; }
const std::string scheme2String{ R"({ ],
"name": "scheme0", "schemes": [
"foreground": "#040404", {
"background": "#050505" "background": "#121314",
})" }; "black": "#121314",
const std::string scheme3String{ R"({ "blue": "#121314",
// by not providing a name, the scheme will have the name "" "brightBlack": "#121314",
"foreground": "#060606", "brightBlue": "#121314",
"background": "#070707" "brightCyan": "#121314",
"brightGreen": "#121314",
"brightPurple": "#121314",
"brightRed": "#121314",
"brightWhite": "#121314",
"brightYellow": "#121314",
"cursorColor": "#121314",
"cyan": "#121314",
"foreground": "#121314",
"green": "#121314",
"name": "Campbell",
"purple": "#121314",
"red": "#121314",
"selectionBackground": "#121314",
"white": "#121314",
"yellow": "#121314"
},
{
"background": "#012456",
"black": "#0C0C0C",
"blue": "#0037DA",
"brightBlack": "#767676",
"brightBlue": "#3B78FF",
"brightCyan": "#61D6D6",
"brightGreen": "#16C60C",
"brightPurple": "#B4009E",
"brightRed": "#E74856",
"brightWhite": "#F2F2F2",
"brightYellow": "#F9F1A5",
"cursorColor": "#FFFFFF",
"cyan": "#3A96DD",
"foreground": "#CCCCCC",
"green": "#13A10E",
"name": "Campbell Powershell",
"purple": "#881798",
"red": "#C50F1F",
"selectionBackground": "#FFFFFF",
"white": "#CCCCCC",
"yellow": "#C19C00"
}
]
})" }; })" };
const auto scheme0Json = VerifyParseSucceeded(scheme0String); const auto settings = winrt::make_self<CascadiaSettings>(userSettings, inboxSettings);
const auto scheme1Json = VerifyParseSucceeded(scheme1String);
const auto scheme2Json = VerifyParseSucceeded(scheme2String);
const auto scheme3Json = VerifyParseSucceeded(scheme3String);
auto settings = winrt::make_self<CascadiaSettings>(); const auto colorSchemes = settings->GlobalSettings().ColorSchemes();
VERIFY_ARE_EQUAL(2u, colorSchemes.Size());
VERIFY_ARE_EQUAL(0u, settings->_globals->ColorSchemes().Size()); const auto scheme0 = winrt::get_self<ColorScheme>(colorSchemes.Lookup(L"Campbell"));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme0Json)); VERIFY_ARE_EQUAL(rgb(0x12, 0x13, 0x14), scheme0->Foreground());
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme1Json)); VERIFY_ARE_EQUAL(rgb(0x12, 0x13, 0x14), scheme0->Background());
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
settings->_LayerOrCreateColorScheme(scheme0Json); const auto scheme1 = winrt::get_self<ColorScheme>(colorSchemes.Lookup(L"Campbell Powershell"));
{ VERIFY_ARE_EQUAL(rgb(0xCC, 0xCC, 0xCC), scheme1->Foreground());
for (auto kv : settings->_globals->ColorSchemes()) VERIFY_ARE_EQUAL(rgb(0x01, 0x24, 0x56), scheme1->Background());
{
Log::Comment(NoThrowString().Format(
L"kv:%s->%s", kv.Key().data(), kv.Value().Name().data()));
}
VERIFY_ARE_EQUAL(1u, settings->_globals->ColorSchemes().Size());
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme0"));
auto scheme0Proj = settings->_globals->ColorSchemes().Lookup(L"scheme0");
auto scheme0 = winrt::get_self<ColorScheme>(scheme0Proj);
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme0Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_Background);
}
settings->_LayerOrCreateColorScheme(scheme1Json);
{
VERIFY_ARE_EQUAL(2u, settings->_globals->ColorSchemes().Size());
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme0"));
auto scheme0Proj = settings->_globals->ColorSchemes().Lookup(L"scheme0");
auto scheme0 = winrt::get_self<ColorScheme>(scheme0Proj);
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme1"));
auto scheme1Proj = settings->_globals->ColorSchemes().Lookup(L"scheme1");
auto scheme1 = winrt::get_self<ColorScheme>(scheme1Proj);
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_Background);
}
settings->_LayerOrCreateColorScheme(scheme2Json);
{
VERIFY_ARE_EQUAL(2u, settings->_globals->ColorSchemes().Size());
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme0"));
auto scheme0Proj = settings->_globals->ColorSchemes().Lookup(L"scheme0");
auto scheme0 = winrt::get_self<ColorScheme>(scheme0Proj);
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme1"));
auto scheme1Proj = settings->_globals->ColorSchemes().Lookup(L"scheme1");
auto scheme1 = winrt::get_self<ColorScheme>(scheme1Proj);
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_Background);
}
settings->_LayerOrCreateColorScheme(scheme3Json);
{
VERIFY_ARE_EQUAL(3u, settings->_globals->ColorSchemes().Size());
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme0"));
auto scheme0Proj = settings->_globals->ColorSchemes().Lookup(L"scheme0");
auto scheme0 = winrt::get_self<ColorScheme>(scheme0Proj);
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme1"));
auto scheme1Proj = settings->_globals->ColorSchemes().Lookup(L"scheme1");
auto scheme1 = winrt::get_self<ColorScheme>(scheme1Proj);
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L""));
auto scheme2Proj = settings->_globals->ColorSchemes().Lookup(L"");
auto scheme2 = winrt::get_self<ColorScheme>(scheme2Proj);
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 6, 6, 6), scheme2->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 7, 7, 7), scheme2->_Background);
}
} }
void ColorSchemeTests::UpdateSchemeReferences() void ColorSchemeTests::UpdateSchemeReferences()
{ {
const std::string settingsString{ R"json({ static constexpr std::string_view settingsString{ R"json({
"defaultProfile": "Inherited reference", "defaultProfile": "Inherited reference",
"profiles": { "profiles": {
"defaults": { "defaults": {
"colorScheme": "Scheme 1" "colorScheme": "Campbell"
}, },
"list": [ "list": [
{ {
"name": "Explicit scheme reference", "name": "Explicit scheme reference",
"colorScheme": "Scheme 1" "colorScheme": "Campbell"
}, },
{ {
"name": "Explicit reference; hidden", "name": "Explicit reference; hidden",
"colorScheme": "Scheme 1", "colorScheme": "Campbell",
"hidden": true "hidden": true
}, },
{ {
"name": "Inherited reference" "name": "Inherited reference"
}, },
{ {
"name": "Different reference", "name": "Different reference",
"colorScheme": "Scheme 2" "colorScheme": "One Half Dark"
} }
] ]
}, },
"schemes": [ "schemes": [
{ "name": "Scheme 1" }, {
{ "name": "Scheme 2" }, "background": "#0C0C0C",
{ "name": "Scheme 1 (renamed)" } "black": "#0C0C0C",
] "blue": "#0037DA",
})json" }; "brightBlack": "#767676",
"brightBlue": "#3B78FF",
"brightCyan": "#61D6D6",
"brightGreen": "#16C60C",
"brightPurple": "#B4009E",
"brightRed": "#E74856",
"brightWhite": "#F2F2F2",
"brightYellow": "#F9F1A5",
"cursorColor": "#FFFFFF",
"cyan": "#3A96DD",
"foreground": "#CCCCCC",
"green": "#13A10E",
"name": "Campbell",
"purple": "#881798",
"red": "#C50F1F",
"selectionBackground": "#FFFFFF",
"white": "#CCCCCC",
"yellow": "#C19C00"
},
{
"background": "#0C0C0C",
"black": "#0C0C0C",
"blue": "#0037DA",
"brightBlack": "#767676",
"brightBlue": "#3B78FF",
"brightCyan": "#61D6D6",
"brightGreen": "#16C60C",
"brightPurple": "#B4009E",
"brightRed": "#E74856",
"brightWhite": "#F2F2F2",
"brightYellow": "#F9F1A5",
"cursorColor": "#FFFFFF",
"cyan": "#3A96DD",
"foreground": "#CCCCCC",
"green": "#13A10E",
"name": "Campbell (renamed)",
"purple": "#881798",
"red": "#C50F1F",
"selectionBackground": "#FFFFFF",
"white": "#CCCCCC",
"yellow": "#C19C00"
},
{
"background": "#282C34",
"black": "#282C34",
"blue": "#61AFEF",
"brightBlack": "#5A6374",
"brightBlue": "#61AFEF",
"brightCyan": "#56B6C2",
"brightGreen": "#98C379",
"brightPurple": "#C678DD",
"brightRed": "#E06C75",
"brightWhite": "#DCDFE4",
"brightYellow": "#E5C07B",
"cursorColor": "#FFFFFF",
"cyan": "#56B6C2",
"foreground": "#DCDFE4",
"green": "#98C379",
"name": "One Half Dark",
"purple": "#C678DD",
"red": "#E06C75",
"selectionBackground": "#FFFFFF",
"white": "#DCDFE4",
"yellow": "#E5C07B"
}
]
})json" };
auto settings{ winrt::make_self<CascadiaSettings>(false) }; const auto settings{ winrt::make_self<CascadiaSettings>(settingsString) };
settings->_ParseJsonString(settingsString, false);
settings->_ApplyDefaultsFromUserSettings();
settings->LayerJson(settings->_userSettings);
settings->_ValidateSettings();
// update all references to "Scheme 1" const auto newName{ L"Campbell (renamed)" };
const auto newName{ L"Scheme 1 (renamed)" }; settings->UpdateColorSchemeReferences(L"Campbell", newName);
settings->UpdateColorSchemeReferences(L"Scheme 1", newName);
// verify profile defaults
Log::Comment(L"Profile Defaults");
VERIFY_ARE_EQUAL(newName, settings->ProfileDefaults().DefaultAppearance().ColorSchemeName()); VERIFY_ARE_EQUAL(newName, settings->ProfileDefaults().DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(settings->ProfileDefaults().DefaultAppearance().HasColorSchemeName()); VERIFY_IS_TRUE(settings->ProfileDefaults().DefaultAppearance().HasColorSchemeName());
// verify all other profiles
const auto& profiles{ settings->AllProfiles() }; const auto& profiles{ settings->AllProfiles() };
{ {
const auto& prof{ profiles.GetAt(0) }; const auto& prof{ profiles.GetAt(0) };
Log::Comment(prof.Name().c_str());
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName()); VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName()); VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName());
} }
{ {
const auto& prof{ profiles.GetAt(1) }; const auto& prof{ profiles.GetAt(1) };
Log::Comment(prof.Name().c_str());
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName()); VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName()); VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName());
} }
{ {
const auto& prof{ profiles.GetAt(2) }; const auto& prof{ profiles.GetAt(2) };
Log::Comment(prof.Name().c_str());
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName()); VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_FALSE(prof.DefaultAppearance().HasColorSchemeName()); VERIFY_IS_FALSE(prof.DefaultAppearance().HasColorSchemeName());
} }
{ {
const auto& prof{ profiles.GetAt(3) }; const auto& prof{ profiles.GetAt(3) };
Log::Comment(prof.Name().c_str()); VERIFY_ARE_EQUAL(L"One Half Dark", prof.DefaultAppearance().ColorSchemeName());
VERIFY_ARE_EQUAL(L"Scheme 2", prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName()); VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName());
} }
} }

View File

@ -43,12 +43,6 @@ namespace SettingsModelLocalTests
TEST_METHOD(TestLayerOnAutogeneratedName); TEST_METHOD(TestLayerOnAutogeneratedName);
TEST_METHOD(TestGenerateCommandline); TEST_METHOD(TestGenerateCommandline);
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
return true;
}
}; };
void CommandTests::ManyCommandsSameAction() void CommandTests::ManyCommandsSameAction()

File diff suppressed because it is too large Load Diff

View File

@ -7,44 +7,34 @@ Module Name:
Abstract: Abstract:
- This class is a helper that can be used to quickly create tests that need to - This class is a helper that can be used to quickly create tests that need to
read & parse json data. Test classes that need to read JSON should make sure read & parse json data.
to derive from this class, and also make sure to call InitializeJsonReader()
in the TEST_CLASS_SETUP().
Author(s): Author(s):
Mike Griese (migrie) August-2019 Mike Griese (migrie) August-2019
--*/ --*/
#pragma once
class JsonTestClass class JsonTestClass
{ {
public: public:
void InitializeJsonReader() static Json::Value VerifyParseSucceeded(const std::string_view& content)
{ {
_reader = std::unique_ptr<Json::CharReader>(Json::CharReaderBuilder::CharReaderBuilder().newCharReader()); static const std::unique_ptr<Json::CharReader> reader{ Json::CharReaderBuilder::CharReaderBuilder().newCharReader() };
};
void InitializeJsonWriter()
{
_writer = std::unique_ptr<Json::StreamWriter>(Json::StreamWriterBuilder::StreamWriterBuilder().newStreamWriter());
}
Json::Value VerifyParseSucceeded(std::string content)
{
Json::Value root; Json::Value root;
std::string errs; std::string errs;
const bool parseResult = _reader->parse(content.c_str(), content.c_str() + content.size(), &root, &errs); const bool parseResult = reader->parse(content.data(), content.data() + content.size(), &root, &errs);
VERIFY_IS_TRUE(parseResult, winrt::to_hstring(errs).c_str()); VERIFY_IS_TRUE(parseResult, winrt::to_hstring(errs).c_str());
return root; return root;
}; };
std::string toString(const Json::Value& json) static std::string toString(const Json::Value& json)
{ {
static const std::unique_ptr<Json::StreamWriter> writer{ Json::StreamWriterBuilder::StreamWriterBuilder().newStreamWriter() };
std::stringstream s; std::stringstream s;
_writer->write(json, &s); writer->write(json, &s);
return s.str(); return s.str();
} }
protected:
std::unique_ptr<Json::CharReader> _reader;
std::unique_ptr<Json::StreamWriter> _writer;
}; };

View File

@ -59,12 +59,6 @@ namespace SettingsModelLocalTests
TEST_METHOD(TestGetKeyBindingForAction); TEST_METHOD(TestGetKeyBindingForAction);
TEST_METHOD(KeybindingsWithoutVkey); TEST_METHOD(KeybindingsWithoutVkey);
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
return true;
}
}; };
void KeyBindingsTests::KeyChords() void KeyBindingsTests::KeyChords()

View File

@ -7,6 +7,8 @@
#include "../TerminalSettingsModel/CascadiaSettings.h" #include "../TerminalSettingsModel/CascadiaSettings.h"
#include "JsonTestClass.h" #include "JsonTestClass.h"
#include <defaults.h>
using namespace Microsoft::Console; using namespace Microsoft::Console;
using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace WEX::Logging; using namespace WEX::Logging;
@ -32,81 +34,86 @@ namespace SettingsModelLocalTests
TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml") TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml")
END_TEST_CLASS() END_TEST_CLASS()
TEST_METHOD(CanLayerProfile); TEST_METHOD(ProfileGeneratesGuid);
TEST_METHOD(LayerProfileProperties); TEST_METHOD(LayerProfileProperties);
TEST_METHOD(LayerProfileIcon); TEST_METHOD(LayerProfileIcon);
TEST_METHOD(LayerProfilesOnArray); TEST_METHOD(LayerProfilesOnArray);
TEST_METHOD(DuplicateProfileTest); TEST_METHOD(DuplicateProfileTest);
TEST_METHOD(TestGenGuidsForProfiles);
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
return true;
}
}; };
void ProfileTests::CanLayerProfile() void ProfileTests::ProfileGeneratesGuid()
{ {
const std::string profile0String{ R"({ // Parse some profiles without guids. We should NOT generate new guids
"name" : "profile0", // for them. If a profile doesn't have a GUID, we'll leave its _guid
"guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}" // set to nullopt. The Profile::Guid() getter will
})" }; // ensure all profiles have a GUID that's actually set.
const std::string profile1String{ R"({ // The null guid _is_ a valid guid, so we won't re-generate that
"name" : "profile1", // guid. null is _not_ a valid guid, so we'll leave that nullopt
"guid" : "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
})" };
const std::string profile2String{ R"({
"name" : "profile2",
"guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
})" };
const std::string profile3String{ R"({
"name" : "profile3"
})" };
const auto profile0Json = VerifyParseSucceeded(profile0String); // See SettingsTests::ValidateProfilesGenerateGuids for a version of
const auto profile1Json = VerifyParseSucceeded(profile1String); // this test that includes synthesizing GUIDS for profiles without GUIDs
const auto profile2Json = VerifyParseSucceeded(profile2String); // set
const auto profile3Json = VerifyParseSucceeded(profile3String);
const std::string profileWithoutGuid{ R"({
"name" : "profile0"
})" };
const std::string secondProfileWithoutGuid{ R"({
"name" : "profile1"
})" };
const std::string profileWithNullForGuid{ R"({
"name" : "profile2",
"guid" : null
})" };
const std::string profileWithNullGuid{ R"({
"name" : "profile3",
"guid" : "{00000000-0000-0000-0000-000000000000}"
})" };
const std::string profileWithGuid{ R"({
"name" : "profile4",
"guid" : "{6239a42c-1de4-49a3-80bd-e8fdd045185c}"
})" };
const auto profile0Json = VerifyParseSucceeded(profileWithoutGuid);
const auto profile1Json = VerifyParseSucceeded(secondProfileWithoutGuid);
const auto profile2Json = VerifyParseSucceeded(profileWithNullForGuid);
const auto profile3Json = VerifyParseSucceeded(profileWithNullGuid);
const auto profile4Json = VerifyParseSucceeded(profileWithGuid);
const auto profile0 = implementation::Profile::FromJson(profile0Json); const auto profile0 = implementation::Profile::FromJson(profile0Json);
VERIFY_IS_FALSE(profile0->ShouldBeLayered(profile1Json));
VERIFY_IS_TRUE(profile0->ShouldBeLayered(profile2Json));
VERIFY_IS_FALSE(profile0->ShouldBeLayered(profile3Json));
const auto profile1 = implementation::Profile::FromJson(profile1Json); const auto profile1 = implementation::Profile::FromJson(profile1Json);
const auto profile2 = implementation::Profile::FromJson(profile2Json);
VERIFY_IS_FALSE(profile1->ShouldBeLayered(profile0Json));
// A profile _can_ be layered with itself, though what's the point?
VERIFY_IS_TRUE(profile1->ShouldBeLayered(profile1Json));
VERIFY_IS_FALSE(profile1->ShouldBeLayered(profile2Json));
VERIFY_IS_FALSE(profile1->ShouldBeLayered(profile3Json));
const auto profile3 = implementation::Profile::FromJson(profile3Json); const auto profile3 = implementation::Profile::FromJson(profile3Json);
const auto profile4 = implementation::Profile::FromJson(profile4Json);
const winrt::guid cmdGuid = Utils::GuidFromString(L"{6239a42c-1de4-49a3-80bd-e8fdd045185c}");
const winrt::guid nullGuid{};
VERIFY_IS_FALSE(profile3->ShouldBeLayered(profile0Json)); VERIFY_IS_FALSE(profile0->HasGuid());
// A profile _can_ be layered with itself, though what's the point? VERIFY_IS_FALSE(profile1->HasGuid());
VERIFY_IS_FALSE(profile3->ShouldBeLayered(profile1Json)); VERIFY_IS_FALSE(profile2->HasGuid());
VERIFY_IS_FALSE(profile3->ShouldBeLayered(profile2Json)); VERIFY_IS_TRUE(profile3->HasGuid());
VERIFY_IS_TRUE(profile3->ShouldBeLayered(profile3Json)); VERIFY_IS_TRUE(profile4->HasGuid());
VERIFY_ARE_EQUAL(profile3->Guid(), nullGuid);
VERIFY_ARE_EQUAL(profile4->Guid(), cmdGuid);
} }
void ProfileTests::LayerProfileProperties() void ProfileTests::LayerProfileProperties()
{ {
const std::string profile0String{ R"({ static constexpr std::string_view profile0String{ R"({
"name": "profile0", "name": "profile0",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"foreground": "#000000", "foreground": "#000000",
"background": "#010101", "background": "#010101",
"selectionBackground": "#010101" "selectionBackground": "#010101"
})" }; })" };
const std::string profile1String{ R"({ static constexpr std::string_view profile1String{ R"({
"name": "profile1", "name": "profile1",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"foreground": "#020202", "foreground": "#020202",
"startingDirectory": "C:/" "startingDirectory": "C:/"
})" }; })" };
const std::string profile2String{ R"({ static constexpr std::string_view profile2String{ R"({
"name": "profile2", "name": "profile2",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"foreground": "#030303", "foreground": "#030303",
@ -172,21 +179,21 @@ namespace SettingsModelLocalTests
void ProfileTests::LayerProfileIcon() void ProfileTests::LayerProfileIcon()
{ {
const std::string profile0String{ R"({ static constexpr std::string_view profile0String{ R"({
"name": "profile0", "name": "profile0",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"icon": "not-null.png" "icon": "not-null.png"
})" }; })" };
const std::string profile1String{ R"({ static constexpr std::string_view profile1String{ R"({
"name": "profile1", "name": "profile1",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"icon": null "icon": null
})" }; })" };
const std::string profile2String{ R"({ static constexpr std::string_view profile2String{ R"({
"name": "profile2", "name": "profile2",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
})" }; })" };
const std::string profile3String{ R"({ static constexpr std::string_view profile3String{ R"({
"name": "profile3", "name": "profile3",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"icon": "another-real.png" "icon": "another-real.png"
@ -228,102 +235,95 @@ namespace SettingsModelLocalTests
void ProfileTests::LayerProfilesOnArray() void ProfileTests::LayerProfilesOnArray()
{ {
const std::string profile0String{ R"({ static constexpr std::string_view inboxProfiles{ R"({
"name" : "profile0", "profiles": [
"guid" : "{6239a42c-0000-49a3-80bd-e8fdd045185c}" {
"name" : "profile0",
"guid" : "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
}, {
"name" : "profile1",
"guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
}, {
"name" : "profile2",
"guid" : "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
}
]
})" }; })" };
const std::string profile1String{ R"({ static constexpr std::string_view userProfiles{ R"({
"name" : "profile1", "profiles": [
"guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}" {
})" }; "name" : "profile3",
const std::string profile2String{ R"({ "guid" : "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
"name" : "profile2", }, {
"guid" : "{6239a42c-2222-49a3-80bd-e8fdd045185c}" "name" : "profile4",
})" }; "guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
const std::string profile3String{ R"({ }
"name" : "profile3", ]
"guid" : "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
})" };
const std::string profile4String{ R"({
"name" : "profile4",
"guid" : "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
})" }; })" };
const auto profile0Json = VerifyParseSucceeded(profile0String); const auto settings = winrt::make_self<implementation::CascadiaSettings>(userProfiles, inboxProfiles);
const auto profile1Json = VerifyParseSucceeded(profile1String); const auto allProfiles = settings->AllProfiles();
const auto profile2Json = VerifyParseSucceeded(profile2String); VERIFY_ARE_EQUAL(3u, allProfiles.Size());
const auto profile3Json = VerifyParseSucceeded(profile3String); VERIFY_ARE_EQUAL(L"profile3", allProfiles.GetAt(0).Name());
const auto profile4Json = VerifyParseSucceeded(profile4String); VERIFY_ARE_EQUAL(L"profile4", allProfiles.GetAt(1).Name());
VERIFY_ARE_EQUAL(L"profile2", allProfiles.GetAt(2).Name());
auto settings = winrt::make_self<implementation::CascadiaSettings>();
VERIFY_ARE_EQUAL(0u, settings->_allProfiles.Size());
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile0Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile1Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile2Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile3Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile4Json));
settings->_LayerOrCreateProfile(profile0Json);
VERIFY_ARE_EQUAL(1u, settings->_allProfiles.Size());
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile0Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile1Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile2Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile3Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile4Json));
settings->_LayerOrCreateProfile(profile1Json);
VERIFY_ARE_EQUAL(2u, settings->_allProfiles.Size());
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile1Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile2Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile3Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile4Json));
settings->_LayerOrCreateProfile(profile2Json);
VERIFY_ARE_EQUAL(3u, settings->_allProfiles.Size());
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile2Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile3Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile4Json));
VERIFY_ARE_EQUAL(L"profile0", settings->_allProfiles.GetAt(0).Name());
settings->_LayerOrCreateProfile(profile3Json);
VERIFY_ARE_EQUAL(3u, settings->_allProfiles.Size());
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile2Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile3Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile4Json));
VERIFY_ARE_EQUAL(L"profile3", settings->_allProfiles.GetAt(0).Name());
settings->_LayerOrCreateProfile(profile4Json);
VERIFY_ARE_EQUAL(3u, settings->_allProfiles.Size());
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile2Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile3Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile4Json));
VERIFY_ARE_EQUAL(L"profile4", settings->_allProfiles.GetAt(0).Name());
} }
void ProfileTests::DuplicateProfileTest() void ProfileTests::DuplicateProfileTest()
{ {
const std::string profile0String{ R"({ static constexpr std::string_view userProfiles{ R"({
"name" : "profile0", "profiles": [
"backgroundImage" : "some//path" {
"name": "profile0",
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"backgroundImage": "file:///some/path",
"hidden": false,
}
]
})" }; })" };
const auto profile0Json = VerifyParseSucceeded(profile0String); const auto settings = winrt::make_self<implementation::CascadiaSettings>(userProfiles);
const auto profile = settings->AllProfiles().GetAt(0);
const auto duplicatedProfile = settings->DuplicateProfile(profile);
auto settings = winrt::make_self<implementation::CascadiaSettings>(); duplicatedProfile.Guid(profile.Guid());
duplicatedProfile.Name(profile.Name());
settings->_LayerOrCreateProfile(profile0Json);
auto duplicatedProfile = settings->DuplicateProfile(*settings->_FindMatchingProfile(profile0Json));
duplicatedProfile.Name(L"profile0");
const auto json = winrt::get_self<implementation::Profile>(profile)->ToJson();
const auto duplicatedJson = winrt::get_self<implementation::Profile>(duplicatedProfile)->ToJson(); const auto duplicatedJson = winrt::get_self<implementation::Profile>(duplicatedProfile)->ToJson();
VERIFY_ARE_EQUAL(profile0Json, duplicatedJson); VERIFY_ARE_EQUAL(json, duplicatedJson, til::u8u16(toString(duplicatedJson)).c_str());
}
void ProfileTests::TestGenGuidsForProfiles()
{
// We'll generate GUIDs in the Profile::Guid getter. We should make sure that
// the GUID generated for a dynamic profile (with a source) is different
// than that of a profile without a source.
static constexpr std::string_view userSettings{ R"({
"profiles": [
{
"name": "profile0",
"source": "Terminal.App.UnitTest.0",
},
{
"name": "profile0"
}
]
})" };
const auto settings = winrt::make_self<implementation::CascadiaSettings>(userSettings, DefaultJson);
VERIFY_ARE_EQUAL(4u, settings->AllProfiles().Size());
VERIFY_ARE_EQUAL(L"profile0", settings->AllProfiles().GetAt(0).Name());
VERIFY_IS_TRUE(settings->AllProfiles().GetAt(0).HasGuid());
VERIFY_IS_FALSE(settings->AllProfiles().GetAt(0).Source().empty());
VERIFY_ARE_EQUAL(L"profile0", settings->AllProfiles().GetAt(1).Name());
VERIFY_IS_TRUE(settings->AllProfiles().GetAt(1).HasGuid());
VERIFY_IS_TRUE(settings->AllProfiles().GetAt(1).Source().empty());
VERIFY_ARE_NOT_EQUAL(settings->AllProfiles().GetAt(0).Guid(), settings->AllProfiles().GetAt(1).Guid());
} }
} }

View File

@ -8,7 +8,6 @@
#include "JsonTestClass.h" #include "JsonTestClass.h"
#include "TestUtils.h" #include "TestUtils.h"
#include <defaults.h> #include <defaults.h>
#include "../ut_app/TestDynamicProfileGenerator.h"
using namespace Microsoft::Console; using namespace Microsoft::Console;
using namespace WEX::Logging; using namespace WEX::Logging;
@ -43,13 +42,6 @@ namespace SettingsModelLocalTests
TEST_METHOD(CascadiaSettings); TEST_METHOD(CascadiaSettings);
TEST_METHOD(LegacyFontSettings); TEST_METHOD(LegacyFontSettings);
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
InitializeJsonWriter();
return true;
}
private: private:
// Method Description: // Method Description:
// - deserializes and reserializes a json string representing a settings object model of type T // - deserializes and reserializes a json string representing a settings object model of type T
@ -309,10 +301,10 @@ namespace SettingsModelLocalTests
])" }; ])" };
const std::string actionsString9B{ R"([ const std::string actionsString9B{ R"([
{ {
"commands": "commands":
[ [
{ {
"command": "command":
{ {
"action": "sendInput", "action": "sendInput",
"input": "${profile.name}" "input": "${profile.name}"
@ -325,13 +317,13 @@ namespace SettingsModelLocalTests
])" }; ])" };
const std::string actionsString9C{ R""([ const std::string actionsString9C{ R""([
{ {
"commands": "commands":
[ [
{ {
"commands": "commands":
[ [
{ {
"command": "command":
{ {
"action": "sendInput", "action": "sendInput",
"input": "${profile.name} ${scheme.name}" "input": "${profile.name} ${scheme.name}"
@ -348,7 +340,7 @@ namespace SettingsModelLocalTests
])"" }; ])"" };
const std::string actionsString9D{ R""([ const std::string actionsString9D{ R""([
{ {
"command": "command":
{ {
"action": "newTab", "action": "newTab",
"profile": "${profile.name}" "profile": "${profile.name}"
@ -404,75 +396,71 @@ namespace SettingsModelLocalTests
void SerializationTests::CascadiaSettings() void SerializationTests::CascadiaSettings()
{ {
const std::string settingsString{ R"({ const std::string settingsString{ R"({
"$schema": "https://aka.ms/terminal-profiles-schema", "$help" : "https://aka.ms/terminal-documentation",
"defaultProfile": "{61c54bbd-1111-5271-96e7-009a87ff44bf}", "$schema" : "https://aka.ms/terminal-profiles-schema",
"disabledProfileSources": [ "Windows.Terminal.Wsl" ], "defaultProfile": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
"disabledProfileSources": [ "Windows.Terminal.Wsl" ],
"profiles": {
"defaults": {
"font": {
"face": "Zamora Code"
}
},
"list": [
{
"font": { "face": "Cascadia Code" },
"guid": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
"name": "HowettShell"
},
{
"hidden": true,
"guid": "{c08b0496-e71c-5503-b84e-3af7a7a6d2a7}",
"name": "BhojwaniShell"
},
{
"antialiasingMode": "aliased",
"guid": "{fe9df758-ac22-5c20-922d-c7766cdd13af}",
"name": "NiksaShell"
}
]
},
"schemes": [
{
"name": "Cinnamon Roll",
"profiles": { "cursorColor": "#FFFFFD",
"defaults": { "selectionBackground": "#FFFFFF",
"font": {
"face": "Zamora Code"
}
},
"list": [
{
"font": { "face": "Cascadia Code" },
"guid": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
"name": "HowettShell"
},
{
"hidden": true,
"name": "BhojwaniShell"
},
{
"antialiasingMode": "aliased",
"name": "NiksaShell"
}
]
},
"schemes": [
{
"name": "Cinnamon Roll",
"cursorColor": "#FFFFFD", "background": "#3C0315",
"selectionBackground": "#FFFFFF", "foreground": "#FFFFFD",
"background": "#3C0315", "black": "#282A2E",
"foreground": "#FFFFFD", "blue": "#0170C5",
"cyan": "#3F8D83",
"green": "#76AB23",
"purple": "#7D498F",
"red": "#BD0940",
"white": "#FFFFFD",
"yellow": "#E0DE48",
"brightBlack": "#676E7A",
"brightBlue": "#5C98C5",
"brightCyan": "#8ABEB7",
"brightGreen": "#B5D680",
"brightPurple": "#AC79BB",
"brightRed": "#BD6D85",
"brightWhite": "#FFFFFD",
"brightYellow": "#FFFD76"
}
],
"actions": [
{ "command": { "action": "sendInput", "input": "VT Griese Mode" }, "keys": "ctrl+k" }
]
})" };
"black": "#282A2E", const auto settings{ winrt::make_self<implementation::CascadiaSettings>(settingsString) };
"blue": "#0170C5",
"cyan": "#3F8D83",
"green": "#76AB23",
"purple": "#7D498F",
"red": "#BD0940",
"white": "#FFFFFD",
"yellow": "#E0DE48",
"brightBlack": "#676E7A",
"brightBlue": "#5C98C5",
"brightCyan": "#8ABEB7",
"brightGreen": "#B5D680",
"brightPurple": "#AC79BB",
"brightRed": "#BD6D85",
"brightWhite": "#FFFFFD",
"brightYellow": "#FFFD76"
}
],
"actions": [
{ "command": { "action": "renameTab", "title": "Liang Tab" }, "keys": "ctrl+t" },
{ "command": { "action": "sendInput", "input": "VT Griese Mode" }, "keys": "ctrl+k" },
{ "command": { "action": "renameWindow", "name": "Hecker Window" }, "keys": "ctrl+l" }
]
})" };
auto settings{ winrt::make_self<implementation::CascadiaSettings>(false) };
settings->_ParseJsonString(settingsString, false);
settings->_ApplyDefaultsFromUserSettings();
settings->LayerJson(settings->_userSettings);
settings->_ValidateSettings();
const auto result{ settings->ToJson() }; const auto result{ settings->ToJson() };
VERIFY_ARE_EQUAL(toString(settings->_userSettings), toString(result)); VERIFY_ARE_EQUAL(toString(VerifyParseSucceeded(settingsString)), toString(result));
} }
void SerializationTests::LegacyFontSettings() void SerializationTests::LegacyFontSettings()

View File

@ -62,7 +62,7 @@ namespace SettingsModelLocalTests
void TerminalSettingsTests::TestTerminalArgsForBinding() void TerminalSettingsTests::TestTerminalArgsForBinding()
{ {
const std::string settingsJson{ R"( static constexpr std::string_view settingsJson{ R"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": { "list": [ "profiles": { "list": [
@ -106,12 +106,12 @@ namespace SettingsModelLocalTests
const winrt::guid guid0{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-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 winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}") };
CascadiaSettings settings{ til::u8u16(settingsJson) }; const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsJson);
auto actionMap = settings.GlobalSettings().ActionMap(); auto actionMap = settings->GlobalSettings().ActionMap();
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); VERIFY_ARE_EQUAL(3u, settings->ActiveProfiles().Size());
const auto profile2Guid = settings.ActiveProfiles().GetAt(2).Guid(); const auto profile2Guid = settings->ActiveProfiles().GetAt(2).Guid();
VERIFY_ARE_NOT_EQUAL(winrt::guid{}, profile2Guid); VERIFY_ARE_NOT_EQUAL(winrt::guid{}, profile2Guid);
const auto& actionMapImpl{ winrt::get_self<implementation::ActionMap>(actionMap) }; const auto& actionMapImpl{ winrt::get_self<implementation::ActionMap>(actionMap) };
@ -131,8 +131,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid0, profile.Guid()); VERIFY_ARE_EQUAL(guid0, profile.Guid());
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
@ -153,8 +153,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}", realArgs.TerminalArgs().Profile()); VERIFY_ARE_EQUAL(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid1, profile.Guid()); VERIFY_ARE_EQUAL(guid1, profile.Guid());
VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline());
@ -175,8 +175,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile()); VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid1, profile.Guid()); VERIFY_ARE_EQUAL(guid1, profile.Guid());
VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline());
@ -197,8 +197,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile()); VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(profile2Guid, profile.Guid()); VERIFY_ARE_EQUAL(profile2Guid, profile.Guid());
VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline());
@ -219,13 +219,13 @@ namespace SettingsModelLocalTests
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline()); VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
if constexpr (Feature_ShowProfileDefaultsInSettings::IsEnabled()) if constexpr (Feature_ShowProfileDefaultsInSettings::IsEnabled())
{ {
// This action specified a command but no profile; it gets reassigned to the base profile // This action specified a command but no profile; it gets reassigned to the base profile
VERIFY_ARE_EQUAL(settings.ProfileDefaults(), profile); VERIFY_ARE_EQUAL(settings->ProfileDefaults(), profile);
VERIFY_ARE_EQUAL(29, termSettings.HistorySize()); VERIFY_ARE_EQUAL(29, termSettings.HistorySize());
} }
else else
@ -251,8 +251,8 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile()); VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile());
VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline()); VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid1, profile.Guid()); VERIFY_ARE_EQUAL(guid1, profile.Guid());
VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline());
@ -271,8 +271,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid0, profile.Guid()); VERIFY_ARE_EQUAL(guid0, profile.Guid());
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
@ -292,8 +292,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"c:\\foo", realArgs.TerminalArgs().StartingDirectory()); VERIFY_ARE_EQUAL(L"c:\\foo", realArgs.TerminalArgs().StartingDirectory());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid0, profile.Guid()); VERIFY_ARE_EQUAL(guid0, profile.Guid());
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
@ -315,8 +315,8 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(L"c:\\foo", realArgs.TerminalArgs().StartingDirectory()); VERIFY_ARE_EQUAL(L"c:\\foo", realArgs.TerminalArgs().StartingDirectory());
VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile()); VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(profile2Guid, profile.Guid()); VERIFY_ARE_EQUAL(profile2Guid, profile.Guid());
VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline());
@ -337,8 +337,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle()); VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid0, profile.Guid()); VERIFY_ARE_EQUAL(guid0, profile.Guid());
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
@ -360,8 +360,8 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle()); VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle());
VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile()); VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(profile2Guid, profile.Guid()); VERIFY_ARE_EQUAL(profile2Guid, profile.Guid());
VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline());
@ -385,8 +385,8 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle()); VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle());
VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile()); VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid1, profile.Guid()); VERIFY_ARE_EQUAL(guid1, profile.Guid());
VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline());
@ -399,7 +399,7 @@ namespace SettingsModelLocalTests
void TerminalSettingsTests::MakeSettingsForProfile() void TerminalSettingsTests::MakeSettingsForProfile()
{ {
// Test that making settings generally works. // Test that making settings generally works.
const std::string settingsString{ R"( static constexpr std::string_view settingsString{ R"(
{ {
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -415,17 +415,17 @@ namespace SettingsModelLocalTests
} }
] ]
})" }; })" };
CascadiaSettings settings{ til::u8u16(settingsString) }; const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsString);
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"); 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 guid2 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}");
const auto profile1 = settings.FindProfile(guid1); const auto profile1 = settings->FindProfile(guid1);
const auto profile2 = settings.FindProfile(guid2); const auto profile2 = settings->FindProfile(guid2);
try try
{ {
auto terminalSettings{ TerminalSettings::CreateWithProfile(settings, profile1, nullptr) }; auto terminalSettings{ TerminalSettings::CreateWithProfile(*settings, profile1, nullptr) };
VERIFY_ARE_NOT_EQUAL(nullptr, terminalSettings); VERIFY_ARE_NOT_EQUAL(nullptr, terminalSettings);
VERIFY_ARE_EQUAL(1, terminalSettings.DefaultSettings().HistorySize()); VERIFY_ARE_EQUAL(1, terminalSettings.DefaultSettings().HistorySize());
} }
@ -436,7 +436,7 @@ namespace SettingsModelLocalTests
try try
{ {
auto terminalSettings{ TerminalSettings::CreateWithProfile(settings, profile2, nullptr) }; auto terminalSettings{ TerminalSettings::CreateWithProfile(*settings, profile2, nullptr) };
VERIFY_ARE_NOT_EQUAL(nullptr, terminalSettings); VERIFY_ARE_NOT_EQUAL(nullptr, terminalSettings);
VERIFY_ARE_EQUAL(2, terminalSettings.DefaultSettings().HistorySize()); VERIFY_ARE_EQUAL(2, terminalSettings.DefaultSettings().HistorySize());
} }
@ -447,7 +447,7 @@ namespace SettingsModelLocalTests
try try
{ {
const auto termSettings{ TerminalSettings::CreateWithNewTerminalArgs(settings, nullptr, nullptr) }; const auto termSettings{ TerminalSettings::CreateWithNewTerminalArgs(*settings, nullptr, nullptr) };
VERIFY_ARE_NOT_EQUAL(nullptr, termSettings); VERIFY_ARE_NOT_EQUAL(nullptr, termSettings);
VERIFY_ARE_EQUAL(1, termSettings.DefaultSettings().HistorySize()); VERIFY_ARE_EQUAL(1, termSettings.DefaultSettings().HistorySize());
} }
@ -463,7 +463,7 @@ namespace SettingsModelLocalTests
// defaultProfile that's not in the list, we validate the settings, and // defaultProfile that's not in the list, we validate the settings, and
// then call MakeSettings(nullopt). The validation should ensure that // then call MakeSettings(nullopt). The validation should ensure that
// the default profile is something reasonable // the default profile is something reasonable
const std::string settingsString{ R"( static constexpr std::string_view settingsString{ R"(
{ {
"defaultProfile": "{6239a42c-3333-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-3333-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -479,14 +479,14 @@ namespace SettingsModelLocalTests
} }
] ]
})" }; })" };
CascadiaSettings settings{ til::u8u16(settingsString) }; const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsString);
VERIFY_ARE_EQUAL(2u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(2u, settings->Warnings().Size());
VERIFY_ARE_EQUAL(2u, settings.ActiveProfiles().Size()); VERIFY_ARE_EQUAL(2u, settings->ActiveProfiles().Size());
VERIFY_ARE_EQUAL(settings.GlobalSettings().DefaultProfile(), settings.ActiveProfiles().GetAt(0).Guid()); VERIFY_ARE_EQUAL(settings->GlobalSettings().DefaultProfile(), settings->ActiveProfiles().GetAt(0).Guid());
try try
{ {
const auto termSettings{ TerminalSettings::CreateWithNewTerminalArgs(settings, nullptr, nullptr) }; const auto termSettings{ TerminalSettings::CreateWithNewTerminalArgs(*settings, nullptr, nullptr) };
VERIFY_ARE_NOT_EQUAL(nullptr, termSettings); VERIFY_ARE_NOT_EQUAL(nullptr, termSettings);
VERIFY_ARE_EQUAL(1, termSettings.DefaultSettings().HistorySize()); VERIFY_ARE_EQUAL(1, termSettings.DefaultSettings().HistorySize());
} }
@ -501,7 +501,7 @@ namespace SettingsModelLocalTests
Log::Comment(NoThrowString().Format( 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.")); 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"( static constexpr std::string_view settings0String{ R"(
{ {
"defaultProfile": "profile5", "defaultProfile": "profile5",
"profiles": [ "profiles": [
@ -534,18 +534,50 @@ namespace SettingsModelLocalTests
"schemes": [ "schemes": [
{ {
"name": "schemeWithCursorColor", "name": "schemeWithCursorColor",
"cursorColor": "#123456" "cursorColor": "#123456",
"black": "#121314",
"red": "#121314",
"green": "#121314",
"yellow": "#121314",
"blue": "#121314",
"purple": "#121314",
"cyan": "#121314",
"white": "#121314",
"brightBlack": "#121314",
"brightRed": "#121314",
"brightGreen": "#121314",
"brightYellow": "#121314",
"brightBlue": "#121314",
"brightPurple": "#121314",
"brightCyan": "#121314",
"brightWhite": "#121314"
}, },
{ {
"name": "schemeWithoutCursorColor" "name": "schemeWithoutCursorColor",
"black": "#121314",
"red": "#121314",
"green": "#121314",
"yellow": "#121314",
"blue": "#121314",
"purple": "#121314",
"cyan": "#121314",
"white": "#121314",
"brightBlack": "#121314",
"brightRed": "#121314",
"brightGreen": "#121314",
"brightYellow": "#121314",
"brightBlue": "#121314",
"brightPurple": "#121314",
"brightCyan": "#121314",
"brightWhite": "#121314"
} }
] ]
})" }; })" };
CascadiaSettings settings{ til::u8u16(settings0String) }; const auto settings = winrt::make_self<implementation::CascadiaSettings>(settings0String);
VERIFY_ARE_EQUAL(6u, settings.ActiveProfiles().Size()); VERIFY_ARE_EQUAL(6u, settings->ActiveProfiles().Size());
VERIFY_ARE_EQUAL(2u, settings.GlobalSettings().ColorSchemes().Size()); VERIFY_ARE_EQUAL(2u, settings->GlobalSettings().ColorSchemes().Size());
auto createTerminalSettings = [&](const auto& profile, const auto& schemes) { auto createTerminalSettings = [&](const auto& profile, const auto& schemes) {
auto terminalSettings{ winrt::make_self<implementation::TerminalSettings>() }; auto terminalSettings{ winrt::make_self<implementation::TerminalSettings>() };
@ -554,12 +586,14 @@ namespace SettingsModelLocalTests
return terminalSettings; return terminalSettings;
}; };
auto terminalSettings0 = createTerminalSettings(settings.ActiveProfiles().GetAt(0), settings.GlobalSettings().ColorSchemes()); const auto activeProfiles = settings->ActiveProfiles();
auto terminalSettings1 = createTerminalSettings(settings.ActiveProfiles().GetAt(1), settings.GlobalSettings().ColorSchemes()); const auto colorSchemes = settings->GlobalSettings().ColorSchemes();
auto terminalSettings2 = createTerminalSettings(settings.ActiveProfiles().GetAt(2), settings.GlobalSettings().ColorSchemes()); const auto terminalSettings0 = createTerminalSettings(activeProfiles.GetAt(0), colorSchemes);
auto terminalSettings3 = createTerminalSettings(settings.ActiveProfiles().GetAt(3), settings.GlobalSettings().ColorSchemes()); const auto terminalSettings1 = createTerminalSettings(activeProfiles.GetAt(1), colorSchemes);
auto terminalSettings4 = createTerminalSettings(settings.ActiveProfiles().GetAt(4), settings.GlobalSettings().ColorSchemes()); const auto terminalSettings2 = createTerminalSettings(activeProfiles.GetAt(2), colorSchemes);
auto terminalSettings5 = createTerminalSettings(settings.ActiveProfiles().GetAt(5), settings.GlobalSettings().ColorSchemes()); const auto terminalSettings3 = createTerminalSettings(activeProfiles.GetAt(3), colorSchemes);
const auto terminalSettings4 = createTerminalSettings(activeProfiles.GetAt(4), colorSchemes);
const auto terminalSettings5 = createTerminalSettings(activeProfiles.GetAt(5), colorSchemes);
VERIFY_ARE_EQUAL(ARGB(0, 0x12, 0x34, 0x56), terminalSettings0->CursorColor()); // from color scheme 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(DEFAULT_CURSOR_COLOR, terminalSettings1->CursorColor()); // default
@ -571,7 +605,7 @@ namespace SettingsModelLocalTests
void TerminalSettingsTests::TestCommandlineToTitlePromotion() void TerminalSettingsTests::TestCommandlineToTitlePromotion()
{ {
const std::string settingsJson{ R"( static constexpr std::string_view settingsJson{ R"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": { "list": [ "profiles": { "list": [
@ -587,65 +621,63 @@ namespace SettingsModelLocalTests
} } } }
})" }; })" };
const winrt::guid guid0{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}") }; const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsJson);
CascadiaSettings settings{ til::u8u16(settingsJson) };
{ // just a profile (profile wins) { // just a profile (profile wins)
NewTerminalArgs args{}; NewTerminalArgs args{};
args.Profile(L"profile0"); args.Profile(L"profile0");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"profile0", settingsStruct.DefaultSettings().StartingTitle()); VERIFY_ARE_EQUAL(L"profile0", settingsStruct.DefaultSettings().StartingTitle());
} }
{ // profile and command line -> no promotion (profile wins) { // profile and command line -> no promotion (profile wins)
NewTerminalArgs args{}; NewTerminalArgs args{};
args.Profile(L"profile0"); args.Profile(L"profile0");
args.Commandline(L"foo.exe"); args.Commandline(L"foo.exe");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"profile0", settingsStruct.DefaultSettings().StartingTitle()); VERIFY_ARE_EQUAL(L"profile0", settingsStruct.DefaultSettings().StartingTitle());
} }
{ // just a title -> it is propagated { // just a title -> it is propagated
NewTerminalArgs args{}; NewTerminalArgs args{};
args.TabTitle(L"Analog Kid"); args.TabTitle(L"Analog Kid");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"Analog Kid", settingsStruct.DefaultSettings().StartingTitle()); VERIFY_ARE_EQUAL(L"Analog Kid", settingsStruct.DefaultSettings().StartingTitle());
} }
{ // title and command line -> no promotion { // title and command line -> no promotion
NewTerminalArgs args{}; NewTerminalArgs args{};
args.TabTitle(L"Digital Man"); args.TabTitle(L"Digital Man");
args.Commandline(L"foo.exe"); args.Commandline(L"foo.exe");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"Digital Man", settingsStruct.DefaultSettings().StartingTitle()); VERIFY_ARE_EQUAL(L"Digital Man", settingsStruct.DefaultSettings().StartingTitle());
} }
{ // just a commandline -> promotion { // just a commandline -> promotion
NewTerminalArgs args{}; NewTerminalArgs args{};
args.Commandline(L"foo.exe"); args.Commandline(L"foo.exe");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"foo.exe", settingsStruct.DefaultSettings().StartingTitle()); VERIFY_ARE_EQUAL(L"foo.exe", settingsStruct.DefaultSettings().StartingTitle());
} }
// various typesof commandline follow // various typesof commandline follow
{ {
NewTerminalArgs args{}; NewTerminalArgs args{};
args.Commandline(L"foo.exe bar"); args.Commandline(L"foo.exe bar");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"foo.exe", settingsStruct.DefaultSettings().StartingTitle()); VERIFY_ARE_EQUAL(L"foo.exe", settingsStruct.DefaultSettings().StartingTitle());
} }
{ {
NewTerminalArgs args{}; NewTerminalArgs args{};
args.Commandline(L"\"foo exe.exe\" bar"); args.Commandline(L"\"foo exe.exe\" bar");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"foo exe.exe", settingsStruct.DefaultSettings().StartingTitle()); VERIFY_ARE_EQUAL(L"foo exe.exe", settingsStruct.DefaultSettings().StartingTitle());
} }
{ {
NewTerminalArgs args{}; NewTerminalArgs args{};
args.Commandline(L"\"\" grand designs"); args.Commandline(L"\"\" grand designs");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"", settingsStruct.DefaultSettings().StartingTitle()); VERIFY_ARE_EQUAL(L"", settingsStruct.DefaultSettings().StartingTitle());
} }
{ {
NewTerminalArgs args{}; NewTerminalArgs args{};
args.Commandline(L" imagine a man"); args.Commandline(L" imagine a man");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"", settingsStruct.DefaultSettings().StartingTitle()); VERIFY_ARE_EQUAL(L"", settingsStruct.DefaultSettings().StartingTitle());
} }
} }

View File

@ -79,7 +79,7 @@ namespace TerminalAppLocalTests
// containing a ${profile.name} to replace. When we expand it, it should // containing a ${profile.name} to replace. When we expand it, it should
// have created one command for each profile. // have created one command for each profile.
const std::string settingsJson{ R"( static constexpr std::wstring_view settingsJson{ LR"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -111,10 +111,7 @@ namespace TerminalAppLocalTests
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
})" }; })" };
const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}"); CascadiaSettings settings{ settingsJson, {} };
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
CascadiaSettings settings{ til::u8u16(settingsJson) };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
@ -207,7 +204,7 @@ namespace TerminalAppLocalTests
// For this test, put an iterable command without a given `name` to // For this test, put an iterable command without a given `name` to
// replace. When we expand it, it should still work. // replace. When we expand it, it should still work.
const std::string settingsJson{ R"( static constexpr std::wstring_view settingsJson{ LR"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -238,10 +235,7 @@ namespace TerminalAppLocalTests
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
})" }; })" };
const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}"); CascadiaSettings settings{ settingsJson, {} };
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
CascadiaSettings settings{ til::u8u16(settingsJson) };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
@ -335,7 +329,7 @@ namespace TerminalAppLocalTests
// cause bad json to be filled in. Something like a profile with a name // cause bad json to be filled in. Something like a profile with a name
// of "Foo\"", so the trailing '"' might break the json parsing. // of "Foo\"", so the trailing '"' might break the json parsing.
const std::string settingsJson{ R"( static constexpr std::wstring_view settingsJson{ LR"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -367,10 +361,7 @@ namespace TerminalAppLocalTests
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
})" }; })" };
const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}"); CascadiaSettings settings{ settingsJson, {} };
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
CascadiaSettings settings{ til::u8u16(settingsJson) };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
@ -468,7 +459,7 @@ namespace TerminalAppLocalTests
// ├─ first.com // ├─ first.com
// └─ second.com // └─ second.com
const std::string settingsJson{ R"( static constexpr std::wstring_view settingsJson{ LR"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -508,7 +499,7 @@ namespace TerminalAppLocalTests
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
})" }; })" };
CascadiaSettings settings{ til::u8u16(settingsJson) }; CascadiaSettings settings{ settingsJson, {} };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
@ -558,7 +549,7 @@ namespace TerminalAppLocalTests
// ├─ child1 // ├─ child1
// └─ child2 // └─ child2
const std::string settingsJson{ R"( static constexpr std::wstring_view settingsJson{ LR"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -603,7 +594,7 @@ namespace TerminalAppLocalTests
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
})" }; })" };
CascadiaSettings settings{ til::u8u16(settingsJson) }; CascadiaSettings settings{ settingsJson, {} };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
@ -691,7 +682,7 @@ namespace TerminalAppLocalTests
// ├─ Split pane, direction: right, profile: profile2 // ├─ Split pane, direction: right, profile: profile2
// └─ Split pane, direction: down, profile: profile2 // └─ Split pane, direction: down, profile: profile2
const std::string settingsJson{ R"( static constexpr std::wstring_view settingsJson{ LR"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -727,7 +718,7 @@ namespace TerminalAppLocalTests
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
})" }; })" };
CascadiaSettings settings{ til::u8u16(settingsJson) }; CascadiaSettings settings{ settingsJson, {} };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
@ -828,7 +819,7 @@ namespace TerminalAppLocalTests
// ├─ Profile 2 // ├─ Profile 2
// └─ Profile 3 // └─ Profile 3
const std::string settingsJson{ R"( static constexpr std::wstring_view settingsJson{ LR"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -864,7 +855,7 @@ namespace TerminalAppLocalTests
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
})" }; })" };
CascadiaSettings settings{ til::u8u16(settingsJson) }; CascadiaSettings settings{ settingsJson, {} };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
@ -926,7 +917,7 @@ namespace TerminalAppLocalTests
// ├─ Split right // ├─ Split right
// └─ Split down // └─ Split down
const std::string settingsJson{ R"( static constexpr std::wstring_view settingsJson{ LR"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -967,7 +958,7 @@ namespace TerminalAppLocalTests
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
})" }; })" };
CascadiaSettings settings{ til::u8u16(settingsJson) }; CascadiaSettings settings{ settingsJson, {} };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
@ -1071,7 +1062,7 @@ namespace TerminalAppLocalTests
// containing a ${profile.name} to replace. When we expand it, it should // containing a ${profile.name} to replace. When we expand it, it should
// have created one command for each profile. // have created one command for each profile.
const std::string settingsJson{ R"( static constexpr std::wstring_view settingsJson{ LR"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -1107,7 +1098,7 @@ namespace TerminalAppLocalTests
] ]
})" }; })" };
CascadiaSettings settings{ til::u8u16(settingsJson) }; CascadiaSettings settings{ settingsJson, {} };
// Since at least one profile does not reference a color scheme, // Since at least one profile does not reference a color scheme,
// we add a warning saying "the color scheme is unknown" // we add a warning saying "the color scheme is unknown"

View File

@ -311,7 +311,7 @@ namespace TerminalAppLocalTests
// TerminalPage and not only create them successfully, but also create a // TerminalPage and not only create them successfully, but also create a
// tab using those settings successfully. // tab using those settings successfully.
const std::string settingsJson0{ R"( static constexpr std::wstring_view settingsJson0{ LR"(
{ {
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -328,7 +328,7 @@ namespace TerminalAppLocalTests
] ]
})" }; })" };
CascadiaSettings settings0{ til::u8u16(settingsJson0) }; CascadiaSettings settings0{ settingsJson0, {} };
VERIFY_IS_NOT_NULL(settings0); VERIFY_IS_NOT_NULL(settings0);
// This is super wacky, but we can't just initialize the // This is super wacky, but we can't just initialize the
@ -357,7 +357,7 @@ namespace TerminalAppLocalTests
// //
// Created to test GH#2455 // Created to test GH#2455
const std::string settingsJson0{ R"( static constexpr std::wstring_view settingsJson0{ LR"(
{ {
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -374,7 +374,7 @@ namespace TerminalAppLocalTests
] ]
})" }; })" };
const std::string settingsJson1{ R"( static constexpr std::wstring_view settingsJson1{ LR"(
{ {
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -386,10 +386,10 @@ namespace TerminalAppLocalTests
] ]
})" }; })" };
CascadiaSettings settings0{ til::u8u16(settingsJson0) }; CascadiaSettings settings0{ settingsJson0, {} };
VERIFY_IS_NOT_NULL(settings0); VERIFY_IS_NOT_NULL(settings0);
CascadiaSettings settings1{ til::u8u16(settingsJson1) }; CascadiaSettings settings1{ settingsJson1, {} };
VERIFY_IS_NOT_NULL(settings1); VERIFY_IS_NOT_NULL(settings1);
const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"); const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
@ -444,7 +444,7 @@ namespace TerminalAppLocalTests
// //
// Created to test GH#2455 // Created to test GH#2455
const std::string settingsJson0{ R"( static constexpr std::wstring_view settingsJson0{ LR"(
{ {
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -461,7 +461,7 @@ namespace TerminalAppLocalTests
] ]
})" }; })" };
const std::string settingsJson1{ R"( static constexpr std::wstring_view settingsJson1{ LR"(
{ {
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -473,10 +473,10 @@ namespace TerminalAppLocalTests
] ]
})" }; })" };
CascadiaSettings settings0{ til::u8u16(settingsJson0) }; CascadiaSettings settings0{ settingsJson0, {} };
VERIFY_IS_NOT_NULL(settings0); VERIFY_IS_NOT_NULL(settings0);
CascadiaSettings settings1{ til::u8u16(settingsJson1) }; CascadiaSettings settings1{ settingsJson1, {} };
VERIFY_IS_NOT_NULL(settings1); VERIFY_IS_NOT_NULL(settings1);
const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"); const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
@ -558,7 +558,7 @@ namespace TerminalAppLocalTests
// - The initialized TerminalPage, ready to use. // - The initialized TerminalPage, ready to use.
winrt::com_ptr<winrt::TerminalApp::implementation::TerminalPage> TabTests::_commonSetup() winrt::com_ptr<winrt::TerminalApp::implementation::TerminalPage> TabTests::_commonSetup()
{ {
const std::string settingsJson0{ R"( static constexpr std::wstring_view settingsJson0{ LR"(
{ {
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"showTabsInTitlebar": false, "showTabsInTitlebar": false,
@ -659,7 +659,7 @@ namespace TerminalAppLocalTests
] ]
})" }; })" };
CascadiaSettings settings0{ til::u8u16(settingsJson0) }; CascadiaSettings settings0{ settingsJson0, {} };
VERIFY_IS_NOT_NULL(settings0); VERIFY_IS_NOT_NULL(settings0);
const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"); const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");

View File

@ -29,12 +29,12 @@ namespace winrt
using IInspectable = Windows::Foundation::IInspectable; using IInspectable = Windows::Foundation::IInspectable;
} }
static const winrt::hstring StartupTaskName = L"StartTerminalOnLoginTask"; static constexpr std::wstring_view StartupTaskName = L"StartTerminalOnLoginTask";
// clang-format off // clang-format off
// !!! IMPORTANT !!! // !!! IMPORTANT !!!
// Make sure that these keys are in the same order as the // Make sure that these keys are in the same order as the
// SettingsLoadWarnings/Errors enum is! // SettingsLoadWarnings/Errors enum is!
static const std::array<std::wstring_view, static_cast<uint32_t>(SettingsLoadWarnings::WARNINGS_SIZE)> settingsLoadWarningsLabels { static const std::array settingsLoadWarningsLabels {
USES_RESOURCE(L"MissingDefaultProfileText"), USES_RESOURCE(L"MissingDefaultProfileText"),
USES_RESOURCE(L"DuplicateProfileText"), USES_RESOURCE(L"DuplicateProfileText"),
USES_RESOURCE(L"UnknownColorSchemeText"), USES_RESOURCE(L"UnknownColorSchemeText"),
@ -43,7 +43,6 @@ static const std::array<std::wstring_view, static_cast<uint32_t>(SettingsLoadWar
USES_RESOURCE(L"AtLeastOneKeybindingWarning"), USES_RESOURCE(L"AtLeastOneKeybindingWarning"),
USES_RESOURCE(L"TooManyKeysForChord"), USES_RESOURCE(L"TooManyKeysForChord"),
USES_RESOURCE(L"MissingRequiredParameter"), USES_RESOURCE(L"MissingRequiredParameter"),
USES_RESOURCE(L"LegacyGlobalsProperty"),
USES_RESOURCE(L"FailedToParseCommandJson"), USES_RESOURCE(L"FailedToParseCommandJson"),
USES_RESOURCE(L"FailedToWriteToSettings"), USES_RESOURCE(L"FailedToWriteToSettings"),
USES_RESOURCE(L"InvalidColorSchemeInCmd"), USES_RESOURCE(L"InvalidColorSchemeInCmd"),
@ -51,12 +50,15 @@ static const std::array<std::wstring_view, static_cast<uint32_t>(SettingsLoadWar
USES_RESOURCE(L"FailedToParseStartupActions"), USES_RESOURCE(L"FailedToParseStartupActions"),
USES_RESOURCE(L"FailedToParseSubCommands"), USES_RESOURCE(L"FailedToParseSubCommands"),
}; };
static const std::array<std::wstring_view, static_cast<uint32_t>(SettingsLoadErrors::ERRORS_SIZE)> settingsLoadErrorsLabels { static const std::array settingsLoadErrorsLabels {
USES_RESOURCE(L"NoProfilesText"), USES_RESOURCE(L"NoProfilesText"),
USES_RESOURCE(L"AllProfilesHiddenText") USES_RESOURCE(L"AllProfilesHiddenText")
}; };
// clang-format on // clang-format on
static_assert(settingsLoadWarningsLabels.size() == static_cast<size_t>(SettingsLoadWarnings::WARNINGS_SIZE));
static_assert(settingsLoadErrorsLabels.size() == static_cast<size_t>(SettingsLoadErrors::ERRORS_SIZE));
// Function Description: // Function Description:
// - General-purpose helper for looking up a localized string for a // - General-purpose helper for looking up a localized string for a
// warning/error. First will look for the given key in the provided map of // warning/error. First will look for the given key in the provided map of
@ -68,12 +70,12 @@ static const std::array<std::wstring_view, static_cast<uint32_t>(SettingsLoadErr
// - map: A map of keys->Resource keys. // - map: A map of keys->Resource keys.
// Return Value: // Return Value:
// - the localized string for the given type, if it exists. // - the localized string for the given type, if it exists.
template<std::size_t N> template<typename T>
static winrt::hstring _GetMessageText(uint32_t index, std::array<std::wstring_view, N> keys) winrt::hstring _GetMessageText(uint32_t index, const T& keys)
{ {
if (index < keys.size()) if (index < keys.size())
{ {
return GetLibraryResourceString(keys.at(index)); return GetLibraryResourceString(til::at(keys, index));
} }
return {}; return {};
} }
@ -488,27 +490,6 @@ namespace winrt::TerminalApp::implementation
if (!warningText.empty()) if (!warningText.empty())
{ {
warningsTextBlock.Inlines().Append(_BuildErrorRun(warningText, ::winrt::Windows::UI::Xaml::Application::Current().as<::winrt::TerminalApp::App>().Resources())); warningsTextBlock.Inlines().Append(_BuildErrorRun(warningText, ::winrt::Windows::UI::Xaml::Application::Current().as<::winrt::TerminalApp::App>().Resources()));
// The "LegacyGlobalsProperty" warning is special - it has a URL
// that goes with it. So we need to manually construct a
// Hyperlink and insert it along with the warning text.
if (warning == SettingsLoadWarnings::LegacyGlobalsProperty)
{
// Add the URL here too
const auto legacyGlobalsLinkLabel = RS_(L"LegacyGlobalsPropertyHrefLabel");
const auto legacyGlobalsLinkUriValue = RS_(L"LegacyGlobalsPropertyHrefUrl");
winrt::Windows::UI::Xaml::Documents::Run legacyGlobalsLinkText;
winrt::Windows::UI::Xaml::Documents::Hyperlink legacyGlobalsLink;
winrt::Windows::Foundation::Uri legacyGlobalsLinkUri{ legacyGlobalsLinkUriValue };
legacyGlobalsLinkText.Text(legacyGlobalsLinkLabel);
legacyGlobalsLink.NavigateUri(legacyGlobalsLinkUri);
legacyGlobalsLink.Inlines().Append(legacyGlobalsLinkText);
warningsTextBlock.Inlines().Append(legacyGlobalsLink);
}
warningsTextBlock.Inlines().Append(Documents::LineBreak{}); warningsTextBlock.Inlines().Append(Documents::LineBreak{});
} }
} }

View File

@ -34,7 +34,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void Launch::OnNavigatedTo(const NavigationEventArgs& e) void Launch::OnNavigatedTo(const NavigationEventArgs& e)
{ {
_State = e.Parameter().as<Editor::LaunchPageNavigationState>(); _State = e.Parameter().as<Editor::LaunchPageNavigationState>();
_State.Settings().RefreshDefaultTerminals();
} }
IInspectable Launch::CurrentDefaultProfile() IInspectable Launch::CurrentDefaultProfile()

View File

@ -74,7 +74,7 @@
x:Uid="Globals_DefaultTerminal" x:Uid="Globals_DefaultTerminal"
x:Load="false"> x:Load="false">
<ComboBox x:Name="DefaultTerminal" <ComboBox x:Name="DefaultTerminal"
ItemsSource="{x:Bind State.Settings.DefaultTerminals, Mode=OneWay}" ItemsSource="{x:Bind State.Settings.DefaultTerminals}"
SelectedItem="{x:Bind State.Settings.CurrentDefaultTerminal, Mode=TwoWay}" SelectedItem="{x:Bind State.Settings.CurrentDefaultTerminal, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}"> Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate> <ComboBox.ItemTemplate>

View File

@ -29,30 +29,29 @@ static constexpr std::string_view IntenseTextStyleKey{ "intenseTextStyle" };
static constexpr std::string_view LegacyAcrylicTransparencyKey{ "acrylicOpacity" }; static constexpr std::string_view LegacyAcrylicTransparencyKey{ "acrylicOpacity" };
static constexpr std::string_view OpacityKey{ "opacity" }; static constexpr std::string_view OpacityKey{ "opacity" };
winrt::Microsoft::Terminal::Settings::Model::implementation::AppearanceConfig::AppearanceConfig(const winrt::weak_ref<Profile> sourceProfile) : AppearanceConfig::AppearanceConfig(winrt::weak_ref<Profile> sourceProfile) :
_sourceProfile(sourceProfile) _sourceProfile(std::move(sourceProfile))
{ {
} }
winrt::com_ptr<AppearanceConfig> AppearanceConfig::CopyAppearance(const winrt::com_ptr<AppearanceConfig> source, const winrt::weak_ref<Profile> sourceProfile) winrt::com_ptr<AppearanceConfig> AppearanceConfig::CopyAppearance(const AppearanceConfig* source, winrt::weak_ref<Profile> sourceProfile)
{ {
auto appearance{ winrt::make_self<AppearanceConfig>(sourceProfile) }; auto appearance{ winrt::make_self<AppearanceConfig>(std::move(sourceProfile)) };
auto const sourceAppearance = source.try_as<AppearanceConfig>(); appearance->_BackgroundImagePath = source->_BackgroundImagePath;
appearance->_BackgroundImagePath = sourceAppearance->_BackgroundImagePath; appearance->_BackgroundImageOpacity = source->_BackgroundImageOpacity;
appearance->_BackgroundImageOpacity = sourceAppearance->_BackgroundImageOpacity; appearance->_BackgroundImageStretchMode = source->_BackgroundImageStretchMode;
appearance->_BackgroundImageStretchMode = sourceAppearance->_BackgroundImageStretchMode; appearance->_ColorSchemeName = source->_ColorSchemeName;
appearance->_ColorSchemeName = sourceAppearance->_ColorSchemeName; appearance->_Foreground = source->_Foreground;
appearance->_Foreground = sourceAppearance->_Foreground; appearance->_Background = source->_Background;
appearance->_Background = sourceAppearance->_Background; appearance->_SelectionBackground = source->_SelectionBackground;
appearance->_SelectionBackground = sourceAppearance->_SelectionBackground; appearance->_CursorColor = source->_CursorColor;
appearance->_CursorColor = sourceAppearance->_CursorColor; appearance->_CursorShape = source->_CursorShape;
appearance->_CursorShape = sourceAppearance->_CursorShape; appearance->_CursorHeight = source->_CursorHeight;
appearance->_CursorHeight = sourceAppearance->_CursorHeight; appearance->_BackgroundImageAlignment = source->_BackgroundImageAlignment;
appearance->_BackgroundImageAlignment = sourceAppearance->_BackgroundImageAlignment; appearance->_RetroTerminalEffect = source->_RetroTerminalEffect;
appearance->_RetroTerminalEffect = sourceAppearance->_RetroTerminalEffect; appearance->_PixelShaderPath = source->_PixelShaderPath;
appearance->_PixelShaderPath = sourceAppearance->_PixelShaderPath; appearance->_IntenseTextStyle = source->_IntenseTextStyle;
appearance->_IntenseTextStyle = sourceAppearance->_IntenseTextStyle; appearance->_Opacity = source->_Opacity;
appearance->_Opacity = sourceAppearance->_Opacity;
return appearance; return appearance;
} }

View File

@ -18,7 +18,6 @@ Author(s):
#include "AppearanceConfig.g.h" #include "AppearanceConfig.g.h"
#include "JsonUtils.h" #include "JsonUtils.h"
#include "../inc/cppwinrt_utils.h"
#include "IInheritable.h" #include "IInheritable.h"
#include <DefaultSettings.h> #include <DefaultSettings.h>
@ -27,8 +26,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
struct AppearanceConfig : AppearanceConfigT<AppearanceConfig>, IInheritable<AppearanceConfig> struct AppearanceConfig : AppearanceConfigT<AppearanceConfig>, IInheritable<AppearanceConfig>
{ {
public: public:
AppearanceConfig(const winrt::weak_ref<Profile> sourceProfile); AppearanceConfig(winrt::weak_ref<Profile> sourceProfile);
static winrt::com_ptr<AppearanceConfig> CopyAppearance(const winrt::com_ptr<AppearanceConfig> source, const winrt::weak_ref<Profile> sourceProfile); static winrt::com_ptr<AppearanceConfig> CopyAppearance(const AppearanceConfig* source, winrt::weak_ref<Profile> sourceProfile);
Json::Value ToJson() const; Json::Value ToJson() const;
void LayerJson(const Json::Value& json); void LayerJson(const Json::Value& json);

View File

@ -6,16 +6,14 @@
#include "AzureCloudShellGenerator.h" #include "AzureCloudShellGenerator.h"
#include "LegacyProfileGeneratorNamespaces.h" #include "LegacyProfileGeneratorNamespaces.h"
#include "../../types/inc/utils.hpp"
#include "../../inc/DefaultSettings.h" #include "../../inc/DefaultSettings.h"
#include "Utils.h" #include "DynamicProfileUtils.h"
#include "DefaultProfileUtils.h"
using namespace ::Microsoft::Terminal::Settings::Model; using namespace ::Microsoft::Terminal::Settings::Model;
using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace winrt::Microsoft::Terminal::TerminalConnection; using namespace winrt::Microsoft::Terminal::TerminalConnection;
std::wstring_view AzureCloudShellGenerator::GetNamespace() std::wstring_view AzureCloudShellGenerator::GetNamespace() const noexcept
{ {
return AzureGeneratorNamespace; return AzureGeneratorNamespace;
} }
@ -27,19 +25,14 @@ std::wstring_view AzureCloudShellGenerator::GetNamespace()
// - <none> // - <none>
// Return Value: // Return Value:
// - a vector with the Azure Cloud Shell connection profile, if available. // - a vector with the Azure Cloud Shell connection profile, if available.
std::vector<Profile> AzureCloudShellGenerator::GenerateProfiles() void AzureCloudShellGenerator::GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const
{ {
std::vector<Profile> profiles;
if (AzureConnection::IsAzureConnectionAvailable()) if (AzureConnection::IsAzureConnectionAvailable())
{ {
auto azureCloudShellProfile{ CreateDefaultProfile(L"Azure Cloud Shell") }; auto azureCloudShellProfile{ CreateDynamicProfile(L"Azure Cloud Shell") };
azureCloudShellProfile.Commandline(L"Azure"); azureCloudShellProfile->StartingDirectory(winrt::hstring{ DEFAULT_STARTING_DIRECTORY });
azureCloudShellProfile.StartingDirectory(DEFAULT_STARTING_DIRECTORY); azureCloudShellProfile->DefaultAppearance().ColorSchemeName(L"Vintage");
azureCloudShellProfile.DefaultAppearance().ColorSchemeName(L"Vintage"); azureCloudShellProfile->ConnectionType(AzureConnection::ConnectionType());
azureCloudShellProfile.ConnectionType(AzureConnection::ConnectionType()); profiles.emplace_back(std::move(azureCloudShellProfile));
profiles.emplace_back(azureCloudShellProfile);
} }
return profiles;
} }

View File

@ -16,17 +16,15 @@ Author(s):
--*/ --*/
#pragma once #pragma once
#include "IDynamicProfileGenerator.h" #include "IDynamicProfileGenerator.h"
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
class AzureCloudShellGenerator : public IDynamicProfileGenerator class AzureCloudShellGenerator final : public IDynamicProfileGenerator
{ {
public: public:
AzureCloudShellGenerator() = default; std::wstring_view GetNamespace() const noexcept override;
~AzureCloudShellGenerator() = default; void GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
std::wstring_view GetNamespace() override;
std::vector<winrt::Microsoft::Terminal::Settings::Model::Profile> GenerateProfiles() override;
}; };
}; };

View File

@ -3,15 +3,12 @@
#include "pch.h" #include "pch.h"
#include "BaseVisualStudioGenerator.h" #include "BaseVisualStudioGenerator.h"
#include "DefaultProfileUtils.h" #include "DynamicProfileUtils.h"
using namespace Microsoft::Terminal::Settings::Model;
using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::Settings::Model;
std::vector<Profile> BaseVisualStudioGenerator::GenerateProfiles() void BaseVisualStudioGenerator::GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const
{ {
std::vector<Profile> profiles;
// There's no point in enumerating valid Visual Studio instances more than once, // There's no point in enumerating valid Visual Studio instances more than once,
// so cache them for use by both Visual Studio profile generators. // so cache them for use by both Visual Studio profile generators.
static const auto instances = VsSetupConfiguration::QueryInstances(); static const auto instances = VsSetupConfiguration::QueryInstances();
@ -25,27 +22,15 @@ std::vector<Profile> BaseVisualStudioGenerator::GenerateProfiles()
continue; continue;
} }
auto DevShell{ CreateProfile(GetProfileGuidSeed(instance)) }; const auto seed = GetProfileGuidSeed(instance);
DevShell.Name(GetProfileName(instance)); const winrt::guid profileGuid{ ::Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID, gsl::as_bytes(gsl::make_span(seed))) };
DevShell.Commandline(GetProfileCommandLine(instance)); auto profile = winrt::make_self<implementation::Profile>(profileGuid);
DevShell.StartingDirectory(instance.GetInstallationPath()); profile->Name(winrt::hstring{ GetProfileName(instance) });
DevShell.Icon(GetProfileIconPath()); profile->Commandline(winrt::hstring{ GetProfileCommandLine(instance) });
profile->StartingDirectory(winrt::hstring{ instance.GetInstallationPath() });
profiles.emplace_back(DevShell); profile->Icon(winrt::hstring{ GetProfileIconPath() });
profiles.emplace_back(std::move(profile));
} }
CATCH_LOG(); CATCH_LOG();
} }
return profiles;
}
Profile BaseVisualStudioGenerator::CreateProfile(const std::wstring_view seed)
{
const winrt::guid profileGuid{ Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID,
gsl::as_bytes(gsl::make_span(seed))) };
auto newProfile = winrt::make_self<implementation::Profile>(profileGuid);
newProfile->Origin(OriginTag::Generated);
return *newProfile;
} }

View File

@ -18,14 +18,12 @@ Author(s):
#include "IDynamicProfileGenerator.h" #include "IDynamicProfileGenerator.h"
#include "VsSetupConfiguration.h" #include "VsSetupConfiguration.h"
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
class BaseVisualStudioGenerator : public IDynamicProfileGenerator class BaseVisualStudioGenerator : public IDynamicProfileGenerator
{ {
public: public:
// Inherited via IDynamicProfileGenerator void GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
std::wstring_view GetNamespace() override = 0;
std::vector<winrt::Microsoft::Terminal::Settings::Model::Profile> GenerateProfiles() override;
protected: protected:
virtual bool IsInstanceValid(const VsSetupConfiguration::VsSetupInstance& instance) const = 0; virtual bool IsInstanceValid(const VsSetupConfiguration::VsSetupInstance& instance) const = 0;
@ -33,8 +31,5 @@ namespace Microsoft::Terminal::Settings::Model
virtual std::wstring GetProfileCommandLine(const VsSetupConfiguration::VsSetupInstance& instance) const = 0; virtual std::wstring GetProfileCommandLine(const VsSetupConfiguration::VsSetupInstance& instance) const = 0;
virtual std::wstring GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance) const = 0; virtual std::wstring GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance) const = 0;
virtual std::wstring GetProfileIconPath() const = 0; virtual std::wstring GetProfileIconPath() const = 0;
private:
winrt::Microsoft::Terminal::Settings::Model::Profile CreateProfile(const std::wstring_view instanceId);
}; };
}; };

File diff suppressed because it is too large Load Diff

View File

@ -20,163 +20,137 @@ Author(s):
#include "CascadiaSettings.g.h" #include "CascadiaSettings.g.h"
#include "GlobalAppSettings.h" #include "GlobalAppSettings.h"
#include "TerminalWarnings.h"
#include "IDynamicProfileGenerator.h"
#include "Profile.h" #include "Profile.h"
#include "ColorScheme.h"
// fwdecl unittest classes namespace winrt::Microsoft::Terminal::Settings::Model
namespace SettingsModelLocalTests
{ {
class SerializationTests; class IDynamicProfileGenerator;
class DeserializationTests; }
class ProfileTests;
class ColorSchemeTests;
class KeyBindingsTests;
};
namespace TerminalAppUnitTests
{
class DynamicProfileTests;
class JsonTests;
};
namespace Microsoft::Terminal::Settings::Model
{
class SettingsTypedDeserializationException;
};
class Microsoft::Terminal::Settings::Model::SettingsTypedDeserializationException final : public std::runtime_error
{
public:
SettingsTypedDeserializationException(const std::string_view description) :
runtime_error(description.data()) {}
};
namespace winrt::Microsoft::Terminal::Settings::Model::implementation namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{ {
winrt::com_ptr<Profile> CreateChild(const winrt::com_ptr<Profile>& parent);
class SettingsTypedDeserializationException final : public std::runtime_error
{
public:
SettingsTypedDeserializationException(const char* message) noexcept :
std::runtime_error(message) {}
};
struct ParsedSettings
{
winrt::com_ptr<implementation::GlobalAppSettings> globals;
winrt::com_ptr<implementation::Profile> baseLayerProfile;
std::vector<winrt::com_ptr<implementation::Profile>> profiles;
std::unordered_map<winrt::guid, winrt::com_ptr<implementation::Profile>> profilesByGuid;
};
struct SettingsLoader
{
static SettingsLoader Default(const std::string_view& userJSON, const std::string_view& inboxJSON);
SettingsLoader(const std::string_view& userJSON, const std::string_view& inboxJSON);
void GenerateProfiles();
void ApplyRuntimeInitialSettings();
void MergeInboxIntoUserSettings();
void FindFragmentsAndMergeIntoUserSettings();
void FinalizeLayering();
bool DisableDeletedProfiles();
ParsedSettings inboxSettings;
ParsedSettings userSettings;
bool duplicateProfile = false;
private:
static std::pair<size_t, size_t> _lineAndColumnFromPosition(const std::string_view& string, const size_t position);
static void _rethrowSerializationExceptionWithLocationInfo(const JsonUtils::DeserializationError& e, const std::string_view& settingsString);
static Json::Value _parseJSON(const std::string_view& content);
static const Json::Value& _getJSONValue(const Json::Value& json, const std::string_view& key) noexcept;
static bool _isValidProfileObject(const Json::Value& profileJson);
gsl::span<const winrt::com_ptr<implementation::Profile>> _getNonUserOriginProfiles() const;
void _parse(const OriginTag origin, const winrt::hstring& source, const std::string_view& content, ParsedSettings& settings);
void _appendProfile(winrt::com_ptr<implementation::Profile>&& profile, ParsedSettings& settings);
void _executeGenerator(const IDynamicProfileGenerator& generator);
std::unordered_set<std::wstring_view> _ignoredNamespaces;
// See _getNonUserOriginProfiles().
size_t _userProfileCount = 0;
};
struct CascadiaSettings : CascadiaSettingsT<CascadiaSettings> struct CascadiaSettings : CascadiaSettingsT<CascadiaSettings>
{ {
public: public:
CascadiaSettings();
explicit CascadiaSettings(const bool addDynamicProfiles);
CascadiaSettings(hstring json);
Model::CascadiaSettings Copy() const;
static Model::CascadiaSettings LoadDefaults(); static Model::CascadiaSettings LoadDefaults();
static Model::CascadiaSettings LoadAll(); static Model::CascadiaSettings LoadAll();
static Model::CascadiaSettings LoadUniversal(); static Model::CascadiaSettings LoadUniversal();
Model::GlobalAppSettings GlobalSettings() const; static winrt::hstring SettingsPath();
Windows::Foundation::Collections::IObservableVector<Model::Profile> AllProfiles() const noexcept; static winrt::hstring DefaultSettingsPath();
Windows::Foundation::Collections::IObservableVector<Model::Profile> ActiveProfiles() const noexcept;
Model::ActionMap ActionMap() const noexcept;
static com_ptr<CascadiaSettings> FromJson(const Json::Value& json);
void LayerJson(const Json::Value& json);
void WriteSettingsToDisk() const;
Json::Value ToJson() const;
static hstring SettingsPath();
static hstring DefaultSettingsPath();
Model::Profile ProfileDefaults() const;
static winrt::hstring ApplicationDisplayName(); static winrt::hstring ApplicationDisplayName();
static winrt::hstring ApplicationVersion(); static winrt::hstring ApplicationVersion();
CascadiaSettings() noexcept = default;
CascadiaSettings(const winrt::hstring& userJSON, const winrt::hstring& inboxJSON);
CascadiaSettings(const std::string_view& userJSON, const std::string_view& inboxJSON = {});
explicit CascadiaSettings(SettingsLoader&& loader);
// user settings
Model::CascadiaSettings Copy() const;
Model::GlobalAppSettings GlobalSettings() const;
winrt::Windows::Foundation::Collections::IObservableVector<Model::Profile> AllProfiles() const noexcept;
winrt::Windows::Foundation::Collections::IObservableVector<Model::Profile> ActiveProfiles() const noexcept;
Model::ActionMap ActionMap() const noexcept;
void WriteSettingsToDisk() const;
Json::Value ToJson() const;
Model::Profile ProfileDefaults() const;
Model::Profile CreateNewProfile(); Model::Profile CreateNewProfile();
Model::Profile FindProfile(const guid& profileGuid) const noexcept; Model::Profile FindProfile(const winrt::guid& guid) const noexcept;
Model::ColorScheme GetColorSchemeForProfile(const Model::Profile& profile) const; Model::ColorScheme GetColorSchemeForProfile(const Model::Profile& profile) const;
void UpdateColorSchemeReferences(const hstring oldName, const hstring newName); void UpdateColorSchemeReferences(const winrt::hstring& oldName, const winrt::hstring& newName);
Windows::Foundation::Collections::IVectorView<SettingsLoadWarnings> Warnings();
void ClearWarnings();
void AppendWarning(SettingsLoadWarnings warning);
Windows::Foundation::IReference<SettingsLoadErrors> GetLoadingError();
hstring GetSerializationErrorMessage();
Model::Profile GetProfileForArgs(const Model::NewTerminalArgs& newTerminalArgs) const; Model::Profile GetProfileForArgs(const Model::NewTerminalArgs& newTerminalArgs) const;
Model::Profile GetProfileByName(const winrt::hstring& name) const;
Model::Profile GetProfileByIndex(uint32_t index) const;
Model::Profile DuplicateProfile(const Model::Profile& source); Model::Profile DuplicateProfile(const Model::Profile& source);
void RefreshDefaultTerminals();
// load errors
winrt::Windows::Foundation::Collections::IVectorView<Model::SettingsLoadWarnings> Warnings() const;
winrt::Windows::Foundation::IReference<Model::SettingsLoadErrors> GetLoadingError() const;
winrt::hstring GetSerializationErrorMessage() const;
// defterm
static bool IsDefaultTerminalAvailable() noexcept; static bool IsDefaultTerminalAvailable() noexcept;
Windows::Foundation::Collections::IObservableVector<Model::DefaultTerminal> DefaultTerminals() const noexcept; winrt::Windows::Foundation::Collections::IObservableVector<Model::DefaultTerminal> DefaultTerminals() const noexcept;
Model::DefaultTerminal CurrentDefaultTerminal() const noexcept; Model::DefaultTerminal CurrentDefaultTerminal() noexcept;
void CurrentDefaultTerminal(Model::DefaultTerminal terminal); void CurrentDefaultTerminal(const Model::DefaultTerminal& terminal);
private: private:
com_ptr<GlobalAppSettings> _globals; static const std::filesystem::path& _settingsPath();
Windows::Foundation::Collections::IObservableVector<Model::Profile> _allProfiles;
Windows::Foundation::Collections::IObservableVector<Model::Profile> _activeProfiles;
Windows::Foundation::Collections::IVector<Model::SettingsLoadWarnings> _warnings;
Windows::Foundation::IReference<SettingsLoadErrors> _loadError;
hstring _deserializationErrorMessage;
Windows::Foundation::Collections::IObservableVector<Model::DefaultTerminal> _defaultTerminals; winrt::com_ptr<implementation::Profile> _createNewProfile(const std::wstring_view& name) const;
Model::DefaultTerminal _currentDefaultTerminal;
std::vector<std::unique_ptr<::Microsoft::Terminal::Settings::Model::IDynamicProfileGenerator>> _profileGenerators; void _resolveDefaultProfile() const;
std::string _userSettingsString; void _validateSettings();
Json::Value _userSettings; void _validateAllSchemesExist();
Json::Value _defaultSettings; void _validateMediaResources();
winrt::com_ptr<Profile> _userDefaultProfileSettings{ nullptr }; void _validateKeybindings() const;
void _validateColorSchemesInCommands() const;
bool _hasInvalidColorScheme(const Model::Command& command) const;
winrt::com_ptr<Profile> _CreateNewProfile(const std::wstring_view& name) const; // user settings
winrt::com_ptr<implementation::GlobalAppSettings> _globals;
winrt::com_ptr<implementation::Profile> _baseLayerProfile;
winrt::Windows::Foundation::Collections::IObservableVector<Model::Profile> _allProfiles;
winrt::Windows::Foundation::Collections::IObservableVector<Model::Profile> _activeProfiles;
void _LayerOrCreateProfile(const Json::Value& profileJson); // load errors
winrt::com_ptr<implementation::Profile> _FindMatchingProfile(const Json::Value& profileJson); winrt::Windows::Foundation::Collections::IVector<Model::SettingsLoadWarnings> _warnings;
std::optional<uint32_t> _FindMatchingProfileIndex(const Json::Value& profileJson); winrt::Windows::Foundation::IReference<Model::SettingsLoadErrors> _loadError;
void _LayerOrCreateColorScheme(const Json::Value& schemeJson); winrt::hstring _deserializationErrorMessage;
Json::Value _ParseUtf8JsonString(std::string_view fileData);
winrt::com_ptr<implementation::ColorScheme> _FindMatchingColorScheme(const Json::Value& schemeJson); // defterm
void _ParseJsonString(std::string_view fileData, const bool isDefaultSettings); Model::DefaultTerminal _currentDefaultTerminal{ nullptr };
static const Json::Value& _GetProfilesJsonObject(const Json::Value& json);
static const Json::Value& _GetDisabledProfileSourcesJsonObject(const Json::Value& json);
bool _PrependSchemaDirective();
bool _AppendDynamicProfilesToUserSettings();
std::string _ApplyFirstRunChangesToSettingsTemplate(std::string_view settingsTemplate) const;
void _CopyProfileInheritanceTree(com_ptr<CascadiaSettings>& cloneSettings) const;
void _ApplyDefaultsFromUserSettings();
void _LoadDynamicProfiles();
void _LoadFragmentExtensions();
void _ApplyJsonStubsHelper(const std::wstring_view directory, const std::unordered_set<std::wstring>& ignoredNamespaces);
std::unordered_set<std::string> _AccumulateJsonFilesInDirectory(const std::wstring_view directory);
void _ParseAndLayerFragmentFiles(const std::unordered_set<std::string> files, const winrt::hstring source);
static const std::filesystem::path& _SettingsPath();
static std::optional<std::string> _ReadUserSettings();
std::optional<guid> _GetProfileGuidByName(const hstring) const;
std::optional<guid> _GetProfileGuidByIndex(std::optional<int> index) const;
void _ValidateSettings();
void _ValidateProfilesExist();
void _ValidateDefaultProfileExists();
void _ValidateNoDuplicateProfiles();
void _ResolveDefaultProfile();
void _ReorderProfilesToMatchUserSettingsOrder();
void _UpdateActiveProfiles();
void _ValidateAllSchemesExist();
void _ValidateMediaResources();
void _ValidateKeybindings();
void _ValidateColorSchemesInCommands();
void _ValidateNoGlobalsKey();
bool _HasInvalidColorScheme(const Model::Command& command);
friend class SettingsModelLocalTests::SerializationTests;
friend class SettingsModelLocalTests::DeserializationTests;
friend class SettingsModelLocalTests::ProfileTests;
friend class SettingsModelLocalTests::ColorSchemeTests;
friend class SettingsModelLocalTests::KeyBindingsTests;
friend class TerminalAppUnitTests::DynamicProfileTests;
friend class TerminalAppUnitTests::JsonTests;
}; };
} }

View File

@ -9,11 +9,6 @@ import "DefaultTerminal.idl";
namespace Microsoft.Terminal.Settings.Model namespace Microsoft.Terminal.Settings.Model
{ {
[default_interface] runtimeclass CascadiaSettings { [default_interface] runtimeclass CascadiaSettings {
CascadiaSettings(String json);
CascadiaSettings Copy();
void WriteSettingsToDisk();
static CascadiaSettings LoadDefaults(); static CascadiaSettings LoadDefaults();
static CascadiaSettings LoadAll(); static CascadiaSettings LoadAll();
static CascadiaSettings LoadUniversal(); static CascadiaSettings LoadUniversal();
@ -23,19 +18,24 @@ namespace Microsoft.Terminal.Settings.Model
static String ApplicationDisplayName { get; }; static String ApplicationDisplayName { get; };
static String ApplicationVersion { get; }; static String ApplicationVersion { get; };
CascadiaSettings(String userJSON, String inboxJSON);
CascadiaSettings Copy();
void WriteSettingsToDisk();
GlobalAppSettings GlobalSettings { get; }; GlobalAppSettings GlobalSettings { get; };
Profile ProfileDefaults { get; }; Profile ProfileDefaults { get; };
Windows.Foundation.Collections.IObservableVector<Profile> AllProfiles { get; }; IObservableVector<Profile> AllProfiles { get; };
Windows.Foundation.Collections.IObservableVector<Profile> ActiveProfiles { get; }; IObservableVector<Profile> ActiveProfiles { get; };
Profile DuplicateProfile(Profile sourceProfile); Profile DuplicateProfile(Profile sourceProfile);
ActionMap ActionMap { get; }; ActionMap ActionMap { get; };
Windows.Foundation.Collections.IVectorView<SettingsLoadWarnings> Warnings { get; }; IVectorView<SettingsLoadWarnings> Warnings { get; };
Windows.Foundation.IReference<SettingsLoadErrors> GetLoadingError { get; }; Windows.Foundation.IReference<SettingsLoadErrors> GetLoadingError { get; };
String GetSerializationErrorMessage { get; }; String GetSerializationErrorMessage { get; };
@ -46,9 +46,8 @@ namespace Microsoft.Terminal.Settings.Model
Profile GetProfileForArgs(NewTerminalArgs newTerminalArgs); Profile GetProfileForArgs(NewTerminalArgs newTerminalArgs);
void RefreshDefaultTerminals();
static Boolean IsDefaultTerminalAvailable { get; }; static Boolean IsDefaultTerminalAvailable { get; };
Windows.Foundation.Collections.IObservableVector<DefaultTerminal> DefaultTerminals { get; }; IObservableVector<DefaultTerminal> DefaultTerminals { get; };
DefaultTerminal CurrentDefaultTerminal; DefaultTerminal CurrentDefaultTerminal;
} }
} }

View File

@ -3,7 +3,6 @@
#include "pch.h" #include "pch.h"
#include "ColorScheme.h" #include "ColorScheme.h"
#include "DefaultSettings.h"
#include "../../types/inc/Utils.hpp" #include "../../types/inc/Utils.hpp"
#include "../../types/inc/colorTable.hpp" #include "../../types/inc/colorTable.hpp"
#include "Utils.h" #include "Utils.h"
@ -41,25 +40,16 @@ static constexpr std::array<std::string_view, 16> TableColors = {
"brightWhite" "brightWhite"
}; };
ColorScheme::ColorScheme() : ColorScheme::ColorScheme() noexcept :
ColorScheme(L"", DEFAULT_FOREGROUND, DEFAULT_BACKGROUND, DEFAULT_CURSOR_COLOR) ColorScheme{ winrt::hstring{} }
{ {
Utils::InitializeCampbellColorTable(_table);
} }
ColorScheme::ColorScheme(winrt::hstring name) : ColorScheme::ColorScheme(const winrt::hstring& name) noexcept :
ColorScheme(name, DEFAULT_FOREGROUND, DEFAULT_BACKGROUND, DEFAULT_CURSOR_COLOR) _Name{ name }
{
Utils::InitializeCampbellColorTable(_table);
}
ColorScheme::ColorScheme(winrt::hstring name, til::color defaultFg, til::color defaultBg, til::color cursorColor) :
_Name{ name },
_Foreground{ defaultFg },
_Background{ defaultBg },
_SelectionBackground{ DEFAULT_FOREGROUND },
_CursorColor{ cursorColor }
{ {
const auto table = Utils::CampbellColorTable();
std::copy_n(table.data(), table.size(), _table.data());
} }
winrt::com_ptr<ColorScheme> ColorScheme::Copy() const winrt::com_ptr<ColorScheme> ColorScheme::Copy() const
@ -79,30 +69,11 @@ winrt::com_ptr<ColorScheme> ColorScheme::Copy() const
// Arguments: // Arguments:
// - json: an object which should be a serialization of a ColorScheme object. // - json: an object which should be a serialization of a ColorScheme object.
// Return Value: // Return Value:
// - a new ColorScheme instance created from the values in `json` // - Returns nullptr for invalid JSON.
winrt::com_ptr<ColorScheme> ColorScheme::FromJson(const Json::Value& json) winrt::com_ptr<ColorScheme> ColorScheme::FromJson(const Json::Value& json)
{ {
auto result = winrt::make_self<ColorScheme>(); auto result = winrt::make_self<ColorScheme>(uninitialized_t{});
result->LayerJson(json); return result->_layerJson(json) ? result : nullptr;
return result;
}
// Method Description:
// - Returns true if we think the provided json object represents an instance of
// the same object as this object. If true, we should layer that json object
// on us, instead of creating a new object.
// Arguments:
// - json: The json object to query to see if it's the same
// Return Value:
// - true iff the json object has the same `name` as we do.
bool ColorScheme::ShouldBeLayered(const Json::Value& json) const
{
std::wstring nameFromJson{};
if (JsonUtils::GetValueForKey(json, NameKey, nameFromJson))
{
return nameFromJson == _Name;
}
return false;
} }
// Method Description: // Method Description:
@ -112,21 +83,27 @@ bool ColorScheme::ShouldBeLayered(const Json::Value& json) const
// the new json object. Properties that _aren't_ in the json object will _not_ // the new json object. Properties that _aren't_ in the json object will _not_
// be replaced. // be replaced.
// Arguments: // Arguments:
// - json: an object which should be a partial serialization of a ColorScheme object. // - json: an object which should be a full serialization of a ColorScheme object.
// Return Value: // Return Value:
// <none> // - Returns true if the given JSON was valid.
void ColorScheme::LayerJson(const Json::Value& json) bool ColorScheme::_layerJson(const Json::Value& json)
{ {
JsonUtils::GetValueForKey(json, NameKey, _Name); // Required fields
auto isValid = JsonUtils::GetValueForKey(json, NameKey, _Name);
// Optional fields (they have defaults in ColorScheme.h)
JsonUtils::GetValueForKey(json, ForegroundKey, _Foreground); JsonUtils::GetValueForKey(json, ForegroundKey, _Foreground);
JsonUtils::GetValueForKey(json, BackgroundKey, _Background); JsonUtils::GetValueForKey(json, BackgroundKey, _Background);
JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _SelectionBackground); JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _SelectionBackground);
JsonUtils::GetValueForKey(json, CursorColorKey, _CursorColor); JsonUtils::GetValueForKey(json, CursorColorKey, _CursorColor);
// Required fields
for (unsigned int i = 0; i < TableColors.size(); ++i) for (unsigned int i = 0; i < TableColors.size(); ++i)
{ {
JsonUtils::GetValueForKey(json, til::at(TableColors, i), _table.at(i)); isValid &= JsonUtils::GetValueForKey(json, til::at(TableColors, i), til::at(_table, i));
} }
return isValid;
} }
// Method Description: // Method Description:
@ -147,7 +124,7 @@ Json::Value ColorScheme::ToJson() const
for (unsigned int i = 0; i < TableColors.size(); ++i) for (unsigned int i = 0; i < TableColors.size(); ++i)
{ {
JsonUtils::SetValueForKey(json, til::at(TableColors, i), _table.at(i)); JsonUtils::SetValueForKey(json, til::at(TableColors, i), til::at(_table, i));
} }
return json; return json;
@ -155,9 +132,7 @@ Json::Value ColorScheme::ToJson() const
winrt::com_array<winrt::Microsoft::Terminal::Core::Color> ColorScheme::Table() const noexcept winrt::com_array<winrt::Microsoft::Terminal::Core::Color> ColorScheme::Table() const noexcept
{ {
winrt::com_array<winrt::Microsoft::Terminal::Core::Color> result{ base::checked_cast<uint32_t>(_table.size()) }; return winrt::com_array<Core::Color>{ _table };
std::transform(_table.begin(), _table.end(), result.begin(), [](til::color c) -> winrt::Microsoft::Terminal::Core::Color { return c; });
return result;
} }
// Method Description: // Method Description:
@ -167,44 +142,8 @@ winrt::com_array<winrt::Microsoft::Terminal::Core::Color> ColorScheme::Table() c
// - value: the color value we are setting the color table color to // - value: the color value we are setting the color table color to
// Return Value: // Return Value:
// - none // - none
void ColorScheme::SetColorTableEntry(uint8_t index, const winrt::Microsoft::Terminal::Core::Color& value) noexcept void ColorScheme::SetColorTableEntry(uint8_t index, const Core::Color& value) noexcept
{ {
THROW_HR_IF(E_INVALIDARG, index > _table.size() - 1); THROW_HR_IF(E_INVALIDARG, index >= _table.size());
_table[index] = value; _table[index] = value;
} }
// Method Description:
// - Validates a given color scheme
// - A color scheme is valid if it has a name and defines all the colors
// Arguments:
// - The color scheme to validate
// Return Value:
// - true if the scheme is valid, false otherwise
bool ColorScheme::ValidateColorScheme(const Json::Value& scheme)
{
for (const auto& key : TableColors)
{
if (!scheme.isMember(JsonKey(key)))
{
return false;
}
}
if (!scheme.isMember(JsonKey(NameKey)))
{
return false;
}
return true;
}
// Method Description:
// - Parse the name from the JSON representation of a ColorScheme.
// Arguments:
// - json: an object which should be a serialization of a ColorScheme object.
// Return Value:
// - the name of the color scheme represented by `json` as a std::wstring optional
// i.e. the value of the `name` property.
// - returns std::nullopt if `json` doesn't have the `name` property
std::optional<std::wstring> ColorScheme::GetNameFromJson(const Json::Value& json)
{
return JsonUtils::GetValueForKey<std::optional<std::wstring>>(json, NameKey);
}

View File

@ -15,38 +15,28 @@ Author(s):
--*/ --*/
#pragma once #pragma once
#include "../../inc/conattrs.hpp" #include "../../inc/conattrs.hpp"
#include "inc/cppwinrt_utils.h" #include "inc/cppwinrt_utils.h"
#include "DefaultSettings.h"
#include "ColorScheme.g.h" #include "ColorScheme.g.h"
// fwdecl unittest classes
namespace SettingsModelLocalTests
{
class SettingsTests;
class ColorSchemeTests;
};
// Use this macro to quick implement both the getter and setter for a color property.
// This should only be used for color types where there's no logic in the
// getter/setter beyond just accessing/updating the value.
// This takes advantage of til::color
#define WINRT_TERMINAL_COLOR_PROPERTY(name, ...) \
public: \
winrt::Microsoft::Terminal::Core::Color name() const noexcept { return _##name; } \
void name(const winrt::Microsoft::Terminal::Core::Color& value) noexcept { _##name = value; } \
\
private: \
til::color _##name{ __VA_ARGS__ };
namespace winrt::Microsoft::Terminal::Settings::Model::implementation namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{ {
struct ColorScheme : ColorSchemeT<ColorScheme> struct ColorScheme : ColorSchemeT<ColorScheme>
{ {
// A ColorScheme constructed with uninitialized_t
// leaves _table uninitialized.
struct uninitialized_t
{
};
public: public:
ColorScheme(); ColorScheme() noexcept;
ColorScheme(hstring name); explicit ColorScheme(uninitialized_t) noexcept {}
ColorScheme(hstring name, til::color defaultFg, til::color defaultBg, til::color cursorColor); explicit ColorScheme(const winrt::hstring& name) noexcept;
com_ptr<ColorScheme> Copy() const; com_ptr<ColorScheme> Copy() const;
hstring ToString() hstring ToString()
@ -55,29 +45,21 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
} }
static com_ptr<ColorScheme> FromJson(const Json::Value& json); static com_ptr<ColorScheme> FromJson(const Json::Value& json);
bool ShouldBeLayered(const Json::Value& json) const;
void LayerJson(const Json::Value& json);
Json::Value ToJson() const; Json::Value ToJson() const;
static std::optional<std::wstring> GetNameFromJson(const Json::Value& json); com_array<Core::Color> Table() const noexcept;
void SetColorTableEntry(uint8_t index, const Core::Color& value) noexcept;
com_array<winrt::Microsoft::Terminal::Core::Color> Table() const noexcept;
void SetColorTableEntry(uint8_t index, const winrt::Microsoft::Terminal::Core::Color& value) noexcept;
static bool ValidateColorScheme(const Json::Value& scheme);
WINRT_PROPERTY(winrt::hstring, Name); WINRT_PROPERTY(winrt::hstring, Name);
WINRT_TERMINAL_COLOR_PROPERTY(Foreground); // defined in constructor WINRT_PROPERTY(Core::Color, Foreground, static_cast<Core::Color>(DEFAULT_FOREGROUND));
WINRT_TERMINAL_COLOR_PROPERTY(Background); // defined in constructor WINRT_PROPERTY(Core::Color, Background, static_cast<Core::Color>(DEFAULT_BACKGROUND));
WINRT_TERMINAL_COLOR_PROPERTY(SelectionBackground); // defined in constructor WINRT_PROPERTY(Core::Color, SelectionBackground, static_cast<Core::Color>(DEFAULT_FOREGROUND));
WINRT_TERMINAL_COLOR_PROPERTY(CursorColor); // defined in constructor WINRT_PROPERTY(Core::Color, CursorColor, static_cast<Core::Color>(DEFAULT_CURSOR_COLOR));
private: private:
std::array<til::color, COLOR_TABLE_SIZE> _table; bool _layerJson(const Json::Value& json);
friend class SettingsModelLocalTests::SettingsTests; std::array<Core::Color, COLOR_TABLE_SIZE> _table;
friend class SettingsModelLocalTests::ColorSchemeTests;
}; };
} }

View File

@ -2,7 +2,7 @@
// Licensed under the MIT license. // Licensed under the MIT license.
#include "pch.h" #include "pch.h"
#include "DefaultProfileUtils.h" #include "DynamicProfileUtils.h"
#include "../../types/inc/utils.hpp" #include "../../types/inc/utils.hpp"
static constexpr std::wstring_view PACKAGED_PROFILE_ICON_PATH{ L"ms-appx:///ProfileIcons/" }; static constexpr std::wstring_view PACKAGED_PROFILE_ICON_PATH{ L"ms-appx:///ProfileIcons/" };
@ -15,20 +15,16 @@ static constexpr std::wstring_view PACKAGED_PROFILE_ICON_EXTENSION{ L".png" };
// - name: the name of the new profile. // - name: the name of the new profile.
// Return Value: // Return Value:
// - A Profile, ready to be filled in // - A Profile, ready to be filled in
winrt::Microsoft::Terminal::Settings::Model::Profile CreateDefaultProfile(const std::wstring_view name) winrt::com_ptr<winrt::Microsoft::Terminal::Settings::Model::implementation::Profile> CreateDynamicProfile(const std::wstring_view& name)
{ {
const winrt::guid profileGuid{ Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID, const auto profileGuid = Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID, gsl::as_bytes(gsl::make_span(name)));
gsl::as_bytes(gsl::make_span(name))) };
auto newProfile = winrt::make_self<winrt::Microsoft::Terminal::Settings::Model::implementation::Profile>(profileGuid);
newProfile->Name(winrt::hstring{ name });
std::wstring iconPath{ PACKAGED_PROFILE_ICON_PATH }; std::wstring iconPath{ PACKAGED_PROFILE_ICON_PATH };
iconPath.append(Microsoft::Console::Utils::GuidToString(profileGuid)); iconPath.append(Microsoft::Console::Utils::GuidToString(profileGuid));
iconPath.append(PACKAGED_PROFILE_ICON_EXTENSION); iconPath.append(PACKAGED_PROFILE_ICON_EXTENSION);
newProfile->Icon(winrt::hstring{ iconPath }); auto profile = winrt::make_self<winrt::Microsoft::Terminal::Settings::Model::implementation::Profile>(profileGuid);
newProfile->Origin(winrt::Microsoft::Terminal::Settings::Model::OriginTag::Generated); profile->Name(winrt::hstring{ name });
profile->Icon(winrt::hstring{ iconPath });
return *newProfile; return profile;
} }

View File

@ -23,4 +23,4 @@ Author(s):
// uuidv5 properties: name format is UTF-16LE bytes // 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 } }; static constexpr GUID TERMINAL_PROFILE_NAMESPACE_GUID = { 0x2bde4a90, 0xd05f, 0x401c, { 0x94, 0x92, 0xe4, 0x8, 0x84, 0xea, 0xd1, 0xd8 } };
winrt::Microsoft::Terminal::Settings::Model::Profile CreateDefaultProfile(const std::wstring_view name); winrt::com_ptr<winrt::Microsoft::Terminal::Settings::Model::implementation::Profile> CreateDynamicProfile(const std::wstring_view& name);

View File

@ -11,7 +11,7 @@
static constexpr std::string_view Utf8Bom{ u8"\uFEFF" }; static constexpr std::string_view Utf8Bom{ u8"\uFEFF" };
static constexpr std::wstring_view UnpackagedSettingsFolderName{ L"Microsoft\\Windows Terminal\\" }; static constexpr std::wstring_view UnpackagedSettingsFolderName{ L"Microsoft\\Windows Terminal\\" };
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
// Returns a path like C:\Users\<username>\AppData\Local\Packages\<packagename>\LocalState // Returns a path like C:\Users\<username>\AppData\Local\Packages\<packagename>\LocalState
// You can put your settings.json or state.json in this directory. // You can put your settings.json or state.json in this directory.
@ -106,7 +106,7 @@ namespace Microsoft::Terminal::Settings::Model
} }
} }
void WriteUTF8File(const std::filesystem::path& path, const std::string_view content) void WriteUTF8File(const std::filesystem::path& path, const std::string_view& content)
{ {
wil::unique_hfile file{ CreateFileW(path.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr) }; wil::unique_hfile file{ CreateFileW(path.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr) };
THROW_LAST_ERROR_IF(!file); THROW_LAST_ERROR_IF(!file);
@ -121,7 +121,7 @@ namespace Microsoft::Terminal::Settings::Model
} }
} }
void WriteUTF8FileAtomic(const std::filesystem::path& path, const std::string_view content) void WriteUTF8FileAtomic(const std::filesystem::path& path, const std::string_view& content)
{ {
// GH#10787: rename() will replace symbolic links themselves and not the path they point at. // GH#10787: rename() will replace symbolic links themselves and not the path they point at.
// It's thus important that we first resolve them before generating temporary path. // It's thus important that we first resolve them before generating temporary path.

View File

@ -1,11 +1,11 @@
// Copyright (c) Microsoft Corporation. // Copyright (c) Microsoft Corporation.
// Licensed under the MIT license. // Licensed under the MIT license.
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
std::filesystem::path GetBaseSettingsPath(); std::filesystem::path GetBaseSettingsPath();
std::string ReadUTF8File(const std::filesystem::path& path); std::string ReadUTF8File(const std::filesystem::path& path);
std::optional<std::string> ReadUTF8FileIfExists(const std::filesystem::path& path); std::optional<std::string> ReadUTF8FileIfExists(const std::filesystem::path& path);
void WriteUTF8File(const std::filesystem::path& path, const std::string_view content); void WriteUTF8File(const std::filesystem::path& path, const std::string_view& content);
void WriteUTF8FileAtomic(const std::filesystem::path& path, const std::string_view content); void WriteUTF8FileAtomic(const std::filesystem::path& path, const std::string_view& content);
} }

View File

@ -4,6 +4,7 @@
#include "pch.h" #include "pch.h"
#include "FontConfig.h" #include "FontConfig.h"
#include "FontConfig.g.cpp" #include "FontConfig.g.cpp"
#include "TerminalSettingsSerializationHelpers.h" #include "TerminalSettingsSerializationHelpers.h"
#include "JsonUtils.h" #include "JsonUtils.h"
@ -25,7 +26,7 @@ winrt::Microsoft::Terminal::Settings::Model::implementation::FontConfig::FontCon
{ {
} }
winrt::com_ptr<FontConfig> FontConfig::CopyFontInfo(const winrt::com_ptr<FontConfig> source, winrt::weak_ref<Profile> sourceProfile) winrt::com_ptr<FontConfig> FontConfig::CopyFontInfo(const FontConfig* source, winrt::weak_ref<Profile> sourceProfile)
{ {
auto fontInfo{ winrt::make_self<FontConfig>(std::move(sourceProfile)) }; auto fontInfo{ winrt::make_self<FontConfig>(std::move(sourceProfile)) };
fontInfo->_FontFace = source->_FontFace; fontInfo->_FontFace = source->_FontFace;

View File

@ -32,7 +32,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{ {
public: public:
FontConfig(winrt::weak_ref<Profile> sourceProfile); FontConfig(winrt::weak_ref<Profile> sourceProfile);
static winrt::com_ptr<FontConfig> CopyFontInfo(const winrt::com_ptr<FontConfig> source, winrt::weak_ref<Profile> sourceProfile); static winrt::com_ptr<FontConfig> CopyFontInfo(const FontConfig* source, winrt::weak_ref<Profile> sourceProfile);
Json::Value ToJson() const; Json::Value ToJson() const;
void LayerJson(const Json::Value& json); void LayerJson(const Json::Value& json);
bool HasAnyOptionSet() const; bool HasAnyOptionSet() const;

View File

@ -4,9 +4,7 @@
#include "pch.h" #include "pch.h"
#include "GlobalAppSettings.h" #include "GlobalAppSettings.h"
#include "../../types/inc/Utils.hpp" #include "../../types/inc/Utils.hpp"
#include "../../inc/DefaultSettings.h"
#include "JsonUtils.h" #include "JsonUtils.h"
#include "TerminalSettingsSerializationHelpers.h"
#include "KeyChordSerialization.h" #include "KeyChordSerialization.h"
#include "GlobalAppSettings.g.cpp" #include "GlobalAppSettings.g.cpp"
@ -52,6 +50,7 @@ static constexpr std::string_view WindowingBehaviorKey{ "windowingBehavior" };
static constexpr std::string_view TrimBlockSelectionKey{ "trimBlockSelection" }; static constexpr std::string_view TrimBlockSelectionKey{ "trimBlockSelection" };
static constexpr std::string_view AlwaysShowNotificationIconKey{ "alwaysShowNotificationIcon" }; static constexpr std::string_view AlwaysShowNotificationIconKey{ "alwaysShowNotificationIcon" };
static constexpr std::string_view MinimizeToNotificationAreaKey{ "minimizeToNotificationArea" }; static constexpr std::string_view MinimizeToNotificationAreaKey{ "minimizeToNotificationArea" };
static constexpr std::string_view DisabledProfileSourcesKey{ "disabledProfileSources" };
static constexpr std::string_view DebugFeaturesKey{ "debugFeatures" }; static constexpr std::string_view DebugFeaturesKey{ "debugFeatures" };
@ -60,26 +59,6 @@ static constexpr std::string_view SoftwareRenderingKey{ "experimental.rendering.
static constexpr std::string_view ForceVTInputKey{ "experimental.input.forceVT" }; static constexpr std::string_view ForceVTInputKey{ "experimental.input.forceVT" };
static constexpr std::string_view DetectURLsKey{ "experimental.detectURLs" }; static constexpr std::string_view DetectURLsKey{ "experimental.detectURLs" };
#ifdef _DEBUG
static constexpr bool debugFeaturesDefault{ true };
#else
static constexpr bool debugFeaturesDefault{ false };
#endif
bool GlobalAppSettings::_getDefaultDebugFeaturesValue()
{
return debugFeaturesDefault;
}
GlobalAppSettings::GlobalAppSettings() :
_actionMap{ winrt::make_self<implementation::ActionMap>() },
_keybindingsWarnings{},
_validDefaultProfile{ false },
_defaultProfile{}
{
_colorSchemes = winrt::single_threaded_map<winrt::hstring, Model::ColorScheme>();
}
// Method Description: // Method Description:
// - Copies any extraneous data from the parent before completing a CreateChild call // - Copies any extraneous data from the parent before completing a CreateChild call
// Arguments: // Arguments:
@ -88,13 +67,17 @@ GlobalAppSettings::GlobalAppSettings() :
// - <none> // - <none>
void GlobalAppSettings::_FinalizeInheritance() void GlobalAppSettings::_FinalizeInheritance()
{ {
// Globals only ever has 1 parent for (const auto& parent : _parents)
FAIL_FAST_IF(_parents.size() > 1);
for (auto parent : _parents)
{ {
_actionMap->InsertParent(parent->_actionMap); _actionMap->InsertParent(parent->_actionMap);
_keybindingsWarnings = std::move(parent->_keybindingsWarnings); _keybindingsWarnings.insert(_keybindingsWarnings.end(), parent->_keybindingsWarnings.begin(), parent->_keybindingsWarnings.end());
_colorSchemes = std::move(parent->_colorSchemes); for (const auto& [k, v] : parent->_colorSchemes)
{
if (!_colorSchemes.HasKey(k))
{
_colorSchemes.Insert(k, v);
}
}
} }
} }
@ -137,12 +120,12 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::Copy() const
globals->_DetectURLs = _DetectURLs; globals->_DetectURLs = _DetectURLs;
globals->_MinimizeToNotificationArea = _MinimizeToNotificationArea; globals->_MinimizeToNotificationArea = _MinimizeToNotificationArea;
globals->_AlwaysShowNotificationIcon = _AlwaysShowNotificationIcon; globals->_AlwaysShowNotificationIcon = _AlwaysShowNotificationIcon;
globals->_DisabledProfileSources = _DisabledProfileSources;
globals->_UnparsedDefaultProfile = _UnparsedDefaultProfile; globals->_UnparsedDefaultProfile = _UnparsedDefaultProfile;
globals->_validDefaultProfile = _validDefaultProfile;
globals->_defaultProfile = _defaultProfile; globals->_defaultProfile = _defaultProfile;
globals->_actionMap = _actionMap->Copy(); globals->_actionMap = _actionMap->Copy();
std::copy(_keybindingsWarnings.begin(), _keybindingsWarnings.end(), std::back_inserter(globals->_keybindingsWarnings)); globals->_keybindingsWarnings = _keybindingsWarnings;
if (_colorSchemes) if (_colorSchemes)
{ {
@ -153,9 +136,7 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::Copy() const
} }
} }
// Globals only ever has 1 parent for (const auto& parent : _parents)
FAIL_FAST_IF(_parents.size() > 1);
for (auto parent : _parents)
{ {
globals->InsertParent(parent->Copy()); globals->InsertParent(parent->Copy());
} }
@ -168,69 +149,18 @@ winrt::Windows::Foundation::Collections::IMapView<winrt::hstring, winrt::Microso
} }
#pragma region DefaultProfile #pragma region DefaultProfile
void GlobalAppSettings::DefaultProfile(const winrt::guid& defaultProfile) noexcept void GlobalAppSettings::DefaultProfile(const winrt::guid& defaultProfile) noexcept
{ {
_validDefaultProfile = true;
_defaultProfile = defaultProfile; _defaultProfile = defaultProfile;
_UnparsedDefaultProfile = Utils::GuidToString(defaultProfile); _UnparsedDefaultProfile = Utils::GuidToString(defaultProfile);
} }
winrt::guid GlobalAppSettings::DefaultProfile() const winrt::guid GlobalAppSettings::DefaultProfile() const
{ {
// If we have an unresolved default profile, we should likely explode.
THROW_HR_IF(E_INVALIDARG, !_validDefaultProfile);
return _defaultProfile; return _defaultProfile;
} }
bool GlobalAppSettings::HasUnparsedDefaultProfile() const
{
return _UnparsedDefaultProfile.has_value();
}
winrt::hstring GlobalAppSettings::UnparsedDefaultProfile() const
{
const auto val{ _getUnparsedDefaultProfileImpl() };
return val ? *val : hstring{ L"" };
}
void GlobalAppSettings::UnparsedDefaultProfile(const hstring& value)
{
if (_UnparsedDefaultProfile != value)
{
_UnparsedDefaultProfile = value;
_validDefaultProfile = false;
}
}
void GlobalAppSettings::ClearUnparsedDefaultProfile()
{
if (HasUnparsedDefaultProfile())
{
_UnparsedDefaultProfile = std::nullopt;
}
}
std::optional<winrt::hstring> GlobalAppSettings::_getUnparsedDefaultProfileImpl() const
{
/*return user set value*/
if (_UnparsedDefaultProfile)
{
return _UnparsedDefaultProfile;
}
/*user set value was not set*/
/*iterate through parents to find a value*/
for (auto parent : _parents)
{
if (auto val{ parent->_getUnparsedDefaultProfileImpl() })
{
return val;
}
}
/*no value was found*/
return std::nullopt;
}
#pragma endregion #pragma endregion
winrt::Microsoft::Terminal::Settings::Model::ActionMap GlobalAppSettings::ActionMap() const noexcept winrt::Microsoft::Terminal::Settings::Model::ActionMap GlobalAppSettings::ActionMap() const noexcept
@ -253,92 +183,53 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::FromJson(const Json::Value&
void GlobalAppSettings::LayerJson(const Json::Value& json) void GlobalAppSettings::LayerJson(const Json::Value& json)
{ {
// _validDefaultProfile keeps track of whether we've verified that DefaultProfile points to something
// CascadiaSettings::_ResolveDefaultProfile performs a validation and updates DefaultProfile() with the
// resolved value, then making it valid.
_validDefaultProfile = false;
JsonUtils::GetValueForKey(json, DefaultProfileKey, _UnparsedDefaultProfile); JsonUtils::GetValueForKey(json, DefaultProfileKey, _UnparsedDefaultProfile);
JsonUtils::GetValueForKey(json, AlwaysShowTabsKey, _AlwaysShowTabs); JsonUtils::GetValueForKey(json, AlwaysShowTabsKey, _AlwaysShowTabs);
JsonUtils::GetValueForKey(json, ConfirmCloseAllKey, _ConfirmCloseAllTabs); JsonUtils::GetValueForKey(json, ConfirmCloseAllKey, _ConfirmCloseAllTabs);
JsonUtils::GetValueForKey(json, InitialRowsKey, _InitialRows); JsonUtils::GetValueForKey(json, InitialRowsKey, _InitialRows);
JsonUtils::GetValueForKey(json, InitialColsKey, _InitialCols); JsonUtils::GetValueForKey(json, InitialColsKey, _InitialCols);
JsonUtils::GetValueForKey(json, InitialPositionKey, _InitialPosition); JsonUtils::GetValueForKey(json, InitialPositionKey, _InitialPosition);
JsonUtils::GetValueForKey(json, CenterOnLaunchKey, _CenterOnLaunch); JsonUtils::GetValueForKey(json, CenterOnLaunchKey, _CenterOnLaunch);
JsonUtils::GetValueForKey(json, ShowTitleInTitlebarKey, _ShowTitleInTitlebar); JsonUtils::GetValueForKey(json, ShowTitleInTitlebarKey, _ShowTitleInTitlebar);
JsonUtils::GetValueForKey(json, ShowTabsInTitlebarKey, _ShowTabsInTitlebar); JsonUtils::GetValueForKey(json, ShowTabsInTitlebarKey, _ShowTabsInTitlebar);
JsonUtils::GetValueForKey(json, WordDelimitersKey, _WordDelimiters); JsonUtils::GetValueForKey(json, WordDelimitersKey, _WordDelimiters);
JsonUtils::GetValueForKey(json, CopyOnSelectKey, _CopyOnSelect); JsonUtils::GetValueForKey(json, CopyOnSelectKey, _CopyOnSelect);
JsonUtils::GetValueForKey(json, InputServiceWarningKey, _InputServiceWarning); JsonUtils::GetValueForKey(json, InputServiceWarningKey, _InputServiceWarning);
JsonUtils::GetValueForKey(json, CopyFormattingKey, _CopyFormatting); JsonUtils::GetValueForKey(json, CopyFormattingKey, _CopyFormatting);
JsonUtils::GetValueForKey(json, WarnAboutLargePasteKey, _WarnAboutLargePaste); JsonUtils::GetValueForKey(json, WarnAboutLargePasteKey, _WarnAboutLargePaste);
JsonUtils::GetValueForKey(json, WarnAboutMultiLinePasteKey, _WarnAboutMultiLinePaste); JsonUtils::GetValueForKey(json, WarnAboutMultiLinePasteKey, _WarnAboutMultiLinePaste);
JsonUtils::GetValueForKey(json, FirstWindowPreferenceKey, _FirstWindowPreference); JsonUtils::GetValueForKey(json, FirstWindowPreferenceKey, _FirstWindowPreference);
JsonUtils::GetValueForKey(json, LaunchModeKey, _LaunchMode); JsonUtils::GetValueForKey(json, LaunchModeKey, _LaunchMode);
JsonUtils::GetValueForKey(json, LanguageKey, _Language); JsonUtils::GetValueForKey(json, LanguageKey, _Language);
JsonUtils::GetValueForKey(json, ThemeKey, _Theme); JsonUtils::GetValueForKey(json, ThemeKey, _Theme);
JsonUtils::GetValueForKey(json, TabWidthModeKey, _TabWidthMode); JsonUtils::GetValueForKey(json, TabWidthModeKey, _TabWidthMode);
JsonUtils::GetValueForKey(json, UseAcrylicInTabRowKey, _UseAcrylicInTabRow); JsonUtils::GetValueForKey(json, UseAcrylicInTabRowKey, _UseAcrylicInTabRow);
JsonUtils::GetValueForKey(json, SnapToGridOnResizeKey, _SnapToGridOnResize); JsonUtils::GetValueForKey(json, SnapToGridOnResizeKey, _SnapToGridOnResize);
// GetValueForKey will only override the current value if the key exists // GetValueForKey will only override the current value if the key exists
JsonUtils::GetValueForKey(json, DebugFeaturesKey, _DebugFeaturesEnabled); JsonUtils::GetValueForKey(json, DebugFeaturesKey, _DebugFeaturesEnabled);
JsonUtils::GetValueForKey(json, ForceFullRepaintRenderingKey, _ForceFullRepaintRendering); JsonUtils::GetValueForKey(json, ForceFullRepaintRenderingKey, _ForceFullRepaintRendering);
JsonUtils::GetValueForKey(json, SoftwareRenderingKey, _SoftwareRendering); JsonUtils::GetValueForKey(json, SoftwareRenderingKey, _SoftwareRendering);
JsonUtils::GetValueForKey(json, ForceVTInputKey, _ForceVTInput); JsonUtils::GetValueForKey(json, ForceVTInputKey, _ForceVTInput);
JsonUtils::GetValueForKey(json, EnableStartupTaskKey, _StartOnUserLogin); JsonUtils::GetValueForKey(json, EnableStartupTaskKey, _StartOnUserLogin);
JsonUtils::GetValueForKey(json, AlwaysOnTopKey, _AlwaysOnTop); JsonUtils::GetValueForKey(json, AlwaysOnTopKey, _AlwaysOnTop);
// GH#8076 - when adding enum values to this key, we also changed it from // GH#8076 - when adding enum values to this key, we also changed it from
// "useTabSwitcher" to "tabSwitcherMode". Continue supporting // "useTabSwitcher" to "tabSwitcherMode". Continue supporting
// "useTabSwitcher", but prefer "tabSwitcherMode" // "useTabSwitcher", but prefer "tabSwitcherMode"
JsonUtils::GetValueForKey(json, LegacyUseTabSwitcherModeKey, _TabSwitcherMode); JsonUtils::GetValueForKey(json, LegacyUseTabSwitcherModeKey, _TabSwitcherMode);
JsonUtils::GetValueForKey(json, TabSwitcherModeKey, _TabSwitcherMode); JsonUtils::GetValueForKey(json, TabSwitcherModeKey, _TabSwitcherMode);
JsonUtils::GetValueForKey(json, DisableAnimationsKey, _DisableAnimations); JsonUtils::GetValueForKey(json, DisableAnimationsKey, _DisableAnimations);
JsonUtils::GetValueForKey(json, StartupActionsKey, _StartupActions); JsonUtils::GetValueForKey(json, StartupActionsKey, _StartupActions);
JsonUtils::GetValueForKey(json, FocusFollowMouseKey, _FocusFollowMouse); JsonUtils::GetValueForKey(json, FocusFollowMouseKey, _FocusFollowMouse);
JsonUtils::GetValueForKey(json, WindowingBehaviorKey, _WindowingBehavior); JsonUtils::GetValueForKey(json, WindowingBehaviorKey, _WindowingBehavior);
JsonUtils::GetValueForKey(json, TrimBlockSelectionKey, _TrimBlockSelection); JsonUtils::GetValueForKey(json, TrimBlockSelectionKey, _TrimBlockSelection);
JsonUtils::GetValueForKey(json, DetectURLsKey, _DetectURLs); JsonUtils::GetValueForKey(json, DetectURLsKey, _DetectURLs);
JsonUtils::GetValueForKey(json, MinimizeToNotificationAreaKey, _MinimizeToNotificationArea); JsonUtils::GetValueForKey(json, MinimizeToNotificationAreaKey, _MinimizeToNotificationArea);
JsonUtils::GetValueForKey(json, AlwaysShowNotificationIconKey, _AlwaysShowNotificationIcon); JsonUtils::GetValueForKey(json, AlwaysShowNotificationIconKey, _AlwaysShowNotificationIcon);
JsonUtils::GetValueForKey(json, DisabledProfileSourcesKey, _DisabledProfileSources);
// This is a helper lambda to get the keybindings and commands out of both static constexpr std::array bindingsKeys{ LegacyKeybindingsKey, ActionsKey };
// and array of objects. We'll use this twice, once on the legacy for (const auto& jsonKey : bindingsKeys)
// `keybindings` key, and again on the newer `bindings` key. {
auto parseBindings = [this, &json](auto jsonKey) {
if (auto bindings{ json[JsonKey(jsonKey)] }) if (auto bindings{ json[JsonKey(jsonKey)] })
{ {
auto warnings = _actionMap->LayerJson(bindings); auto warnings = _actionMap->LayerJson(bindings);
@ -351,9 +242,7 @@ void GlobalAppSettings::LayerJson(const Json::Value& json)
// list of warnings. // list of warnings.
_keybindingsWarnings.insert(_keybindingsWarnings.end(), warnings.begin(), warnings.end()); _keybindingsWarnings.insert(_keybindingsWarnings.end(), warnings.begin(), warnings.end());
} }
}; }
parseBindings(LegacyKeybindingsKey);
parseBindings(ActionsKey);
} }
// Method Description: // Method Description:
@ -381,7 +270,7 @@ void GlobalAppSettings::RemoveColorScheme(hstring schemeName)
// - <none> // - <none>
// Return Value: // Return Value:
// - <none> // - <none>
std::vector<winrt::Microsoft::Terminal::Settings::Model::SettingsLoadWarnings> GlobalAppSettings::KeybindingsWarnings() const const std::vector<winrt::Microsoft::Terminal::Settings::Model::SettingsLoadWarnings>& GlobalAppSettings::KeybindingsWarnings() const
{ {
return _keybindingsWarnings; return _keybindingsWarnings;
} }
@ -433,7 +322,8 @@ Json::Value GlobalAppSettings::ToJson() const
JsonUtils::SetValueForKey(json, TrimBlockSelectionKey, _TrimBlockSelection); JsonUtils::SetValueForKey(json, TrimBlockSelectionKey, _TrimBlockSelection);
JsonUtils::SetValueForKey(json, DetectURLsKey, _DetectURLs); JsonUtils::SetValueForKey(json, DetectURLsKey, _DetectURLs);
JsonUtils::SetValueForKey(json, MinimizeToNotificationAreaKey, _MinimizeToNotificationArea); JsonUtils::SetValueForKey(json, MinimizeToNotificationAreaKey, _MinimizeToNotificationArea);
JsonUtils::SetValueForKey(json, AlwaysShowNotificationIconKey, _AlwaysShowNotificationIcon); JsonUtils::SetValueForKey(json, AlwaysShowNotificationIconKey, _AlwaysShowNotificationIcon);
JsonUtils::SetValueForKey(json, DisabledProfileSourcesKey, _DisabledProfileSources);
// clang-format on // clang-format on
json[JsonKey(ActionsKey)] = _actionMap->ToJson(); json[JsonKey(ActionsKey)] = _actionMap->ToJson();

View File

@ -34,7 +34,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
struct GlobalAppSettings : GlobalAppSettingsT<GlobalAppSettings>, IInheritable<GlobalAppSettings> struct GlobalAppSettings : GlobalAppSettingsT<GlobalAppSettings>, IInheritable<GlobalAppSettings>
{ {
public: public:
GlobalAppSettings();
void _FinalizeInheritance() override; void _FinalizeInheritance() override;
com_ptr<GlobalAppSettings> Copy() const; com_ptr<GlobalAppSettings> Copy() const;
@ -49,16 +48,12 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
Json::Value ToJson() const; Json::Value ToJson() const;
std::vector<SettingsLoadWarnings> KeybindingsWarnings() const; const std::vector<SettingsLoadWarnings>& KeybindingsWarnings() const;
// These are implemented manually to handle the string/GUID exchange // This DefaultProfile() setter is called by CascadiaSettings,
// by higher layers in the app. // when it parses UnparsedDefaultProfile in _finalizeSettings().
void DefaultProfile(const guid& defaultProfile) noexcept; void DefaultProfile(const guid& defaultProfile) noexcept;
guid DefaultProfile() const; guid DefaultProfile() const;
bool HasUnparsedDefaultProfile() const;
winrt::hstring UnparsedDefaultProfile() const;
void UnparsedDefaultProfile(const hstring& value);
void ClearUnparsedDefaultProfile();
// TODO GH#9207: Remove this once we have a GlobalAppSettingsViewModel in TerminalSettingsEditor // TODO GH#9207: Remove this once we have a GlobalAppSettingsViewModel in TerminalSettingsEditor
void SetInvertedDisableAnimationsValue(bool invertedDisableAnimationsValue) void SetInvertedDisableAnimationsValue(bool invertedDisableAnimationsValue)
@ -90,7 +85,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, ForceFullRepaintRendering, false); INHERITABLE_SETTING(Model::GlobalAppSettings, bool, ForceFullRepaintRendering, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, SoftwareRendering, false); INHERITABLE_SETTING(Model::GlobalAppSettings, bool, SoftwareRendering, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, ForceVTInput, false); INHERITABLE_SETTING(Model::GlobalAppSettings, bool, ForceVTInput, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, DebugFeaturesEnabled, _getDefaultDebugFeaturesValue()); INHERITABLE_SETTING(Model::GlobalAppSettings, bool, DebugFeaturesEnabled, debugFeaturesDefault);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, StartOnUserLogin, false); INHERITABLE_SETTING(Model::GlobalAppSettings, bool, StartOnUserLogin, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, AlwaysOnTop, false); INHERITABLE_SETTING(Model::GlobalAppSettings, bool, AlwaysOnTop, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, Model::TabSwitcherMode, TabSwitcherMode, Model::TabSwitcherMode::InOrder); INHERITABLE_SETTING(Model::GlobalAppSettings, Model::TabSwitcherMode, TabSwitcherMode, Model::TabSwitcherMode::InOrder);
@ -102,21 +97,19 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, DetectURLs, true); INHERITABLE_SETTING(Model::GlobalAppSettings, bool, DetectURLs, true);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, MinimizeToNotificationArea, false); INHERITABLE_SETTING(Model::GlobalAppSettings, bool, MinimizeToNotificationArea, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, AlwaysShowNotificationIcon, false); INHERITABLE_SETTING(Model::GlobalAppSettings, bool, AlwaysShowNotificationIcon, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, winrt::Windows::Foundation::Collections::IVector<winrt::hstring>, DisabledProfileSources, nullptr);
INHERITABLE_SETTING(Model::GlobalAppSettings, hstring, UnparsedDefaultProfile, L"");
private: private:
guid _defaultProfile; #ifdef NDEBUG
std::optional<hstring> _UnparsedDefaultProfile{ std::nullopt }; static constexpr bool debugFeaturesDefault{ false };
bool _validDefaultProfile; #else
static constexpr bool debugFeaturesDefault{ true };
#endif
com_ptr<implementation::ActionMap> _actionMap; winrt::guid _defaultProfile;
winrt::com_ptr<implementation::ActionMap> _actionMap{ winrt::make_self<implementation::ActionMap>() };
std::vector<SettingsLoadWarnings> _keybindingsWarnings; std::vector<SettingsLoadWarnings> _keybindingsWarnings;
Windows::Foundation::Collections::IMap<winrt::hstring, Model::ColorScheme> _colorSchemes{ winrt::single_threaded_map<winrt::hstring, Model::ColorScheme>() };
Windows::Foundation::Collections::IMap<hstring, Model::ColorScheme> _colorSchemes;
std::optional<hstring> _getUnparsedDefaultProfileImpl() const;
static bool _getDefaultDebugFeaturesValue();
friend class SettingsModelLocalTests::DeserializationTests;
friend class SettingsModelLocalTests::ColorSchemeTests;
}; };
} }

View File

@ -83,6 +83,7 @@ namespace Microsoft.Terminal.Settings.Model
INHERITABLE_SETTING(Boolean, DetectURLs); INHERITABLE_SETTING(Boolean, DetectURLs);
INHERITABLE_SETTING(Boolean, MinimizeToNotificationArea); INHERITABLE_SETTING(Boolean, MinimizeToNotificationArea);
INHERITABLE_SETTING(Boolean, AlwaysShowNotificationIcon); INHERITABLE_SETTING(Boolean, AlwaysShowNotificationIcon);
INHERITABLE_SETTING(IVector<String>, DisabledProfileSources);
Windows.Foundation.Collections.IMapView<String, ColorScheme> ColorSchemes(); Windows.Foundation.Collections.IMapView<String, ColorScheme> ColorSchemes();
void AddColorScheme(ColorScheme scheme); void AddColorScheme(ColorScheme scheme);

View File

@ -20,18 +20,16 @@ Author(s):
--*/ --*/
#pragma once #pragma once
#include "Profile.h" #include "Profile.h"
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
class IDynamicProfileGenerator; class IDynamicProfileGenerator
{
public:
virtual ~IDynamicProfileGenerator(){};
virtual std::wstring_view GetNamespace() const noexcept = 0;
virtual void GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const = 0;
};
}; };
class Microsoft::Terminal::Settings::Model::IDynamicProfileGenerator
{
public:
virtual ~IDynamicProfileGenerator() = 0;
virtual std::wstring_view GetNamespace() = 0;
virtual std::vector<winrt::Microsoft::Terminal::Settings::Model::Profile> GenerateProfiles() = 0;
};
inline Microsoft::Terminal::Settings::Model::IDynamicProfileGenerator::~IDynamicProfileGenerator() {}

View File

@ -48,13 +48,13 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
void InsertParent(com_ptr<T> parent) void InsertParent(com_ptr<T> parent)
{ {
_parents.push_back(parent); _parents.emplace_back(std::move(parent));
} }
void InsertParent(size_t index, com_ptr<T> parent) void InsertParent(size_t index, com_ptr<T> parent)
{ {
auto pos{ _parents.begin() + index }; auto pos{ _parents.begin() + index };
_parents.insert(pos, parent); _parents.emplace(pos, std::move(parent));
} }
const std::vector<com_ptr<T>>& Parents() const std::vector<com_ptr<T>>& Parents()

View File

@ -678,7 +678,7 @@ namespace Microsoft::Terminal::Settings::Model::JsonUtils
{ {
GUID FromJson(const Json::Value& json) GUID FromJson(const Json::Value& json)
{ {
return ::Microsoft::Console::Utils::GuidFromString(til::u8u16(Detail::GetStringView(json))); return ::Microsoft::Console::Utils::GuidFromString(til::u8u16(Detail::GetStringView(json)).c_str());
} }
bool CanConvert(const Json::Value& json) bool CanConvert(const Json::Value& json)

View File

@ -44,7 +44,7 @@
<ClInclude Include="Command.h"> <ClInclude Include="Command.h">
<DependentUpon>Command.idl</DependentUpon> <DependentUpon>Command.idl</DependentUpon>
</ClInclude> </ClInclude>
<ClInclude Include="DefaultProfileUtils.h" /> <ClInclude Include="DynamicProfileUtils.h" />
<ClInclude Include="FileUtils.h" /> <ClInclude Include="FileUtils.h" />
<ClInclude Include="GlobalAppSettings.h"> <ClInclude Include="GlobalAppSettings.h">
<DependentUpon>GlobalAppSettings.idl</DependentUpon> <DependentUpon>GlobalAppSettings.idl</DependentUpon>
@ -123,7 +123,7 @@
<ClCompile Include="Command.cpp"> <ClCompile Include="Command.cpp">
<DependentUpon>Command.idl</DependentUpon> <DependentUpon>Command.idl</DependentUpon>
</ClCompile> </ClCompile>
<ClCompile Include="DefaultProfileUtils.cpp" /> <ClCompile Include="DynamicProfileUtils.cpp" />
<ClCompile Include="FileUtils.cpp" /> <ClCompile Include="FileUtils.cpp" />
<ClCompile Include="GlobalAppSettings.cpp"> <ClCompile Include="GlobalAppSettings.cpp">
<DependentUpon>GlobalAppSettings.idl</DependentUpon> <DependentUpon>GlobalAppSettings.idl</DependentUpon>
@ -254,15 +254,15 @@
we can include in the code directly. This way, we don't need to worry about we can include in the code directly. This way, we don't need to worry about
failing to load the default settings at runtime. --> failing to load the default settings at runtime. -->
<Target Name="_TerminalAppGenerateDefaultsH" Inputs="defaults.json" Outputs="Generated Files\defaults.h" BeforeTargets="BeforeClCompile"> <Target Name="_TerminalAppGenerateDefaultsH" Inputs="defaults.json" Outputs="Generated Files\defaults.h" BeforeTargets="BeforeClCompile">
<Exec Command="powershell.exe -noprofile ExecutionPolicy Unrestricted $(OpenConsoleDir)\tools\GenerateHeaderForJson.ps1 -JsonFile defaults.json -OutPath '&quot;Generated Files\defaults.h&quot;' -VariableName DefaultJson" /> <Exec Command="pwsh.exe -NoProfile ExecutionPolicy Unrestricted $(OpenConsoleDir)\tools\GenerateHeaderForJson.ps1 -JsonFile defaults.json -OutPath &quot;Generated Files\defaults.h&quot; -VariableName DefaultJson" />
</Target> </Target>
<!-- A different set of defaults for Universal variant --> <!-- A different set of defaults for Universal variant -->
<Target Name="_TerminalAppGenerateDefaultsUniversalH" Inputs="defaults-universal.json" Outputs="Generated Files\defaults-universal.h" BeforeTargets="BeforeClCompile"> <Target Name="_TerminalAppGenerateDefaultsUniversalH" Inputs="defaults-universal.json" Outputs="Generated Files\defaults-universal.h" BeforeTargets="BeforeClCompile">
<Exec Command="powershell.exe -noprofile ExecutionPolicy Unrestricted $(OpenConsoleDir)\tools\GenerateHeaderForJson.ps1 -JsonFile defaults-universal.json -OutPath '&quot;Generated Files\defaults-universal.h&quot;' -VariableName DefaultUniversalJson" /> <Exec Command="pwsh.exe -NoProfile ExecutionPolicy Unrestricted $(OpenConsoleDir)\tools\GenerateHeaderForJson.ps1 -JsonFile defaults-universal.json -OutPath &quot;Generated Files\defaults-universal.h&quot; -VariableName DefaultUniversalJson" />
</Target> </Target>
<!-- Same as above, but for the default settings.json template --> <!-- Same as above, but for the default settings.json template -->
<Target Name="_TerminalAppGenerateUserSettingsH" Inputs="userDefaults.json" Outputs="Generated Files\userDefaults.h" BeforeTargets="BeforeClCompile"> <Target Name="_TerminalAppGenerateUserSettingsH" Inputs="userDefaults.json" Outputs="Generated Files\userDefaults.h" BeforeTargets="BeforeClCompile">
<Exec Command="powershell.exe -noprofile ExecutionPolicy Unrestricted $(OpenConsoleDir)\tools\GenerateHeaderForJson.ps1 -JsonFile userDefaults.json -OutPath '&quot;Generated Files\userDefaults.h&quot;' -VariableName UserSettingsJson" /> <Exec Command="pwsh.exe -NoProfile ExecutionPolicy Unrestricted $(OpenConsoleDir)\tools\GenerateHeaderForJson.ps1 -JsonFile userDefaults.json -OutPath &quot;Generated Files\userDefaults.h&quot; -VariableName UserSettingsJson" />
</Target> </Target>
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" /> <Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
<Import Project="..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets" Condition="Exists('..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets')" /> <Import Project="..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets" Condition="Exists('..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets')" />

View File

@ -24,7 +24,7 @@
<ClCompile Include="KeyChordSerialization.cpp" /> <ClCompile Include="KeyChordSerialization.cpp" />
<ClCompile Include="Profile.cpp" /> <ClCompile Include="Profile.cpp" />
<ClCompile Include="ColorScheme.cpp" /> <ClCompile Include="ColorScheme.cpp" />
<ClCompile Include="DefaultProfileUtils.cpp"> <ClCompile Include="DynamicProfileUtils.cpp">
<Filter>profileGeneration</Filter> <Filter>profileGeneration</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="$(OpenConsoleDir)\dep\jsoncpp\jsoncpp.cpp"> <ClCompile Include="$(OpenConsoleDir)\dep\jsoncpp\jsoncpp.cpp">
@ -69,7 +69,7 @@
<ClInclude Include="SettingsTypes.h" /> <ClInclude Include="SettingsTypes.h" />
<ClInclude Include="TerminalWarnings.h" /> <ClInclude Include="TerminalWarnings.h" />
<ClInclude Include="ColorScheme.h" /> <ClInclude Include="ColorScheme.h" />
<ClInclude Include="DefaultProfileUtils.h"> <ClInclude Include="DynamicProfileUtils.h">
<Filter>profileGeneration</Filter> <Filter>profileGeneration</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="JsonUtils.h"> <ClInclude Include="JsonUtils.h">
@ -123,4 +123,4 @@
<UniqueIdentifier>{81a6314f-aa5b-4533-a499-13bc3a5c4af0}</UniqueIdentifier> <UniqueIdentifier>{81a6314f-aa5b-4533-a499-13bc3a5c4af0}</UniqueIdentifier>
</Filter> </Filter>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -8,7 +8,7 @@
#include "../../types/inc/utils.hpp" #include "../../types/inc/utils.hpp"
#include "../../inc/DefaultSettings.h" #include "../../inc/DefaultSettings.h"
#include "Utils.h" #include "Utils.h"
#include "DefaultProfileUtils.h" #include "DynamicProfileUtils.h"
// These four are headers we do not want proliferating, so they're not in the PCH. // These four are headers we do not want proliferating, so they're not in the PCH.
#include <winrt/Windows.ApplicationModel.h> #include <winrt/Windows.ApplicationModel.h>
@ -289,7 +289,7 @@ static std::vector<PowerShellInstance> _collectPowerShellInstances()
// - PowerShell Core 574e775e-4f2a-5b96-ac1e-a2962a402336 // - PowerShell Core 574e775e-4f2a-5b96-ac1e-a2962a402336
static constexpr winrt::guid PowershellCoreGuid{ 0x574e775e, 0x4f2a, 0x5b96, { 0xac, 0x1e, 0xa2, 0x96, 0x2a, 0x40, 0x23, 0x36 } }; static constexpr winrt::guid PowershellCoreGuid{ 0x574e775e, 0x4f2a, 0x5b96, { 0xac, 0x1e, 0xa2, 0x96, 0x2a, 0x40, 0x23, 0x36 } };
std::wstring_view PowershellCoreProfileGenerator::GetNamespace() std::wstring_view PowershellCoreProfileGenerator::GetNamespace() const noexcept
{ {
return PowershellCoreGeneratorNamespace; return PowershellCoreGeneratorNamespace;
} }
@ -300,34 +300,33 @@ std::wstring_view PowershellCoreProfileGenerator::GetNamespace()
// - <none> // - <none>
// Return Value: // Return Value:
// - a vector with the PowerShell Core profile, if available. // - a vector with the PowerShell Core profile, if available.
std::vector<Profile> PowershellCoreProfileGenerator::GenerateProfiles() void PowershellCoreProfileGenerator::GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const
{ {
std::vector<Profile> profiles; const auto psInstances = _collectPowerShellInstances();
bool first = true;
auto psInstances = _collectPowerShellInstances();
for (const auto& psI : psInstances) for (const auto& psI : psInstances)
{ {
const auto name = psI.Name(); const auto name = psI.Name();
auto profile{ CreateDefaultProfile(name) }; auto profile{ CreateDynamicProfile(name) };
profile.Commandline(psI.executablePath.wstring()); profile->Commandline(winrt::hstring{ psI.executablePath.native() });
profile.StartingDirectory(DEFAULT_STARTING_DIRECTORY); profile->StartingDirectory(winrt::hstring{ DEFAULT_STARTING_DIRECTORY });
profile.DefaultAppearance().ColorSchemeName(L"Campbell"); profile->DefaultAppearance().ColorSchemeName(L"Campbell");
profile->Icon(winrt::hstring{ WI_IsFlagSet(psI.flags, PowerShellFlags::Preview) ? POWERSHELL_PREVIEW_ICON : POWERSHELL_ICON });
if (first)
{
// Give the first ("algorithmically best") profile the official, and original, "PowerShell Core" GUID.
// This will turn the anchored default profile into "PowerShell Core Latest for Native Architecture through Store"
// (or the closest approximation thereof). It may choose a preview instance as the "best" if it is a higher version.
profile->Guid(PowershellCoreGuid);
profile->Name(winrt::hstring{ POWERSHELL_PREFERRED_PROFILE_NAME });
first = false;
}
profile.Icon(WI_IsFlagSet(psI.flags, PowerShellFlags::Preview) ? POWERSHELL_PREVIEW_ICON : POWERSHELL_ICON);
profiles.emplace_back(std::move(profile)); profiles.emplace_back(std::move(profile));
} }
if (profiles.size() > 0)
{
// Give the first ("algorithmically best") profile the official, and original, "PowerShell Core" GUID.
// This will turn the anchored default profile into "PowerShell Core Latest for Native Architecture through Store"
// (or the closest approximation thereof). It may choose a preview instance as the "best" if it is a higher version.
auto firstProfile = profiles.begin();
firstProfile->Guid(PowershellCoreGuid);
firstProfile->Name(POWERSHELL_PREFERRED_PROFILE_NAME);
}
return profiles;
} }
// Function Description: // Function Description:

View File

@ -18,17 +18,14 @@ Author(s):
#include "IDynamicProfileGenerator.h" #include "IDynamicProfileGenerator.h"
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
class PowershellCoreProfileGenerator : public Microsoft::Terminal::Settings::Model::IDynamicProfileGenerator class PowershellCoreProfileGenerator final : public IDynamicProfileGenerator
{ {
public: public:
static const std::wstring_view GetPreferredPowershellProfileName(); static const std::wstring_view GetPreferredPowershellProfileName();
PowershellCoreProfileGenerator() = default; std::wstring_view GetNamespace() const noexcept override;
~PowershellCoreProfileGenerator() = default; void GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
std::wstring_view GetNamespace() override;
std::vector<winrt::Microsoft::Terminal::Settings::Model::Profile> GenerateProfiles() override;
}; };
}; };

View File

@ -5,9 +5,7 @@
#include "Profile.h" #include "Profile.h"
#include "JsonUtils.h" #include "JsonUtils.h"
#include "../../types/inc/Utils.hpp" #include "../../types/inc/Utils.hpp"
#include <DefaultSettings.h>
#include "LegacyProfileGeneratorNamespaces.h"
#include "TerminalSettingsSerializationHelpers.h" #include "TerminalSettingsSerializationHelpers.h"
#include "AppearanceConfig.h" #include "AppearanceConfig.h"
#include "FontConfig.h" #include "FontConfig.h"
@ -22,6 +20,7 @@ using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::Foundation; using namespace winrt::Windows::Foundation;
using namespace ::Microsoft::Console; using namespace ::Microsoft::Console;
static constexpr std::string_view UpdatesKey{ "updates" };
static constexpr std::string_view NameKey{ "name" }; static constexpr std::string_view NameKey{ "name" };
static constexpr std::string_view GuidKey{ "guid" }; static constexpr std::string_view GuidKey{ "guid" };
static constexpr std::string_view SourceKey{ "source" }; static constexpr std::string_view SourceKey{ "source" };
@ -47,13 +46,7 @@ static constexpr std::string_view TabColorKey{ "tabColor" };
static constexpr std::string_view BellStyleKey{ "bellStyle" }; static constexpr std::string_view BellStyleKey{ "bellStyle" };
static constexpr std::string_view UnfocusedAppearanceKey{ "unfocusedAppearance" }; static constexpr std::string_view UnfocusedAppearanceKey{ "unfocusedAppearance" };
static constexpr std::wstring_view DesktopWallpaperEnum{ L"desktopWallpaper" }; Profile::Profile(guid guid) noexcept :
Profile::Profile()
{
}
Profile::Profile(guid guid) :
_Guid(guid) _Guid(guid)
{ {
} }
@ -79,61 +72,81 @@ void Profile::DeleteUnfocusedAppearance()
_UnfocusedAppearance = std::nullopt; _UnfocusedAppearance = std::nullopt;
} }
winrt::com_ptr<Profile> Profile::CopySettings(winrt::com_ptr<Profile> source) // See CopyInheritanceGraph (singular) for more information.
// This does the same, but runs it on a list of graph nodes and clones each sub-graph.
void Profile::CopyInheritanceGraphs(std::unordered_map<const Profile*, winrt::com_ptr<Profile>>& visited, const std::vector<winrt::com_ptr<Profile>>& source, std::vector<winrt::com_ptr<Profile>>& target)
{ {
auto profile{ winrt::make_self<Profile>() }; for (const auto& sourceProfile : source)
{
target.emplace_back(sourceProfile->CopyInheritanceGraph(visited));
}
}
profile->_Deleted = source->_Deleted; // A profile and its IInheritable parents basically behave like a directed acyclic graph (DAG).
profile->_Guid = source->_Guid; // Cloning a DAG requires us to prevent the duplication of already cloned nodes (or profiles).
profile->_Name = source->_Name; // This is where "visited" comes into play: It contains previously cloned sub-graphs of profiles and "interns" them.
profile->_Source = source->_Source; winrt::com_ptr<Profile>& Profile::CopyInheritanceGraph(std::unordered_map<const Profile*, winrt::com_ptr<Profile>>& visited) const
profile->_Hidden = source->_Hidden; {
profile->_Icon = source->_Icon; // The operator[] is usually considered to suck, because it implicitly creates entries
profile->_CloseOnExit = source->_CloseOnExit; // in maps/sets if the entry doesn't exist yet, which is often an unwanted behavior.
profile->_TabTitle = source->_TabTitle; // But in this case it's just perfect. We want to return a reference to the profile if it's
profile->_TabColor = source->_TabColor; // been created before and create a cloned profile if it doesn't. With the operator[]
profile->_SuppressApplicationTitle = source->_SuppressApplicationTitle; // we can just assign the returned reference allowing us to write some lean code.
profile->_UseAcrylic = source->_UseAcrylic; auto& clone = visited[this];
profile->_ScrollState = source->_ScrollState;
profile->_Padding = source->_Padding;
profile->_Commandline = source->_Commandline;
profile->_StartingDirectory = source->_StartingDirectory;
profile->_AntialiasingMode = source->_AntialiasingMode;
profile->_ForceFullRepaintRendering = source->_ForceFullRepaintRendering;
profile->_SoftwareRendering = source->_SoftwareRendering;
profile->_HistorySize = source->_HistorySize;
profile->_SnapOnInput = source->_SnapOnInput;
profile->_AltGrAliasing = source->_AltGrAliasing;
profile->_BellStyle = source->_BellStyle;
profile->_ConnectionType = source->_ConnectionType;
profile->_Origin = source->_Origin;
// Copy over the font info if (!clone)
const auto weakRefToProfile = weak_ref<Model::Profile>(*profile); {
winrt::com_ptr<FontConfig> sourceFontInfoImpl; clone = CopySettings();
sourceFontInfoImpl.copy_from(winrt::get_self<FontConfig>(source->_FontInfo)); CopyInheritanceGraphs(visited, _parents, clone->_parents);
auto copiedFontInfo = FontConfig::CopyFontInfo(sourceFontInfoImpl, weakRefToProfile); clone->_FinalizeInheritance();
profile->_FontInfo = *copiedFontInfo; }
// Copy over the appearance return clone;
winrt::com_ptr<AppearanceConfig> sourceDefaultAppearanceImpl; }
sourceDefaultAppearanceImpl.copy_from(winrt::get_self<AppearanceConfig>(source->_DefaultAppearance));
auto copiedDefaultAppearance = AppearanceConfig::CopyAppearance(sourceDefaultAppearanceImpl, weakRefToProfile);
profile->_DefaultAppearance = *copiedDefaultAppearance;
if (source->_UnfocusedAppearance.has_value()) winrt::com_ptr<Profile> Profile::CopySettings() const
{
const auto profile = winrt::make_self<Profile>();
const auto weakProfile = winrt::make_weak<Model::Profile>(*profile);
const auto fontInfo = FontConfig::CopyFontInfo(winrt::get_self<FontConfig>(_FontInfo), weakProfile);
const auto defaultAppearance = AppearanceConfig::CopyAppearance(winrt::get_self<AppearanceConfig>(_DefaultAppearance), weakProfile);
profile->_Deleted = _Deleted;
profile->_Updates = _Updates;
profile->_Guid = _Guid;
profile->_Name = _Name;
profile->_Source = _Source;
profile->_Hidden = _Hidden;
profile->_Icon = _Icon;
profile->_CloseOnExit = _CloseOnExit;
profile->_TabTitle = _TabTitle;
profile->_TabColor = _TabColor;
profile->_SuppressApplicationTitle = _SuppressApplicationTitle;
profile->_UseAcrylic = _UseAcrylic;
profile->_ScrollState = _ScrollState;
profile->_Padding = _Padding;
profile->_Commandline = _Commandline;
profile->_StartingDirectory = _StartingDirectory;
profile->_AntialiasingMode = _AntialiasingMode;
profile->_ForceFullRepaintRendering = _ForceFullRepaintRendering;
profile->_SoftwareRendering = _SoftwareRendering;
profile->_HistorySize = _HistorySize;
profile->_SnapOnInput = _SnapOnInput;
profile->_AltGrAliasing = _AltGrAliasing;
profile->_BellStyle = _BellStyle;
profile->_ConnectionType = _ConnectionType;
profile->_Origin = _Origin;
profile->_FontInfo = *fontInfo;
profile->_DefaultAppearance = *defaultAppearance;
if (_UnfocusedAppearance)
{ {
Model::AppearanceConfig unfocused{ nullptr }; Model::AppearanceConfig unfocused{ nullptr };
if (source->_UnfocusedAppearance.value() != nullptr) if (*_UnfocusedAppearance)
{ {
// Copy over the unfocused appearance const auto appearance = AppearanceConfig::CopyAppearance(winrt::get_self<AppearanceConfig>(*_UnfocusedAppearance), weakProfile);
winrt::com_ptr<AppearanceConfig> sourceUnfocusedAppearanceImpl; appearance->InsertParent(defaultAppearance);
sourceUnfocusedAppearanceImpl.copy_from(winrt::get_self<AppearanceConfig>(source->_UnfocusedAppearance.value())); unfocused = *appearance;
auto copiedUnfocusedAppearance = AppearanceConfig::CopyAppearance(sourceUnfocusedAppearanceImpl, weakRefToProfile);
// Make sure to add the default appearance as a parent
copiedUnfocusedAppearance->InsertParent(copiedDefaultAppearance);
unfocused = *copiedUnfocusedAppearance;
} }
profile->_UnfocusedAppearance = unfocused; profile->_UnfocusedAppearance = unfocused;
} }
@ -141,104 +154,6 @@ winrt::com_ptr<Profile> Profile::CopySettings(winrt::com_ptr<Profile> source)
return profile; return profile;
} }
// Method Description:
// - Creates a copy of the inheritance graph by performing a depth-first traversal recursively.
// Profiles are recorded as visited via the "visited" parameter.
// Unvisited Profiles are copied into the "cloneGraph" parameter, then marked as visited.
// Arguments:
// - sourceGraph - the graph of Profile's we're cloning
// - cloneGraph - the clone of sourceGraph that is being constructed
// - visited - a map of which Profiles have been visited, and, if so, a reference to the Profile's clone
// Return Value:
// - a clone in both inheritance structure and Profile values of sourceGraph
winrt::com_ptr<Profile> Profile::CloneInheritanceGraph(winrt::com_ptr<Profile> sourceGraph, winrt::com_ptr<Profile> cloneGraph, std::unordered_map<void*, winrt::com_ptr<Profile>>& visited)
{
// If this is an unexplored Profile
// and we have parents...
if (visited.find(sourceGraph.get()) == visited.end() && !sourceGraph->_parents.empty())
{
// iterate through all of our parents to copy them
for (const auto& sourceParent : sourceGraph->_parents)
{
// If we visited this Profile already...
auto kv{ visited.find(sourceParent.get()) };
if (kv != visited.end())
{
// add this Profile's clone as a parent
InsertParentHelper(cloneGraph, kv->second);
}
else
{
// We have not visited this Profile yet,
// copy contents of sourceParent to clone
winrt::com_ptr<Profile> clone{ CopySettings(sourceParent) };
// add the new copy to the cloneGraph
InsertParentHelper(cloneGraph, clone);
// copy the sub-graph at "clone"
CloneInheritanceGraph(sourceParent, clone, visited);
// mark clone as "visited"
// save it to the map in case somebody else references it
visited[sourceParent.get()] = clone;
}
}
}
// we have no more to explore down this path.
return cloneGraph;
}
// Method Description:
// - Inserts a parent profile into a child profile, at the specified index if one was provided
// - Makes sure to call _FinalizeInheritance after inserting the parent
// Arguments:
// - child: the child profile to insert the parent into
// - parent: the parent profile to insert into the child
// - index: an optional index value to insert the parent into
void Profile::InsertParentHelper(winrt::com_ptr<Profile> child, winrt::com_ptr<Profile> parent, std::optional<size_t> index)
{
if (index)
{
child->InsertParent(index.value(), parent);
}
else
{
child->InsertParent(parent);
}
child->_FinalizeInheritance();
}
// Method Description:
// - Generates a Json::Value which is a "stub" of this profile. This stub will
// have enough information that it could be layered with this profile.
// - This method is used during dynamic profile generation - if a profile is
// ever generated that didn't already exist in the user's settings, we'll add
// this stub to the user's settings file, so the user has an easy point to
// modify the generated profile.
// Arguments:
// - <none>
// Return Value:
// - A json::Value with a guid, name and source (if applicable).
Json::Value Profile::GenerateStub() const
{
Json::Value stub;
///// Profile-specific settings /////
stub[JsonKey(GuidKey)] = winrt::to_string(Utils::GuidToString(Guid()));
stub[JsonKey(NameKey)] = winrt::to_string(Name());
const auto source{ Source() };
if (!source.empty())
{
stub[JsonKey(SourceKey)] = winrt::to_string(source);
}
return stub;
}
// Method Description: // Method Description:
// - Create a new instance of this class from a serialized JsonObject. // - Create a new instance of this class from a serialized JsonObject.
// Arguments: // Arguments:
@ -252,71 +167,6 @@ winrt::com_ptr<winrt::Microsoft::Terminal::Settings::Model::implementation::Prof
return result; return result;
} }
// Method Description:
// - Returns true if we think the provided json object represents an instance of
// the same object as this object. If true, we should layer that json object
// on us, instead of creating a new object.
// Arguments:
// - json: The json object to query to see if it's the same
// Return Value:
// - true iff the json object has the same `GUID` as we do.
bool Profile::ShouldBeLayered(const Json::Value& json) const
{
// First, check that GUIDs match. This is easy. If they don't match, they
// should _definitely_ not layer.
const auto otherGuid{ JsonUtils::GetValueForKey<std::optional<winrt::guid>>(json, GuidKey) };
const auto otherSource{ JsonUtils::GetValueForKey<std::optional<winrt::hstring>>(json, SourceKey) };
if (otherGuid)
{
if (otherGuid.value() != Guid())
{
return false;
}
}
else
{
// If the other json object didn't have a GUID,
// check if we auto-generate the same guid using the name and source.
const auto otherName{ JsonUtils::GetValueForKey<std::optional<winrt::hstring>>(json, NameKey) };
if (Guid() != _GenerateGuidForProfile(otherName ? *otherName : L"Default", otherSource ? *otherSource : L""))
{
return false;
}
}
// For profiles with a `source`, also check the `source` property.
bool sourceMatches = false;
const auto mySource{ Source() };
if (!mySource.empty())
{
if (otherSource.has_value())
{
// If we have a source and the other has a source, compare them!
sourceMatches = *otherSource == mySource;
}
else
{
// Special case the legacy dynamic profiles here. In this case,
// `this` is a dynamic profile with a source, and our _source is one
// of the legacy DPG namespaces. We're looking to see if the other
// json object has the same guid, but _no_ "source"
if (mySource == WslGeneratorNamespace ||
mySource == AzureGeneratorNamespace ||
mySource == PowershellCoreGeneratorNamespace)
{
sourceMatches = true;
}
}
}
else
{
// We do not have a source. The only way we match is if source is unset or set to "".
sourceMatches = (!otherSource.has_value() || otherSource.value() == L"");
}
return sourceMatches;
}
// Method Description: // Method Description:
// - Layer values from the given json object on top of the existing properties // - Layer values from the given json object on top of the existing properties
// of this object. For any keys we're expecting to be able to parse in the // of this object. For any keys we're expecting to be able to parse in the
@ -341,6 +191,7 @@ void Profile::LayerJson(const Json::Value& json)
// Profile-specific Settings // Profile-specific Settings
JsonUtils::GetValueForKey(json, NameKey, _Name); JsonUtils::GetValueForKey(json, NameKey, _Name);
JsonUtils::GetValueForKey(json, UpdatesKey, _Updates);
JsonUtils::GetValueForKey(json, GuidKey, _Guid); JsonUtils::GetValueForKey(json, GuidKey, _Guid);
JsonUtils::GetValueForKey(json, HiddenKey, _Hidden); JsonUtils::GetValueForKey(json, HiddenKey, _Hidden);
JsonUtils::GetValueForKey(json, SourceKey, _Source); JsonUtils::GetValueForKey(json, SourceKey, _Source);
@ -459,27 +310,13 @@ std::wstring Profile::EvaluateStartingDirectory(const std::wstring& directory)
return wil::ExpandEnvironmentStringsW<std::wstring>(directory.c_str()); return wil::ExpandEnvironmentStringsW<std::wstring>(directory.c_str());
} }
// Function Description:
// - Returns true if the given JSON object represents a dynamic profile object.
// If it is a dynamic profile object, we should make sure to only layer the
// object on a matching profile from a dynamic source.
// Arguments:
// - json: the partial serialization of a profile object to check
// Return Value:
// - true iff the object has a non-null `source` property
bool Profile::IsDynamicProfileObject(const Json::Value& json)
{
const auto& source = json.isMember(JsonKey(SourceKey)) ? json[JsonKey(SourceKey)] : Json::Value::null;
return !source.isNull();
}
// Function Description: // Function Description:
// - Generates a unique guid for a profile, given the name. For an given name, will always return the same GUID. // - Generates a unique guid for a profile, given the name. For an given name, will always return the same GUID.
// Arguments: // Arguments:
// - name: The name to generate a unique GUID from // - name: The name to generate a unique GUID from
// Return Value: // Return Value:
// - a uuidv5 GUID generated from the given name. // - a uuidv5 GUID generated from the given name.
winrt::guid Profile::_GenerateGuidForProfile(const hstring& name, const hstring& source) noexcept winrt::guid Profile::_GenerateGuidForProfile(const std::wstring_view& name, const std::wstring_view& source) noexcept
{ {
// If we have a _source, then we can from a dynamic profile generator. Use // If we have a _source, then we can from a dynamic profile generator. Use
// our source to build the namespace guid, instead of using the default GUID. // our source to build the namespace guid, instead of using the default GUID.
@ -493,27 +330,6 @@ winrt::guid Profile::_GenerateGuidForProfile(const hstring& name, const hstring&
return { Utils::CreateV5Uuid(namespaceGuid, gsl::as_bytes(gsl::make_span(name))) }; return { Utils::CreateV5Uuid(namespaceGuid, gsl::as_bytes(gsl::make_span(name))) };
} }
// Function Description:
// - Parses the given JSON object to get its GUID. If the json object does not
// have a `guid` set, we'll generate one, using the `name` field.
// Arguments:
// - json: the JSON object to get a GUID from, or generate a unique GUID for
// (given the `name`)
// Return Value:
// - The json's `guid`, or a guid synthesized for it.
winrt::guid Profile::GetGuidOrGenerateForJson(const Json::Value& json) noexcept
{
if (const auto guid{ JsonUtils::GetValueForKey<std::optional<GUID>>(json, GuidKey) })
{
return { guid.value() };
}
const auto name{ JsonUtils::GetValueForKey<hstring>(json, NameKey) };
const auto source{ JsonUtils::GetValueForKey<hstring>(json, SourceKey) };
return Profile::_GenerateGuidForProfile(name, source);
}
// Method Description: // Method Description:
// - Create a new serialized JsonObject from an instance of this class // - Create a new serialized JsonObject from an instance of this class
// Arguments: // Arguments:

View File

@ -76,8 +76,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
struct Profile : ProfileT<Profile>, IInheritable<Profile> struct Profile : ProfileT<Profile>, IInheritable<Profile>
{ {
public: public:
Profile(); Profile() noexcept = default;
Profile(guid guid); Profile(guid guid) noexcept;
void CreateUnfocusedAppearance(); void CreateUnfocusedAppearance();
void DeleteUnfocusedAppearance(); void DeleteUnfocusedAppearance();
@ -87,19 +87,15 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
return Name(); return Name();
} }
static com_ptr<Profile> CloneInheritanceGraph(com_ptr<Profile> oldProfile, com_ptr<Profile> newProfile, std::unordered_map<void*, com_ptr<Profile>>& visited); static void CopyInheritanceGraphs(std::unordered_map<const Profile*, winrt::com_ptr<Profile>>& visited, const std::vector<winrt::com_ptr<Profile>>& source, std::vector<winrt::com_ptr<Profile>>& target);
static com_ptr<Profile> CopySettings(com_ptr<Profile> source); winrt::com_ptr<Profile>& CopyInheritanceGraph(std::unordered_map<const Profile*, winrt::com_ptr<Profile>>& visited) const;
static void InsertParentHelper(com_ptr<Profile> child, com_ptr<Profile> parent, std::optional<size_t> index = std::nullopt); winrt::com_ptr<Profile> CopySettings() const;
Json::Value GenerateStub() const;
static com_ptr<Profile> FromJson(const Json::Value& json); static com_ptr<Profile> FromJson(const Json::Value& json);
bool ShouldBeLayered(const Json::Value& json) const;
void LayerJson(const Json::Value& json); void LayerJson(const Json::Value& json);
static bool IsDynamicProfileObject(const Json::Value& json);
Json::Value ToJson() const; Json::Value ToJson() const;
hstring EvaluatedStartingDirectory() const; hstring EvaluatedStartingDirectory() const;
static guid GetGuidOrGenerateForJson(const Json::Value& json) noexcept;
Model::IAppearanceConfig DefaultAppearance(); Model::IAppearanceConfig DefaultAppearance();
Model::FontConfig FontInfo(); Model::FontConfig FontInfo();
@ -109,6 +105,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
WINRT_PROPERTY(bool, Deleted, false); WINRT_PROPERTY(bool, Deleted, false);
WINRT_PROPERTY(OriginTag, Origin, OriginTag::None); WINRT_PROPERTY(OriginTag, Origin, OriginTag::None);
WINRT_PROPERTY(guid, Updates);
INHERITABLE_SETTING(Model::Profile, guid, Guid, _GenerateGuidForProfile(Name(), Source())); INHERITABLE_SETTING(Model::Profile, guid, Guid, _GenerateGuidForProfile(Name(), Source()));
INHERITABLE_SETTING(Model::Profile, hstring, Name, L"Default"); INHERITABLE_SETTING(Model::Profile, hstring, Name, L"Default");
INHERITABLE_SETTING(Model::Profile, hstring, Source); INHERITABLE_SETTING(Model::Profile, hstring, Source);
@ -124,7 +121,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
INHERITABLE_SETTING(Model::Profile, bool, SuppressApplicationTitle, false); INHERITABLE_SETTING(Model::Profile, bool, SuppressApplicationTitle, false);
INHERITABLE_SETTING(Model::Profile, bool, UseAcrylic, false); INHERITABLE_SETTING(Model::Profile, bool, UseAcrylic, false);
INHERITABLE_SETTING(Model::Profile, double, AcrylicOpacity, 0.5);
INHERITABLE_SETTING(Model::Profile, Microsoft::Terminal::Control::ScrollbarState, ScrollState, Microsoft::Terminal::Control::ScrollbarState::Visible); INHERITABLE_SETTING(Model::Profile, Microsoft::Terminal::Control::ScrollbarState, ScrollState, Microsoft::Terminal::Control::ScrollbarState::Visible);
INHERITABLE_SETTING(Model::Profile, hstring, Padding, DEFAULT_PADDING); INHERITABLE_SETTING(Model::Profile, hstring, Padding, DEFAULT_PADDING);
@ -149,7 +145,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
Model::FontConfig _FontInfo{ winrt::make<FontConfig>(weak_ref<Model::Profile>(*this)) }; Model::FontConfig _FontInfo{ winrt::make<FontConfig>(weak_ref<Model::Profile>(*this)) };
static std::wstring EvaluateStartingDirectory(const std::wstring& directory); static std::wstring EvaluateStartingDirectory(const std::wstring& directory);
static guid _GenerateGuidForProfile(const hstring& name, const hstring& source) noexcept; static guid _GenerateGuidForProfile(const std::wstring_view& name, const std::wstring_view& source) noexcept;
friend class SettingsModelLocalTests::DeserializationTests; friend class SettingsModelLocalTests::DeserializationTests;
friend class SettingsModelLocalTests::ProfileTests; friend class SettingsModelLocalTests::ProfileTests;

View File

@ -50,17 +50,11 @@ namespace Microsoft.Terminal.Settings.Model
Boolean Deleted { get; }; Boolean Deleted { get; };
OriginTag Origin { get; }; OriginTag Origin { get; };
INHERITABLE_PROFILE_SETTING(Guid, Guid);
INHERITABLE_PROFILE_SETTING(String, Name); INHERITABLE_PROFILE_SETTING(String, Name);
Boolean HasGuid();
Guid Guid;
INHERITABLE_PROFILE_SETTING(String, Source); INHERITABLE_PROFILE_SETTING(String, Source);
Boolean HasConnectionType();
Guid ConnectionType;
INHERITABLE_PROFILE_SETTING(Boolean, Hidden); INHERITABLE_PROFILE_SETTING(Boolean, Hidden);
INHERITABLE_PROFILE_SETTING(Guid, ConnectionType);
INHERITABLE_PROFILE_SETTING(String, Icon); INHERITABLE_PROFILE_SETTING(String, Icon);
INHERITABLE_PROFILE_SETTING(CloseOnExitMode, CloseOnExit); INHERITABLE_PROFILE_SETTING(CloseOnExitMode, CloseOnExit);
INHERITABLE_PROFILE_SETTING(String, TabTitle); INHERITABLE_PROFILE_SETTING(String, TabTitle);

View File

@ -8,20 +8,19 @@ namespace Microsoft.Terminal.Settings.Model
enum SettingsLoadWarnings enum SettingsLoadWarnings
{ {
MissingDefaultProfile = 0, MissingDefaultProfile = 0,
DuplicateProfile = 1, DuplicateProfile,
UnknownColorScheme = 2, UnknownColorScheme,
InvalidBackgroundImage = 3, InvalidBackgroundImage,
InvalidIcon = 4, InvalidIcon,
AtLeastOneKeybindingWarning = 5, AtLeastOneKeybindingWarning,
TooManyKeysForChord = 6, TooManyKeysForChord,
MissingRequiredParameter = 7, MissingRequiredParameter,
LegacyGlobalsProperty = 8, FailedToParseCommandJson,
FailedToParseCommandJson = 9, FailedToWriteToSettings,
FailedToWriteToSettings = 10, InvalidColorSchemeInCmd,
InvalidColorSchemeInCmd = 11, InvalidSplitSize,
InvalidSplitSize = 12, FailedToParseStartupActions,
FailedToParseStartupActions = 13, FailedToParseSubCommands,
FailedToParseSubCommands = 14,
WARNINGS_SIZE // IMPORTANT: This MUST be the last value in this enum. It's an unused placeholder. WARNINGS_SIZE // IMPORTANT: This MUST be the last value in this enum. It's an unused placeholder.
}; };

View File

@ -4,7 +4,7 @@
#include "pch.h" #include "pch.h"
#include "VsDevCmdGenerator.h" #include "VsDevCmdGenerator.h"
using namespace Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::Settings::Model;
std::wstring VsDevCmdGenerator::GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const std::wstring VsDevCmdGenerator::GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const
{ {

View File

@ -16,12 +16,12 @@ Author(s):
#pragma once #pragma once
#include "BaseVisualStudioGenerator.h" #include "BaseVisualStudioGenerator.h"
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
class VsDevCmdGenerator : public BaseVisualStudioGenerator class VsDevCmdGenerator final : public BaseVisualStudioGenerator
{ {
public: public:
std::wstring_view GetNamespace() override std::wstring_view GetNamespace() const noexcept override
{ {
return std::wstring_view{ L"Windows.Terminal.VisualStudio.CommandPrompt" }; return std::wstring_view{ L"Windows.Terminal.VisualStudio.CommandPrompt" };
} }

View File

@ -5,7 +5,7 @@
#include "VsDevShellGenerator.h" #include "VsDevShellGenerator.h"
#include "VsSetupConfiguration.h" #include "VsSetupConfiguration.h"
using namespace Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::Settings::Model;
std::wstring VsDevShellGenerator::GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const std::wstring VsDevShellGenerator::GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const
{ {

View File

@ -16,12 +16,12 @@ Author(s):
#pragma once #pragma once
#include "BaseVisualStudioGenerator.h" #include "BaseVisualStudioGenerator.h"
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
class VsDevShellGenerator : public BaseVisualStudioGenerator class VsDevShellGenerator final : public BaseVisualStudioGenerator
{ {
public: public:
std::wstring_view GetNamespace() override std::wstring_view GetNamespace() const noexcept override
{ {
return std::wstring_view{ L"Windows.Terminal.VisualStudio.Powershell" }; return std::wstring_view{ L"Windows.Terminal.VisualStudio.Powershell" };
} }

View File

@ -4,7 +4,7 @@
#include "pch.h" #include "pch.h"
#include "VsSetupConfiguration.h" #include "VsSetupConfiguration.h"
using namespace Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::Settings::Model;
std::vector<VsSetupConfiguration::VsSetupInstance> VsSetupConfiguration::QueryInstances() std::vector<VsSetupConfiguration::VsSetupInstance> VsSetupConfiguration::QueryInstances()
{ {

View File

@ -17,7 +17,7 @@ Author(s):
#include "Setup.Configuration.h" #include "Setup.Configuration.h"
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
/// <summary> /// <summary>
/// See https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.setup.configuration?view=visualstudiosdk-2019 /// See https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.setup.configuration?view=visualstudiosdk-2019

View File

@ -5,13 +5,11 @@
#include "WslDistroGenerator.h" #include "WslDistroGenerator.h"
#include "LegacyProfileGeneratorNamespaces.h" #include "LegacyProfileGeneratorNamespaces.h"
#include "../../types/inc/utils.hpp"
#include "../../inc/DefaultSettings.h" #include "../../inc/DefaultSettings.h"
#include "Utils.h"
#include <io.h> #include <io.h>
#include <fcntl.h> #include <fcntl.h>
#include "DefaultProfileUtils.h" #include "DynamicProfileUtils.h"
static constexpr std::wstring_view DockerDistributionPrefix{ L"docker-desktop" }; static constexpr std::wstring_view DockerDistributionPrefix{ L"docker-desktop" };
@ -31,21 +29,29 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
// - Alpine 1777cdf0-b2c4-5a63-a204-eb60f349ea7c // - Alpine 1777cdf0-b2c4-5a63-a204-eb60f349ea7c
// - Ubuntu-18.04 c6eaf9f4-32a7-5fdc-b5cf-066e8a4b1e40 // - Ubuntu-18.04 c6eaf9f4-32a7-5fdc-b5cf-066e8a4b1e40
std::wstring_view WslDistroGenerator::GetNamespace() std::wstring_view WslDistroGenerator::GetNamespace() const noexcept
{ {
return WslGeneratorNamespace; return WslGeneratorNamespace;
} }
static winrt::com_ptr<implementation::Profile> makeProfile(const std::wstring& distName)
{
const auto WSLDistro{ CreateDynamicProfile(distName) };
WSLDistro->Commandline(winrt::hstring{ L"wsl.exe -d " + distName });
WSLDistro->DefaultAppearance().ColorSchemeName(L"Campbell");
WSLDistro->StartingDirectory(winrt::hstring{ DEFAULT_STARTING_DIRECTORY });
WSLDistro->Icon(L"ms-appx:///ProfileIcons/{9acb9455-ca41-5af7-950f-6bca1bc9722f}.png");
return WSLDistro;
}
// Method Description: // Method Description:
// - Enumerates all the installed WSL distros to create profiles for them. // - Enumerates all the installed WSL distros to create profiles for them.
// Arguments: // Arguments:
// - <none> // - <none>
// Return Value: // Return Value:
// - a vector with all distros for all the installed WSL distros // - a vector with all distros for all the installed WSL distros
static std::vector<Profile> legacyGenerate() static void legacyGenerate(std::vector<winrt::com_ptr<implementation::Profile>>& profiles)
{ {
std::vector<Profile> profiles;
wil::unique_handle readPipe; wil::unique_handle readPipe;
wil::unique_handle writePipe; wil::unique_handle writePipe;
SECURITY_ATTRIBUTES sa{ sizeof(sa), nullptr, true }; SECURITY_ATTRIBUTES sa{ sizeof(sa), nullptr, true };
@ -77,7 +83,7 @@ static std::vector<Profile> legacyGenerate()
break; break;
case WAIT_ABANDONED: case WAIT_ABANDONED:
case WAIT_TIMEOUT: case WAIT_TIMEOUT:
return profiles; return;
case WAIT_FAILED: case WAIT_FAILED:
THROW_LAST_ERROR(); THROW_LAST_ERROR();
default: default:
@ -90,7 +96,7 @@ static std::vector<Profile> legacyGenerate()
} }
else if (exitCode != 0) else if (exitCode != 0)
{ {
return profiles; return;
} }
DWORD bytesAvailable; DWORD bytesAvailable;
THROW_IF_WIN32_BOOL_FALSE(PeekNamedPipe(readPipe.get(), nullptr, NULL, nullptr, &bytesAvailable, nullptr)); THROW_IF_WIN32_BOOL_FALSE(PeekNamedPipe(readPipe.get(), nullptr, NULL, nullptr, &bytesAvailable, nullptr));
@ -117,7 +123,7 @@ static std::vector<Profile> legacyGenerate()
std::wstring distName; std::wstring distName;
std::getline(wlinestream, distName, L'\r'); std::getline(wlinestream, distName, L'\r');
if (distName.substr(0, std::min(distName.size(), DockerDistributionPrefix.size())) == DockerDistributionPrefix) if (til::starts_with(distName, DockerDistributionPrefix))
{ {
// Docker for Windows creates some utility distributions to handle Docker commands. // Docker for Windows creates some utility distributions to handle Docker commands.
// Pursuant to GH#3556, because they are _not_ user-facing we want to hide them. // Pursuant to GH#3556, because they are _not_ user-facing we want to hide them.
@ -131,17 +137,10 @@ static std::vector<Profile> legacyGenerate()
{ {
distName.resize(firstChar); distName.resize(firstChar);
} }
auto WSLDistro{ CreateDefaultProfile(distName) };
WSLDistro.Commandline(L"wsl.exe -d " + distName); profiles.emplace_back(makeProfile(distName));
WSLDistro.DefaultAppearance().ColorSchemeName(L"Campbell");
WSLDistro.StartingDirectory(DEFAULT_STARTING_DIRECTORY);
WSLDistro.Icon(L"ms-appx:///ProfileIcons/{9acb9455-ca41-5af7-950f-6bca1bc9722f}.png");
profiles.emplace_back(WSLDistro);
} }
} }
return profiles;
} }
// Function Description: // Function Description:
@ -151,9 +150,8 @@ static std::vector<Profile> legacyGenerate()
// - names: a list of distro names to turn into profiles // - names: a list of distro names to turn into profiles
// Return Value: // Return Value:
// - the list of profiles we've generated. // - the list of profiles we've generated.
static std::vector<Profile> namesToProfiles(const std::vector<std::wstring>& names) static void namesToProfiles(const std::vector<std::wstring>& names, std::vector<winrt::com_ptr<implementation::Profile>>& profiles)
{ {
std::vector<Profile> profiles;
for (const auto& distName : names) for (const auto& distName : names)
{ {
if (til::starts_with(distName, DockerDistributionPrefix)) if (til::starts_with(distName, DockerDistributionPrefix))
@ -163,15 +161,8 @@ static std::vector<Profile> namesToProfiles(const std::vector<std::wstring>& nam
continue; continue;
} }
auto WSLDistro{ CreateDefaultProfile(distName) }; profiles.emplace_back(makeProfile(distName));
WSLDistro.Commandline(L"wsl.exe -d " + distName);
WSLDistro.DefaultAppearance().ColorSchemeName(L"Campbell");
WSLDistro.StartingDirectory(DEFAULT_STARTING_DIRECTORY);
WSLDistro.Icon(L"ms-appx:///ProfileIcons/{9acb9455-ca41-5af7-950f-6bca1bc9722f}.png");
profiles.emplace_back(WSLDistro);
} }
return profiles;
} }
// Function Description: // Function Description:
@ -304,7 +295,7 @@ static bool getWslNames(const wil::unique_hkey& wslRootKey,
// - <none> // - <none>
// Return Value: // Return Value:
// - A list of WSL profiles. // - A list of WSL profiles.
std::vector<Profile> WslDistroGenerator::GenerateProfiles() void WslDistroGenerator::GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const
{ {
wil::unique_hkey wslRootKey{ openWslRegKey() }; wil::unique_hkey wslRootKey{ openWslRegKey() };
if (wslRootKey) if (wslRootKey)
@ -316,10 +307,10 @@ std::vector<Profile> WslDistroGenerator::GenerateProfiles()
names.reserve(guidStrings.size()); names.reserve(guidStrings.size());
if (getWslNames(wslRootKey, guidStrings, names)) if (getWslNames(wslRootKey, guidStrings, names))
{ {
return namesToProfiles(names); return namesToProfiles(names, profiles);
} }
} }
} }
return legacyGenerate(); legacyGenerate(profiles);
} }

View File

@ -15,16 +15,15 @@ Author(s):
--*/ --*/
#pragma once #pragma once
#include "IDynamicProfileGenerator.h" #include "IDynamicProfileGenerator.h"
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
class WslDistroGenerator : public Microsoft::Terminal::Settings::Model::IDynamicProfileGenerator class WslDistroGenerator final : public IDynamicProfileGenerator
{ {
public: public:
WslDistroGenerator() = default; std::wstring_view GetNamespace() const noexcept override;
~WslDistroGenerator() = default; void GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
std::wstring_view GetNamespace() override;
std::vector<winrt::Microsoft::Terminal::Settings::Model::Profile> GenerateProfiles() override;
}; };
}; };

View File

@ -1,75 +1,31 @@
// This file was initially generated by %PRODUCT% %VERSION%
// It should still be usable in newer versions, but newer versions might have additional
// settings, help text, or changes that you will not see unless you clear this file
// and let us generate a new one for you.
// To view the default settings, hold "alt" while clicking on the "Settings" button.
// For documentation on these settings, see: https://aka.ms/terminal-documentation
{ {
"$schema": "https://aka.ms/terminal-profiles-schema", // "defaultProfile" is filled in by CascadiaSettings, depending on
// what dynamic profiles are present during the first launch.
"defaultProfile": "%DEFAULT_PROFILE%",
// You can add more global application settings here.
// To learn more about global settings, visit https://aka.ms/terminal-global-settings
// If enabled, selections are automatically copied to your clipboard.
"copyOnSelect": false, "copyOnSelect": false,
// If enabled, formatted data is also copied to your clipboard
"copyFormatting": false, "copyFormatting": false,
// A profile specifies a command to execute paired with information about how it should look and feel.
// Each one of them will appear in the 'New Tab' dropdown,
// and can be invoked from the commandline with `wt.exe -p xxx`
// To learn more about profiles, visit https://aka.ms/terminal-profile-settings
"profiles": "profiles":
{ {
"defaults":
{
// Put settings here that you want to apply to all profiles.
},
"list": "list":
[ [
{ {
// Make changes here to the powershell.exe profile.
"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}", "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
"name": "Windows PowerShell", "name": "Windows PowerShell",
"commandline": "powershell.exe", "commandline": "powershell.exe",
"hidden": false "hidden": false
}, },
{ {
// Make changes here to the cmd.exe profile. // "name" is filled in by CascadiaSettings as a localized string.
"guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}", "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
"name": "%COMMAND_PROMPT_LOCALIZED_NAME%",
"commandline": "cmd.exe", "commandline": "cmd.exe",
"hidden": false "hidden": false
} }
] ]
}, },
// Add custom color schemes to this array.
// To learn more about color schemes, visit https://aka.ms/terminal-color-schemes
"schemes": [],
// Add custom actions and keybindings to this array.
// To unbind a key combination from your defaults.json, set the command to "unbound".
// To learn more about actions and keybindings, visit https://aka.ms/terminal-keybindings
"actions": "actions":
[ [
// Copy and paste are bound to Ctrl+Shift+C and Ctrl+Shift+V in your defaults.json.
// These two lines additionally bind them to Ctrl+C and Ctrl+V.
// To learn more about selection, visit https://aka.ms/terminal-selection
{ "command": {"action": "copy", "singleLine": false }, "keys": "ctrl+c" }, { "command": {"action": "copy", "singleLine": false }, "keys": "ctrl+c" },
{ "command": "paste", "keys": "ctrl+v" }, { "command": "paste", "keys": "ctrl+v" },
// Press Ctrl+Shift+F to open the search box
{ "command": "find", "keys": "ctrl+shift+f" }, { "command": "find", "keys": "ctrl+shift+f" },
// Press Alt+Shift+D to open a new pane.
// - "split": "auto" makes this pane open in the direction that provides the most surface area.
// - "splitMode": "duplicate" makes the new pane use the focused pane's profile.
// To learn more about panes, visit https://aka.ms/terminal-panes
{ "command": { "action": "splitPane", "split": "auto", "splitMode": "duplicate" }, "keys": "alt+shift+d" } { "command": { "action": "splitPane", "split": "auto", "splitMode": "duplicate" }, "keys": "alt+shift+d" }
] ]
} }

View File

@ -379,7 +379,6 @@ namespace ControlUnitTests
// For this test, don't use any modifiers // For this test, don't use any modifiers
const auto modifiers = ControlKeyStates(); const auto modifiers = ControlKeyStates();
const Control::MouseButtonState leftMouseDown{ Control::MouseButtonState::IsLeftButtonDown }; const Control::MouseButtonState leftMouseDown{ Control::MouseButtonState::IsLeftButtonDown };
const Control::MouseButtonState noMouseDown{};
const til::size fontSize{ 9, 21 }; const til::size fontSize{ 9, 21 };
@ -530,7 +529,6 @@ namespace ControlUnitTests
// For this test, don't use any modifiers // For this test, don't use any modifiers
const auto modifiers = ControlKeyStates(); const auto modifiers = ControlKeyStates();
const Control::MouseButtonState leftMouseDown{ Control::MouseButtonState::IsLeftButtonDown }; const Control::MouseButtonState leftMouseDown{ Control::MouseButtonState::IsLeftButtonDown };
const Control::MouseButtonState noMouseDown{};
const til::size fontSize{ 9, 21 }; const til::size fontSize{ 9, 21 };
@ -742,7 +740,6 @@ namespace ControlUnitTests
// For this test, don't use any modifiers // For this test, don't use any modifiers
const auto modifiers = ControlKeyStates(); const auto modifiers = ControlKeyStates();
const Control::MouseButtonState leftMouseDown{ Control::MouseButtonState::IsLeftButtonDown }; const Control::MouseButtonState leftMouseDown{ Control::MouseButtonState::IsLeftButtonDown };
const Control::MouseButtonState noMouseDown{};
const til::size fontSize{ 9, 21 }; const til::size fontSize{ 9, 21 };

View File

@ -1,673 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"
#include "../TerminalSettingsModel/ColorScheme.h"
#include "../TerminalSettingsModel/Profile.h"
#include "../TerminalSettingsModel/CascadiaSettings.h"
#include "../TerminalSettingsModel/LegacyProfileGeneratorNamespaces.h"
#include "../LocalTests_SettingsModel/JsonTestClass.h"
#include "TestDynamicProfileGenerator.h"
using namespace Microsoft::Console;
using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace WEX::Logging;
using namespace WEX::TestExecution;
using namespace WEX::Common;
namespace TerminalAppUnitTests
{
class DynamicProfileTests : public JsonTestClass
{
BEGIN_TEST_CLASS(DynamicProfileTests)
TEST_CLASS_PROPERTY(L"ActivationContext", L"TerminalApp.Unit.Tests.manifest")
END_TEST_CLASS()
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
return true;
}
TEST_METHOD(TestSimpleGenerate);
// Simple test of CascadiaSettings generating profiles with _LoadDynamicProfiles
TEST_METHOD(TestSimpleGenerateMultipleGenerators);
// Make sure we gen GUIDs for profiles without guids
TEST_METHOD(TestGenGuidsForProfiles);
// Profiles without a source should not be layered on those with one
TEST_METHOD(DontLayerUserProfilesOnDynamicProfiles);
TEST_METHOD(DoLayerUserProfilesOnDynamicsWhenSourceMatches);
// Make sure profiles that are disabled in _userSettings don't get generated
TEST_METHOD(TestDontRunDisabledGenerators);
// Make sure profiles that are disabled in _userSettings don't get generated
TEST_METHOD(TestLegacyProfilesMigrate);
// Both these do similar things:
// This makes sure that a profile with a `source` _only_ layers, it won't create a new profile
TEST_METHOD(UserProfilesWithInvalidSourcesAreIgnored);
// This does the same, but by disabling a profile source
TEST_METHOD(UserProfilesFromDisabledSourcesDontAppear);
};
void DynamicProfileTests::TestSimpleGenerate()
{
TestDynamicProfileGenerator gen{ L"Terminal.App.UnitTest" };
gen.pfnGenerate = []() {
std::vector<Profile> profiles;
Profile p0;
p0.Name(L"profile0");
profiles.push_back(p0);
return profiles;
};
VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest", gen.GetNamespace());
std::vector<Profile> profiles = gen.GenerateProfiles();
VERIFY_ARE_EQUAL(1u, profiles.size());
VERIFY_ARE_EQUAL(L"profile0", profiles.at(0).Name());
VERIFY_IS_FALSE(profiles.at(0).HasGuid());
}
void DynamicProfileTests::TestSimpleGenerateMultipleGenerators()
{
auto gen0 = std::make_unique<TestDynamicProfileGenerator>(L"Terminal.App.UnitTest.0");
gen0->pfnGenerate = []() {
std::vector<Profile> profiles;
Profile p0;
p0.Name(L"profile0");
profiles.push_back(p0);
return profiles;
};
auto gen1 = std::make_unique<TestDynamicProfileGenerator>(L"Terminal.App.UnitTest.1");
gen1->pfnGenerate = []() {
std::vector<Profile> profiles;
Profile p0;
p0.Name(L"profile1");
profiles.push_back(p0);
return profiles;
};
auto settings = winrt::make_self<implementation::CascadiaSettings>(false);
settings->_profileGenerators.emplace_back(std::move(gen0));
settings->_profileGenerators.emplace_back(std::move(gen1));
settings->_LoadDynamicProfiles();
VERIFY_ARE_EQUAL(2u, settings->_allProfiles.Size());
VERIFY_ARE_EQUAL(L"profile0", settings->_allProfiles.GetAt(0).Name());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(0).HasGuid());
VERIFY_ARE_EQUAL(L"profile1", settings->_allProfiles.GetAt(1).Name());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(1).HasGuid());
}
void DynamicProfileTests::TestGenGuidsForProfiles()
{
// We'll generate GUIDs in the Profile::Guid getter. We should make sure that
// the GUID generated for a dynamic profile (with a source) is different
// than that of a profile without a source.
auto gen0 = std::make_unique<TestDynamicProfileGenerator>(L"Terminal.App.UnitTest.0");
gen0->pfnGenerate = []() {
std::vector<Profile> profiles;
Profile p0;
p0.Name(L"profile0"); // this is _allProfiles.at(2)
profiles.push_back(p0);
return profiles;
};
auto gen1 = std::make_unique<TestDynamicProfileGenerator>(L"Terminal.App.UnitTest.1");
gen1->pfnGenerate = []() {
std::vector<Profile> profiles;
Profile p0, p1;
p0.Name(L"profile0"); // this is _allProfiles.at(3)
p1.Name(L"profile1"); // this is _allProfiles.at(4)
profiles.push_back(p0);
profiles.push_back(p1);
return profiles;
};
auto settings = winrt::make_self<implementation::CascadiaSettings>(false);
settings->_profileGenerators.emplace_back(std::move(gen0));
settings->_profileGenerators.emplace_back(std::move(gen1));
Profile p0, p1;
p0.Name(L"profile0"); // this is _allProfiles.GetAt(0)
p1.Name(L"profile1"); // this is _allProfiles.GetAt(1)
settings->_allProfiles.Append(p0);
settings->_allProfiles.Append(p1);
settings->_LoadDynamicProfiles();
VERIFY_ARE_EQUAL(5u, settings->_allProfiles.Size());
VERIFY_ARE_EQUAL(L"profile0", settings->_allProfiles.GetAt(0).Name());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(0).HasGuid());
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(0).Source().empty());
VERIFY_ARE_EQUAL(L"profile1", settings->_allProfiles.GetAt(1).Name());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(1).HasGuid());
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(1).Source().empty());
VERIFY_ARE_EQUAL(L"profile0", settings->_allProfiles.GetAt(2).Name());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(2).HasGuid());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(2).Source().empty());
VERIFY_ARE_EQUAL(L"profile0", settings->_allProfiles.GetAt(3).Name());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(3).HasGuid());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(3).Source().empty());
VERIFY_ARE_EQUAL(L"profile1", settings->_allProfiles.GetAt(4).Name());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(4).HasGuid());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(4).Source().empty());
VERIFY_ARE_NOT_EQUAL(settings->_allProfiles.GetAt(0).Guid(),
settings->_allProfiles.GetAt(1).Guid());
VERIFY_ARE_NOT_EQUAL(settings->_allProfiles.GetAt(0).Guid(),
settings->_allProfiles.GetAt(2).Guid());
VERIFY_ARE_NOT_EQUAL(settings->_allProfiles.GetAt(0).Guid(),
settings->_allProfiles.GetAt(3).Guid());
VERIFY_ARE_NOT_EQUAL(settings->_allProfiles.GetAt(1).Guid(),
settings->_allProfiles.GetAt(4).Guid());
VERIFY_ARE_NOT_EQUAL(settings->_allProfiles.GetAt(3).Guid(),
settings->_allProfiles.GetAt(4).Guid());
}
void DynamicProfileTests::DontLayerUserProfilesOnDynamicProfiles()
{
winrt::guid guid0 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
winrt::guid guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}");
const std::string userProfiles{ R"(
{
"profiles": [
{
"name" : "profile0",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
},
{
"name" : "profile1",
"guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
}
]
})" };
auto gen0 = std::make_unique<TestDynamicProfileGenerator>(L"Terminal.App.UnitTest.0");
gen0->pfnGenerate = [guid0, guid1]() {
std::vector<Profile> profiles;
Profile p0 = winrt::make<implementation::Profile>(guid0);
p0.Name(L"profile0"); // this is _allProfiles.at(0)
profiles.push_back(p0);
return profiles;
};
auto gen1 = std::make_unique<TestDynamicProfileGenerator>(L"Terminal.App.UnitTest.1");
gen1->pfnGenerate = [guid0, guid1]() {
std::vector<Profile> profiles;
Profile p0 = winrt::make<implementation::Profile>(guid0);
Profile p1 = winrt::make<implementation::Profile>(guid1);
p0.Name(L"profile0"); // this is _allProfiles.at(1)
p1.Name(L"profile1"); // this is _allProfiles.at(2)
profiles.push_back(p0);
profiles.push_back(p1);
return profiles;
};
auto settings = winrt::make_self<implementation::CascadiaSettings>(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 sources"));
// parse userProfiles as the user settings
settings->_ParseJsonString(userProfiles, false);
VERIFY_ARE_EQUAL(0u, settings->_allProfiles.Size(), L"Just parsing the user settings doesn't actually layer them");
settings->_LoadDynamicProfiles();
VERIFY_ARE_EQUAL(3u, settings->_allProfiles.Size());
settings->LayerJson(settings->_userSettings);
VERIFY_ARE_EQUAL(5u, settings->_allProfiles.Size());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(0).Source().empty());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(1).Source().empty());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(2).Source().empty());
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(3).Source().empty());
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(4).Source().empty());
VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.0", settings->_allProfiles.GetAt(0).Source());
VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.1", settings->_allProfiles.GetAt(1).Source());
VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.1", settings->_allProfiles.GetAt(2).Source());
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(0).HasGuid());
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(1).HasGuid());
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(2).HasGuid());
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(3).HasGuid());
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(4).HasGuid());
VERIFY_ARE_EQUAL(guid0, settings->_allProfiles.GetAt(0).Guid());
VERIFY_ARE_EQUAL(guid0, settings->_allProfiles.GetAt(1).Guid());
VERIFY_ARE_EQUAL(guid1, settings->_allProfiles.GetAt(2).Guid());
VERIFY_ARE_EQUAL(guid0, settings->_allProfiles.GetAt(3).Guid());
VERIFY_ARE_EQUAL(guid1, settings->_allProfiles.GetAt(4).Guid());
}
void DynamicProfileTests::DoLayerUserProfilesOnDynamicsWhenSourceMatches()
{
winrt::guid guid0 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
winrt::guid guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}");
const std::string userProfiles{ R"(
{
"profiles": [
{
"name" : "profile0FromUserSettings", // this is _allProfiles.at(0)
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"source": "Terminal.App.UnitTest.0"
},
{
"name" : "profile1FromUserSettings", // this is _allProfiles.at(2)
"guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
"source": "Terminal.App.UnitTest.1"
}
]
})" };
auto gen0 = std::make_unique<TestDynamicProfileGenerator>(L"Terminal.App.UnitTest.0");
gen0->pfnGenerate = [guid0, guid1]() {
std::vector<Profile> profiles;
Profile p0 = winrt::make<implementation::Profile>(guid0);
p0.Name(L"profile0"); // this is _allProfiles.at(0)
profiles.push_back(p0);
return profiles;
};
auto gen1 = std::make_unique<TestDynamicProfileGenerator>(L"Terminal.App.UnitTest.1");
gen1->pfnGenerate = [guid0, guid1]() {
std::vector<Profile> profiles;
Profile p0 = winrt::make<implementation::Profile>(guid0);
Profile p1 = winrt::make<implementation::Profile>(guid1);
p0.Name(L"profile0"); // this is _allProfiles.at(1)
p1.Name(L"profile1"); // this is _allProfiles.at(2)
profiles.push_back(p0);
profiles.push_back(p1);
return profiles;
};
auto settings = winrt::make_self<implementation::CascadiaSettings>(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->_allProfiles.Size(), L"Just parsing the user settings doesn't actually layer them");
settings->_LoadDynamicProfiles();
VERIFY_ARE_EQUAL(3u, settings->_allProfiles.Size());
settings->LayerJson(settings->_userSettings);
VERIFY_ARE_EQUAL(3u, settings->_allProfiles.Size());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(0).Source().empty());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(1).Source().empty());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(2).Source().empty());
VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.0", settings->_allProfiles.GetAt(0).Source());
VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.1", settings->_allProfiles.GetAt(1).Source());
VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.1", settings->_allProfiles.GetAt(2).Source());
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(0).HasGuid());
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(1).HasGuid());
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(2).HasGuid());
VERIFY_ARE_EQUAL(guid0, settings->_allProfiles.GetAt(0).Guid());
VERIFY_ARE_EQUAL(guid0, settings->_allProfiles.GetAt(1).Guid());
VERIFY_ARE_EQUAL(guid1, settings->_allProfiles.GetAt(2).Guid());
VERIFY_ARE_EQUAL(L"profile0FromUserSettings", settings->_allProfiles.GetAt(0).Name());
VERIFY_ARE_EQUAL(L"profile0", settings->_allProfiles.GetAt(1).Name());
VERIFY_ARE_EQUAL(L"profile1FromUserSettings", settings->_allProfiles.GetAt(2).Name());
}
void DynamicProfileTests::TestDontRunDisabledGenerators()
{
const std::string settings0String{ R"(
{
"disabledProfileSources": ["Terminal.App.UnitTest.0"]
})" };
const std::string settings1String{ R"(
{
"disabledProfileSources": ["Terminal.App.UnitTest.0", "Terminal.App.UnitTest.1"]
})" };
const auto settings0Json = VerifyParseSucceeded(settings0String);
auto gen0GenerateFn = []() {
std::vector<Profile> profiles;
Profile p0;
p0.Name(L"profile0");
profiles.push_back(p0);
return profiles;
};
auto gen1GenerateFn = []() {
std::vector<Profile> profiles;
Profile p0, p1;
p0.Name(L"profile1");
p1.Name(L"profile2");
profiles.push_back(p0);
profiles.push_back(p1);
return profiles;
};
auto gen2GenerateFn = []() {
std::vector<Profile> profiles;
Profile p0, p1;
p0.Name(L"profile3");
p1.Name(L"profile4");
profiles.push_back(p0);
profiles.push_back(p1);
return profiles;
};
{
Log::Comment(NoThrowString().Format(
L"Case 1: Disable a single profile generator"));
auto settings = winrt::make_self<implementation::CascadiaSettings>(false);
auto gen0 = std::make_unique<TestDynamicProfileGenerator>(L"Terminal.App.UnitTest.0");
auto gen1 = std::make_unique<TestDynamicProfileGenerator>(L"Terminal.App.UnitTest.1");
auto gen2 = std::make_unique<TestDynamicProfileGenerator>(L"Terminal.App.UnitTest.2");
gen0->pfnGenerate = gen0GenerateFn;
gen1->pfnGenerate = gen1GenerateFn;
gen2->pfnGenerate = gen2GenerateFn;
settings->_profileGenerators.emplace_back(std::move(gen0));
settings->_profileGenerators.emplace_back(std::move(gen1));
settings->_profileGenerators.emplace_back(std::move(gen2));
// Parse as the user settings:
settings->_ParseJsonString(settings0String, false);
settings->_LoadDynamicProfiles();
VERIFY_ARE_EQUAL(4u, settings->_allProfiles.Size());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(0).Source().empty());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(1).Source().empty());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(2).Source().empty());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(3).Source().empty());
VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.1", settings->_allProfiles.GetAt(0).Source());
VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.1", settings->_allProfiles.GetAt(1).Source());
VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.2", settings->_allProfiles.GetAt(2).Source());
VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.2", settings->_allProfiles.GetAt(3).Source());
VERIFY_ARE_EQUAL(L"profile1", settings->_allProfiles.GetAt(0).Name());
VERIFY_ARE_EQUAL(L"profile2", settings->_allProfiles.GetAt(1).Name());
VERIFY_ARE_EQUAL(L"profile3", settings->_allProfiles.GetAt(2).Name());
VERIFY_ARE_EQUAL(L"profile4", settings->_allProfiles.GetAt(3).Name());
}
{
Log::Comment(NoThrowString().Format(
L"Case 2: Disable multiple profile generators"));
auto settings = winrt::make_self<implementation::CascadiaSettings>(false);
auto gen0 = std::make_unique<TestDynamicProfileGenerator>(L"Terminal.App.UnitTest.0");
auto gen1 = std::make_unique<TestDynamicProfileGenerator>(L"Terminal.App.UnitTest.1");
auto gen2 = std::make_unique<TestDynamicProfileGenerator>(L"Terminal.App.UnitTest.2");
gen0->pfnGenerate = gen0GenerateFn;
gen1->pfnGenerate = gen1GenerateFn;
gen2->pfnGenerate = gen2GenerateFn;
settings->_profileGenerators.emplace_back(std::move(gen0));
settings->_profileGenerators.emplace_back(std::move(gen1));
settings->_profileGenerators.emplace_back(std::move(gen2));
// Parse as the user settings:
settings->_ParseJsonString(settings1String, false);
settings->_LoadDynamicProfiles();
VERIFY_ARE_EQUAL(2u, settings->_allProfiles.Size());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(0).Source().empty());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(1).Source().empty());
VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.2", settings->_allProfiles.GetAt(0).Source());
VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.2", settings->_allProfiles.GetAt(1).Source());
VERIFY_ARE_EQUAL(L"profile3", settings->_allProfiles.GetAt(0).Name());
VERIFY_ARE_EQUAL(L"profile4", settings->_allProfiles.GetAt(1).Name());
}
}
void DynamicProfileTests::TestLegacyProfilesMigrate()
{
winrt::guid guid0 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}");
winrt::guid guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
winrt::guid guid2 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}");
winrt::guid guid3 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-3333-49a3-80bd-e8fdd045185c}");
winrt::guid guid4 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-4444-49a3-80bd-e8fdd045185c}");
const std::string settings0String{ R"(
{
"profiles": [
{
// This pwsh profile does not have a source, but should still be layered
"name" : "profile0FromUserSettings", // this is _allProfiles.at(0)
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
},
{
// This Azure profile does not have a source, but should still be layered
"name" : "profile3FromUserSettings", // this is _allProfiles.at(3)
"guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}"
},
{
// This profile did not come from a dynamic source
"name" : "profile4FromUserSettings", // this is _allProfiles.at(4)
"guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}"
},
{
// This WSL profile does not have a source, but should still be layered
"name" : "profile1FromUserSettings", // this is _allProfiles.at(1)
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
},
{
// This WSL profile does have a source, and should be layered
"name" : "profile2FromUserSettings", // this is _allProfiles.at(2)
"guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
"source": "Windows.Terminal.Wsl"
}
]
})" };
auto gen0 = std::make_unique<TestDynamicProfileGenerator>(L"Windows.Terminal.PowershellCore");
gen0->pfnGenerate = [guid0, guid1]() {
std::vector<Profile> profiles;
Profile p0 = winrt::make<implementation::Profile>(guid0);
p0.Name(L"profile0");
profiles.push_back(p0);
return profiles;
};
auto gen1 = std::make_unique<TestDynamicProfileGenerator>(L"Windows.Terminal.Wsl");
gen1->pfnGenerate = [guid2, guid1]() {
std::vector<Profile> profiles;
Profile p0 = winrt::make<implementation::Profile>(guid1);
Profile p1 = winrt::make<implementation::Profile>(guid2);
p0.Name(L"profile1");
p1.Name(L"profile2");
profiles.push_back(p0);
profiles.push_back(p1);
return profiles;
};
auto gen2 = std::make_unique<TestDynamicProfileGenerator>(L"Windows.Terminal.Azure");
gen2->pfnGenerate = [guid3]() {
std::vector<Profile> profiles;
Profile p0 = winrt::make<implementation::Profile>(guid3);
p0.Name(L"profile3");
profiles.push_back(p0);
return profiles;
};
auto settings = winrt::make_self<implementation::CascadiaSettings>(false);
settings->_profileGenerators.emplace_back(std::move(gen0));
settings->_profileGenerators.emplace_back(std::move(gen1));
settings->_profileGenerators.emplace_back(std::move(gen2));
settings->_ParseJsonString(settings0String, false);
VERIFY_ARE_EQUAL(0u, settings->_allProfiles.Size());
settings->_LoadDynamicProfiles();
VERIFY_ARE_EQUAL(4u, settings->_allProfiles.Size());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(0).Source().empty());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(1).Source().empty());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(2).Source().empty());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(3).Source().empty());
VERIFY_ARE_EQUAL(L"Windows.Terminal.PowershellCore", settings->_allProfiles.GetAt(0).Source());
VERIFY_ARE_EQUAL(L"Windows.Terminal.Wsl", settings->_allProfiles.GetAt(1).Source());
VERIFY_ARE_EQUAL(L"Windows.Terminal.Wsl", settings->_allProfiles.GetAt(2).Source());
VERIFY_ARE_EQUAL(L"Windows.Terminal.Azure", settings->_allProfiles.GetAt(3).Source());
VERIFY_ARE_EQUAL(L"profile0", settings->_allProfiles.GetAt(0).Name());
VERIFY_ARE_EQUAL(L"profile1", settings->_allProfiles.GetAt(1).Name());
VERIFY_ARE_EQUAL(L"profile2", settings->_allProfiles.GetAt(2).Name());
VERIFY_ARE_EQUAL(L"profile3", settings->_allProfiles.GetAt(3).Name());
settings->LayerJson(settings->_userSettings);
VERIFY_ARE_EQUAL(5u, settings->_allProfiles.Size());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(0).Source().empty());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(1).Source().empty());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(2).Source().empty());
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(3).Source().empty());
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(4).Source().empty());
VERIFY_ARE_EQUAL(L"Windows.Terminal.PowershellCore", settings->_allProfiles.GetAt(0).Source());
VERIFY_ARE_EQUAL(L"Windows.Terminal.Wsl", settings->_allProfiles.GetAt(1).Source());
VERIFY_ARE_EQUAL(L"Windows.Terminal.Wsl", settings->_allProfiles.GetAt(2).Source());
VERIFY_ARE_EQUAL(L"Windows.Terminal.Azure", settings->_allProfiles.GetAt(3).Source());
// settings->_allProfiles.GetAt(4) does not have a source
VERIFY_ARE_EQUAL(L"profile0FromUserSettings", settings->_allProfiles.GetAt(0).Name());
VERIFY_ARE_EQUAL(L"profile1FromUserSettings", settings->_allProfiles.GetAt(1).Name());
VERIFY_ARE_EQUAL(L"profile2FromUserSettings", settings->_allProfiles.GetAt(2).Name());
VERIFY_ARE_EQUAL(L"profile3FromUserSettings", settings->_allProfiles.GetAt(3).Name());
VERIFY_ARE_EQUAL(L"profile4FromUserSettings", settings->_allProfiles.GetAt(4).Name());
}
void DynamicProfileTests::UserProfilesWithInvalidSourcesAreIgnored()
{
winrt::guid guid0 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
winrt::guid guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}");
const std::string settings0String{ R"(
{
"profiles": [
{
"name" : "profile0FromUserSettings", // this is _allProfiles.at(0)
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"source": "Terminal.App.UnitTest.0"
},
{
"name" : "profile2", // this shouldn't be in the profiles at all
"guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}",
"source": "Terminal.App.UnitTest.1"
},
{
"name" : "profile3", // this is _allProfiles.at(3)
"guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}"
}
]
})" };
auto gen0 = std::make_unique<TestDynamicProfileGenerator>(L"Terminal.App.UnitTest.0");
gen0->pfnGenerate = [guid0, guid1]() {
std::vector<Profile> profiles;
Profile p0 = winrt::make<implementation::Profile>(guid0);
p0.Name(L"profile0"); // this is _allProfiles.at(0)
profiles.push_back(p0);
return profiles;
};
auto gen1 = std::make_unique<TestDynamicProfileGenerator>(L"Terminal.App.UnitTest.1");
gen1->pfnGenerate = [guid0, guid1]() {
std::vector<Profile> profiles;
Profile p0 = winrt::make<implementation::Profile>(guid0);
Profile p1 = winrt::make<implementation::Profile>(guid1);
p0.Name(L"profile0"); // this is _allProfiles.at(1)
p1.Name(L"profile1"); // this is _allProfiles.at(2)
profiles.push_back(p0);
profiles.push_back(p1);
return profiles;
};
auto settings = winrt::make_self<implementation::CascadiaSettings>(false);
settings->_profileGenerators.emplace_back(std::move(gen0));
settings->_profileGenerators.emplace_back(std::move(gen1));
settings->_ParseJsonString(settings0String, false);
VERIFY_ARE_EQUAL(0u, settings->_allProfiles.Size());
settings->_LoadDynamicProfiles();
VERIFY_ARE_EQUAL(3u, settings->_allProfiles.Size());
settings->LayerJson(settings->_userSettings);
VERIFY_ARE_EQUAL(4u, settings->_allProfiles.Size());
}
void DynamicProfileTests::UserProfilesFromDisabledSourcesDontAppear()
{
winrt::guid guid0 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
winrt::guid guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}");
const std::string settings0String{ R"(
{
"disabledProfileSources": ["Terminal.App.UnitTest.1"],
"profiles": [
{
"name" : "profile0FromUserSettings", // this is _allProfiles.at(0)
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"source": "Terminal.App.UnitTest.0"
},
{
"name" : "profile1FromUserSettings", // this shouldn't be in the profiles at all
"guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
"source": "Terminal.App.UnitTest.1"
},
{
"name" : "profile3", // this is _allProfiles.at(1)
"guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}"
}
]
})" };
auto gen0 = std::make_unique<TestDynamicProfileGenerator>(L"Terminal.App.UnitTest.0");
gen0->pfnGenerate = [guid0, guid1]() {
std::vector<Profile> profiles;
Profile p0 = winrt::make<implementation::Profile>(guid0);
p0.Name(L"profile0"); // this is _allProfiles.at(0)
profiles.push_back(p0);
return profiles;
};
auto gen1 = std::make_unique<TestDynamicProfileGenerator>(L"Terminal.App.UnitTest.1");
gen1->pfnGenerate = [guid0, guid1]() {
std::vector<Profile> profiles;
Profile p0 = winrt::make<implementation::Profile>(guid0);
Profile p1 = winrt::make<implementation::Profile>(guid1);
p0.Name(L"profile0"); // this shouldn't be in the profiles at all
p1.Name(L"profile1"); // this shouldn't be in the profiles at all
profiles.push_back(p0);
profiles.push_back(p1);
return profiles;
};
auto settings = winrt::make_self<implementation::CascadiaSettings>(false);
settings->_profileGenerators.emplace_back(std::move(gen0));
settings->_profileGenerators.emplace_back(std::move(gen1));
settings->_ParseJsonString(settings0String, false);
VERIFY_ARE_EQUAL(0u, settings->_allProfiles.Size());
settings->_LoadDynamicProfiles();
VERIFY_ARE_EQUAL(1u, settings->_allProfiles.Size());
settings->LayerJson(settings->_userSettings);
VERIFY_ARE_EQUAL(2u, settings->_allProfiles.Size());
}
};

View File

@ -1,175 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"
#include "../TerminalSettingsModel/ColorScheme.h"
#include "../TerminalSettingsModel/Profile.h"
#include "../TerminalSettingsModel/CascadiaSettings.h"
#include "../LocalTests_SettingsModel/JsonTestClass.h"
#include "../types/inc/colorTable.hpp"
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::Control;
namespace TerminalAppUnitTests
{
class JsonTests : public JsonTestClass
{
BEGIN_TEST_CLASS(JsonTests)
TEST_CLASS_PROPERTY(L"ActivationContext", L"TerminalApp.Unit.Tests.manifest")
END_TEST_CLASS()
TEST_METHOD(ParseInvalidJson);
TEST_METHOD(ParseSimpleColorScheme);
TEST_METHOD(ProfileGeneratesGuid);
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
// Use 4 spaces to indent instead of \t
_builder.settings_["indentation"] = " ";
return true;
}
Json::Value VerifyParseSucceeded(std::string_view content);
void VerifyParseFailed(std::string_view content);
private:
Json::StreamWriterBuilder _builder;
};
Json::Value JsonTests::VerifyParseSucceeded(std::string_view content)
{
Json::Value root;
std::string errs;
const bool parseResult = _reader->parse(content.data(), content.data() + content.size(), &root, &errs);
VERIFY_IS_TRUE(parseResult, winrt::to_hstring(errs).c_str());
return root;
}
void JsonTests::VerifyParseFailed(std::string_view content)
{
Json::Value root;
std::string errs;
const bool parseResult = _reader->parse(content.data(), content.data() + content.size(), &root, &errs);
VERIFY_IS_FALSE(parseResult);
}
void JsonTests::ParseInvalidJson()
{
const std::string badJson{ "{ foo : bar : baz }" };
VerifyParseFailed(badJson);
}
void JsonTests::ParseSimpleColorScheme()
{
const std::string campbellScheme{ "{"
"\"background\" : \"#0C0C0C\","
"\"black\" : \"#0C0C0C\","
"\"blue\" : \"#0037DA\","
"\"brightBlack\" : \"#767676\","
"\"brightBlue\" : \"#3B78FF\","
"\"brightCyan\" : \"#61D6D6\","
"\"brightGreen\" : \"#16C60C\","
"\"brightPurple\" : \"#B4009E\","
"\"brightRed\" : \"#E74856\","
"\"brightWhite\" : \"#F2F2F2\","
"\"brightYellow\" : \"#F9F1A5\","
"\"cursorColor\" : \"#FFFFFF\","
"\"cyan\" : \"#3A96DD\","
"\"foreground\" : \"#F2F2F2\","
"\"green\" : \"#13A10E\","
"\"name\" : \"Campbell\","
"\"purple\" : \"#881798\","
"\"red\" : \"#C50F1F\","
"\"selectionBackground\" : \"#131313\","
"\"white\" : \"#CCCCCC\","
"\"yellow\" : \"#C19C00\""
"}" };
const auto schemeObject = VerifyParseSucceeded(campbellScheme);
auto scheme = implementation::ColorScheme::FromJson(schemeObject);
VERIFY_ARE_EQUAL(L"Campbell", scheme->Name());
VERIFY_ARE_EQUAL(til::color(0xf2, 0xf2, 0xf2, 255), til::color{ scheme->Foreground() });
VERIFY_ARE_EQUAL(til::color(0x0c, 0x0c, 0x0c, 255), til::color{ scheme->Background() });
VERIFY_ARE_EQUAL(til::color(0x13, 0x13, 0x13, 255), til::color{ scheme->SelectionBackground() });
VERIFY_ARE_EQUAL(til::color(0xFF, 0xFF, 0xFF, 255), til::color{ scheme->CursorColor() });
std::array<COLORREF, COLOR_TABLE_SIZE> expectedCampbellTable;
auto campbellSpan = gsl::span<COLORREF>(&expectedCampbellTable[0], COLOR_TABLE_SIZE);
Utils::InitializeCampbellColorTable(campbellSpan);
Utils::SetColorTableAlpha(campbellSpan, 0);
for (size_t i = 0; i < expectedCampbellTable.size(); i++)
{
const auto& expected = expectedCampbellTable.at(i);
const til::color actual{ scheme->Table().at(static_cast<uint32_t>(i)) };
VERIFY_ARE_EQUAL(expected, actual);
}
Log::Comment(L"Roundtrip Test for Color Scheme");
Json::Value outJson{ scheme->ToJson() };
VERIFY_ARE_EQUAL(schemeObject, outJson);
}
void JsonTests::ProfileGeneratesGuid()
{
// Parse some profiles without guids. We should NOT generate new guids
// for them. If a profile doesn't have a GUID, we'll leave its _guid
// set to nullopt. The Profile::Guid() getter will
// ensure all profiles have a GUID that's actually set.
// The null guid _is_ a valid guid, so we won't re-generate that
// guid. null is _not_ a valid guid, so we'll leave that nullopt
// See SettingsTests::ValidateProfilesGenerateGuids for a version of
// this test that includes synthesizing GUIDS for profiles without GUIDs
// set
const std::string profileWithoutGuid{ R"({
"name" : "profile0"
})" };
const std::string secondProfileWithoutGuid{ R"({
"name" : "profile1"
})" };
const std::string profileWithNullForGuid{ R"({
"name" : "profile2",
"guid" : null
})" };
const std::string profileWithNullGuid{ R"({
"name" : "profile3",
"guid" : "{00000000-0000-0000-0000-000000000000}"
})" };
const std::string profileWithGuid{ R"({
"name" : "profile4",
"guid" : "{6239a42c-1de4-49a3-80bd-e8fdd045185c}"
})" };
const auto profile0Json = VerifyParseSucceeded(profileWithoutGuid);
const auto profile1Json = VerifyParseSucceeded(secondProfileWithoutGuid);
const auto profile2Json = VerifyParseSucceeded(profileWithNullForGuid);
const auto profile3Json = VerifyParseSucceeded(profileWithNullGuid);
const auto profile4Json = VerifyParseSucceeded(profileWithGuid);
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 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_ARE_EQUAL(profile3->Guid(), nullGuid);
VERIFY_ARE_EQUAL(profile4->Guid(), cmdGuid);
}
}

View File

@ -29,9 +29,9 @@
<!-- ========================= Cpp Files ======================== --> <!-- ========================= Cpp Files ======================== -->
<ItemGroup> <ItemGroup>
<ClCompile Include="ColorHelperTests.cpp" /> <ClCompile Include="ColorHelperTests.cpp" />
<ClCompile Include="JsonTests.cpp" />
<ClCompile Include="JsonUtilsTests.cpp" /> <ClCompile Include="JsonUtilsTests.cpp" />
<ClCompile Include="DynamicProfileTests.cpp" />
<ClCompile Include="precomp.cpp"> <ClCompile Include="precomp.cpp">
<PrecompiledHeader>Create</PrecompiledHeader> <PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile> </ClCompile>

View File

@ -1,44 +0,0 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- TestDynamicProfileGenerator.hpp
Abstract:
- This is a helper class for writing tests using dynamic profiles. Lets you
easily set a arbitrary namespace and generation function for the profiles.
Author(s):
- Mike Griese - August 2019
--*/
#include "../TerminalSettingsModel/IDynamicProfileGenerator.h"
namespace TerminalAppUnitTests
{
class TestDynamicProfileGenerator;
};
class TerminalAppUnitTests::TestDynamicProfileGenerator final :
public Microsoft::Terminal::Settings::Model::IDynamicProfileGenerator
{
public:
TestDynamicProfileGenerator(std::wstring_view ns) :
_namespace{ ns } {};
std::wstring_view GetNamespace() override { return _namespace; };
std::vector<winrt::Microsoft::Terminal::Settings::Model::Profile> GenerateProfiles() override
{
if (pfnGenerate)
{
return pfnGenerate();
}
return std::vector<winrt::Microsoft::Terminal::Settings::Model::Profile>{};
}
std::wstring _namespace;
std::function<std::vector<winrt::Microsoft::Terminal::Settings::Model::Profile>()> pfnGenerate{ nullptr };
};

View File

@ -33,8 +33,8 @@ constexpr uint16_t DEFAULT_FONT_WEIGHT = 400; // normal
constexpr int DEFAULT_ROWS = 30; constexpr int DEFAULT_ROWS = 30;
constexpr int DEFAULT_COLS = 120; constexpr int DEFAULT_COLS = 120;
const std::wstring DEFAULT_PADDING{ L"8, 8, 8, 8" }; constexpr std::wstring_view DEFAULT_PADDING{ L"8, 8, 8, 8" };
const std::wstring DEFAULT_STARTING_DIRECTORY{ L"%USERPROFILE%" }; constexpr std::wstring_view DEFAULT_STARTING_DIRECTORY{ L"%USERPROFILE%" };
constexpr auto DEFAULT_CURSOR_COLOR = COLOR_WHITE; constexpr auto DEFAULT_CURSOR_COLOR = COLOR_WHITE;
constexpr COLORREF DEFAULT_CURSOR_HEIGHT = 25; constexpr COLORREF DEFAULT_CURSOR_HEIGHT = 25;

View File

@ -70,7 +70,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
{ {
} }
operator COLORREF() const noexcept constexpr operator COLORREF() const noexcept
{ {
return static_cast<COLORREF>(abgr & 0x00FFFFFFu); return static_cast<COLORREF>(abgr & 0x00FFFFFFu);
} }
@ -147,14 +147,9 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
{ {
} }
operator winrt::Windows::UI::Color() const constexpr operator winrt::Windows::UI::Color() const
{ {
winrt::Windows::UI::Color ret; return { a, r, g, b };
ret.R = r;
ret.G = g;
ret.B = b;
ret.A = a;
return ret;
} }
#endif #endif
@ -164,14 +159,9 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
{ {
} }
operator winrt::Microsoft::Terminal::Core::Color() const noexcept constexpr operator winrt::Microsoft::Terminal::Core::Color() const noexcept
{ {
winrt::Microsoft::Terminal::Core::Color ret; return { r, g, b, a };
ret.R = r;
ret.G = g;
ret.B = b;
ret.A = a;
return ret;
} }
#endif #endif

View File

@ -40,7 +40,7 @@ namespace Microsoft::Console::Utils
} }
std::wstring GuidToString(const GUID guid); std::wstring GuidToString(const GUID guid);
GUID GuidFromString(const std::wstring wstr); GUID GuidFromString(_Null_terminated_ const wchar_t* str);
GUID CreateGuid(); GUID CreateGuid();
std::string ColorToHexString(const til::color color); std::string ColorToHexString(const til::color color);

View File

@ -39,10 +39,10 @@ std::wstring Utils::GuidToString(const GUID guid)
// Return Value: // Return Value:
// - A GUID if the string could successfully be parsed. On failure, throws the // - A GUID if the string could successfully be parsed. On failure, throws the
// failing HRESULT. // failing HRESULT.
GUID Utils::GuidFromString(const std::wstring wstr) GUID Utils::GuidFromString(_Null_terminated_ const wchar_t* str)
{ {
GUID result{}; GUID result;
THROW_IF_FAILED(IIDFromString(wstr.c_str(), &result)); THROW_IF_FAILED(IIDFromString(str, &result));
return result; return result;
} }

View File

@ -13,7 +13,7 @@ param (
) )
$fullPath = Resolve-Path $JsonFile $fullPath = Resolve-Path $JsonFile
$jsonData = Get-Content $JsonFile $jsonData = Get-Content -Raw $JsonFile | ConvertFrom-Json | ConvertTo-Json -Compress -Depth 100
@( @(
"// Copyright (c) Microsoft Corporation", "// Copyright (c) Microsoft Corporation",
@ -21,7 +21,5 @@ $jsonData = Get-Content $JsonFile
"", "",
"// THIS IS AN AUTO-GENERATED FILE", "// THIS IS AN AUTO-GENERATED FILE",
"// Generated from $($fullPath.Path)", "// Generated from $($fullPath.Path)",
"constexpr std::string_view $($VariableName){", "constexpr std::string_view $VariableName{ R`"#($jsonData)#`" };"
($jsonData | ForEach-Object { "R`"#($_`n)#`"" }),
"};"
) | Out-File -FilePath $OutPath -Encoding utf8 ) | Out-File -FilePath $OutPath -Encoding utf8