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
DECTCEM
Dedupe
deduplicate
deduplicated
DEFAPP
DEFAULTBACKGROUND
@ -784,6 +785,7 @@ FINDSTRINGEXACT
FINDUP
FIter
FIXEDCONVERTED
FIXEDFILEINFO
Flg
flyout
fmodern
@ -1992,6 +1994,7 @@ resx
retval
rfa
rfc
rfid
rftp
rgb
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
app](https://docs.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development)
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
SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk)
installed

View File

@ -5,9 +5,11 @@
#include "../TerminalSettingsModel/ColorScheme.h"
#include "../TerminalSettingsModel/CascadiaSettings.h"
#include "../types/inc/colorTable.hpp"
#include "JsonTestClass.h"
using namespace Microsoft::Console;
using namespace winrt::Microsoft::Terminal;
using namespace winrt::Microsoft::Terminal::Settings::Model::implementation;
using namespace WEX::Logging;
using namespace WEX::TestExecution;
@ -32,339 +34,293 @@ namespace SettingsModelLocalTests
TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml")
END_TEST_CLASS()
TEST_METHOD(CanLayerColorScheme);
TEST_METHOD(LayerColorSchemeProperties);
TEST_METHOD(ParseSimpleColorScheme);
TEST_METHOD(LayerColorSchemesOnArray);
TEST_METHOD(UpdateSchemeReferences);
TEST_CLASS_SETUP(ClassSetup)
static Core::Color rgb(uint8_t r, uint8_t g, uint8_t b) noexcept
{
InitializeJsonReader();
return true;
return Core::Color{ r, g, b, 255 };
}
};
void ColorSchemeTests::CanLayerColorScheme()
void ColorSchemeTests::ParseSimpleColorScheme()
{
const std::string scheme0String{ R"({
"name": "scheme0",
"foreground": "#000000",
"background": "#010101"
})" };
const std::string scheme1String{ R"({
"name": "scheme1",
"foreground": "#020202",
"background": "#030303"
})" };
const std::string scheme2String{ R"({
"name": "scheme0",
"foreground": "#040404",
"background": "#050505"
})" };
const std::string scheme3String{ R"({
// "name": "scheme3",
"foreground": "#060606",
"background": "#070707"
})" };
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 scheme0Json = VerifyParseSucceeded(scheme0String);
const auto scheme1Json = VerifyParseSucceeded(scheme1String);
const auto scheme2Json = VerifyParseSucceeded(scheme2String);
const auto scheme3Json = VerifyParseSucceeded(scheme3String);
const auto schemeObject = VerifyParseSucceeded(campbellScheme);
auto scheme = 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() });
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));
VERIFY_IS_FALSE(scheme0->ShouldBeLayered(scheme1Json));
VERIFY_IS_TRUE(scheme0->ShouldBeLayered(scheme2Json));
VERIFY_IS_FALSE(scheme0->ShouldBeLayered(scheme3Json));
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);
}
const auto scheme1 = ColorScheme::FromJson(scheme1Json);
VERIFY_IS_FALSE(scheme1->ShouldBeLayered(scheme0Json));
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]);
Log::Comment(L"Roundtrip Test for Color Scheme");
Json::Value outJson{ scheme->ToJson() };
VERIFY_ARE_EQUAL(schemeObject, outJson);
}
void ColorSchemeTests::LayerColorSchemesOnArray()
{
const std::string scheme0String{ R"({
"name": "scheme0",
"foreground": "#000000",
"background": "#010101"
static constexpr std::string_view inboxSettings{ R"({
"schemes": [
{
"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"({
"name": "scheme1",
"foreground": "#020202",
"background": "#030303"
})" };
const std::string scheme2String{ R"({
"name": "scheme0",
"foreground": "#040404",
"background": "#050505"
})" };
const std::string scheme3String{ R"({
// by not providing a name, the scheme will have the name ""
"foreground": "#060606",
"background": "#070707"
static constexpr std::string_view userSettings{ R"({
"profiles": [
{
"name" : "profile0"
}
],
"schemes": [
{
"background": "#121314",
"black": "#121314",
"blue": "#121314",
"brightBlack": "#121314",
"brightBlue": "#121314",
"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 scheme1Json = VerifyParseSucceeded(scheme1String);
const auto scheme2Json = VerifyParseSucceeded(scheme2String);
const auto scheme3Json = VerifyParseSucceeded(scheme3String);
const auto settings = winrt::make_self<CascadiaSettings>(userSettings, inboxSettings);
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());
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme0Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
const auto scheme0 = winrt::get_self<ColorScheme>(colorSchemes.Lookup(L"Campbell"));
VERIFY_ARE_EQUAL(rgb(0x12, 0x13, 0x14), scheme0->Foreground());
VERIFY_ARE_EQUAL(rgb(0x12, 0x13, 0x14), scheme0->Background());
settings->_LayerOrCreateColorScheme(scheme0Json);
{
for (auto kv : settings->_globals->ColorSchemes())
{
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);
}
const auto scheme1 = winrt::get_self<ColorScheme>(colorSchemes.Lookup(L"Campbell Powershell"));
VERIFY_ARE_EQUAL(rgb(0xCC, 0xCC, 0xCC), scheme1->Foreground());
VERIFY_ARE_EQUAL(rgb(0x01, 0x24, 0x56), scheme1->Background());
}
void ColorSchemeTests::UpdateSchemeReferences()
{
const std::string settingsString{ R"json({
"defaultProfile": "Inherited reference",
"profiles": {
"defaults": {
"colorScheme": "Scheme 1"
},
"list": [
{
"name": "Explicit scheme reference",
"colorScheme": "Scheme 1"
},
{
"name": "Explicit reference; hidden",
"colorScheme": "Scheme 1",
"hidden": true
},
{
"name": "Inherited reference"
},
{
"name": "Different reference",
"colorScheme": "Scheme 2"
}
]
},
"schemes": [
{ "name": "Scheme 1" },
{ "name": "Scheme 2" },
{ "name": "Scheme 1 (renamed)" }
]
})json" };
static constexpr std::string_view settingsString{ R"json({
"defaultProfile": "Inherited reference",
"profiles": {
"defaults": {
"colorScheme": "Campbell"
},
"list": [
{
"name": "Explicit scheme reference",
"colorScheme": "Campbell"
},
{
"name": "Explicit reference; hidden",
"colorScheme": "Campbell",
"hidden": true
},
{
"name": "Inherited reference"
},
{
"name": "Different reference",
"colorScheme": "One Half Dark"
}
]
},
"schemes": [
{
"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"
},
{
"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) };
settings->_ParseJsonString(settingsString, false);
settings->_ApplyDefaultsFromUserSettings();
settings->LayerJson(settings->_userSettings);
settings->_ValidateSettings();
const auto settings{ winrt::make_self<CascadiaSettings>(settingsString) };
// update all references to "Scheme 1"
const auto newName{ L"Scheme 1 (renamed)" };
settings->UpdateColorSchemeReferences(L"Scheme 1", newName);
const auto newName{ L"Campbell (renamed)" };
settings->UpdateColorSchemeReferences(L"Campbell", newName);
// verify profile defaults
Log::Comment(L"Profile Defaults");
VERIFY_ARE_EQUAL(newName, settings->ProfileDefaults().DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(settings->ProfileDefaults().DefaultAppearance().HasColorSchemeName());
// verify all other profiles
const auto& profiles{ settings->AllProfiles() };
{
const auto& prof{ profiles.GetAt(0) };
Log::Comment(prof.Name().c_str());
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName());
}
{
const auto& prof{ profiles.GetAt(1) };
Log::Comment(prof.Name().c_str());
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName());
}
{
const auto& prof{ profiles.GetAt(2) };
Log::Comment(prof.Name().c_str());
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_FALSE(prof.DefaultAppearance().HasColorSchemeName());
}
{
const auto& prof{ profiles.GetAt(3) };
Log::Comment(prof.Name().c_str());
VERIFY_ARE_EQUAL(L"Scheme 2", prof.DefaultAppearance().ColorSchemeName());
VERIFY_ARE_EQUAL(L"One Half Dark", prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName());
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -7,44 +7,34 @@ Module Name:
Abstract:
- 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
to derive from this class, and also make sure to call InitializeJsonReader()
in the TEST_CLASS_SETUP().
read & parse json data.
Author(s):
Mike Griese (migrie) August-2019
--*/
#pragma once
class JsonTestClass
{
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;
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());
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;
_writer->write(json, &s);
writer->write(json, &s);
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(KeybindingsWithoutVkey);
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
return true;
}
};
void KeyBindingsTests::KeyChords()

View File

@ -7,6 +7,8 @@
#include "../TerminalSettingsModel/CascadiaSettings.h"
#include "JsonTestClass.h"
#include <defaults.h>
using namespace Microsoft::Console;
using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace WEX::Logging;
@ -32,81 +34,86 @@ namespace SettingsModelLocalTests
TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml")
END_TEST_CLASS()
TEST_METHOD(CanLayerProfile);
TEST_METHOD(ProfileGeneratesGuid);
TEST_METHOD(LayerProfileProperties);
TEST_METHOD(LayerProfileIcon);
TEST_METHOD(LayerProfilesOnArray);
TEST_METHOD(DuplicateProfileTest);
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
return true;
}
TEST_METHOD(TestGenGuidsForProfiles);
};
void ProfileTests::CanLayerProfile()
void ProfileTests::ProfileGeneratesGuid()
{
const std::string profile0String{ R"({
"name" : "profile0",
"guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
})" };
const std::string profile1String{ R"({
"name" : "profile1",
"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"
})" };
// 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
const auto profile0Json = VerifyParseSucceeded(profile0String);
const auto profile1Json = VerifyParseSucceeded(profile1String);
const auto profile2Json = VerifyParseSucceeded(profile2String);
const auto profile3Json = VerifyParseSucceeded(profile3String);
// 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);
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);
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 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(profile3->ShouldBeLayered(profile0Json));
// A profile _can_ be layered with itself, though what's the point?
VERIFY_IS_FALSE(profile3->ShouldBeLayered(profile1Json));
VERIFY_IS_FALSE(profile3->ShouldBeLayered(profile2Json));
VERIFY_IS_TRUE(profile3->ShouldBeLayered(profile3Json));
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);
}
void ProfileTests::LayerProfileProperties()
{
const std::string profile0String{ R"({
static constexpr std::string_view profile0String{ R"({
"name": "profile0",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"foreground": "#000000",
"background": "#010101",
"selectionBackground": "#010101"
})" };
const std::string profile1String{ R"({
static constexpr std::string_view profile1String{ R"({
"name": "profile1",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"foreground": "#020202",
"startingDirectory": "C:/"
})" };
const std::string profile2String{ R"({
static constexpr std::string_view profile2String{ R"({
"name": "profile2",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"foreground": "#030303",
@ -172,21 +179,21 @@ namespace SettingsModelLocalTests
void ProfileTests::LayerProfileIcon()
{
const std::string profile0String{ R"({
static constexpr std::string_view profile0String{ R"({
"name": "profile0",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"icon": "not-null.png"
})" };
const std::string profile1String{ R"({
static constexpr std::string_view profile1String{ R"({
"name": "profile1",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"icon": null
})" };
const std::string profile2String{ R"({
static constexpr std::string_view profile2String{ R"({
"name": "profile2",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
})" };
const std::string profile3String{ R"({
static constexpr std::string_view profile3String{ R"({
"name": "profile3",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"icon": "another-real.png"
@ -228,102 +235,95 @@ namespace SettingsModelLocalTests
void ProfileTests::LayerProfilesOnArray()
{
const std::string profile0String{ R"({
"name" : "profile0",
"guid" : "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
static constexpr std::string_view inboxProfiles{ R"({
"profiles": [
{
"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"({
"name" : "profile1",
"guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
})" };
const std::string profile2String{ R"({
"name" : "profile2",
"guid" : "{6239a42c-2222-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}"
static constexpr std::string_view userProfiles{ R"({
"profiles": [
{
"name" : "profile3",
"guid" : "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
}, {
"name" : "profile4",
"guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
}
]
})" };
const auto profile0Json = VerifyParseSucceeded(profile0String);
const auto profile1Json = VerifyParseSucceeded(profile1String);
const auto profile2Json = VerifyParseSucceeded(profile2String);
const auto profile3Json = VerifyParseSucceeded(profile3String);
const auto profile4Json = VerifyParseSucceeded(profile4String);
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());
const auto settings = winrt::make_self<implementation::CascadiaSettings>(userProfiles, inboxProfiles);
const auto allProfiles = settings->AllProfiles();
VERIFY_ARE_EQUAL(3u, allProfiles.Size());
VERIFY_ARE_EQUAL(L"profile3", allProfiles.GetAt(0).Name());
VERIFY_ARE_EQUAL(L"profile4", allProfiles.GetAt(1).Name());
VERIFY_ARE_EQUAL(L"profile2", allProfiles.GetAt(2).Name());
}
void ProfileTests::DuplicateProfileTest()
{
const std::string profile0String{ R"({
"name" : "profile0",
"backgroundImage" : "some//path"
static constexpr std::string_view userProfiles{ R"({
"profiles": [
{
"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>();
settings->_LayerOrCreateProfile(profile0Json);
auto duplicatedProfile = settings->DuplicateProfile(*settings->_FindMatchingProfile(profile0Json));
duplicatedProfile.Name(L"profile0");
duplicatedProfile.Guid(profile.Guid());
duplicatedProfile.Name(profile.Name());
const auto json = winrt::get_self<implementation::Profile>(profile)->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 "TestUtils.h"
#include <defaults.h>
#include "../ut_app/TestDynamicProfileGenerator.h"
using namespace Microsoft::Console;
using namespace WEX::Logging;
@ -43,13 +42,6 @@ namespace SettingsModelLocalTests
TEST_METHOD(CascadiaSettings);
TEST_METHOD(LegacyFontSettings);
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
InitializeJsonWriter();
return true;
}
private:
// Method Description:
// - 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"([
{
"commands":
"commands":
[
{
"command":
"command":
{
"action": "sendInput",
"input": "${profile.name}"
@ -325,13 +317,13 @@ namespace SettingsModelLocalTests
])" };
const std::string actionsString9C{ R""([
{
"commands":
"commands":
[
{
"commands":
"commands":
[
{
"command":
"command":
{
"action": "sendInput",
"input": "${profile.name} ${scheme.name}"
@ -348,7 +340,7 @@ namespace SettingsModelLocalTests
])"" };
const std::string actionsString9D{ R""([
{
"command":
"command":
{
"action": "newTab",
"profile": "${profile.name}"
@ -404,75 +396,71 @@ namespace SettingsModelLocalTests
void SerializationTests::CascadiaSettings()
{
const std::string settingsString{ R"({
"$schema": "https://aka.ms/terminal-profiles-schema",
"defaultProfile": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
"disabledProfileSources": [ "Windows.Terminal.Wsl" ],
"$help" : "https://aka.ms/terminal-documentation",
"$schema" : "https://aka.ms/terminal-profiles-schema",
"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": {
"defaults": {
"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",
"selectionBackground": "#FFFFFF",
"cursorColor": "#FFFFFD",
"selectionBackground": "#FFFFFF",
"background": "#3C0315",
"foreground": "#FFFFFD",
"background": "#3C0315",
"foreground": "#FFFFFD",
"black": "#282A2E",
"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",
"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 settings{ winrt::make_self<implementation::CascadiaSettings>(settingsString) };
const auto result{ settings->ToJson() };
VERIFY_ARE_EQUAL(toString(settings->_userSettings), toString(result));
VERIFY_ARE_EQUAL(toString(VerifyParseSucceeded(settingsString)), toString(result));
}
void SerializationTests::LegacyFontSettings()

View File

@ -62,7 +62,7 @@ namespace SettingsModelLocalTests
void TerminalSettingsTests::TestTerminalArgsForBinding()
{
const std::string settingsJson{ R"(
static constexpr std::string_view settingsJson{ R"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"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 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();
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
auto actionMap = settings->GlobalSettings().ActionMap();
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);
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().Profile().empty());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid0, profile.Guid());
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
@ -153,8 +153,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid1, profile.Guid());
VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline());
@ -175,8 +175,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid1, profile.Guid());
VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline());
@ -197,8 +197,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(profile2Guid, profile.Guid());
VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline());
@ -219,13 +219,13 @@ namespace SettingsModelLocalTests
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
if constexpr (Feature_ShowProfileDefaultsInSettings::IsEnabled())
{
// 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());
}
else
@ -251,8 +251,8 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile());
VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid1, profile.Guid());
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().Profile().empty());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid0, profile.Guid());
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
@ -292,8 +292,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"c:\\foo", realArgs.TerminalArgs().StartingDirectory());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid0, profile.Guid());
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"profile2", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(profile2Guid, profile.Guid());
VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline());
@ -337,8 +337,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid0, profile.Guid());
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"profile2", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(profile2Guid, profile.Guid());
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"profile1", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) };
const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid1, profile.Guid());
VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline());
@ -399,7 +399,7 @@ namespace SettingsModelLocalTests
void TerminalSettingsTests::MakeSettingsForProfile()
{
// Test that making settings generally works.
const std::string settingsString{ R"(
static constexpr std::string_view settingsString{ R"(
{
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"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 guid2 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}");
const auto profile1 = settings.FindProfile(guid1);
const auto profile2 = settings.FindProfile(guid2);
const auto profile1 = settings->FindProfile(guid1);
const auto profile2 = settings->FindProfile(guid2);
try
{
auto terminalSettings{ TerminalSettings::CreateWithProfile(settings, profile1, nullptr) };
auto terminalSettings{ TerminalSettings::CreateWithProfile(*settings, profile1, nullptr) };
VERIFY_ARE_NOT_EQUAL(nullptr, terminalSettings);
VERIFY_ARE_EQUAL(1, terminalSettings.DefaultSettings().HistorySize());
}
@ -436,7 +436,7 @@ namespace SettingsModelLocalTests
try
{
auto terminalSettings{ TerminalSettings::CreateWithProfile(settings, profile2, nullptr) };
auto terminalSettings{ TerminalSettings::CreateWithProfile(*settings, profile2, nullptr) };
VERIFY_ARE_NOT_EQUAL(nullptr, terminalSettings);
VERIFY_ARE_EQUAL(2, terminalSettings.DefaultSettings().HistorySize());
}
@ -447,7 +447,7 @@ namespace SettingsModelLocalTests
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_EQUAL(1, termSettings.DefaultSettings().HistorySize());
}
@ -463,7 +463,7 @@ namespace SettingsModelLocalTests
// defaultProfile that's not in the list, we validate the settings, and
// then call MakeSettings(nullopt). The validation should ensure that
// the default profile is something reasonable
const std::string settingsString{ R"(
static constexpr std::string_view settingsString{ R"(
{
"defaultProfile": "{6239a42c-3333-49a3-80bd-e8fdd045185c}",
"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.ActiveProfiles().Size());
VERIFY_ARE_EQUAL(settings.GlobalSettings().DefaultProfile(), settings.ActiveProfiles().GetAt(0).Guid());
VERIFY_ARE_EQUAL(2u, settings->Warnings().Size());
VERIFY_ARE_EQUAL(2u, settings->ActiveProfiles().Size());
VERIFY_ARE_EQUAL(settings->GlobalSettings().DefaultProfile(), settings->ActiveProfiles().GetAt(0).Guid());
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_EQUAL(1, termSettings.DefaultSettings().HistorySize());
}
@ -501,7 +501,7 @@ namespace SettingsModelLocalTests
Log::Comment(NoThrowString().Format(
L"Ensure that setting (or not) a property in the profile that should override a property of the color scheme works correctly."));
const std::string settings0String{ R"(
static constexpr std::string_view settings0String{ R"(
{
"defaultProfile": "profile5",
"profiles": [
@ -534,18 +534,50 @@ namespace SettingsModelLocalTests
"schemes": [
{
"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(2u, settings.GlobalSettings().ColorSchemes().Size());
VERIFY_ARE_EQUAL(6u, settings->ActiveProfiles().Size());
VERIFY_ARE_EQUAL(2u, settings->GlobalSettings().ColorSchemes().Size());
auto createTerminalSettings = [&](const auto& profile, const auto& schemes) {
auto terminalSettings{ winrt::make_self<implementation::TerminalSettings>() };
@ -554,12 +586,14 @@ namespace SettingsModelLocalTests
return terminalSettings;
};
auto terminalSettings0 = createTerminalSettings(settings.ActiveProfiles().GetAt(0), settings.GlobalSettings().ColorSchemes());
auto terminalSettings1 = createTerminalSettings(settings.ActiveProfiles().GetAt(1), settings.GlobalSettings().ColorSchemes());
auto terminalSettings2 = createTerminalSettings(settings.ActiveProfiles().GetAt(2), settings.GlobalSettings().ColorSchemes());
auto terminalSettings3 = createTerminalSettings(settings.ActiveProfiles().GetAt(3), settings.GlobalSettings().ColorSchemes());
auto terminalSettings4 = createTerminalSettings(settings.ActiveProfiles().GetAt(4), settings.GlobalSettings().ColorSchemes());
auto terminalSettings5 = createTerminalSettings(settings.ActiveProfiles().GetAt(5), settings.GlobalSettings().ColorSchemes());
const auto activeProfiles = settings->ActiveProfiles();
const auto colorSchemes = settings->GlobalSettings().ColorSchemes();
const auto terminalSettings0 = createTerminalSettings(activeProfiles.GetAt(0), colorSchemes);
const auto terminalSettings1 = createTerminalSettings(activeProfiles.GetAt(1), colorSchemes);
const auto terminalSettings2 = createTerminalSettings(activeProfiles.GetAt(2), 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(DEFAULT_CURSOR_COLOR, terminalSettings1->CursorColor()); // default
@ -571,7 +605,7 @@ namespace SettingsModelLocalTests
void TerminalSettingsTests::TestCommandlineToTitlePromotion()
{
const std::string settingsJson{ R"(
static constexpr std::string_view settingsJson{ R"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": { "list": [
@ -587,65 +621,63 @@ namespace SettingsModelLocalTests
} }
})" };
const winrt::guid guid0{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}") };
CascadiaSettings settings{ til::u8u16(settingsJson) };
const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsJson);
{ // just a profile (profile wins)
NewTerminalArgs args{};
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());
}
{ // profile and command line -> no promotion (profile wins)
NewTerminalArgs args{};
args.Profile(L"profile0");
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());
}
{ // just a title -> it is propagated
NewTerminalArgs args{};
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());
}
{ // title and command line -> no promotion
NewTerminalArgs args{};
args.TabTitle(L"Digital Man");
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());
}
{ // just a commandline -> promotion
NewTerminalArgs args{};
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());
}
// various typesof commandline follow
{
NewTerminalArgs args{};
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());
}
{
NewTerminalArgs args{};
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());
}
{
NewTerminalArgs args{};
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());
}
{
NewTerminalArgs args{};
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());
}
}

View File

@ -79,7 +79,7 @@ namespace TerminalAppLocalTests
// containing a ${profile.name} to replace. When we expand it, it should
// 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}",
"profiles": [
@ -111,10 +111,7 @@ namespace TerminalAppLocalTests
"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}");
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
CascadiaSettings settings{ til::u8u16(settingsJson) };
CascadiaSettings settings{ settingsJson, {} };
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
// 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}",
"profiles": [
@ -238,10 +235,7 @@ namespace TerminalAppLocalTests
"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}");
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
CascadiaSettings settings{ til::u8u16(settingsJson) };
CascadiaSettings settings{ settingsJson, {} };
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
// 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}",
"profiles": [
@ -367,10 +361,7 @@ namespace TerminalAppLocalTests
"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}");
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
CascadiaSettings settings{ til::u8u16(settingsJson) };
CascadiaSettings settings{ settingsJson, {} };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
@ -468,7 +459,7 @@ namespace TerminalAppLocalTests
// ├─ first.com
// └─ second.com
const std::string settingsJson{ R"(
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
@ -508,7 +499,7 @@ namespace TerminalAppLocalTests
"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(3u, settings.ActiveProfiles().Size());
@ -558,7 +549,7 @@ namespace TerminalAppLocalTests
// ├─ child1
// └─ child2
const std::string settingsJson{ R"(
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
@ -603,7 +594,7 @@ namespace TerminalAppLocalTests
"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(3u, settings.ActiveProfiles().Size());
@ -691,7 +682,7 @@ namespace TerminalAppLocalTests
// ├─ Split pane, direction: right, 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}",
"profiles": [
@ -727,7 +718,7 @@ namespace TerminalAppLocalTests
"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(3u, settings.ActiveProfiles().Size());
@ -828,7 +819,7 @@ namespace TerminalAppLocalTests
// ├─ Profile 2
// └─ Profile 3
const std::string settingsJson{ R"(
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
@ -864,7 +855,7 @@ namespace TerminalAppLocalTests
"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(3u, settings.ActiveProfiles().Size());
@ -926,7 +917,7 @@ namespace TerminalAppLocalTests
// ├─ Split right
// └─ Split down
const std::string settingsJson{ R"(
static constexpr std::wstring_view settingsJson{ LR"(
{
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [
@ -967,7 +958,7 @@ namespace TerminalAppLocalTests
"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(3u, settings.ActiveProfiles().Size());
@ -1071,7 +1062,7 @@ namespace TerminalAppLocalTests
// containing a ${profile.name} to replace. When we expand it, it should
// 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}",
"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,
// 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
// tab using those settings successfully.
const std::string settingsJson0{ R"(
static constexpr std::wstring_view settingsJson0{ LR"(
{
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"profiles": [
@ -328,7 +328,7 @@ namespace TerminalAppLocalTests
]
})" };
CascadiaSettings settings0{ til::u8u16(settingsJson0) };
CascadiaSettings settings0{ settingsJson0, {} };
VERIFY_IS_NOT_NULL(settings0);
// This is super wacky, but we can't just initialize the
@ -357,7 +357,7 @@ namespace TerminalAppLocalTests
//
// Created to test GH#2455
const std::string settingsJson0{ R"(
static constexpr std::wstring_view settingsJson0{ LR"(
{
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"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}",
"profiles": [
@ -386,10 +386,10 @@ namespace TerminalAppLocalTests
]
})" };
CascadiaSettings settings0{ til::u8u16(settingsJson0) };
CascadiaSettings settings0{ settingsJson0, {} };
VERIFY_IS_NOT_NULL(settings0);
CascadiaSettings settings1{ til::u8u16(settingsJson1) };
CascadiaSettings settings1{ settingsJson1, {} };
VERIFY_IS_NOT_NULL(settings1);
const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
@ -444,7 +444,7 @@ namespace TerminalAppLocalTests
//
// Created to test GH#2455
const std::string settingsJson0{ R"(
static constexpr std::wstring_view settingsJson0{ LR"(
{
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"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}",
"profiles": [
@ -473,10 +473,10 @@ namespace TerminalAppLocalTests
]
})" };
CascadiaSettings settings0{ til::u8u16(settingsJson0) };
CascadiaSettings settings0{ settingsJson0, {} };
VERIFY_IS_NOT_NULL(settings0);
CascadiaSettings settings1{ til::u8u16(settingsJson1) };
CascadiaSettings settings1{ settingsJson1, {} };
VERIFY_IS_NOT_NULL(settings1);
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.
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}",
"showTabsInTitlebar": false,
@ -659,7 +659,7 @@ namespace TerminalAppLocalTests
]
})" };
CascadiaSettings settings0{ til::u8u16(settingsJson0) };
CascadiaSettings settings0{ settingsJson0, {} };
VERIFY_IS_NOT_NULL(settings0);
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;
}
static const winrt::hstring StartupTaskName = L"StartTerminalOnLoginTask";
static constexpr std::wstring_view StartupTaskName = L"StartTerminalOnLoginTask";
// clang-format off
// !!! IMPORTANT !!!
// Make sure that these keys are in the same order as the
// 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"DuplicateProfileText"),
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"TooManyKeysForChord"),
USES_RESOURCE(L"MissingRequiredParameter"),
USES_RESOURCE(L"LegacyGlobalsProperty"),
USES_RESOURCE(L"FailedToParseCommandJson"),
USES_RESOURCE(L"FailedToWriteToSettings"),
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"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"AllProfilesHiddenText")
};
// 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:
// - 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
@ -68,12 +70,12 @@ static const std::array<std::wstring_view, static_cast<uint32_t>(SettingsLoadErr
// - map: A map of keys->Resource keys.
// Return Value:
// - the localized string for the given type, if it exists.
template<std::size_t N>
static winrt::hstring _GetMessageText(uint32_t index, std::array<std::wstring_view, N> keys)
template<typename T>
winrt::hstring _GetMessageText(uint32_t index, const T& keys)
{
if (index < keys.size())
{
return GetLibraryResourceString(keys.at(index));
return GetLibraryResourceString(til::at(keys, index));
}
return {};
}
@ -488,27 +490,6 @@ namespace winrt::TerminalApp::implementation
if (!warningText.empty())
{
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{});
}
}

View File

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

View File

@ -74,7 +74,7 @@
x:Uid="Globals_DefaultTerminal"
x:Load="false">
<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}"
Style="{StaticResource ComboBoxSettingStyle}">
<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 OpacityKey{ "opacity" };
winrt::Microsoft::Terminal::Settings::Model::implementation::AppearanceConfig::AppearanceConfig(const winrt::weak_ref<Profile> sourceProfile) :
_sourceProfile(sourceProfile)
AppearanceConfig::AppearanceConfig(winrt::weak_ref<Profile> 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 const sourceAppearance = source.try_as<AppearanceConfig>();
appearance->_BackgroundImagePath = sourceAppearance->_BackgroundImagePath;
appearance->_BackgroundImageOpacity = sourceAppearance->_BackgroundImageOpacity;
appearance->_BackgroundImageStretchMode = sourceAppearance->_BackgroundImageStretchMode;
appearance->_ColorSchemeName = sourceAppearance->_ColorSchemeName;
appearance->_Foreground = sourceAppearance->_Foreground;
appearance->_Background = sourceAppearance->_Background;
appearance->_SelectionBackground = sourceAppearance->_SelectionBackground;
appearance->_CursorColor = sourceAppearance->_CursorColor;
appearance->_CursorShape = sourceAppearance->_CursorShape;
appearance->_CursorHeight = sourceAppearance->_CursorHeight;
appearance->_BackgroundImageAlignment = sourceAppearance->_BackgroundImageAlignment;
appearance->_RetroTerminalEffect = sourceAppearance->_RetroTerminalEffect;
appearance->_PixelShaderPath = sourceAppearance->_PixelShaderPath;
appearance->_IntenseTextStyle = sourceAppearance->_IntenseTextStyle;
appearance->_Opacity = sourceAppearance->_Opacity;
auto appearance{ winrt::make_self<AppearanceConfig>(std::move(sourceProfile)) };
appearance->_BackgroundImagePath = source->_BackgroundImagePath;
appearance->_BackgroundImageOpacity = source->_BackgroundImageOpacity;
appearance->_BackgroundImageStretchMode = source->_BackgroundImageStretchMode;
appearance->_ColorSchemeName = source->_ColorSchemeName;
appearance->_Foreground = source->_Foreground;
appearance->_Background = source->_Background;
appearance->_SelectionBackground = source->_SelectionBackground;
appearance->_CursorColor = source->_CursorColor;
appearance->_CursorShape = source->_CursorShape;
appearance->_CursorHeight = source->_CursorHeight;
appearance->_BackgroundImageAlignment = source->_BackgroundImageAlignment;
appearance->_RetroTerminalEffect = source->_RetroTerminalEffect;
appearance->_PixelShaderPath = source->_PixelShaderPath;
appearance->_IntenseTextStyle = source->_IntenseTextStyle;
appearance->_Opacity = source->_Opacity;
return appearance;
}

View File

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

View File

@ -6,16 +6,14 @@
#include "AzureCloudShellGenerator.h"
#include "LegacyProfileGeneratorNamespaces.h"
#include "../../types/inc/utils.hpp"
#include "../../inc/DefaultSettings.h"
#include "Utils.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::TerminalConnection;
std::wstring_view AzureCloudShellGenerator::GetNamespace()
std::wstring_view AzureCloudShellGenerator::GetNamespace() const noexcept
{
return AzureGeneratorNamespace;
}
@ -27,19 +25,14 @@ std::wstring_view AzureCloudShellGenerator::GetNamespace()
// - <none>
// Return Value:
// - 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())
{
auto azureCloudShellProfile{ CreateDefaultProfile(L"Azure Cloud Shell") };
azureCloudShellProfile.Commandline(L"Azure");
azureCloudShellProfile.StartingDirectory(DEFAULT_STARTING_DIRECTORY);
azureCloudShellProfile.DefaultAppearance().ColorSchemeName(L"Vintage");
azureCloudShellProfile.ConnectionType(AzureConnection::ConnectionType());
profiles.emplace_back(azureCloudShellProfile);
auto azureCloudShellProfile{ CreateDynamicProfile(L"Azure Cloud Shell") };
azureCloudShellProfile->StartingDirectory(winrt::hstring{ DEFAULT_STARTING_DIRECTORY });
azureCloudShellProfile->DefaultAppearance().ColorSchemeName(L"Vintage");
azureCloudShellProfile->ConnectionType(AzureConnection::ConnectionType());
profiles.emplace_back(std::move(azureCloudShellProfile));
}
return profiles;
}

View File

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

View File

@ -3,15 +3,12 @@
#include "pch.h"
#include "BaseVisualStudioGenerator.h"
#include "DefaultProfileUtils.h"
#include "DynamicProfileUtils.h"
using namespace 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,
// so cache them for use by both Visual Studio profile generators.
static const auto instances = VsSetupConfiguration::QueryInstances();
@ -25,27 +22,15 @@ std::vector<Profile> BaseVisualStudioGenerator::GenerateProfiles()
continue;
}
auto DevShell{ CreateProfile(GetProfileGuidSeed(instance)) };
DevShell.Name(GetProfileName(instance));
DevShell.Commandline(GetProfileCommandLine(instance));
DevShell.StartingDirectory(instance.GetInstallationPath());
DevShell.Icon(GetProfileIconPath());
profiles.emplace_back(DevShell);
const auto seed = GetProfileGuidSeed(instance);
const winrt::guid profileGuid{ ::Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID, gsl::as_bytes(gsl::make_span(seed))) };
auto profile = winrt::make_self<implementation::Profile>(profileGuid);
profile->Name(winrt::hstring{ GetProfileName(instance) });
profile->Commandline(winrt::hstring{ GetProfileCommandLine(instance) });
profile->StartingDirectory(winrt::hstring{ instance.GetInstallationPath() });
profile->Icon(winrt::hstring{ GetProfileIconPath() });
profiles.emplace_back(std::move(profile));
}
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 "VsSetupConfiguration.h"
namespace Microsoft::Terminal::Settings::Model
namespace winrt::Microsoft::Terminal::Settings::Model
{
class BaseVisualStudioGenerator : public IDynamicProfileGenerator
{
public:
// Inherited via IDynamicProfileGenerator
std::wstring_view GetNamespace() override = 0;
std::vector<winrt::Microsoft::Terminal::Settings::Model::Profile> GenerateProfiles() override;
void GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
protected:
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 GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance) 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 "GlobalAppSettings.h"
#include "TerminalWarnings.h"
#include "IDynamicProfileGenerator.h"
#include "Profile.h"
#include "ColorScheme.h"
// fwdecl unittest classes
namespace SettingsModelLocalTests
namespace winrt::Microsoft::Terminal::Settings::Model
{
class SerializationTests;
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()) {}
};
class IDynamicProfileGenerator;
}
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>
{
public:
CascadiaSettings();
explicit CascadiaSettings(const bool addDynamicProfiles);
CascadiaSettings(hstring json);
Model::CascadiaSettings Copy() const;
static Model::CascadiaSettings LoadDefaults();
static Model::CascadiaSettings LoadAll();
static Model::CascadiaSettings LoadUniversal();
Model::GlobalAppSettings GlobalSettings() const;
Windows::Foundation::Collections::IObservableVector<Model::Profile> AllProfiles() const noexcept;
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 SettingsPath();
static winrt::hstring DefaultSettingsPath();
static winrt::hstring ApplicationDisplayName();
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 FindProfile(const guid& profileGuid) const noexcept;
Model::Profile FindProfile(const winrt::guid& guid) const noexcept;
Model::ColorScheme GetColorSchemeForProfile(const Model::Profile& profile) const;
void UpdateColorSchemeReferences(const hstring oldName, const hstring newName);
Windows::Foundation::Collections::IVectorView<SettingsLoadWarnings> Warnings();
void ClearWarnings();
void AppendWarning(SettingsLoadWarnings warning);
Windows::Foundation::IReference<SettingsLoadErrors> GetLoadingError();
hstring GetSerializationErrorMessage();
void UpdateColorSchemeReferences(const winrt::hstring& oldName, const winrt::hstring& newName);
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);
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;
Windows::Foundation::Collections::IObservableVector<Model::DefaultTerminal> DefaultTerminals() const noexcept;
Model::DefaultTerminal CurrentDefaultTerminal() const noexcept;
void CurrentDefaultTerminal(Model::DefaultTerminal terminal);
winrt::Windows::Foundation::Collections::IObservableVector<Model::DefaultTerminal> DefaultTerminals() const noexcept;
Model::DefaultTerminal CurrentDefaultTerminal() noexcept;
void CurrentDefaultTerminal(const Model::DefaultTerminal& terminal);
private:
com_ptr<GlobalAppSettings> _globals;
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;
static const std::filesystem::path& _settingsPath();
Windows::Foundation::Collections::IObservableVector<Model::DefaultTerminal> _defaultTerminals;
Model::DefaultTerminal _currentDefaultTerminal;
winrt::com_ptr<implementation::Profile> _createNewProfile(const std::wstring_view& name) const;
std::vector<std::unique_ptr<::Microsoft::Terminal::Settings::Model::IDynamicProfileGenerator>> _profileGenerators;
void _resolveDefaultProfile() const;
std::string _userSettingsString;
Json::Value _userSettings;
Json::Value _defaultSettings;
winrt::com_ptr<Profile> _userDefaultProfileSettings{ nullptr };
void _validateSettings();
void _validateAllSchemesExist();
void _validateMediaResources();
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);
winrt::com_ptr<implementation::Profile> _FindMatchingProfile(const Json::Value& profileJson);
std::optional<uint32_t> _FindMatchingProfileIndex(const Json::Value& profileJson);
void _LayerOrCreateColorScheme(const Json::Value& schemeJson);
Json::Value _ParseUtf8JsonString(std::string_view fileData);
// load errors
winrt::Windows::Foundation::Collections::IVector<Model::SettingsLoadWarnings> _warnings;
winrt::Windows::Foundation::IReference<Model::SettingsLoadErrors> _loadError;
winrt::hstring _deserializationErrorMessage;
winrt::com_ptr<implementation::ColorScheme> _FindMatchingColorScheme(const Json::Value& schemeJson);
void _ParseJsonString(std::string_view fileData, const bool isDefaultSettings);
static const Json::Value& _GetProfilesJsonObject(const Json::Value& json);
static const Json::Value& _GetDisabledProfileSourcesJsonObject(const Json::Value& json);
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;
// defterm
Model::DefaultTerminal _currentDefaultTerminal{ nullptr };
};
}

View File

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

View File

@ -3,7 +3,6 @@
#include "pch.h"
#include "ColorScheme.h"
#include "DefaultSettings.h"
#include "../../types/inc/Utils.hpp"
#include "../../types/inc/colorTable.hpp"
#include "Utils.h"
@ -41,25 +40,16 @@ static constexpr std::array<std::string_view, 16> TableColors = {
"brightWhite"
};
ColorScheme::ColorScheme() :
ColorScheme(L"", DEFAULT_FOREGROUND, DEFAULT_BACKGROUND, DEFAULT_CURSOR_COLOR)
ColorScheme::ColorScheme() noexcept :
ColorScheme{ winrt::hstring{} }
{
Utils::InitializeCampbellColorTable(_table);
}
ColorScheme::ColorScheme(winrt::hstring name) :
ColorScheme(name, DEFAULT_FOREGROUND, DEFAULT_BACKGROUND, DEFAULT_CURSOR_COLOR)
{
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 }
ColorScheme::ColorScheme(const winrt::hstring& name) noexcept :
_Name{ name }
{
const auto table = Utils::CampbellColorTable();
std::copy_n(table.data(), table.size(), _table.data());
}
winrt::com_ptr<ColorScheme> ColorScheme::Copy() const
@ -79,30 +69,11 @@ winrt::com_ptr<ColorScheme> ColorScheme::Copy() const
// Arguments:
// - json: an object which should be a serialization of a ColorScheme object.
// 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)
{
auto result = winrt::make_self<ColorScheme>();
result->LayerJson(json);
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;
auto result = winrt::make_self<ColorScheme>(uninitialized_t{});
return result->_layerJson(json) ? result : nullptr;
}
// 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_
// be replaced.
// 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:
// <none>
void ColorScheme::LayerJson(const Json::Value& json)
// - Returns true if the given JSON was valid.
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, BackgroundKey, _Background);
JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _SelectionBackground);
JsonUtils::GetValueForKey(json, CursorColorKey, _CursorColor);
// Required fields
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:
@ -147,7 +124,7 @@ Json::Value ColorScheme::ToJson() const
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;
@ -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> result{ base::checked_cast<uint32_t>(_table.size()) };
std::transform(_table.begin(), _table.end(), result.begin(), [](til::color c) -> winrt::Microsoft::Terminal::Core::Color { return c; });
return result;
return winrt::com_array<Core::Color>{ _table };
}
// 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
// Return Value:
// - 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;
}
// 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
#include "../../inc/conattrs.hpp"
#include "inc/cppwinrt_utils.h"
#include "DefaultSettings.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
{
struct ColorScheme : ColorSchemeT<ColorScheme>
{
// A ColorScheme constructed with uninitialized_t
// leaves _table uninitialized.
struct uninitialized_t
{
};
public:
ColorScheme();
ColorScheme(hstring name);
ColorScheme(hstring name, til::color defaultFg, til::color defaultBg, til::color cursorColor);
ColorScheme() noexcept;
explicit ColorScheme(uninitialized_t) noexcept {}
explicit ColorScheme(const winrt::hstring& name) noexcept;
com_ptr<ColorScheme> Copy() const;
hstring ToString()
@ -55,29 +45,21 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
}
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;
static std::optional<std::wstring> GetNameFromJson(const Json::Value& json);
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);
com_array<Core::Color> Table() const noexcept;
void SetColorTableEntry(uint8_t index, const Core::Color& value) noexcept;
WINRT_PROPERTY(winrt::hstring, Name);
WINRT_TERMINAL_COLOR_PROPERTY(Foreground); // defined in constructor
WINRT_TERMINAL_COLOR_PROPERTY(Background); // defined in constructor
WINRT_TERMINAL_COLOR_PROPERTY(SelectionBackground); // defined in constructor
WINRT_TERMINAL_COLOR_PROPERTY(CursorColor); // defined in constructor
WINRT_PROPERTY(Core::Color, Foreground, static_cast<Core::Color>(DEFAULT_FOREGROUND));
WINRT_PROPERTY(Core::Color, Background, static_cast<Core::Color>(DEFAULT_BACKGROUND));
WINRT_PROPERTY(Core::Color, SelectionBackground, static_cast<Core::Color>(DEFAULT_FOREGROUND));
WINRT_PROPERTY(Core::Color, CursorColor, static_cast<Core::Color>(DEFAULT_CURSOR_COLOR));
private:
std::array<til::color, COLOR_TABLE_SIZE> _table;
bool _layerJson(const Json::Value& json);
friend class SettingsModelLocalTests::SettingsTests;
friend class SettingsModelLocalTests::ColorSchemeTests;
std::array<Core::Color, COLOR_TABLE_SIZE> _table;
};
}

View File

@ -2,7 +2,7 @@
// Licensed under the MIT license.
#include "pch.h"
#include "DefaultProfileUtils.h"
#include "DynamicProfileUtils.h"
#include "../../types/inc/utils.hpp"
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.
// Return Value:
// - 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,
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 });
const auto profileGuid = Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID, gsl::as_bytes(gsl::make_span(name)));
std::wstring iconPath{ PACKAGED_PROFILE_ICON_PATH };
iconPath.append(Microsoft::Console::Utils::GuidToString(profileGuid));
iconPath.append(PACKAGED_PROFILE_ICON_EXTENSION);
newProfile->Icon(winrt::hstring{ iconPath });
newProfile->Origin(winrt::Microsoft::Terminal::Settings::Model::OriginTag::Generated);
return *newProfile;
auto profile = winrt::make_self<winrt::Microsoft::Terminal::Settings::Model::implementation::Profile>(profileGuid);
profile->Name(winrt::hstring{ name });
profile->Icon(winrt::hstring{ iconPath });
return profile;
}

View File

@ -23,4 +23,4 @@ Author(s):
// uuidv5 properties: name format is UTF-16LE bytes
static constexpr GUID TERMINAL_PROFILE_NAMESPACE_GUID = { 0x2bde4a90, 0xd05f, 0x401c, { 0x94, 0x92, 0xe4, 0x8, 0x84, 0xea, 0xd1, 0xd8 } };
winrt::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::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
// 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) };
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.
// It's thus important that we first resolve them before generating temporary path.

View File

@ -1,11 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace Microsoft::Terminal::Settings::Model
namespace winrt::Microsoft::Terminal::Settings::Model
{
std::filesystem::path GetBaseSettingsPath();
std::string ReadUTF8File(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 WriteUTF8FileAtomic(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);
}

View File

@ -4,6 +4,7 @@
#include "pch.h"
#include "FontConfig.h"
#include "FontConfig.g.cpp"
#include "TerminalSettingsSerializationHelpers.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)) };
fontInfo->_FontFace = source->_FontFace;

View File

@ -32,7 +32,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{
public:
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;
void LayerJson(const Json::Value& json);
bool HasAnyOptionSet() const;

View File

@ -4,9 +4,7 @@
#include "pch.h"
#include "GlobalAppSettings.h"
#include "../../types/inc/Utils.hpp"
#include "../../inc/DefaultSettings.h"
#include "JsonUtils.h"
#include "TerminalSettingsSerializationHelpers.h"
#include "KeyChordSerialization.h"
#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 AlwaysShowNotificationIconKey{ "alwaysShowNotificationIcon" };
static constexpr std::string_view MinimizeToNotificationAreaKey{ "minimizeToNotificationArea" };
static constexpr std::string_view DisabledProfileSourcesKey{ "disabledProfileSources" };
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 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:
// - Copies any extraneous data from the parent before completing a CreateChild call
// Arguments:
@ -88,13 +67,17 @@ GlobalAppSettings::GlobalAppSettings() :
// - <none>
void GlobalAppSettings::_FinalizeInheritance()
{
// Globals only ever has 1 parent
FAIL_FAST_IF(_parents.size() > 1);
for (auto parent : _parents)
for (const auto& parent : _parents)
{
_actionMap->InsertParent(parent->_actionMap);
_keybindingsWarnings = std::move(parent->_keybindingsWarnings);
_colorSchemes = std::move(parent->_colorSchemes);
_keybindingsWarnings.insert(_keybindingsWarnings.end(), parent->_keybindingsWarnings.begin(), parent->_keybindingsWarnings.end());
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->_MinimizeToNotificationArea = _MinimizeToNotificationArea;
globals->_AlwaysShowNotificationIcon = _AlwaysShowNotificationIcon;
globals->_DisabledProfileSources = _DisabledProfileSources;
globals->_UnparsedDefaultProfile = _UnparsedDefaultProfile;
globals->_validDefaultProfile = _validDefaultProfile;
globals->_defaultProfile = _defaultProfile;
globals->_actionMap = _actionMap->Copy();
std::copy(_keybindingsWarnings.begin(), _keybindingsWarnings.end(), std::back_inserter(globals->_keybindingsWarnings));
globals->_keybindingsWarnings = _keybindingsWarnings;
if (_colorSchemes)
{
@ -153,9 +136,7 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::Copy() const
}
}
// Globals only ever has 1 parent
FAIL_FAST_IF(_parents.size() > 1);
for (auto parent : _parents)
for (const auto& parent : _parents)
{
globals->InsertParent(parent->Copy());
}
@ -168,69 +149,18 @@ winrt::Windows::Foundation::Collections::IMapView<winrt::hstring, winrt::Microso
}
#pragma region DefaultProfile
void GlobalAppSettings::DefaultProfile(const winrt::guid& defaultProfile) noexcept
{
_validDefaultProfile = true;
_defaultProfile = defaultProfile;
_UnparsedDefaultProfile = Utils::GuidToString(defaultProfile);
}
winrt::guid GlobalAppSettings::DefaultProfile() const
{
// If we have an unresolved default profile, we should likely explode.
THROW_HR_IF(E_INVALIDARG, !_validDefaultProfile);
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
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)
{
// _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, AlwaysShowTabsKey, _AlwaysShowTabs);
JsonUtils::GetValueForKey(json, ConfirmCloseAllKey, _ConfirmCloseAllTabs);
JsonUtils::GetValueForKey(json, InitialRowsKey, _InitialRows);
JsonUtils::GetValueForKey(json, InitialColsKey, _InitialCols);
JsonUtils::GetValueForKey(json, InitialPositionKey, _InitialPosition);
JsonUtils::GetValueForKey(json, CenterOnLaunchKey, _CenterOnLaunch);
JsonUtils::GetValueForKey(json, ShowTitleInTitlebarKey, _ShowTitleInTitlebar);
JsonUtils::GetValueForKey(json, ShowTabsInTitlebarKey, _ShowTabsInTitlebar);
JsonUtils::GetValueForKey(json, WordDelimitersKey, _WordDelimiters);
JsonUtils::GetValueForKey(json, CopyOnSelectKey, _CopyOnSelect);
JsonUtils::GetValueForKey(json, InputServiceWarningKey, _InputServiceWarning);
JsonUtils::GetValueForKey(json, CopyFormattingKey, _CopyFormatting);
JsonUtils::GetValueForKey(json, WarnAboutLargePasteKey, _WarnAboutLargePaste);
JsonUtils::GetValueForKey(json, WarnAboutMultiLinePasteKey, _WarnAboutMultiLinePaste);
JsonUtils::GetValueForKey(json, FirstWindowPreferenceKey, _FirstWindowPreference);
JsonUtils::GetValueForKey(json, LaunchModeKey, _LaunchMode);
JsonUtils::GetValueForKey(json, LanguageKey, _Language);
JsonUtils::GetValueForKey(json, ThemeKey, _Theme);
JsonUtils::GetValueForKey(json, TabWidthModeKey, _TabWidthMode);
JsonUtils::GetValueForKey(json, UseAcrylicInTabRowKey, _UseAcrylicInTabRow);
JsonUtils::GetValueForKey(json, SnapToGridOnResizeKey, _SnapToGridOnResize);
// GetValueForKey will only override the current value if the key exists
JsonUtils::GetValueForKey(json, DebugFeaturesKey, _DebugFeaturesEnabled);
JsonUtils::GetValueForKey(json, ForceFullRepaintRenderingKey, _ForceFullRepaintRendering);
JsonUtils::GetValueForKey(json, SoftwareRenderingKey, _SoftwareRendering);
JsonUtils::GetValueForKey(json, ForceVTInputKey, _ForceVTInput);
JsonUtils::GetValueForKey(json, EnableStartupTaskKey, _StartOnUserLogin);
JsonUtils::GetValueForKey(json, AlwaysOnTopKey, _AlwaysOnTop);
// GH#8076 - when adding enum values to this key, we also changed it from
// "useTabSwitcher" to "tabSwitcherMode". Continue supporting
// "useTabSwitcher", but prefer "tabSwitcherMode"
JsonUtils::GetValueForKey(json, LegacyUseTabSwitcherModeKey, _TabSwitcherMode);
JsonUtils::GetValueForKey(json, TabSwitcherModeKey, _TabSwitcherMode);
JsonUtils::GetValueForKey(json, DisableAnimationsKey, _DisableAnimations);
JsonUtils::GetValueForKey(json, StartupActionsKey, _StartupActions);
JsonUtils::GetValueForKey(json, FocusFollowMouseKey, _FocusFollowMouse);
JsonUtils::GetValueForKey(json, WindowingBehaviorKey, _WindowingBehavior);
JsonUtils::GetValueForKey(json, TrimBlockSelectionKey, _TrimBlockSelection);
JsonUtils::GetValueForKey(json, DetectURLsKey, _DetectURLs);
JsonUtils::GetValueForKey(json, MinimizeToNotificationAreaKey, _MinimizeToNotificationArea);
JsonUtils::GetValueForKey(json, AlwaysShowNotificationIconKey, _AlwaysShowNotificationIcon);
JsonUtils::GetValueForKey(json, DisabledProfileSourcesKey, _DisabledProfileSources);
// This is a helper lambda to get the keybindings and commands out of both
// and array of objects. We'll use this twice, once on the legacy
// `keybindings` key, and again on the newer `bindings` key.
auto parseBindings = [this, &json](auto jsonKey) {
static constexpr std::array bindingsKeys{ LegacyKeybindingsKey, ActionsKey };
for (const auto& jsonKey : bindingsKeys)
{
if (auto bindings{ json[JsonKey(jsonKey)] })
{
auto warnings = _actionMap->LayerJson(bindings);
@ -351,9 +242,7 @@ void GlobalAppSettings::LayerJson(const Json::Value& json)
// list of warnings.
_keybindingsWarnings.insert(_keybindingsWarnings.end(), warnings.begin(), warnings.end());
}
};
parseBindings(LegacyKeybindingsKey);
parseBindings(ActionsKey);
}
}
// Method Description:
@ -381,7 +270,7 @@ void GlobalAppSettings::RemoveColorScheme(hstring schemeName)
// - <none>
// Return Value:
// - <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;
}
@ -433,7 +322,8 @@ Json::Value GlobalAppSettings::ToJson() const
JsonUtils::SetValueForKey(json, TrimBlockSelectionKey, _TrimBlockSelection);
JsonUtils::SetValueForKey(json, DetectURLsKey, _DetectURLs);
JsonUtils::SetValueForKey(json, MinimizeToNotificationAreaKey, _MinimizeToNotificationArea);
JsonUtils::SetValueForKey(json, AlwaysShowNotificationIconKey, _AlwaysShowNotificationIcon);
JsonUtils::SetValueForKey(json, AlwaysShowNotificationIconKey, _AlwaysShowNotificationIcon);
JsonUtils::SetValueForKey(json, DisabledProfileSourcesKey, _DisabledProfileSources);
// clang-format on
json[JsonKey(ActionsKey)] = _actionMap->ToJson();

View File

@ -34,7 +34,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
struct GlobalAppSettings : GlobalAppSettingsT<GlobalAppSettings>, IInheritable<GlobalAppSettings>
{
public:
GlobalAppSettings();
void _FinalizeInheritance() override;
com_ptr<GlobalAppSettings> Copy() const;
@ -49,16 +48,12 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
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
// by higher layers in the app.
// This DefaultProfile() setter is called by CascadiaSettings,
// when it parses UnparsedDefaultProfile in _finalizeSettings().
void DefaultProfile(const guid& defaultProfile) noexcept;
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
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, SoftwareRendering, 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, AlwaysOnTop, false);
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, MinimizeToNotificationArea, 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:
guid _defaultProfile;
std::optional<hstring> _UnparsedDefaultProfile{ std::nullopt };
bool _validDefaultProfile;
#ifdef NDEBUG
static constexpr bool debugFeaturesDefault{ false };
#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;
Windows::Foundation::Collections::IMap<hstring, Model::ColorScheme> _colorSchemes;
std::optional<hstring> _getUnparsedDefaultProfileImpl() const;
static bool _getDefaultDebugFeaturesValue();
friend class SettingsModelLocalTests::DeserializationTests;
friend class SettingsModelLocalTests::ColorSchemeTests;
Windows::Foundation::Collections::IMap<winrt::hstring, Model::ColorScheme> _colorSchemes{ winrt::single_threaded_map<winrt::hstring, Model::ColorScheme>() };
};
}

View File

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

View File

@ -20,18 +20,16 @@ Author(s):
--*/
#pragma once
#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)
{
_parents.push_back(parent);
_parents.emplace_back(std::move(parent));
}
void InsertParent(size_t index, com_ptr<T> parent)
{
auto pos{ _parents.begin() + index };
_parents.insert(pos, parent);
_parents.emplace(pos, std::move(parent));
}
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)
{
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)

View File

@ -44,7 +44,7 @@
<ClInclude Include="Command.h">
<DependentUpon>Command.idl</DependentUpon>
</ClInclude>
<ClInclude Include="DefaultProfileUtils.h" />
<ClInclude Include="DynamicProfileUtils.h" />
<ClInclude Include="FileUtils.h" />
<ClInclude Include="GlobalAppSettings.h">
<DependentUpon>GlobalAppSettings.idl</DependentUpon>
@ -123,7 +123,7 @@
<ClCompile Include="Command.cpp">
<DependentUpon>Command.idl</DependentUpon>
</ClCompile>
<ClCompile Include="DefaultProfileUtils.cpp" />
<ClCompile Include="DynamicProfileUtils.cpp" />
<ClCompile Include="FileUtils.cpp" />
<ClCompile Include="GlobalAppSettings.cpp">
<DependentUpon>GlobalAppSettings.idl</DependentUpon>
@ -254,15 +254,15 @@
we can include in the code directly. This way, we don't need to worry about
failing to load the default settings at runtime. -->
<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>
<!-- A different set of defaults for Universal variant -->
<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>
<!-- Same as above, but for the default settings.json template -->
<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>
<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')" />

View File

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

View File

@ -8,7 +8,7 @@
#include "../../types/inc/utils.hpp"
#include "../../inc/DefaultSettings.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.
#include <winrt/Windows.ApplicationModel.h>
@ -289,7 +289,7 @@ static std::vector<PowerShellInstance> _collectPowerShellInstances()
// - PowerShell Core 574e775e-4f2a-5b96-ac1e-a2962a402336
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;
}
@ -300,34 +300,33 @@ std::wstring_view PowershellCoreProfileGenerator::GetNamespace()
// - <none>
// Return Value:
// - 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)
{
const auto name = psI.Name();
auto profile{ CreateDefaultProfile(name) };
profile.Commandline(psI.executablePath.wstring());
profile.StartingDirectory(DEFAULT_STARTING_DIRECTORY);
profile.DefaultAppearance().ColorSchemeName(L"Campbell");
auto profile{ CreateDynamicProfile(name) };
profile->Commandline(winrt::hstring{ psI.executablePath.native() });
profile->StartingDirectory(winrt::hstring{ DEFAULT_STARTING_DIRECTORY });
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));
}
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:

View File

@ -18,17 +18,14 @@ Author(s):
#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:
static const std::wstring_view GetPreferredPowershellProfileName();
PowershellCoreProfileGenerator() = default;
~PowershellCoreProfileGenerator() = default;
std::wstring_view GetNamespace() override;
std::vector<winrt::Microsoft::Terminal::Settings::Model::Profile> GenerateProfiles() override;
std::wstring_view GetNamespace() const noexcept override;
void GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
};
};

View File

@ -5,9 +5,7 @@
#include "Profile.h"
#include "JsonUtils.h"
#include "../../types/inc/Utils.hpp"
#include <DefaultSettings.h>
#include "LegacyProfileGeneratorNamespaces.h"
#include "TerminalSettingsSerializationHelpers.h"
#include "AppearanceConfig.h"
#include "FontConfig.h"
@ -22,6 +20,7 @@ using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::Foundation;
using namespace ::Microsoft::Console;
static constexpr std::string_view UpdatesKey{ "updates" };
static constexpr std::string_view NameKey{ "name" };
static constexpr std::string_view GuidKey{ "guid" };
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 UnfocusedAppearanceKey{ "unfocusedAppearance" };
static constexpr std::wstring_view DesktopWallpaperEnum{ L"desktopWallpaper" };
Profile::Profile()
{
}
Profile::Profile(guid guid) :
Profile::Profile(guid guid) noexcept :
_Guid(guid)
{
}
@ -79,61 +72,81 @@ void Profile::DeleteUnfocusedAppearance()
_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;
profile->_Guid = source->_Guid;
profile->_Name = source->_Name;
profile->_Source = source->_Source;
profile->_Hidden = source->_Hidden;
profile->_Icon = source->_Icon;
profile->_CloseOnExit = source->_CloseOnExit;
profile->_TabTitle = source->_TabTitle;
profile->_TabColor = source->_TabColor;
profile->_SuppressApplicationTitle = source->_SuppressApplicationTitle;
profile->_UseAcrylic = source->_UseAcrylic;
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;
// A profile and its IInheritable parents basically behave like a directed acyclic graph (DAG).
// Cloning a DAG requires us to prevent the duplication of already cloned nodes (or profiles).
// This is where "visited" comes into play: It contains previously cloned sub-graphs of profiles and "interns" them.
winrt::com_ptr<Profile>& Profile::CopyInheritanceGraph(std::unordered_map<const Profile*, winrt::com_ptr<Profile>>& visited) const
{
// The operator[] is usually considered to suck, because it implicitly creates entries
// in maps/sets if the entry doesn't exist yet, which is often an unwanted behavior.
// But in this case it's just perfect. We want to return a reference to the profile if it's
// been created before and create a cloned profile if it doesn't. With the operator[]
// we can just assign the returned reference allowing us to write some lean code.
auto& clone = visited[this];
// Copy over the font info
const auto weakRefToProfile = weak_ref<Model::Profile>(*profile);
winrt::com_ptr<FontConfig> sourceFontInfoImpl;
sourceFontInfoImpl.copy_from(winrt::get_self<FontConfig>(source->_FontInfo));
auto copiedFontInfo = FontConfig::CopyFontInfo(sourceFontInfoImpl, weakRefToProfile);
profile->_FontInfo = *copiedFontInfo;
if (!clone)
{
clone = CopySettings();
CopyInheritanceGraphs(visited, _parents, clone->_parents);
clone->_FinalizeInheritance();
}
// Copy over the appearance
winrt::com_ptr<AppearanceConfig> sourceDefaultAppearanceImpl;
sourceDefaultAppearanceImpl.copy_from(winrt::get_self<AppearanceConfig>(source->_DefaultAppearance));
auto copiedDefaultAppearance = AppearanceConfig::CopyAppearance(sourceDefaultAppearanceImpl, weakRefToProfile);
profile->_DefaultAppearance = *copiedDefaultAppearance;
return clone;
}
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 };
if (source->_UnfocusedAppearance.value() != nullptr)
if (*_UnfocusedAppearance)
{
// Copy over the unfocused appearance
winrt::com_ptr<AppearanceConfig> sourceUnfocusedAppearanceImpl;
sourceUnfocusedAppearanceImpl.copy_from(winrt::get_self<AppearanceConfig>(source->_UnfocusedAppearance.value()));
auto copiedUnfocusedAppearance = AppearanceConfig::CopyAppearance(sourceUnfocusedAppearanceImpl, weakRefToProfile);
// Make sure to add the default appearance as a parent
copiedUnfocusedAppearance->InsertParent(copiedDefaultAppearance);
unfocused = *copiedUnfocusedAppearance;
const auto appearance = AppearanceConfig::CopyAppearance(winrt::get_self<AppearanceConfig>(*_UnfocusedAppearance), weakProfile);
appearance->InsertParent(defaultAppearance);
unfocused = *appearance;
}
profile->_UnfocusedAppearance = unfocused;
}
@ -141,104 +154,6 @@ winrt::com_ptr<Profile> Profile::CopySettings(winrt::com_ptr<Profile> source)
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:
// - Create a new instance of this class from a serialized JsonObject.
// Arguments:
@ -252,71 +167,6 @@ winrt::com_ptr<winrt::Microsoft::Terminal::Settings::Model::implementation::Prof
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:
// - 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
@ -341,6 +191,7 @@ void Profile::LayerJson(const Json::Value& json)
// Profile-specific Settings
JsonUtils::GetValueForKey(json, NameKey, _Name);
JsonUtils::GetValueForKey(json, UpdatesKey, _Updates);
JsonUtils::GetValueForKey(json, GuidKey, _Guid);
JsonUtils::GetValueForKey(json, HiddenKey, _Hidden);
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());
}
// 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:
// - Generates a unique guid for a profile, given the name. For an given name, will always return the same GUID.
// Arguments:
// - name: The name to generate a unique GUID from
// Return Value:
// - 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
// 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))) };
}
// 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:
// - Create a new serialized JsonObject from an instance of this class
// Arguments:

View File

@ -76,8 +76,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
struct Profile : ProfileT<Profile>, IInheritable<Profile>
{
public:
Profile();
Profile(guid guid);
Profile() noexcept = default;
Profile(guid guid) noexcept;
void CreateUnfocusedAppearance();
void DeleteUnfocusedAppearance();
@ -87,19 +87,15 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
return Name();
}
static com_ptr<Profile> CloneInheritanceGraph(com_ptr<Profile> oldProfile, com_ptr<Profile> newProfile, std::unordered_map<void*, com_ptr<Profile>>& visited);
static com_ptr<Profile> CopySettings(com_ptr<Profile> source);
static void InsertParentHelper(com_ptr<Profile> child, com_ptr<Profile> parent, std::optional<size_t> index = std::nullopt);
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);
winrt::com_ptr<Profile>& CopyInheritanceGraph(std::unordered_map<const Profile*, winrt::com_ptr<Profile>>& visited) const;
winrt::com_ptr<Profile> CopySettings() const;
Json::Value GenerateStub() const;
static com_ptr<Profile> FromJson(const Json::Value& json);
bool ShouldBeLayered(const Json::Value& json) const;
void LayerJson(const Json::Value& json);
static bool IsDynamicProfileObject(const Json::Value& json);
Json::Value ToJson() const;
hstring EvaluatedStartingDirectory() const;
static guid GetGuidOrGenerateForJson(const Json::Value& json) noexcept;
Model::IAppearanceConfig DefaultAppearance();
Model::FontConfig FontInfo();
@ -109,6 +105,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
WINRT_PROPERTY(bool, Deleted, false);
WINRT_PROPERTY(OriginTag, Origin, OriginTag::None);
WINRT_PROPERTY(guid, Updates);
INHERITABLE_SETTING(Model::Profile, guid, Guid, _GenerateGuidForProfile(Name(), Source()));
INHERITABLE_SETTING(Model::Profile, hstring, Name, L"Default");
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, 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, 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)) };
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::ProfileTests;

View File

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

View File

@ -8,20 +8,19 @@ namespace Microsoft.Terminal.Settings.Model
enum SettingsLoadWarnings
{
MissingDefaultProfile = 0,
DuplicateProfile = 1,
UnknownColorScheme = 2,
InvalidBackgroundImage = 3,
InvalidIcon = 4,
AtLeastOneKeybindingWarning = 5,
TooManyKeysForChord = 6,
MissingRequiredParameter = 7,
LegacyGlobalsProperty = 8,
FailedToParseCommandJson = 9,
FailedToWriteToSettings = 10,
InvalidColorSchemeInCmd = 11,
InvalidSplitSize = 12,
FailedToParseStartupActions = 13,
FailedToParseSubCommands = 14,
DuplicateProfile,
UnknownColorScheme,
InvalidBackgroundImage,
InvalidIcon,
AtLeastOneKeybindingWarning,
TooManyKeysForChord,
MissingRequiredParameter,
FailedToParseCommandJson,
FailedToWriteToSettings,
InvalidColorSchemeInCmd,
InvalidSplitSize,
FailedToParseStartupActions,
FailedToParseSubCommands,
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 "VsDevCmdGenerator.h"
using namespace Microsoft::Terminal::Settings::Model;
using namespace winrt::Microsoft::Terminal::Settings::Model;
std::wstring VsDevCmdGenerator::GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const
{

View File

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

View File

@ -5,7 +5,7 @@
#include "VsDevShellGenerator.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
{

View File

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

View File

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

View File

@ -17,7 +17,7 @@ Author(s):
#include "Setup.Configuration.h"
namespace Microsoft::Terminal::Settings::Model
namespace winrt::Microsoft::Terminal::Settings::Model
{
/// <summary>
/// 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 "LegacyProfileGeneratorNamespaces.h"
#include "../../types/inc/utils.hpp"
#include "../../inc/DefaultSettings.h"
#include "Utils.h"
#include <io.h>
#include <fcntl.h>
#include "DefaultProfileUtils.h"
#include "DynamicProfileUtils.h"
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
// - Ubuntu-18.04 c6eaf9f4-32a7-5fdc-b5cf-066e8a4b1e40
std::wstring_view WslDistroGenerator::GetNamespace()
std::wstring_view WslDistroGenerator::GetNamespace() const noexcept
{
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:
// - Enumerates all the installed WSL distros to create profiles for them.
// Arguments:
// - <none>
// Return Value:
// - 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 writePipe;
SECURITY_ATTRIBUTES sa{ sizeof(sa), nullptr, true };
@ -77,7 +83,7 @@ static std::vector<Profile> legacyGenerate()
break;
case WAIT_ABANDONED:
case WAIT_TIMEOUT:
return profiles;
return;
case WAIT_FAILED:
THROW_LAST_ERROR();
default:
@ -90,7 +96,7 @@ static std::vector<Profile> legacyGenerate()
}
else if (exitCode != 0)
{
return profiles;
return;
}
DWORD bytesAvailable;
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::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.
// 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);
}
auto WSLDistro{ CreateDefaultProfile(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);
profiles.emplace_back(makeProfile(distName));
}
}
return profiles;
}
// Function Description:
@ -151,9 +150,8 @@ static std::vector<Profile> legacyGenerate()
// - names: a list of distro names to turn into profiles
// Return Value:
// - 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)
{
if (til::starts_with(distName, DockerDistributionPrefix))
@ -163,15 +161,8 @@ static std::vector<Profile> namesToProfiles(const std::vector<std::wstring>& nam
continue;
}
auto WSLDistro{ CreateDefaultProfile(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);
profiles.emplace_back(makeProfile(distName));
}
return profiles;
}
// Function Description:
@ -304,7 +295,7 @@ static bool getWslNames(const wil::unique_hkey& wslRootKey,
// - <none>
// Return Value:
// - 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() };
if (wslRootKey)
@ -316,10 +307,10 @@ std::vector<Profile> WslDistroGenerator::GenerateProfiles()
names.reserve(guidStrings.size());
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
#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:
WslDistroGenerator() = default;
~WslDistroGenerator() = default;
std::wstring_view GetNamespace() override;
std::vector<winrt::Microsoft::Terminal::Settings::Model::Profile> GenerateProfiles() override;
std::wstring_view GetNamespace() const noexcept override;
void GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const 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": "%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.
// "defaultProfile" is filled in by CascadiaSettings, depending on
// what dynamic profiles are present during the first launch.
"copyOnSelect": false,
// If enabled, formatted data is also copied to your clipboard
"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":
{
"defaults":
{
// Put settings here that you want to apply to all profiles.
},
"list":
[
{
// Make changes here to the powershell.exe profile.
"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
"name": "Windows PowerShell",
"commandline": "powershell.exe",
"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}",
"name": "%COMMAND_PROMPT_LOCALIZED_NAME%",
"commandline": "cmd.exe",
"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":
[
// 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": "paste", "keys": "ctrl+v" },
// Press Ctrl+Shift+F to open the search box
{ "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" }
]
}

View File

@ -379,7 +379,6 @@ namespace ControlUnitTests
// For this test, don't use any modifiers
const auto modifiers = ControlKeyStates();
const Control::MouseButtonState leftMouseDown{ Control::MouseButtonState::IsLeftButtonDown };
const Control::MouseButtonState noMouseDown{};
const til::size fontSize{ 9, 21 };
@ -530,7 +529,6 @@ namespace ControlUnitTests
// For this test, don't use any modifiers
const auto modifiers = ControlKeyStates();
const Control::MouseButtonState leftMouseDown{ Control::MouseButtonState::IsLeftButtonDown };
const Control::MouseButtonState noMouseDown{};
const til::size fontSize{ 9, 21 };
@ -742,7 +740,6 @@ namespace ControlUnitTests
// For this test, don't use any modifiers
const auto modifiers = ControlKeyStates();
const Control::MouseButtonState leftMouseDown{ Control::MouseButtonState::IsLeftButtonDown };
const Control::MouseButtonState noMouseDown{};
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 ======================== -->
<ItemGroup>
<ClCompile Include="ColorHelperTests.cpp" />
<ClCompile Include="JsonTests.cpp" />
<ClCompile Include="JsonUtilsTests.cpp" />
<ClCompile Include="DynamicProfileTests.cpp" />
<ClCompile Include="precomp.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</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_COLS = 120;
const std::wstring DEFAULT_PADDING{ L"8, 8, 8, 8" };
const std::wstring DEFAULT_STARTING_DIRECTORY{ L"%USERPROFILE%" };
constexpr std::wstring_view DEFAULT_PADDING{ L"8, 8, 8, 8" };
constexpr std::wstring_view DEFAULT_STARTING_DIRECTORY{ L"%USERPROFILE%" };
constexpr auto DEFAULT_CURSOR_COLOR = COLOR_WHITE;
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);
}
@ -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;
ret.R = r;
ret.G = g;
ret.B = b;
ret.A = a;
return ret;
return { a, r, g, b };
}
#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;
ret.R = r;
ret.G = g;
ret.B = b;
ret.A = a;
return ret;
return { r, g, b, a };
}
#endif

View File

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

View File

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

View File

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