Make Global and Profile settings inheritable (#7923)
## Summary of the Pull Request Introduces `IInheritable` as an interface that helps move cascading settings into the Terminal Settings Model. `GlobalAppSettings` and `Profile` both are now `IInheritable`. `CascadiaSettings` was updated to `CreateChild()` for globals and each profile when we are loading the JSON data. IInheritable does most of the heavy lifting. It introduces a two new macros and the interface. The macros help implement the fallback functionality for nullable and non-nullable settings. ## References #7876 - Spec Addendum #6904 - TSM Spec #1564 - Settings UI #7876 - `Copy()` needs to be updated to include _parent
This commit is contained in:
parent
7e8600147e
commit
b603929214
|
@ -21,6 +21,7 @@ ICustom
|
||||||
IDialog
|
IDialog
|
||||||
IDirect
|
IDirect
|
||||||
IExplorer
|
IExplorer
|
||||||
|
IInheritable
|
||||||
IMap
|
IMap
|
||||||
IObject
|
IObject
|
||||||
IStorage
|
IStorage
|
||||||
|
|
|
@ -81,6 +81,7 @@ namespace SettingsModelLocalTests
|
||||||
TEST_METHOD(TestRebindNestedCommand);
|
TEST_METHOD(TestRebindNestedCommand);
|
||||||
|
|
||||||
TEST_METHOD(TestCopy);
|
TEST_METHOD(TestCopy);
|
||||||
|
TEST_METHOD(TestCloneInheritanceTree);
|
||||||
|
|
||||||
TEST_CLASS_SETUP(ClassSetup)
|
TEST_CLASS_SETUP(ClassSetup)
|
||||||
{
|
{
|
||||||
|
@ -831,7 +832,7 @@ namespace SettingsModelLocalTests
|
||||||
const auto serialized0Profile = profile0->GenerateStub();
|
const auto serialized0Profile = profile0->GenerateStub();
|
||||||
const auto profile1 = implementation::Profile::FromJson(serialized0Profile);
|
const auto profile1 = implementation::Profile::FromJson(serialized0Profile);
|
||||||
VERIFY_IS_FALSE(profile0->HasGuid());
|
VERIFY_IS_FALSE(profile0->HasGuid());
|
||||||
VERIFY_IS_FALSE(profile1->HasGuid());
|
VERIFY_IS_TRUE(profile1->HasGuid());
|
||||||
|
|
||||||
auto settings = winrt::make_self<implementation::CascadiaSettings>();
|
auto settings = winrt::make_self<implementation::CascadiaSettings>();
|
||||||
settings->_profiles.Append(*profile1);
|
settings->_profiles.Append(*profile1);
|
||||||
|
@ -1355,6 +1356,7 @@ namespace SettingsModelLocalTests
|
||||||
const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-6666-49a3-80bd-e8fdd045185c}") };
|
const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-6666-49a3-80bd-e8fdd045185c}") };
|
||||||
const winrt::guid guid2{ ::Microsoft::Console::Utils::GuidFromString(L"{2C4DE342-38B7-51CF-B940-2309A097F518}") };
|
const winrt::guid guid2{ ::Microsoft::Console::Utils::GuidFromString(L"{2C4DE342-38B7-51CF-B940-2309A097F518}") };
|
||||||
const winrt::guid fakeGuid{ ::Microsoft::Console::Utils::GuidFromString(L"{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}") };
|
const winrt::guid fakeGuid{ ::Microsoft::Console::Utils::GuidFromString(L"{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}") };
|
||||||
|
const winrt::guid autogeneratedGuid{ implementation::Profile::_GenerateGuidForProfile(name3, L"") };
|
||||||
const std::optional<winrt::guid> badGuid{};
|
const std::optional<winrt::guid> badGuid{};
|
||||||
|
|
||||||
VerifyParseSucceeded(settings0String);
|
VerifyParseSucceeded(settings0String);
|
||||||
|
@ -1366,7 +1368,7 @@ namespace SettingsModelLocalTests
|
||||||
VERIFY_ARE_EQUAL(guid0, settings->_GetProfileGuidByName(name0));
|
VERIFY_ARE_EQUAL(guid0, settings->_GetProfileGuidByName(name0));
|
||||||
VERIFY_ARE_EQUAL(guid1, settings->_GetProfileGuidByName(name1));
|
VERIFY_ARE_EQUAL(guid1, settings->_GetProfileGuidByName(name1));
|
||||||
VERIFY_ARE_EQUAL(guid2, settings->_GetProfileGuidByName(name2));
|
VERIFY_ARE_EQUAL(guid2, settings->_GetProfileGuidByName(name2));
|
||||||
VERIFY_ARE_EQUAL(badGuid, settings->_GetProfileGuidByName(name3));
|
VERIFY_ARE_EQUAL(autogeneratedGuid, settings->_GetProfileGuidByName(name3));
|
||||||
VERIFY_ARE_EQUAL(badGuid, settings->_GetProfileGuidByName(badName));
|
VERIFY_ARE_EQUAL(badGuid, settings->_GetProfileGuidByName(badName));
|
||||||
|
|
||||||
auto prof0{ settings->FindProfile(guid0) };
|
auto prof0{ settings->FindProfile(guid0) };
|
||||||
|
@ -1521,9 +1523,9 @@ namespace SettingsModelLocalTests
|
||||||
{
|
{
|
||||||
auto settings = winrt::make_self<implementation::CascadiaSettings>(false);
|
auto settings = winrt::make_self<implementation::CascadiaSettings>(false);
|
||||||
settings->_ParseJsonString(settings0String, false);
|
settings->_ParseJsonString(settings0String, false);
|
||||||
VERIFY_IS_TRUE(settings->_userDefaultProfileSettings == Json::Value::null);
|
VERIFY_IS_NULL(settings->_userDefaultProfileSettings);
|
||||||
settings->_ApplyDefaultsFromUserSettings();
|
settings->_ApplyDefaultsFromUserSettings();
|
||||||
VERIFY_IS_FALSE(settings->_userDefaultProfileSettings == Json::Value::null);
|
VERIFY_IS_NOT_NULL(settings->_userDefaultProfileSettings);
|
||||||
settings->LayerJson(settings->_userSettings);
|
settings->LayerJson(settings->_userSettings);
|
||||||
|
|
||||||
VERIFY_ARE_EQUAL(guid1String, settings->_globals->UnparsedDefaultProfile());
|
VERIFY_ARE_EQUAL(guid1String, settings->_globals->UnparsedDefaultProfile());
|
||||||
|
@ -1573,9 +1575,9 @@ namespace SettingsModelLocalTests
|
||||||
VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
|
VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
|
||||||
|
|
||||||
settings->_ParseJsonString(settings0String, false);
|
settings->_ParseJsonString(settings0String, false);
|
||||||
VERIFY_IS_TRUE(settings->_userDefaultProfileSettings == Json::Value::null);
|
VERIFY_IS_NULL(settings->_userDefaultProfileSettings);
|
||||||
settings->_ApplyDefaultsFromUserSettings();
|
settings->_ApplyDefaultsFromUserSettings();
|
||||||
VERIFY_IS_FALSE(settings->_userDefaultProfileSettings == Json::Value::null);
|
VERIFY_IS_NOT_NULL(settings->_userDefaultProfileSettings);
|
||||||
|
|
||||||
Log::Comment(NoThrowString().Format(
|
Log::Comment(NoThrowString().Format(
|
||||||
L"Ensure that cmd and powershell don't get their GUIDs overwritten"));
|
L"Ensure that cmd and powershell don't get their GUIDs overwritten"));
|
||||||
|
@ -1692,10 +1694,6 @@ namespace SettingsModelLocalTests
|
||||||
VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.1", settings->_profiles.GetAt(1).Source());
|
VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.1", settings->_profiles.GetAt(1).Source());
|
||||||
VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.1", settings->_profiles.GetAt(2).Source());
|
VERIFY_ARE_EQUAL(L"Terminal.App.UnitTest.1", settings->_profiles.GetAt(2).Source());
|
||||||
|
|
||||||
VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
|
|
||||||
VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
|
|
||||||
VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid());
|
|
||||||
|
|
||||||
VERIFY_ARE_EQUAL(guid1, settings->_profiles.GetAt(0).Guid());
|
VERIFY_ARE_EQUAL(guid1, settings->_profiles.GetAt(0).Guid());
|
||||||
VERIFY_ARE_EQUAL(guid1, settings->_profiles.GetAt(1).Guid());
|
VERIFY_ARE_EQUAL(guid1, settings->_profiles.GetAt(1).Guid());
|
||||||
VERIFY_ARE_EQUAL(guid2, settings->_profiles.GetAt(2).Guid());
|
VERIFY_ARE_EQUAL(guid2, settings->_profiles.GetAt(2).Guid());
|
||||||
|
@ -2256,6 +2254,7 @@ namespace SettingsModelLocalTests
|
||||||
settings->_ParseJsonString(settings1Json, false);
|
settings->_ParseJsonString(settings1Json, false);
|
||||||
settings->LayerJson(settings->_userSettings);
|
settings->LayerJson(settings->_userSettings);
|
||||||
settings->_ValidateSettings();
|
settings->_ValidateSettings();
|
||||||
|
commands = settings->_globals->Commands();
|
||||||
_logCommandNames(commands);
|
_logCommandNames(commands);
|
||||||
VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
|
VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
|
||||||
VERIFY_ARE_EQUAL(0u, commands.Size());
|
VERIFY_ARE_EQUAL(0u, commands.Size());
|
||||||
|
@ -2350,6 +2349,7 @@ namespace SettingsModelLocalTests
|
||||||
settings->_ParseJsonString(settings1Json, false);
|
settings->_ParseJsonString(settings1Json, false);
|
||||||
settings->LayerJson(settings->_userSettings);
|
settings->LayerJson(settings->_userSettings);
|
||||||
settings->_ValidateSettings();
|
settings->_ValidateSettings();
|
||||||
|
commands = settings->_globals->Commands();
|
||||||
_logCommandNames(commands);
|
_logCommandNames(commands);
|
||||||
VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
|
VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
|
||||||
VERIFY_ARE_EQUAL(1u, commands.Size());
|
VERIFY_ARE_EQUAL(1u, commands.Size());
|
||||||
|
@ -2460,4 +2460,126 @@ namespace SettingsModelLocalTests
|
||||||
copyImpl->_globals->WordDelimiters(L"changed value");
|
copyImpl->_globals->WordDelimiters(L"changed value");
|
||||||
VERIFY_ARE_NOT_EQUAL(settings->_globals->WordDelimiters(), copyImpl->_globals->WordDelimiters());
|
VERIFY_ARE_NOT_EQUAL(settings->_globals->WordDelimiters(), copyImpl->_globals->WordDelimiters());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeserializationTests::TestCloneInheritanceTree()
|
||||||
|
{
|
||||||
|
const std::string settingsJson{ R"(
|
||||||
|
{
|
||||||
|
"defaultProfile": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
|
||||||
|
"profiles":
|
||||||
|
{
|
||||||
|
"defaults": {
|
||||||
|
"name": "PROFILE DEFAULTS"
|
||||||
|
},
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"guid": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
|
||||||
|
"name": "CMD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"guid": "{61c54bbd-2222-5271-96e7-009a87ff44bf}",
|
||||||
|
"name": "PowerShell"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"guid": "{61c54bbd-3333-5271-96e7-009a87ff44bf}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})" };
|
||||||
|
|
||||||
|
VerifyParseSucceeded(settingsJson);
|
||||||
|
|
||||||
|
auto settings{ winrt::make_self<implementation::CascadiaSettings>() };
|
||||||
|
settings->_ParseJsonString(settingsJson, false);
|
||||||
|
settings->_ApplyDefaultsFromUserSettings();
|
||||||
|
settings->LayerJson(settings->_userSettings);
|
||||||
|
settings->_ValidateSettings();
|
||||||
|
|
||||||
|
const auto copy{ settings->Copy() };
|
||||||
|
const auto copyImpl{ winrt::get_self<implementation::CascadiaSettings>(copy) };
|
||||||
|
|
||||||
|
// test globals
|
||||||
|
VERIFY_ARE_EQUAL(settings->_globals->DefaultProfile(), copyImpl->_globals->DefaultProfile());
|
||||||
|
|
||||||
|
// test profiles
|
||||||
|
VERIFY_ARE_EQUAL(settings->_profiles.Size(), copyImpl->_profiles.Size());
|
||||||
|
VERIFY_ARE_EQUAL(settings->_profiles.GetAt(0).Name(), copyImpl->_profiles.GetAt(0).Name());
|
||||||
|
VERIFY_ARE_EQUAL(settings->_profiles.GetAt(1).Name(), copyImpl->_profiles.GetAt(1).Name());
|
||||||
|
VERIFY_ARE_EQUAL(settings->_profiles.GetAt(2).Name(), copyImpl->_profiles.GetAt(2).Name());
|
||||||
|
VERIFY_ARE_EQUAL(settings->_userDefaultProfileSettings->Name(), copyImpl->_userDefaultProfileSettings->Name());
|
||||||
|
|
||||||
|
// Modifying profile.defaults should...
|
||||||
|
VERIFY_ARE_EQUAL(settings->_userDefaultProfileSettings->HasName(), copyImpl->_userDefaultProfileSettings->HasName());
|
||||||
|
copyImpl->_userDefaultProfileSettings->Name(L"changed value");
|
||||||
|
|
||||||
|
// ...keep the same name for the first two profiles
|
||||||
|
VERIFY_ARE_EQUAL(settings->_profiles.Size(), copyImpl->_profiles.Size());
|
||||||
|
VERIFY_ARE_EQUAL(settings->_profiles.GetAt(0).Name(), copyImpl->_profiles.GetAt(0).Name());
|
||||||
|
VERIFY_ARE_EQUAL(settings->_profiles.GetAt(1).Name(), copyImpl->_profiles.GetAt(1).Name());
|
||||||
|
|
||||||
|
// ...but change the name for the one that inherited it from profile.defaults
|
||||||
|
VERIFY_ARE_NOT_EQUAL(settings->_profiles.GetAt(2).Name(), copyImpl->_profiles.GetAt(2).Name());
|
||||||
|
|
||||||
|
// profile.defaults should be different between the two graphs
|
||||||
|
VERIFY_ARE_EQUAL(settings->_userDefaultProfileSettings->HasName(), copyImpl->_userDefaultProfileSettings->HasName());
|
||||||
|
VERIFY_ARE_NOT_EQUAL(settings->_userDefaultProfileSettings->Name(), copyImpl->_userDefaultProfileSettings->Name());
|
||||||
|
|
||||||
|
Log::Comment(L"Test empty profiles.defaults");
|
||||||
|
const std::string emptyPDJson{ R"(
|
||||||
|
{
|
||||||
|
"defaultProfile": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
|
||||||
|
"profiles":
|
||||||
|
{
|
||||||
|
"defaults": {
|
||||||
|
},
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"guid": "{61c54bbd-2222-5271-96e7-009a87ff44bf}",
|
||||||
|
"name": "PowerShell"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})" };
|
||||||
|
|
||||||
|
const std::string missingPDJson{ R"(
|
||||||
|
{
|
||||||
|
"defaultProfile": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
|
||||||
|
"profiles":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"guid": "{61c54bbd-2222-5271-96e7-009a87ff44bf}",
|
||||||
|
"name": "PowerShell"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})" };
|
||||||
|
|
||||||
|
auto verifyEmptyPD = [this](const std::string json) {
|
||||||
|
VerifyParseSucceeded(json);
|
||||||
|
|
||||||
|
auto settings{ winrt::make_self<implementation::CascadiaSettings>() };
|
||||||
|
settings->_ParseJsonString(json, false);
|
||||||
|
settings->_ApplyDefaultsFromUserSettings();
|
||||||
|
settings->LayerJson(settings->_userSettings);
|
||||||
|
settings->_ValidateSettings();
|
||||||
|
|
||||||
|
const auto copy{ settings->Copy() };
|
||||||
|
const auto copyImpl{ winrt::get_self<implementation::CascadiaSettings>(copy) };
|
||||||
|
|
||||||
|
// test optimization: if we don't have profiles.defaults, don't add it to the tree
|
||||||
|
VERIFY_IS_NULL(settings->_userDefaultProfileSettings);
|
||||||
|
VERIFY_ARE_EQUAL(settings->_userDefaultProfileSettings, copyImpl->_userDefaultProfileSettings);
|
||||||
|
|
||||||
|
VERIFY_ARE_EQUAL(settings->Profiles().Size(), 1u);
|
||||||
|
VERIFY_ARE_EQUAL(settings->Profiles().Size(), copyImpl->Profiles().Size());
|
||||||
|
|
||||||
|
// so we should only have one parent, instead of two
|
||||||
|
auto srcProfile{ winrt::get_self<implementation::Profile>(settings->Profiles().GetAt(0)) };
|
||||||
|
auto copyProfile{ winrt::get_self<implementation::Profile>(copyImpl->Profiles().GetAt(0)) };
|
||||||
|
VERIFY_ARE_EQUAL(srcProfile->Parents().size(), 0u);
|
||||||
|
VERIFY_ARE_EQUAL(srcProfile->Parents().size(), copyProfile->Parents().size());
|
||||||
|
};
|
||||||
|
|
||||||
|
verifyEmptyPD(emptyPDJson);
|
||||||
|
verifyEmptyPD(missingPDJson);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ namespace SettingsModelLocalTests
|
||||||
// A profile _can_ be layered with itself, though what's the point?
|
// A profile _can_ be layered with itself, though what's the point?
|
||||||
VERIFY_IS_FALSE(profile3->ShouldBeLayered(profile1Json));
|
VERIFY_IS_FALSE(profile3->ShouldBeLayered(profile1Json));
|
||||||
VERIFY_IS_FALSE(profile3->ShouldBeLayered(profile2Json));
|
VERIFY_IS_FALSE(profile3->ShouldBeLayered(profile2Json));
|
||||||
VERIFY_IS_FALSE(profile3->ShouldBeLayered(profile3Json));
|
VERIFY_IS_TRUE(profile3->ShouldBeLayered(profile3Json));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfileTests::LayerProfileProperties()
|
void ProfileTests::LayerProfileProperties()
|
||||||
|
@ -132,39 +132,41 @@ namespace SettingsModelLocalTests
|
||||||
|
|
||||||
Log::Comment(NoThrowString().Format(
|
Log::Comment(NoThrowString().Format(
|
||||||
L"Layering profile1 on top of profile0"));
|
L"Layering profile1 on top of profile0"));
|
||||||
profile0->LayerJson(profile1Json);
|
auto profile1{ profile0->CreateChild() };
|
||||||
|
profile1->LayerJson(profile1Json);
|
||||||
|
|
||||||
VERIFY_IS_NOT_NULL(profile0->Foreground());
|
VERIFY_IS_NOT_NULL(profile1->Foreground());
|
||||||
VERIFY_ARE_EQUAL(til::color(2, 2, 2), til::color{ profile0->Foreground().Value() });
|
VERIFY_ARE_EQUAL(til::color(2, 2, 2), til::color{ profile1->Foreground().Value() });
|
||||||
|
|
||||||
VERIFY_IS_NOT_NULL(profile0->Background());
|
VERIFY_IS_NOT_NULL(profile1->Background());
|
||||||
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile0->Background().Value() });
|
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile1->Background().Value() });
|
||||||
|
|
||||||
VERIFY_IS_NOT_NULL(profile0->Background());
|
VERIFY_IS_NOT_NULL(profile1->Background());
|
||||||
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile0->Background().Value() });
|
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile1->Background().Value() });
|
||||||
|
|
||||||
VERIFY_ARE_EQUAL(L"profile1", profile0->Name());
|
VERIFY_ARE_EQUAL(L"profile1", profile1->Name());
|
||||||
|
|
||||||
VERIFY_IS_FALSE(profile0->StartingDirectory().empty());
|
VERIFY_IS_FALSE(profile1->StartingDirectory().empty());
|
||||||
VERIFY_ARE_EQUAL(L"C:/", profile0->StartingDirectory());
|
VERIFY_ARE_EQUAL(L"C:/", profile1->StartingDirectory());
|
||||||
|
|
||||||
Log::Comment(NoThrowString().Format(
|
Log::Comment(NoThrowString().Format(
|
||||||
L"Layering profile2 on top of (profile0+profile1)"));
|
L"Layering profile2 on top of (profile0+profile1)"));
|
||||||
profile0->LayerJson(profile2Json);
|
auto profile2{ profile1->CreateChild() };
|
||||||
|
profile2->LayerJson(profile2Json);
|
||||||
|
|
||||||
VERIFY_IS_NOT_NULL(profile0->Foreground());
|
VERIFY_IS_NOT_NULL(profile2->Foreground());
|
||||||
VERIFY_ARE_EQUAL(til::color(3, 3, 3), til::color{ profile0->Foreground().Value() });
|
VERIFY_ARE_EQUAL(til::color(3, 3, 3), til::color{ profile2->Foreground().Value() });
|
||||||
|
|
||||||
VERIFY_IS_NOT_NULL(profile0->Background());
|
VERIFY_IS_NOT_NULL(profile2->Background());
|
||||||
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile0->Background().Value() });
|
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile2->Background().Value() });
|
||||||
|
|
||||||
VERIFY_IS_NOT_NULL(profile0->SelectionBackground());
|
VERIFY_IS_NOT_NULL(profile2->SelectionBackground());
|
||||||
VERIFY_ARE_EQUAL(til::color(2, 2, 2), til::color{ profile0->SelectionBackground().Value() });
|
VERIFY_ARE_EQUAL(til::color(2, 2, 2), til::color{ profile2->SelectionBackground().Value() });
|
||||||
|
|
||||||
VERIFY_ARE_EQUAL(L"profile2", profile0->Name());
|
VERIFY_ARE_EQUAL(L"profile2", profile2->Name());
|
||||||
|
|
||||||
VERIFY_IS_FALSE(profile0->StartingDirectory().empty());
|
VERIFY_IS_FALSE(profile2->StartingDirectory().empty());
|
||||||
VERIFY_ARE_EQUAL(L"C:/", profile0->StartingDirectory());
|
VERIFY_ARE_EQUAL(L"C:/", profile2->StartingDirectory());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfileTests::LayerProfileIcon()
|
void ProfileTests::LayerProfileIcon()
|
||||||
|
|
|
@ -499,6 +499,7 @@ namespace TerminalAppLocalTests
|
||||||
|
|
||||||
const std::string settings0String{ R"(
|
const std::string settings0String{ R"(
|
||||||
{
|
{
|
||||||
|
"defaultProfile": "profile5",
|
||||||
"profiles": [
|
"profiles": [
|
||||||
{
|
{
|
||||||
"name" : "profile0",
|
"name" : "profile0",
|
||||||
|
|
|
@ -756,17 +756,10 @@ namespace winrt::TerminalApp::implementation
|
||||||
|
|
||||||
TerminalConnection::ITerminalConnection connection{ nullptr };
|
TerminalConnection::ITerminalConnection connection{ nullptr };
|
||||||
|
|
||||||
winrt::guid connectionType{};
|
winrt::guid connectionType = profile.ConnectionType();
|
||||||
winrt::guid sessionGuid{};
|
winrt::guid sessionGuid{};
|
||||||
|
|
||||||
const auto hasConnectionType = profile.HasConnectionType();
|
if (connectionType == TerminalConnection::AzureConnection::ConnectionType() &&
|
||||||
if (hasConnectionType)
|
|
||||||
{
|
|
||||||
connectionType = profile.ConnectionType();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasConnectionType &&
|
|
||||||
connectionType == TerminalConnection::AzureConnection::ConnectionType() &&
|
|
||||||
TerminalConnection::AzureConnection::IsAzureConnectionAvailable())
|
TerminalConnection::AzureConnection::IsAzureConnectionAvailable())
|
||||||
{
|
{
|
||||||
// TODO GH#4661: Replace this with directly using the AzCon when our VT is better
|
// TODO GH#4661: Replace this with directly using the AzCon when our VT is better
|
||||||
|
|
|
@ -94,10 +94,7 @@ namespace winrt::TerminalApp::implementation
|
||||||
|
|
||||||
_Commandline = profile.Commandline();
|
_Commandline = profile.Commandline();
|
||||||
|
|
||||||
if (!profile.StartingDirectory().empty())
|
_StartingDirectory = profile.EvaluatedStartingDirectory();
|
||||||
{
|
|
||||||
_StartingDirectory = profile.EvaluatedStartingDirectory();
|
|
||||||
}
|
|
||||||
|
|
||||||
// GH#2373: Use the tabTitle as the starting title if it exists, otherwise
|
// GH#2373: Use the tabTitle as the starting title if it exists, otherwise
|
||||||
// use the profile name
|
// use the profile name
|
||||||
|
|
|
@ -71,11 +71,6 @@ winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings CascadiaSettings::
|
||||||
// dynamic profile generators added by default
|
// dynamic profile generators added by default
|
||||||
auto settings{ winrt::make_self<CascadiaSettings>() };
|
auto settings{ winrt::make_self<CascadiaSettings>() };
|
||||||
settings->_globals = _globals->Copy();
|
settings->_globals = _globals->Copy();
|
||||||
for (const auto profile : _profiles)
|
|
||||||
{
|
|
||||||
auto profImpl{ winrt::get_self<Profile>(profile) };
|
|
||||||
settings->_profiles.Append(*profImpl->Copy());
|
|
||||||
}
|
|
||||||
for (auto warning : _warnings)
|
for (auto warning : _warnings)
|
||||||
{
|
{
|
||||||
settings->_warnings.Append(warning);
|
settings->_warnings.Append(warning);
|
||||||
|
@ -85,10 +80,54 @@ winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings CascadiaSettings::
|
||||||
settings->_userSettingsString = _userSettingsString;
|
settings->_userSettingsString = _userSettingsString;
|
||||||
settings->_userSettings = _userSettings;
|
settings->_userSettings = _userSettings;
|
||||||
settings->_defaultSettings = _defaultSettings;
|
settings->_defaultSettings = _defaultSettings;
|
||||||
settings->_userDefaultProfileSettings = _userDefaultProfileSettings;
|
|
||||||
|
_CopyProfileInheritanceTree(settings);
|
||||||
|
|
||||||
return *settings;
|
return *settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Description:
|
||||||
|
// - Copies the inheritance tree for profiles and hooks them up to a clone CascadiaSettings
|
||||||
|
// Arguments:
|
||||||
|
// - cloneSettings: the CascadiaSettings we're copying the inheritance tree to
|
||||||
|
// Return Value:
|
||||||
|
// - <none>
|
||||||
|
void CascadiaSettings::_CopyProfileInheritanceTree(winrt::com_ptr<CascadiaSettings>& cloneSettings) const
|
||||||
|
{
|
||||||
|
// Our profiles inheritance graph doesn't have a formal root.
|
||||||
|
// However, if we create a dummy Profile, and set _profiles as the parent,
|
||||||
|
// we now have a root. So we'll do just that, then copy the inheritance graph
|
||||||
|
// from the dummyRoot.
|
||||||
|
auto dummyRootSource{ winrt::make_self<Profile>() };
|
||||||
|
for (const auto& profile : _profiles)
|
||||||
|
{
|
||||||
|
winrt::com_ptr<Profile> profileImpl;
|
||||||
|
profileImpl.copy_from(winrt::get_self<Profile>(profile));
|
||||||
|
dummyRootSource->InsertParent(profileImpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dummyRootClone{ winrt::make_self<Profile>() };
|
||||||
|
std::unordered_map<void*, winrt::com_ptr<Profile>> visited{};
|
||||||
|
|
||||||
|
if (_userDefaultProfileSettings)
|
||||||
|
{
|
||||||
|
// profile.defaults must be saved to CascadiaSettings
|
||||||
|
// So let's do that manually first, and add that to visited
|
||||||
|
cloneSettings->_userDefaultProfileSettings = Profile::CopySettings(_userDefaultProfileSettings);
|
||||||
|
visited[_userDefaultProfileSettings.get()] = cloneSettings->_userDefaultProfileSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
Profile::CloneInheritanceGraph(dummyRootSource, dummyRootClone, visited);
|
||||||
|
|
||||||
|
// All of the parents of the dummy root clone are _profiles.
|
||||||
|
// Get the parents and add them to the settings clone.
|
||||||
|
const auto cloneParents{ dummyRootClone->Parents() };
|
||||||
|
for (const auto& profile : cloneParents)
|
||||||
|
{
|
||||||
|
cloneSettings->_profiles.Append(*profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Finds a profile that matches the given GUID. If there is no profile in this
|
// - Finds a profile that matches the given GUID. If there is no profile in this
|
||||||
// settings object that matches, returns nullptr.
|
// settings object that matches, returns nullptr.
|
||||||
|
|
|
@ -102,10 +102,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||||
std::string _userSettingsString;
|
std::string _userSettingsString;
|
||||||
Json::Value _userSettings;
|
Json::Value _userSettings;
|
||||||
Json::Value _defaultSettings;
|
Json::Value _defaultSettings;
|
||||||
Json::Value _userDefaultProfileSettings{ Json::Value::null };
|
winrt::com_ptr<Profile> _userDefaultProfileSettings{ nullptr };
|
||||||
|
|
||||||
void _LayerOrCreateProfile(const Json::Value& profileJson);
|
void _LayerOrCreateProfile(const Json::Value& profileJson);
|
||||||
winrt::com_ptr<implementation::Profile> _FindMatchingProfile(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);
|
void _LayerOrCreateColorScheme(const Json::Value& schemeJson);
|
||||||
winrt::com_ptr<implementation::ColorScheme> _FindMatchingColorScheme(const Json::Value& schemeJson);
|
winrt::com_ptr<implementation::ColorScheme> _FindMatchingColorScheme(const Json::Value& schemeJson);
|
||||||
void _ParseJsonString(std::string_view fileData, const bool isDefaultSettings);
|
void _ParseJsonString(std::string_view fileData, const bool isDefaultSettings);
|
||||||
|
@ -114,6 +115,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||||
bool _PrependSchemaDirective();
|
bool _PrependSchemaDirective();
|
||||||
bool _AppendDynamicProfilesToUserSettings();
|
bool _AppendDynamicProfilesToUserSettings();
|
||||||
std::string _ApplyFirstRunChangesToSettingsTemplate(std::string_view settingsTemplate) const;
|
std::string _ApplyFirstRunChangesToSettingsTemplate(std::string_view settingsTemplate) const;
|
||||||
|
void _CopyProfileInheritanceTree(com_ptr<CascadiaSettings>& cloneSettings) const;
|
||||||
|
|
||||||
void _ApplyDefaultsFromUserSettings();
|
void _ApplyDefaultsFromUserSettings();
|
||||||
|
|
||||||
|
|
|
@ -519,20 +519,6 @@ bool CascadiaSettings::_AppendDynamicProfilesToUserSettings()
|
||||||
|
|
||||||
for (const auto& profile : _profiles)
|
for (const auto& profile : _profiles)
|
||||||
{
|
{
|
||||||
if (!profile.HasGuid())
|
|
||||||
{
|
|
||||||
// If the profile doesn't have a guid, it's a name-only profile.
|
|
||||||
// During validation, we'll generate a GUID for the profile, but
|
|
||||||
// validation occurs after this. We should ignore these types of
|
|
||||||
// profiles.
|
|
||||||
// If a dynamic profile was generated _without_ a GUID, we also
|
|
||||||
// don't want it serialized here. The first check in
|
|
||||||
// Profile::ShouldBeLayered checks that the profile has a guid. For a
|
|
||||||
// dynamic profile without a GUID, that'll _never_ be true, so it
|
|
||||||
// would be impossible to be layered.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip profiles that are in the user settings or the default settings.
|
// Skip profiles that are in the user settings or the default settings.
|
||||||
if (isInJsonObj(profile, _userSettings) || isInJsonObj(profile, _defaultSettings))
|
if (isInJsonObj(profile, _userSettings) || isInJsonObj(profile, _defaultSettings))
|
||||||
{
|
{
|
||||||
|
@ -598,6 +584,8 @@ winrt::com_ptr<CascadiaSettings> CascadiaSettings::FromJson(const Json::Value& j
|
||||||
// <none>
|
// <none>
|
||||||
void CascadiaSettings::LayerJson(const Json::Value& json)
|
void CascadiaSettings::LayerJson(const Json::Value& json)
|
||||||
{
|
{
|
||||||
|
// add a new inheritance layer, and apply json values to child
|
||||||
|
_globals = _globals->CreateChild();
|
||||||
_globals->LayerJson(json);
|
_globals->LayerJson(json);
|
||||||
|
|
||||||
if (auto schemes{ json[SchemesKey.data()] })
|
if (auto schemes{ json[SchemesKey.data()] })
|
||||||
|
@ -635,10 +623,28 @@ void CascadiaSettings::LayerJson(const Json::Value& json)
|
||||||
void CascadiaSettings::_LayerOrCreateProfile(const Json::Value& profileJson)
|
void CascadiaSettings::_LayerOrCreateProfile(const Json::Value& profileJson)
|
||||||
{
|
{
|
||||||
// Layer the json on top of an existing profile, if we have one:
|
// Layer the json on top of an existing profile, if we have one:
|
||||||
auto pProfile = _FindMatchingProfile(profileJson);
|
auto profileIndex{ _FindMatchingProfileIndex(profileJson) };
|
||||||
if (pProfile)
|
if (profileIndex)
|
||||||
{
|
{
|
||||||
pProfile->LayerJson(profileJson);
|
auto parentProj{ _profiles.GetAt(*profileIndex) };
|
||||||
|
auto parent{ winrt::get_self<Profile>(parentProj) };
|
||||||
|
|
||||||
|
if (_userDefaultProfileSettings)
|
||||||
|
{
|
||||||
|
// We don't actually need to CreateChild() here.
|
||||||
|
// When we loaded Profile.Defaults, we created an empty child already.
|
||||||
|
// So this just populates the empty child
|
||||||
|
parent->LayerJson(profileJson);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// otherwise, add a new inheritance layer
|
||||||
|
auto childImpl{ parent->CreateChild() };
|
||||||
|
childImpl->LayerJson(profileJson);
|
||||||
|
|
||||||
|
// replace parent in _profiles with child
|
||||||
|
_profiles.SetAt(*profileIndex, *childImpl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -647,13 +653,13 @@ void CascadiaSettings::_LayerOrCreateProfile(const Json::Value& profileJson)
|
||||||
// `source`. Dynamic profiles _must_ be layered on an existing profile.
|
// `source`. Dynamic profiles _must_ be layered on an existing profile.
|
||||||
if (!Profile::IsDynamicProfileObject(profileJson))
|
if (!Profile::IsDynamicProfileObject(profileJson))
|
||||||
{
|
{
|
||||||
auto profile = winrt::make_self<Profile>();
|
auto profile{ winrt::make_self<Profile>() };
|
||||||
|
|
||||||
// GH#2325: If we have a set of default profile settings, apply them here.
|
// GH#2325: If we have a set of default profile settings, set that as my parent.
|
||||||
// We _won't_ have these settings yet for defaults, dynamic profiles.
|
// We _won't_ have these settings yet for defaults, dynamic profiles.
|
||||||
if (_userDefaultProfileSettings)
|
if (_userDefaultProfileSettings)
|
||||||
{
|
{
|
||||||
profile->LayerJson(_userDefaultProfileSettings);
|
profile->InsertParent(0, _userDefaultProfileSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
profile->LayerJson(profileJson);
|
profile->LayerJson(profileJson);
|
||||||
|
@ -675,17 +681,40 @@ void CascadiaSettings::_LayerOrCreateProfile(const Json::Value& profileJson)
|
||||||
// profile exists.
|
// profile exists.
|
||||||
winrt::com_ptr<Profile> CascadiaSettings::_FindMatchingProfile(const Json::Value& profileJson)
|
winrt::com_ptr<Profile> CascadiaSettings::_FindMatchingProfile(const Json::Value& profileJson)
|
||||||
{
|
{
|
||||||
for (auto profile : _profiles)
|
auto index{ _FindMatchingProfileIndex(profileJson) };
|
||||||
|
if (index)
|
||||||
{
|
{
|
||||||
auto profileImpl = winrt::get_self<Profile>(profile);
|
auto profile{ _profiles.GetAt(*index) };
|
||||||
if (profileImpl->ShouldBeLayered(profileJson))
|
auto profileImpl{ winrt::get_self<Profile>(profile) };
|
||||||
{
|
return profileImpl->get_strong();
|
||||||
return profileImpl->get_strong();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Description:
|
||||||
|
// - Finds a profile from our list of profiles that matches the given json
|
||||||
|
// object. Uses Profile::ShouldBeLayered to determine if the Json::Value is a
|
||||||
|
// match or not. This method should be used to find a profile to layer the
|
||||||
|
// given settings upon.
|
||||||
|
// - Returns nullopt if no such match exists.
|
||||||
|
// Arguments:
|
||||||
|
// - json: an object which may be a partial serialization of a Profile object.
|
||||||
|
// Return Value:
|
||||||
|
// - The index for the matching Profile, iff it exists. Otherwise, nullopt.
|
||||||
|
std::optional<uint32_t> CascadiaSettings::_FindMatchingProfileIndex(const Json::Value& profileJson)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < _profiles.Size(); ++i)
|
||||||
|
{
|
||||||
|
const auto profile{ _profiles.GetAt(i) };
|
||||||
|
const auto profileImpl = winrt::get_self<Profile>(profile);
|
||||||
|
if (profileImpl->ShouldBeLayered(profileJson))
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Finds the "default profile settings" if they exist in the users settings,
|
// - Finds the "default profile settings" if they exist in the users settings,
|
||||||
// and applies them to the existing profiles. The "default profile settings"
|
// and applies them to the existing profiles. The "default profile settings"
|
||||||
|
@ -704,7 +733,7 @@ void CascadiaSettings::_ApplyDefaultsFromUserSettings()
|
||||||
auto defaultSettings{ Json::Value::null };
|
auto defaultSettings{ Json::Value::null };
|
||||||
if (const auto profiles{ _userSettings[JsonKey(ProfilesKey)] })
|
if (const auto profiles{ _userSettings[JsonKey(ProfilesKey)] })
|
||||||
{
|
{
|
||||||
if (profiles.isObject())
|
if (profiles.isObject() && !profiles[JsonKey(DefaultSettingsKey)].empty())
|
||||||
{
|
{
|
||||||
defaultSettings = profiles[JsonKey(DefaultSettingsKey)];
|
defaultSettings = profiles[JsonKey(DefaultSettingsKey)];
|
||||||
}
|
}
|
||||||
|
@ -714,16 +743,26 @@ void CascadiaSettings::_ApplyDefaultsFromUserSettings()
|
||||||
// from user settings file
|
// from user settings file
|
||||||
if (defaultSettings)
|
if (defaultSettings)
|
||||||
{
|
{
|
||||||
_userDefaultProfileSettings = defaultSettings;
|
|
||||||
|
|
||||||
// Remove the `guid` member from the default settings. That'll
|
// Remove the `guid` member from the default settings. That'll
|
||||||
// hyper-explode, so just don't let them do that.
|
// hyper-explode, so just don't let them do that.
|
||||||
_userDefaultProfileSettings.removeMember({ "guid" });
|
defaultSettings.removeMember({ "guid" });
|
||||||
|
|
||||||
for (auto profile : _profiles)
|
_userDefaultProfileSettings = winrt::make_self<Profile>();
|
||||||
|
_userDefaultProfileSettings->LayerJson(defaultSettings);
|
||||||
|
|
||||||
|
const auto numOfProfiles{ _profiles.Size() };
|
||||||
|
for (uint32_t profileIndex = 0; profileIndex < numOfProfiles; ++profileIndex)
|
||||||
{
|
{
|
||||||
auto profileImpl = winrt::get_self<Profile>(profile);
|
// create a child, so we inherit from the defaults.json layer
|
||||||
profileImpl->LayerJson(_userDefaultProfileSettings);
|
auto parentProj{ _profiles.GetAt(profileIndex) };
|
||||||
|
auto parentImpl{ winrt::get_self<Profile>(parentProj) };
|
||||||
|
auto childImpl{ parentImpl->CreateChild() };
|
||||||
|
|
||||||
|
// Add profile.defaults as the _first_ parent to the child
|
||||||
|
childImpl->InsertParent(0, _userDefaultProfileSettings);
|
||||||
|
|
||||||
|
// replace parent in _profiles with child
|
||||||
|
_profiles.SetAt(profileIndex, *childImpl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ winrt::Microsoft::Terminal::Settings::Model::Profile CreateDefaultProfile(const
|
||||||
{
|
{
|
||||||
const winrt::guid profileGuid{ Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID,
|
const winrt::guid profileGuid{ Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID,
|
||||||
gsl::as_bytes(gsl::make_span(name))) };
|
gsl::as_bytes(gsl::make_span(name))) };
|
||||||
|
|
||||||
auto newProfile = winrt::make<winrt::Microsoft::Terminal::Settings::Model::implementation::Profile>(profileGuid);
|
auto newProfile = winrt::make<winrt::Microsoft::Terminal::Settings::Model::implementation::Profile>(profileGuid);
|
||||||
newProfile.Name(name);
|
newProfile.Name(name);
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,9 @@ Author(s):
|
||||||
|
|
||||||
#include "Profile.h"
|
#include "Profile.h"
|
||||||
|
|
||||||
|
// !!! LOAD-BEARING
|
||||||
|
// If you change or delete this GUID, all dynamic profiles
|
||||||
|
// will become disconnected from user settings.
|
||||||
// {2bde4a90-d05f-401c-9492-e40884ead1d8}
|
// {2bde4a90-d05f-401c-9492-e40884ead1d8}
|
||||||
// uuidv5 properties: name format is UTF-16LE bytes
|
// uuidv5 properties: name format is UTF-16LE bytes
|
||||||
static constexpr GUID TERMINAL_PROFILE_NAMESPACE_GUID = { 0x2bde4a90, 0xd05f, 0x401c, { 0x94, 0x92, 0xe4, 0x8, 0x84, 0xea, 0xd1, 0xd8 } };
|
static constexpr GUID TERMINAL_PROFILE_NAMESPACE_GUID = { 0x2bde4a90, 0xd05f, 0x401c, { 0x94, 0x92, 0xe4, 0x8, 0x84, 0xea, 0xd1, 0xd8 } };
|
||||||
|
|
|
@ -55,7 +55,7 @@ static constexpr bool debugFeaturesDefault{ false };
|
||||||
GlobalAppSettings::GlobalAppSettings() :
|
GlobalAppSettings::GlobalAppSettings() :
|
||||||
_keymap{ winrt::make_self<KeyMapping>() },
|
_keymap{ winrt::make_self<KeyMapping>() },
|
||||||
_keybindingsWarnings{},
|
_keybindingsWarnings{},
|
||||||
_unparsedDefaultProfile{},
|
_validDefaultProfile{ false },
|
||||||
_defaultProfile{},
|
_defaultProfile{},
|
||||||
_DebugFeaturesEnabled{ debugFeaturesDefault }
|
_DebugFeaturesEnabled{ debugFeaturesDefault }
|
||||||
{
|
{
|
||||||
|
@ -63,6 +63,25 @@ GlobalAppSettings::GlobalAppSettings() :
|
||||||
_colorSchemes = winrt::single_threaded_map<winrt::hstring, Model::ColorScheme>();
|
_colorSchemes = winrt::single_threaded_map<winrt::hstring, Model::ColorScheme>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Description:
|
||||||
|
// - Copies any extraneous data from the parent before completing a CreateChild call
|
||||||
|
// Arguments:
|
||||||
|
// - <none>
|
||||||
|
// Return Value:
|
||||||
|
// - <none>
|
||||||
|
void GlobalAppSettings::_FinalizeInheritance()
|
||||||
|
{
|
||||||
|
// Globals only ever has 1 parent
|
||||||
|
FAIL_FAST_IF(_parents.size() > 1);
|
||||||
|
for (auto parent : _parents)
|
||||||
|
{
|
||||||
|
_keymap = std::move(parent->_keymap);
|
||||||
|
_keybindingsWarnings = std::move(parent->_keybindingsWarnings);
|
||||||
|
_colorSchemes = std::move(parent->_colorSchemes);
|
||||||
|
_commands = std::move(parent->_commands);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::Copy() const
|
winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::Copy() const
|
||||||
{
|
{
|
||||||
auto globals{ winrt::make_self<GlobalAppSettings>() };
|
auto globals{ winrt::make_self<GlobalAppSettings>() };
|
||||||
|
@ -91,21 +110,38 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::Copy() const
|
||||||
globals->_UseTabSwitcher = _UseTabSwitcher;
|
globals->_UseTabSwitcher = _UseTabSwitcher;
|
||||||
globals->_DisableAnimations = _DisableAnimations;
|
globals->_DisableAnimations = _DisableAnimations;
|
||||||
|
|
||||||
globals->_unparsedDefaultProfile = _unparsedDefaultProfile;
|
globals->_UnparsedDefaultProfile = _UnparsedDefaultProfile;
|
||||||
|
globals->_validDefaultProfile = _validDefaultProfile;
|
||||||
globals->_defaultProfile = _defaultProfile;
|
globals->_defaultProfile = _defaultProfile;
|
||||||
globals->_keymap = _keymap->Copy();
|
if (_keymap)
|
||||||
|
{
|
||||||
|
globals->_keymap = _keymap->Copy();
|
||||||
|
}
|
||||||
std::copy(_keybindingsWarnings.begin(), _keybindingsWarnings.end(), std::back_inserter(globals->_keybindingsWarnings));
|
std::copy(_keybindingsWarnings.begin(), _keybindingsWarnings.end(), std::back_inserter(globals->_keybindingsWarnings));
|
||||||
|
|
||||||
for (auto kv : _colorSchemes)
|
if (_colorSchemes)
|
||||||
{
|
{
|
||||||
const auto schemeImpl{ winrt::get_self<ColorScheme>(kv.Value()) };
|
for (auto kv : _colorSchemes)
|
||||||
globals->_colorSchemes.Insert(kv.Key(), *schemeImpl->Copy());
|
{
|
||||||
|
const auto schemeImpl{ winrt::get_self<ColorScheme>(kv.Value()) };
|
||||||
|
globals->_colorSchemes.Insert(kv.Key(), *schemeImpl->Copy());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto kv : _commands)
|
if (_commands)
|
||||||
{
|
{
|
||||||
const auto commandImpl{ winrt::get_self<Command>(kv.Value()) };
|
for (auto kv : _commands)
|
||||||
globals->_commands.Insert(kv.Key(), *commandImpl->Copy());
|
{
|
||||||
|
const auto commandImpl{ winrt::get_self<Command>(kv.Value()) };
|
||||||
|
globals->_commands.Insert(kv.Key(), *commandImpl->Copy());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Globals only ever has 1 parent
|
||||||
|
FAIL_FAST_IF(_parents.size() > 1);
|
||||||
|
for (auto parent : _parents)
|
||||||
|
{
|
||||||
|
globals->InsertParent(parent->Copy());
|
||||||
}
|
}
|
||||||
return globals;
|
return globals;
|
||||||
}
|
}
|
||||||
|
@ -115,24 +151,71 @@ winrt::Windows::Foundation::Collections::IMapView<winrt::hstring, winrt::Microso
|
||||||
return _colorSchemes.GetView();
|
return _colorSchemes.GetView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma region DefaultProfile
|
||||||
void GlobalAppSettings::DefaultProfile(const winrt::guid& defaultProfile) noexcept
|
void GlobalAppSettings::DefaultProfile(const winrt::guid& defaultProfile) noexcept
|
||||||
{
|
{
|
||||||
_unparsedDefaultProfile.clear();
|
_validDefaultProfile = true;
|
||||||
_defaultProfile = defaultProfile;
|
_defaultProfile = defaultProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
winrt::guid GlobalAppSettings::DefaultProfile() const
|
winrt::guid GlobalAppSettings::DefaultProfile() const
|
||||||
{
|
{
|
||||||
// If we have an unresolved default profile, we should likely explode.
|
// If we have an unresolved default profile, we should likely explode.
|
||||||
THROW_HR_IF(E_INVALIDARG, !_unparsedDefaultProfile.empty());
|
THROW_HR_IF(E_INVALIDARG, !_validDefaultProfile);
|
||||||
return _defaultProfile;
|
return _defaultProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GlobalAppSettings::HasUnparsedDefaultProfile() const
|
||||||
|
{
|
||||||
|
return _UnparsedDefaultProfile.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
winrt::hstring GlobalAppSettings::UnparsedDefaultProfile() const
|
winrt::hstring GlobalAppSettings::UnparsedDefaultProfile() const
|
||||||
{
|
{
|
||||||
return _unparsedDefaultProfile;
|
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::KeyMapping GlobalAppSettings::KeyMap() const noexcept
|
winrt::Microsoft::Terminal::Settings::Model::KeyMapping GlobalAppSettings::KeyMap() const noexcept
|
||||||
{
|
{
|
||||||
return *_keymap;
|
return *_keymap;
|
||||||
|
@ -153,7 +236,11 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::FromJson(const Json::Value&
|
||||||
|
|
||||||
void GlobalAppSettings::LayerJson(const Json::Value& json)
|
void GlobalAppSettings::LayerJson(const Json::Value& json)
|
||||||
{
|
{
|
||||||
JsonUtils::GetValueForKey(json, DefaultProfileKey, _unparsedDefaultProfile);
|
// _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, AlwaysShowTabsKey, _AlwaysShowTabs);
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ Copyright (c) Microsoft Corporation
|
||||||
Licensed under the MIT license.
|
Licensed under the MIT license.
|
||||||
|
|
||||||
Module Name:
|
Module Name:
|
||||||
- CascadiaSettings.hpp
|
- GlobalAppSettings.h
|
||||||
|
|
||||||
Abstract:
|
Abstract:
|
||||||
- This class encapsulates all of the settings that are global to the app, and
|
- This class encapsulates all of the settings that are global to the app, and
|
||||||
|
@ -16,6 +16,7 @@ Author(s):
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "GlobalAppSettings.g.h"
|
#include "GlobalAppSettings.g.h"
|
||||||
|
#include "IInheritable.h"
|
||||||
|
|
||||||
#include "KeyMapping.h"
|
#include "KeyMapping.h"
|
||||||
#include "Command.h"
|
#include "Command.h"
|
||||||
|
@ -30,10 +31,11 @@ namespace SettingsModelLocalTests
|
||||||
|
|
||||||
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||||
{
|
{
|
||||||
struct GlobalAppSettings : GlobalAppSettingsT<GlobalAppSettings>
|
struct GlobalAppSettings : GlobalAppSettingsT<GlobalAppSettings>, IInheritable<GlobalAppSettings>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GlobalAppSettings();
|
GlobalAppSettings();
|
||||||
|
void _FinalizeInheritance() override;
|
||||||
com_ptr<GlobalAppSettings> Copy() const;
|
com_ptr<GlobalAppSettings> Copy() const;
|
||||||
|
|
||||||
Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme> ColorSchemes() noexcept;
|
Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme> ColorSchemes() noexcept;
|
||||||
|
@ -52,36 +54,40 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||||
// by higher layers in the app.
|
// by higher layers in the app.
|
||||||
void DefaultProfile(const guid& defaultProfile) noexcept;
|
void DefaultProfile(const guid& defaultProfile) noexcept;
|
||||||
guid DefaultProfile() const;
|
guid DefaultProfile() const;
|
||||||
hstring UnparsedDefaultProfile() const;
|
bool HasUnparsedDefaultProfile() const;
|
||||||
|
winrt::hstring UnparsedDefaultProfile() const;
|
||||||
|
void UnparsedDefaultProfile(const hstring& value);
|
||||||
|
void ClearUnparsedDefaultProfile();
|
||||||
|
|
||||||
GETSET_PROPERTY(int32_t, InitialRows, DEFAULT_ROWS);
|
GETSET_SETTING(int32_t, InitialRows, DEFAULT_ROWS);
|
||||||
GETSET_PROPERTY(int32_t, InitialCols, DEFAULT_COLS);
|
GETSET_SETTING(int32_t, InitialCols, DEFAULT_COLS);
|
||||||
GETSET_PROPERTY(bool, AlwaysShowTabs, true);
|
GETSET_SETTING(bool, AlwaysShowTabs, true);
|
||||||
GETSET_PROPERTY(bool, ShowTitleInTitlebar, true);
|
GETSET_SETTING(bool, ShowTitleInTitlebar, true);
|
||||||
GETSET_PROPERTY(bool, ConfirmCloseAllTabs, true);
|
GETSET_SETTING(bool, ConfirmCloseAllTabs, true);
|
||||||
GETSET_PROPERTY(winrt::Windows::UI::Xaml::ElementTheme, Theme, winrt::Windows::UI::Xaml::ElementTheme::Default);
|
GETSET_SETTING(winrt::Windows::UI::Xaml::ElementTheme, Theme, winrt::Windows::UI::Xaml::ElementTheme::Default);
|
||||||
GETSET_PROPERTY(winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode, TabWidthMode, winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode::Equal);
|
GETSET_SETTING(winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode, TabWidthMode, winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode::Equal);
|
||||||
GETSET_PROPERTY(bool, ShowTabsInTitlebar, true);
|
GETSET_SETTING(bool, ShowTabsInTitlebar, true);
|
||||||
GETSET_PROPERTY(hstring, WordDelimiters, DEFAULT_WORD_DELIMITERS);
|
GETSET_SETTING(hstring, WordDelimiters, DEFAULT_WORD_DELIMITERS);
|
||||||
GETSET_PROPERTY(bool, CopyOnSelect, false);
|
GETSET_SETTING(bool, CopyOnSelect, false);
|
||||||
GETSET_PROPERTY(winrt::Microsoft::Terminal::TerminalControl::CopyFormat, CopyFormatting, 0);
|
GETSET_SETTING(winrt::Microsoft::Terminal::TerminalControl::CopyFormat, CopyFormatting, 0);
|
||||||
GETSET_PROPERTY(bool, WarnAboutLargePaste, true);
|
GETSET_SETTING(bool, WarnAboutLargePaste, true);
|
||||||
GETSET_PROPERTY(bool, WarnAboutMultiLinePaste, true);
|
GETSET_SETTING(bool, WarnAboutMultiLinePaste, true);
|
||||||
GETSET_PROPERTY(Model::LaunchPosition, InitialPosition, nullptr, nullptr);
|
GETSET_SETTING(Model::LaunchPosition, InitialPosition, nullptr, nullptr);
|
||||||
GETSET_PROPERTY(Model::LaunchMode, LaunchMode, LaunchMode::DefaultMode);
|
GETSET_SETTING(Model::LaunchMode, LaunchMode, LaunchMode::DefaultMode);
|
||||||
GETSET_PROPERTY(bool, SnapToGridOnResize, true);
|
GETSET_SETTING(bool, SnapToGridOnResize, true);
|
||||||
GETSET_PROPERTY(bool, ForceFullRepaintRendering, false);
|
GETSET_SETTING(bool, ForceFullRepaintRendering, false);
|
||||||
GETSET_PROPERTY(bool, SoftwareRendering, false);
|
GETSET_SETTING(bool, SoftwareRendering, false);
|
||||||
GETSET_PROPERTY(bool, ForceVTInput, false);
|
GETSET_SETTING(bool, ForceVTInput, false);
|
||||||
GETSET_PROPERTY(bool, DebugFeaturesEnabled); // default value set in constructor
|
GETSET_SETTING(bool, DebugFeaturesEnabled); // default value set in constructor
|
||||||
GETSET_PROPERTY(bool, StartOnUserLogin, false);
|
GETSET_SETTING(bool, StartOnUserLogin, false);
|
||||||
GETSET_PROPERTY(bool, AlwaysOnTop, false);
|
GETSET_SETTING(bool, AlwaysOnTop, false);
|
||||||
GETSET_PROPERTY(bool, UseTabSwitcher, true);
|
GETSET_SETTING(bool, UseTabSwitcher, true);
|
||||||
GETSET_PROPERTY(bool, DisableAnimations, false);
|
GETSET_SETTING(bool, DisableAnimations, false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
hstring _unparsedDefaultProfile;
|
|
||||||
guid _defaultProfile;
|
guid _defaultProfile;
|
||||||
|
std::optional<hstring> _UnparsedDefaultProfile{ std::nullopt };
|
||||||
|
bool _validDefaultProfile;
|
||||||
|
|
||||||
com_ptr<KeyMapping> _keymap;
|
com_ptr<KeyMapping> _keymap;
|
||||||
std::vector<SettingsLoadWarnings> _keybindingsWarnings;
|
std::vector<SettingsLoadWarnings> _keybindingsWarnings;
|
||||||
|
@ -89,6 +95,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||||
Windows::Foundation::Collections::IMap<hstring, Model::ColorScheme> _colorSchemes;
|
Windows::Foundation::Collections::IMap<hstring, Model::ColorScheme> _colorSchemes;
|
||||||
Windows::Foundation::Collections::IMap<hstring, Model::Command> _commands;
|
Windows::Foundation::Collections::IMap<hstring, Model::Command> _commands;
|
||||||
|
|
||||||
|
std::optional<hstring> _getUnparsedDefaultProfileImpl() const;
|
||||||
|
|
||||||
friend class SettingsModelLocalTests::DeserializationTests;
|
friend class SettingsModelLocalTests::DeserializationTests;
|
||||||
friend class SettingsModelLocalTests::ColorSchemeTests;
|
friend class SettingsModelLocalTests::ColorSchemeTests;
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,31 +28,104 @@ namespace Microsoft.Terminal.Settings.Model
|
||||||
|
|
||||||
[default_interface] runtimeclass GlobalAppSettings {
|
[default_interface] runtimeclass GlobalAppSettings {
|
||||||
Guid DefaultProfile;
|
Guid DefaultProfile;
|
||||||
String UnparsedDefaultProfile();
|
Boolean HasUnparsedDefaultProfile();
|
||||||
|
void ClearUnparsedDefaultProfile();
|
||||||
|
String UnparsedDefaultProfile;
|
||||||
|
|
||||||
|
Boolean HasInitialRows();
|
||||||
|
void ClearInitialRows();
|
||||||
Int32 InitialRows;
|
Int32 InitialRows;
|
||||||
|
|
||||||
|
Boolean HasInitialCols();
|
||||||
|
void ClearInitialCols();
|
||||||
Int32 InitialCols;
|
Int32 InitialCols;
|
||||||
|
|
||||||
|
Boolean HasAlwaysShowTabs();
|
||||||
|
void ClearAlwaysShowTabs();
|
||||||
Boolean AlwaysShowTabs;
|
Boolean AlwaysShowTabs;
|
||||||
|
|
||||||
|
Boolean HasShowTitleInTitlebar();
|
||||||
|
void ClearShowTitleInTitlebar();
|
||||||
Boolean ShowTitleInTitlebar;
|
Boolean ShowTitleInTitlebar;
|
||||||
|
|
||||||
|
Boolean HasConfirmCloseAllTabs();
|
||||||
|
void ClearConfirmCloseAllTabs();
|
||||||
Boolean ConfirmCloseAllTabs;
|
Boolean ConfirmCloseAllTabs;
|
||||||
|
|
||||||
|
Boolean HasTheme();
|
||||||
|
void ClearTheme();
|
||||||
Windows.UI.Xaml.ElementTheme Theme;
|
Windows.UI.Xaml.ElementTheme Theme;
|
||||||
|
|
||||||
|
Boolean HasTabWidthMode();
|
||||||
|
void ClearTabWidthMode();
|
||||||
Microsoft.UI.Xaml.Controls.TabViewWidthMode TabWidthMode;
|
Microsoft.UI.Xaml.Controls.TabViewWidthMode TabWidthMode;
|
||||||
|
|
||||||
|
Boolean HasShowTabsInTitlebar();
|
||||||
|
void ClearShowTabsInTitlebar();
|
||||||
Boolean ShowTabsInTitlebar;
|
Boolean ShowTabsInTitlebar;
|
||||||
|
|
||||||
|
Boolean HasWordDelimiters();
|
||||||
|
void ClearWordDelimiters();
|
||||||
String WordDelimiters;
|
String WordDelimiters;
|
||||||
|
|
||||||
|
Boolean HasCopyOnSelect();
|
||||||
|
void ClearCopyOnSelect();
|
||||||
Boolean CopyOnSelect;
|
Boolean CopyOnSelect;
|
||||||
|
|
||||||
|
Boolean HasCopyFormatting();
|
||||||
|
void ClearCopyFormatting();
|
||||||
Microsoft.Terminal.TerminalControl.CopyFormat CopyFormatting;
|
Microsoft.Terminal.TerminalControl.CopyFormat CopyFormatting;
|
||||||
|
|
||||||
|
Boolean HasWarnAboutLargePaste();
|
||||||
|
void ClearWarnAboutLargePaste();
|
||||||
Boolean WarnAboutLargePaste;
|
Boolean WarnAboutLargePaste;
|
||||||
|
|
||||||
|
Boolean HasWarnAboutMultiLinePaste();
|
||||||
|
void ClearWarnAboutMultiLinePaste();
|
||||||
Boolean WarnAboutMultiLinePaste;
|
Boolean WarnAboutMultiLinePaste;
|
||||||
|
|
||||||
|
Boolean HasInitialPosition();
|
||||||
|
void ClearInitialPosition();
|
||||||
LaunchPosition InitialPosition;
|
LaunchPosition InitialPosition;
|
||||||
|
|
||||||
|
Boolean HasLaunchMode();
|
||||||
|
void ClearLaunchMode();
|
||||||
LaunchMode LaunchMode;
|
LaunchMode LaunchMode;
|
||||||
|
|
||||||
|
Boolean HasSnapToGridOnResize();
|
||||||
|
void ClearSnapToGridOnResize();
|
||||||
Boolean SnapToGridOnResize;
|
Boolean SnapToGridOnResize;
|
||||||
|
|
||||||
|
Boolean HasForceFullRepaintRendering();
|
||||||
|
void ClearForceFullRepaintRendering();
|
||||||
Boolean ForceFullRepaintRendering;
|
Boolean ForceFullRepaintRendering;
|
||||||
|
|
||||||
|
Boolean HasSoftwareRendering();
|
||||||
|
void ClearSoftwareRendering();
|
||||||
Boolean SoftwareRendering;
|
Boolean SoftwareRendering;
|
||||||
|
|
||||||
|
Boolean HasForceVTInput();
|
||||||
|
void ClearForceVTInput();
|
||||||
Boolean ForceVTInput;
|
Boolean ForceVTInput;
|
||||||
|
|
||||||
|
Boolean HasDebugFeaturesEnabled();
|
||||||
|
void ClearDebugFeaturesEnabled();
|
||||||
Boolean DebugFeaturesEnabled;
|
Boolean DebugFeaturesEnabled;
|
||||||
|
|
||||||
|
Boolean HasStartOnUserLogin();
|
||||||
|
void ClearStartOnUserLogin();
|
||||||
Boolean StartOnUserLogin;
|
Boolean StartOnUserLogin;
|
||||||
|
|
||||||
|
Boolean HasAlwaysOnTop();
|
||||||
|
void ClearAlwaysOnTop();
|
||||||
Boolean AlwaysOnTop;
|
Boolean AlwaysOnTop;
|
||||||
|
|
||||||
|
Boolean HasUseTabSwitcher();
|
||||||
|
void ClearUseTabSwitcher();
|
||||||
Boolean UseTabSwitcher;
|
Boolean UseTabSwitcher;
|
||||||
|
|
||||||
|
Boolean HasDisableAnimations();
|
||||||
|
void ClearDisableAnimations();
|
||||||
Boolean DisableAnimations;
|
Boolean DisableAnimations;
|
||||||
|
|
||||||
Windows.Foundation.Collections.IMapView<String, ColorScheme> ColorSchemes();
|
Windows.Foundation.Collections.IMapView<String, ColorScheme> ColorSchemes();
|
||||||
|
|
212
src/cascadia/TerminalSettingsModel/IInheritable.h
Normal file
212
src/cascadia/TerminalSettingsModel/IInheritable.h
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) Microsoft Corporation
|
||||||
|
Licensed under the MIT license.
|
||||||
|
|
||||||
|
Module Name:
|
||||||
|
- IInheritable.h
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
- An interface allowing settings objects to inherit settings from a parent
|
||||||
|
|
||||||
|
Author(s):
|
||||||
|
- Carlos Zamora - October 2020
|
||||||
|
|
||||||
|
--*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
struct IInheritable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Method Description:
|
||||||
|
// - Create a new instance of T, but set its parent to this instance
|
||||||
|
// Arguments:
|
||||||
|
// - <none>
|
||||||
|
// Return Value:
|
||||||
|
// - a new instance of T with this instance set as its parent
|
||||||
|
com_ptr<T> CreateChild() const
|
||||||
|
{
|
||||||
|
auto child{ winrt::make_self<T>() };
|
||||||
|
|
||||||
|
// set "this" as the parent.
|
||||||
|
// However, "this" is an IInheritable, so we need to cast it as T (the impl winrt type)
|
||||||
|
// to pass ownership over to the com_ptr.
|
||||||
|
com_ptr<T> parent;
|
||||||
|
winrt::copy_from_abi(parent, const_cast<T*>(static_cast<const T*>(this)));
|
||||||
|
child->InsertParent(parent);
|
||||||
|
|
||||||
|
child->_FinalizeInheritance();
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InsertParent(com_ptr<T> parent)
|
||||||
|
{
|
||||||
|
_parents.push_back(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InsertParent(size_t index, com_ptr<T> parent)
|
||||||
|
{
|
||||||
|
auto pos{ _parents.begin() + index };
|
||||||
|
_parents.insert(pos, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<com_ptr<T>>& Parents()
|
||||||
|
{
|
||||||
|
return _parents;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<com_ptr<T>> _parents{};
|
||||||
|
|
||||||
|
// Method Description:
|
||||||
|
// - Actions to be performed after a child was created. Generally used to set
|
||||||
|
// any extraneous data from the parent into the child.
|
||||||
|
// Arguments:
|
||||||
|
// - <none>
|
||||||
|
// Return Value:
|
||||||
|
// - <none>
|
||||||
|
virtual void _FinalizeInheritance() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is like std::optional, but we can use it in inheritance to determine whether the user explicitly cleared it
|
||||||
|
template<typename T>
|
||||||
|
struct NullableSetting
|
||||||
|
{
|
||||||
|
std::optional<T> setting{ std::nullopt };
|
||||||
|
bool set{ false };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use this macro to quickly implement both getters and the setter for an
|
||||||
|
// inheritable setting property. This is similar to the GETSET_PROPERTY macro, except...
|
||||||
|
// - Has(): checks if the user explicitly set a value for this setting
|
||||||
|
// - Getter(): return the resolved value
|
||||||
|
// - Setter(): set the value directly
|
||||||
|
// - Clear(): clear the user set value
|
||||||
|
// - the setting is saved as an optional, where nullopt means
|
||||||
|
// that we must inherit the value from our parent
|
||||||
|
#define GETSET_SETTING(type, name, ...) \
|
||||||
|
public: \
|
||||||
|
/* Returns true if the user explicitly set the value, false otherwise*/ \
|
||||||
|
bool Has##name() const \
|
||||||
|
{ \
|
||||||
|
return _##name.has_value(); \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
/* Returns the resolved value for this setting */ \
|
||||||
|
/* fallback: user set value --> inherited value --> system set value */ \
|
||||||
|
type name() const \
|
||||||
|
{ \
|
||||||
|
const auto val{ _get##name##Impl() }; \
|
||||||
|
return val ? *val : type{ __VA_ARGS__ }; \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
/* Overwrite the user set value */ \
|
||||||
|
void name(const type& value) \
|
||||||
|
{ \
|
||||||
|
_##name = value; \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
/* Clear the user set value */ \
|
||||||
|
void Clear##name() \
|
||||||
|
{ \
|
||||||
|
_##name = std::nullopt; \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
private: \
|
||||||
|
std::optional<type> _##name{ std::nullopt }; \
|
||||||
|
std::optional<type> _get##name##Impl() const \
|
||||||
|
{ \
|
||||||
|
/*return user set value*/ \
|
||||||
|
if (_##name) \
|
||||||
|
{ \
|
||||||
|
return _##name; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/*user set value was not set*/ \
|
||||||
|
/*iterate through parents to find a value*/ \
|
||||||
|
for (auto parent : _parents) \
|
||||||
|
{ \
|
||||||
|
if (auto val{ parent->_get##name##Impl() }) \
|
||||||
|
{ \
|
||||||
|
return val; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/*no value was found*/ \
|
||||||
|
return std::nullopt; \
|
||||||
|
};
|
||||||
|
|
||||||
|
// This macro is similar to the one above, but is reserved for optional settings
|
||||||
|
// like Profile.Foreground (where null is interpreted
|
||||||
|
// as an acceptable value, rather than "inherit")
|
||||||
|
// "type" is exposed as an IReference
|
||||||
|
#define GETSET_NULLABLE_SETTING(type, name, ...) \
|
||||||
|
public: \
|
||||||
|
/* Returns true if the user explicitly set the value, false otherwise*/ \
|
||||||
|
bool Has##name() const \
|
||||||
|
{ \
|
||||||
|
return _##name.set; \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
/* Returns the resolved value for this setting */ \
|
||||||
|
/* fallback: user set value --> inherited value --> system set value */ \
|
||||||
|
winrt::Windows::Foundation::IReference<type> name() const \
|
||||||
|
{ \
|
||||||
|
const auto val{ _get##name##Impl() }; \
|
||||||
|
if (val.set) \
|
||||||
|
{ \
|
||||||
|
if (val.setting) \
|
||||||
|
{ \
|
||||||
|
return *val.setting; \
|
||||||
|
} \
|
||||||
|
return nullptr; \
|
||||||
|
} \
|
||||||
|
return winrt::Windows::Foundation::IReference<type>{ __VA_ARGS__ }; \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
/* Overwrite the user set value */ \
|
||||||
|
void name(const winrt::Windows::Foundation::IReference<type>& value) \
|
||||||
|
{ \
|
||||||
|
if (value) /*set value is different*/ \
|
||||||
|
{ \
|
||||||
|
_##name.setting = value.Value(); \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
_##name.setting = std::nullopt; \
|
||||||
|
} \
|
||||||
|
_##name.set = true; \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
/* Clear the user set value */ \
|
||||||
|
void Clear##name() \
|
||||||
|
{ \
|
||||||
|
_##name.set = false; \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
private: \
|
||||||
|
NullableSetting<type> _##name{}; \
|
||||||
|
NullableSetting<type> _get##name##Impl() const \
|
||||||
|
{ \
|
||||||
|
/*return user set value*/ \
|
||||||
|
if (Has##name()) \
|
||||||
|
{ \
|
||||||
|
return _##name; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/*user set value was not set*/ \
|
||||||
|
/*iterate through parents to find a value*/ \
|
||||||
|
for (auto parent : _parents) \
|
||||||
|
{ \
|
||||||
|
auto val{ parent->_get##name##Impl() }; \
|
||||||
|
if (val.set) \
|
||||||
|
{ \
|
||||||
|
return val; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
/*no value was found*/ \
|
||||||
|
return { std::nullopt, false }; \
|
||||||
|
};
|
|
@ -43,6 +43,7 @@
|
||||||
<ClInclude Include="GlobalAppSettings.h">
|
<ClInclude Include="GlobalAppSettings.h">
|
||||||
<DependentUpon>GlobalAppSettings.idl</DependentUpon>
|
<DependentUpon>GlobalAppSettings.idl</DependentUpon>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="IInheritable.h" />
|
||||||
<ClInclude Include="IDynamicProfileGenerator.h" />
|
<ClInclude Include="IDynamicProfileGenerator.h" />
|
||||||
<ClInclude Include="JsonUtils.h" />
|
<ClInclude Include="JsonUtils.h" />
|
||||||
<ClInclude Include="KeyChordSerialization.h">
|
<ClInclude Include="KeyChordSerialization.h">
|
||||||
|
|
|
@ -70,49 +70,100 @@ Profile::Profile(guid guid) :
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
winrt::com_ptr<Profile> Profile::Copy() const
|
winrt::com_ptr<Profile> Profile::CopySettings(winrt::com_ptr<Profile> source)
|
||||||
{
|
{
|
||||||
auto profile{ winrt::make_self<Profile>() };
|
auto profile{ winrt::make_self<Profile>() };
|
||||||
profile->_Name = _Name;
|
profile->_Guid = source->_Guid;
|
||||||
profile->_Source = _Source;
|
profile->_Name = source->_Name;
|
||||||
profile->_Hidden = _Hidden;
|
profile->_Source = source->_Source;
|
||||||
profile->_Icon = _Icon;
|
profile->_Hidden = source->_Hidden;
|
||||||
profile->_CloseOnExit = _CloseOnExit;
|
profile->_Icon = source->_Icon;
|
||||||
profile->_TabTitle = _TabTitle;
|
profile->_CloseOnExit = source->_CloseOnExit;
|
||||||
profile->_TabColor = _TabColor;
|
profile->_TabTitle = source->_TabTitle;
|
||||||
profile->_SuppressApplicationTitle = _SuppressApplicationTitle;
|
profile->_TabColor = source->_TabColor;
|
||||||
profile->_UseAcrylic = _UseAcrylic;
|
profile->_SuppressApplicationTitle = source->_SuppressApplicationTitle;
|
||||||
profile->_AcrylicOpacity = _AcrylicOpacity;
|
profile->_UseAcrylic = source->_UseAcrylic;
|
||||||
profile->_ScrollState = _ScrollState;
|
profile->_AcrylicOpacity = source->_AcrylicOpacity;
|
||||||
profile->_FontFace = _FontFace;
|
profile->_ScrollState = source->_ScrollState;
|
||||||
profile->_FontSize = _FontSize;
|
profile->_FontFace = source->_FontFace;
|
||||||
profile->_FontWeight = _FontWeight;
|
profile->_FontSize = source->_FontSize;
|
||||||
profile->_Padding = _Padding;
|
profile->_FontWeight = source->_FontWeight;
|
||||||
profile->_Commandline = _Commandline;
|
profile->_Padding = source->_Padding;
|
||||||
profile->_StartingDirectory = _StartingDirectory;
|
profile->_Commandline = source->_Commandline;
|
||||||
profile->_BackgroundImagePath = _BackgroundImagePath;
|
profile->_StartingDirectory = source->_StartingDirectory;
|
||||||
profile->_BackgroundImageOpacity = _BackgroundImageOpacity;
|
profile->_BackgroundImagePath = source->_BackgroundImagePath;
|
||||||
profile->_BackgroundImageStretchMode = _BackgroundImageStretchMode;
|
profile->_BackgroundImageOpacity = source->_BackgroundImageOpacity;
|
||||||
profile->_AntialiasingMode = _AntialiasingMode;
|
profile->_BackgroundImageStretchMode = source->_BackgroundImageStretchMode;
|
||||||
profile->_RetroTerminalEffect = _RetroTerminalEffect;
|
profile->_AntialiasingMode = source->_AntialiasingMode;
|
||||||
profile->_ForceFullRepaintRendering = _ForceFullRepaintRendering;
|
profile->_RetroTerminalEffect = source->_RetroTerminalEffect;
|
||||||
profile->_SoftwareRendering = _SoftwareRendering;
|
profile->_ForceFullRepaintRendering = source->_ForceFullRepaintRendering;
|
||||||
profile->_ColorSchemeName = _ColorSchemeName;
|
profile->_SoftwareRendering = source->_SoftwareRendering;
|
||||||
profile->_Foreground = _Foreground;
|
profile->_ColorSchemeName = source->_ColorSchemeName;
|
||||||
profile->_Background = _Background;
|
profile->_Foreground = source->_Foreground;
|
||||||
profile->_SelectionBackground = _SelectionBackground;
|
profile->_Background = source->_Background;
|
||||||
profile->_CursorColor = _CursorColor;
|
profile->_SelectionBackground = source->_SelectionBackground;
|
||||||
profile->_HistorySize = _HistorySize;
|
profile->_CursorColor = source->_CursorColor;
|
||||||
profile->_SnapOnInput = _SnapOnInput;
|
profile->_HistorySize = source->_HistorySize;
|
||||||
profile->_AltGrAliasing = _AltGrAliasing;
|
profile->_SnapOnInput = source->_SnapOnInput;
|
||||||
profile->_CursorShape = _CursorShape;
|
profile->_AltGrAliasing = source->_AltGrAliasing;
|
||||||
profile->_CursorHeight = _CursorHeight;
|
profile->_CursorShape = source->_CursorShape;
|
||||||
profile->_Guid = _Guid;
|
profile->_CursorHeight = source->_CursorHeight;
|
||||||
profile->_ConnectionType = _ConnectionType;
|
profile->_BellStyle = source->_BellStyle;
|
||||||
profile->_BackgroundImageAlignment = _BackgroundImageAlignment;
|
profile->_BackgroundImageAlignment = source->_BackgroundImageAlignment;
|
||||||
|
profile->_ConnectionType = source->_ConnectionType;
|
||||||
|
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Description:
|
||||||
|
// - Creates a copy of the inheritance graph by performing a depth-first traversal recursively.
|
||||||
|
// Profiles are recorded as visited via the "visited" parameter.
|
||||||
|
// Unvisited Profiles are copied into the "cloneGraph" parameter, then marked as visited.
|
||||||
|
// Arguments:
|
||||||
|
// - sourceGraph - the graph of Profile's we're cloning
|
||||||
|
// - cloneGraph - the clone of sourceGraph that is being constructed
|
||||||
|
// - visited - a map of which Profiles have been visited, and, if so, a reference to the Profile's clone
|
||||||
|
// Return Value:
|
||||||
|
// - a clone in both inheritance structure and Profile values of sourceGraph
|
||||||
|
winrt::com_ptr<Profile> Profile::CloneInheritanceGraph(winrt::com_ptr<Profile> sourceGraph, winrt::com_ptr<Profile> cloneGraph, std::unordered_map<void*, winrt::com_ptr<Profile>>& visited)
|
||||||
|
{
|
||||||
|
// If this is an unexplored Profile
|
||||||
|
// and we have parents...
|
||||||
|
if (visited.find(sourceGraph.get()) == visited.end() && !sourceGraph->_parents.empty())
|
||||||
|
{
|
||||||
|
// iterate through all of our parents to copy them
|
||||||
|
for (const auto& sourceParent : sourceGraph->_parents)
|
||||||
|
{
|
||||||
|
// If we visited this Profile already...
|
||||||
|
auto kv{ visited.find(sourceParent.get()) };
|
||||||
|
if (kv != visited.end())
|
||||||
|
{
|
||||||
|
// add this Profile's clone as a parent
|
||||||
|
cloneGraph->InsertParent(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
|
||||||
|
cloneGraph->InsertParent(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:
|
// Method Description:
|
||||||
// - Generates a Json::Value which is a "stub" of this profile. This stub will
|
// - 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.
|
// have enough information that it could be layered with this profile.
|
||||||
|
@ -129,19 +180,17 @@ Json::Value Profile::GenerateStub() const
|
||||||
Json::Value stub;
|
Json::Value stub;
|
||||||
|
|
||||||
///// Profile-specific settings /////
|
///// Profile-specific settings /////
|
||||||
if (_Guid.has_value())
|
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(GuidKey)] = winrt::to_string(Utils::GuidToString(*_Guid));
|
stub[JsonKey(SourceKey)] = winrt::to_string(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
stub[JsonKey(NameKey)] = winrt::to_string(_Name);
|
stub[JsonKey(HiddenKey)] = Hidden();
|
||||||
|
|
||||||
if (!_Source.empty())
|
|
||||||
{
|
|
||||||
stub[JsonKey(SourceKey)] = winrt::to_string(_Source);
|
|
||||||
}
|
|
||||||
|
|
||||||
stub[JsonKey(HiddenKey)] = _Hidden;
|
|
||||||
|
|
||||||
return stub;
|
return stub;
|
||||||
}
|
}
|
||||||
|
@ -169,40 +218,37 @@ winrt::com_ptr<winrt::Microsoft::Terminal::Settings::Model::implementation::Prof
|
||||||
// - true iff the json object has the same `GUID` as we do.
|
// - true iff the json object has the same `GUID` as we do.
|
||||||
bool Profile::ShouldBeLayered(const Json::Value& json) const
|
bool Profile::ShouldBeLayered(const Json::Value& json) const
|
||||||
{
|
{
|
||||||
if (!_Guid.has_value())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// First, check that GUIDs match. This is easy. If they don't match, they
|
// First, check that GUIDs match. This is easy. If they don't match, they
|
||||||
// should _definitely_ not layer.
|
// should _definitely_ not layer.
|
||||||
if (const auto otherGuid{ JsonUtils::GetValueForKey<std::optional<winrt::guid>>(json, GuidKey) })
|
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)
|
if (otherGuid.value() != Guid())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If the other json object didn't have a GUID, we definitely don't want
|
// If the other json object didn't have a GUID,
|
||||||
// to layer. We technically might have the same name, and would
|
// check if we auto-generate the same guid using the name and source.
|
||||||
// auto-generate the same guid, but they should be treated as different
|
const auto otherName{ JsonUtils::GetValueForKey<std::optional<winrt::hstring>>(json, NameKey) };
|
||||||
// profiles.
|
if (Guid() != _GenerateGuidForProfile(otherName ? *otherName : L"Default", otherSource ? *otherSource : L""))
|
||||||
return false;
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::wstring> otherSource;
|
|
||||||
bool otherHadSource = JsonUtils::GetValueForKey(json, SourceKey, otherSource);
|
|
||||||
|
|
||||||
// For profiles with a `source`, also check the `source` property.
|
// For profiles with a `source`, also check the `source` property.
|
||||||
bool sourceMatches = false;
|
bool sourceMatches = false;
|
||||||
if (!_Source.empty())
|
const auto mySource{ Source() };
|
||||||
|
if (!mySource.empty())
|
||||||
{
|
{
|
||||||
if (otherHadSource)
|
if (otherSource.has_value())
|
||||||
{
|
{
|
||||||
// If we have a source and the other has a source, compare them!
|
// If we have a source and the other has a source, compare them!
|
||||||
sourceMatches = *otherSource == _Source;
|
sourceMatches = *otherSource == mySource;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -210,9 +256,9 @@ bool Profile::ShouldBeLayered(const Json::Value& json) const
|
||||||
// `this` is a dynamic profile with a source, and our _source is one
|
// `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
|
// of the legacy DPG namespaces. We're looking to see if the other
|
||||||
// json object has the same guid, but _no_ "source"
|
// json object has the same guid, but _no_ "source"
|
||||||
if (_Source == WslGeneratorNamespace ||
|
if (mySource == WslGeneratorNamespace ||
|
||||||
_Source == AzureGeneratorNamespace ||
|
mySource == AzureGeneratorNamespace ||
|
||||||
_Source == PowershellCoreGeneratorNamespace)
|
mySource == PowershellCoreGeneratorNamespace)
|
||||||
{
|
{
|
||||||
sourceMatches = true;
|
sourceMatches = true;
|
||||||
}
|
}
|
||||||
|
@ -247,10 +293,10 @@ void Profile::LayerJson(const Json::Value& json)
|
||||||
JsonUtils::GetValueForKey(json, HiddenKey, _Hidden);
|
JsonUtils::GetValueForKey(json, HiddenKey, _Hidden);
|
||||||
|
|
||||||
// Core Settings
|
// Core Settings
|
||||||
JsonUtils::GetValueForKey(json, ForegroundKey, _Foreground);
|
_Foreground.set = JsonUtils::GetValueForKey(json, ForegroundKey, _Foreground.setting);
|
||||||
JsonUtils::GetValueForKey(json, BackgroundKey, _Background);
|
_Background.set = JsonUtils::GetValueForKey(json, BackgroundKey, _Background.setting);
|
||||||
JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _SelectionBackground);
|
_SelectionBackground.set = JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _SelectionBackground.setting);
|
||||||
JsonUtils::GetValueForKey(json, CursorColorKey, _CursorColor);
|
_CursorColor.set = JsonUtils::GetValueForKey(json, CursorColorKey, _CursorColor.setting);
|
||||||
JsonUtils::GetValueForKey(json, ColorSchemeKey, _ColorSchemeName);
|
JsonUtils::GetValueForKey(json, ColorSchemeKey, _ColorSchemeName);
|
||||||
|
|
||||||
// TODO:MSFT:20642297 - Use a sentinel value (-1) for "Infinite scrollback"
|
// TODO:MSFT:20642297 - Use a sentinel value (-1) for "Infinite scrollback"
|
||||||
|
@ -277,7 +323,16 @@ void Profile::LayerJson(const Json::Value& json)
|
||||||
JsonUtils::GetValueForKey(json, PaddingKey, _Padding, JsonUtils::PermissiveStringConverter<std::wstring>{});
|
JsonUtils::GetValueForKey(json, PaddingKey, _Padding, JsonUtils::PermissiveStringConverter<std::wstring>{});
|
||||||
|
|
||||||
JsonUtils::GetValueForKey(json, ScrollbarStateKey, _ScrollState);
|
JsonUtils::GetValueForKey(json, ScrollbarStateKey, _ScrollState);
|
||||||
JsonUtils::GetValueForKey(json, StartingDirectoryKey, _StartingDirectory);
|
|
||||||
|
// StartingDirectory is "nullable". But we represent a null starting directory as the empty string
|
||||||
|
// When null is set in the JSON, we empty initialize startDir (empty string), and set StartingDirectory to that
|
||||||
|
// Without this, we're accidentally setting StartingDirectory to nullopt instead.
|
||||||
|
hstring startDir;
|
||||||
|
if (JsonUtils::GetValueForKey(json, StartingDirectoryKey, startDir))
|
||||||
|
{
|
||||||
|
_StartingDirectory = startDir;
|
||||||
|
}
|
||||||
|
|
||||||
JsonUtils::GetValueForKey(json, IconKey, _Icon);
|
JsonUtils::GetValueForKey(json, IconKey, _Icon);
|
||||||
JsonUtils::GetValueForKey(json, BackgroundImageKey, _BackgroundImagePath);
|
JsonUtils::GetValueForKey(json, BackgroundImageKey, _BackgroundImagePath);
|
||||||
JsonUtils::GetValueForKey(json, BackgroundImageOpacityKey, _BackgroundImageOpacity);
|
JsonUtils::GetValueForKey(json, BackgroundImageOpacityKey, _BackgroundImageOpacity);
|
||||||
|
@ -286,7 +341,7 @@ void Profile::LayerJson(const Json::Value& json)
|
||||||
JsonUtils::GetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect);
|
JsonUtils::GetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect);
|
||||||
JsonUtils::GetValueForKey(json, AntialiasingModeKey, _AntialiasingMode);
|
JsonUtils::GetValueForKey(json, AntialiasingModeKey, _AntialiasingMode);
|
||||||
|
|
||||||
JsonUtils::GetValueForKey(json, TabColorKey, _TabColor);
|
_TabColor.set = JsonUtils::GetValueForKey(json, TabColorKey, _TabColor.setting);
|
||||||
|
|
||||||
JsonUtils::GetValueForKey(json, BellStyleKey, _BellStyle);
|
JsonUtils::GetValueForKey(json, BellStyleKey, _BellStyle);
|
||||||
}
|
}
|
||||||
|
@ -300,13 +355,14 @@ void Profile::LayerJson(const Json::Value& json)
|
||||||
// - This profile's expanded background image path / desktops's wallpaper path /the empty string.
|
// - This profile's expanded background image path / desktops's wallpaper path /the empty string.
|
||||||
winrt::hstring Profile::ExpandedBackgroundImagePath() const
|
winrt::hstring Profile::ExpandedBackgroundImagePath() const
|
||||||
{
|
{
|
||||||
if (_BackgroundImagePath.empty())
|
const auto path{ BackgroundImagePath() };
|
||||||
|
if (path.empty())
|
||||||
{
|
{
|
||||||
return _BackgroundImagePath;
|
return path;
|
||||||
}
|
}
|
||||||
// checks if the user would like to copy their desktop wallpaper
|
// checks if the user would like to copy their desktop wallpaper
|
||||||
// if so, replaces the path with the desktop wallpaper's path
|
// if so, replaces the path with the desktop wallpaper's path
|
||||||
else if (_BackgroundImagePath == to_hstring(DesktopWallpaperEnum))
|
else if (path == to_hstring(DesktopWallpaperEnum))
|
||||||
{
|
{
|
||||||
WCHAR desktopWallpaper[MAX_PATH];
|
WCHAR desktopWallpaper[MAX_PATH];
|
||||||
|
|
||||||
|
@ -322,13 +378,19 @@ winrt::hstring Profile::ExpandedBackgroundImagePath() const
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return winrt::hstring{ wil::ExpandEnvironmentStringsW<std::wstring>(_BackgroundImagePath.c_str()) };
|
return winrt::hstring{ wil::ExpandEnvironmentStringsW<std::wstring>(path.c_str()) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
winrt::hstring Profile::EvaluatedStartingDirectory() const
|
winrt::hstring Profile::EvaluatedStartingDirectory() const
|
||||||
{
|
{
|
||||||
return winrt::hstring{ Profile::EvaluateStartingDirectory(_StartingDirectory.c_str()) };
|
auto path{ StartingDirectory() };
|
||||||
|
if (!path.empty())
|
||||||
|
{
|
||||||
|
return winrt::hstring{ Profile::EvaluateStartingDirectory(path.c_str()) };
|
||||||
|
}
|
||||||
|
// treated as "inherit directory from parent process"
|
||||||
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
|
@ -368,11 +430,11 @@ std::wstring Profile::EvaluateStartingDirectory(const std::wstring& directory)
|
||||||
// will _not_ change the profile's GUID.
|
// will _not_ change the profile's GUID.
|
||||||
void Profile::GenerateGuidIfNecessary() noexcept
|
void Profile::GenerateGuidIfNecessary() noexcept
|
||||||
{
|
{
|
||||||
if (!_Guid.has_value())
|
if (!_getGuidImpl().has_value())
|
||||||
{
|
{
|
||||||
// Always use the name to generate the temporary GUID. That way, across
|
// Always use the name to generate the temporary GUID. That way, across
|
||||||
// reloads, we'll generate the same static GUID.
|
// reloads, we'll generate the same static GUID.
|
||||||
_Guid = Profile::_GenerateGuidForProfile(_Name, _Source);
|
_Guid = Profile::_GenerateGuidForProfile(Name(), Source());
|
||||||
|
|
||||||
TraceLoggingWrite(
|
TraceLoggingWrite(
|
||||||
g_hSettingsModelProvider,
|
g_hSettingsModelProvider,
|
||||||
|
@ -438,54 +500,50 @@ winrt::guid Profile::GetGuidOrGenerateForJson(const Json::Value& json) noexcept
|
||||||
return Profile::_GenerateGuidForProfile(name, source);
|
return Profile::_GenerateGuidForProfile(name, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma region BackgroundImageAlignment
|
||||||
|
bool Profile::HasBackgroundImageAlignment() const noexcept
|
||||||
|
{
|
||||||
|
return _BackgroundImageAlignment.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Profile::ClearBackgroundImageAlignment() noexcept
|
||||||
|
{
|
||||||
|
_BackgroundImageAlignment = std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
const HorizontalAlignment Profile::BackgroundImageHorizontalAlignment() const noexcept
|
const HorizontalAlignment Profile::BackgroundImageHorizontalAlignment() const noexcept
|
||||||
{
|
{
|
||||||
return std::get<HorizontalAlignment>(_BackgroundImageAlignment);
|
const auto val{ _getBackgroundImageAlignmentImpl() };
|
||||||
|
return val ? std::get<HorizontalAlignment>(*val) : HorizontalAlignment::Center;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Profile::BackgroundImageHorizontalAlignment(const HorizontalAlignment& value) noexcept
|
void Profile::BackgroundImageHorizontalAlignment(const HorizontalAlignment& value) noexcept
|
||||||
{
|
{
|
||||||
std::get<HorizontalAlignment>(_BackgroundImageAlignment) = value;
|
if (HasBackgroundImageAlignment())
|
||||||
|
{
|
||||||
|
std::get<HorizontalAlignment>(*_BackgroundImageAlignment) = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_BackgroundImageAlignment = { value, VerticalAlignment::Center };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const VerticalAlignment Profile::BackgroundImageVerticalAlignment() const noexcept
|
const VerticalAlignment Profile::BackgroundImageVerticalAlignment() const noexcept
|
||||||
{
|
{
|
||||||
return std::get<VerticalAlignment>(_BackgroundImageAlignment);
|
const auto val{ _getBackgroundImageAlignmentImpl() };
|
||||||
|
return val ? std::get<VerticalAlignment>(*val) : VerticalAlignment::Center;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Profile::BackgroundImageVerticalAlignment(const VerticalAlignment& value) noexcept
|
void Profile::BackgroundImageVerticalAlignment(const VerticalAlignment& value) noexcept
|
||||||
{
|
{
|
||||||
std::get<VerticalAlignment>(_BackgroundImageAlignment) = value;
|
if (HasBackgroundImageAlignment())
|
||||||
}
|
{
|
||||||
|
std::get<VerticalAlignment>(*_BackgroundImageAlignment) = value;
|
||||||
bool Profile::HasGuid() const noexcept
|
}
|
||||||
{
|
else
|
||||||
return _Guid.has_value();
|
{
|
||||||
}
|
_BackgroundImageAlignment = { HorizontalAlignment::Center, value };
|
||||||
|
}
|
||||||
winrt::guid Profile::Guid() const
|
|
||||||
{
|
|
||||||
// This can throw if we never had our guid set to a legitimate value.
|
|
||||||
THROW_HR_IF_MSG(E_FAIL, !_Guid.has_value(), "Profile._guid always expected to have a value");
|
|
||||||
return *_Guid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Profile::Guid(const winrt::guid& guid) noexcept
|
|
||||||
{
|
|
||||||
_Guid = guid;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Profile::HasConnectionType() const noexcept
|
|
||||||
{
|
|
||||||
return _ConnectionType.has_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
winrt::guid Profile::ConnectionType() const noexcept
|
|
||||||
{
|
|
||||||
return *_ConnectionType;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Profile::ConnectionType(const winrt::guid& conType) noexcept
|
|
||||||
{
|
|
||||||
_ConnectionType = conType;
|
|
||||||
}
|
}
|
||||||
|
#pragma endregion
|
||||||
|
|
|
@ -16,21 +16,24 @@ Author(s):
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Profile.g.h"
|
#include "Profile.g.h"
|
||||||
|
#include "IInheritable.h"
|
||||||
|
|
||||||
#include "../inc/cppwinrt_utils.h"
|
#include "../inc/cppwinrt_utils.h"
|
||||||
#include "JsonUtils.h"
|
#include "JsonUtils.h"
|
||||||
#include <DefaultSettings.h>
|
#include <DefaultSettings.h>
|
||||||
|
|
||||||
// fwdecl unittest classes
|
// fwdecl unittest classes
|
||||||
namespace TerminalAppLocalTests
|
namespace SettingsModelLocalTests
|
||||||
{
|
{
|
||||||
class SettingsTests;
|
class DeserializationTests;
|
||||||
class ProfileTests;
|
class ProfileTests;
|
||||||
|
class ColorSchemeTests;
|
||||||
|
class KeyBindingsTests;
|
||||||
};
|
};
|
||||||
namespace TerminalAppUnitTests
|
namespace TerminalAppUnitTests
|
||||||
{
|
{
|
||||||
class JsonTests;
|
|
||||||
class DynamicProfileTests;
|
class DynamicProfileTests;
|
||||||
|
class JsonTests;
|
||||||
};
|
};
|
||||||
|
|
||||||
// GUID used for generating GUIDs at runtime, for profiles that did not have a
|
// GUID used for generating GUIDs at runtime, for profiles that did not have a
|
||||||
|
@ -39,12 +42,13 @@ constexpr GUID RUNTIME_GENERATED_PROFILE_NAMESPACE_GUID = { 0xf65ddb7e, 0x706b,
|
||||||
|
|
||||||
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||||
{
|
{
|
||||||
struct Profile : ProfileT<Profile>
|
struct Profile : ProfileT<Profile>, IInheritable<Profile>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Profile();
|
Profile();
|
||||||
Profile(guid guid);
|
Profile(guid guid);
|
||||||
com_ptr<Profile> Copy() const;
|
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);
|
||||||
|
|
||||||
Json::Value GenerateStub() const;
|
Json::Value GenerateStub() const;
|
||||||
static com_ptr<Profile> FromJson(const Json::Value& json);
|
static com_ptr<Profile> FromJson(const Json::Value& json);
|
||||||
|
@ -57,83 +61,97 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||||
void GenerateGuidIfNecessary() noexcept;
|
void GenerateGuidIfNecessary() noexcept;
|
||||||
static guid GetGuidOrGenerateForJson(const Json::Value& json) noexcept;
|
static guid GetGuidOrGenerateForJson(const Json::Value& json) noexcept;
|
||||||
|
|
||||||
bool HasGuid() const noexcept;
|
|
||||||
winrt::guid Guid() const;
|
|
||||||
void Guid(const winrt::guid& guid) noexcept;
|
|
||||||
|
|
||||||
bool HasConnectionType() const noexcept;
|
|
||||||
winrt::guid ConnectionType() const noexcept;
|
|
||||||
void ConnectionType(const winrt::guid& conType) noexcept;
|
|
||||||
|
|
||||||
// BackgroundImageAlignment is 1 setting saved as 2 separate values
|
// BackgroundImageAlignment is 1 setting saved as 2 separate values
|
||||||
|
bool HasBackgroundImageAlignment() const noexcept;
|
||||||
|
void ClearBackgroundImageAlignment() noexcept;
|
||||||
const Windows::UI::Xaml::HorizontalAlignment BackgroundImageHorizontalAlignment() const noexcept;
|
const Windows::UI::Xaml::HorizontalAlignment BackgroundImageHorizontalAlignment() const noexcept;
|
||||||
void BackgroundImageHorizontalAlignment(const Windows::UI::Xaml::HorizontalAlignment& value) noexcept;
|
void BackgroundImageHorizontalAlignment(const Windows::UI::Xaml::HorizontalAlignment& value) noexcept;
|
||||||
const Windows::UI::Xaml::VerticalAlignment BackgroundImageVerticalAlignment() const noexcept;
|
const Windows::UI::Xaml::VerticalAlignment BackgroundImageVerticalAlignment() const noexcept;
|
||||||
void BackgroundImageVerticalAlignment(const Windows::UI::Xaml::VerticalAlignment& value) noexcept;
|
void BackgroundImageVerticalAlignment(const Windows::UI::Xaml::VerticalAlignment& value) noexcept;
|
||||||
|
|
||||||
GETSET_PROPERTY(hstring, Name, L"Default");
|
GETSET_SETTING(guid, Guid, _GenerateGuidForProfile(Name(), Source()));
|
||||||
GETSET_PROPERTY(hstring, Source);
|
GETSET_SETTING(hstring, Name, L"Default");
|
||||||
GETSET_PROPERTY(bool, Hidden, false);
|
GETSET_SETTING(hstring, Source);
|
||||||
|
GETSET_SETTING(bool, Hidden, false);
|
||||||
|
GETSET_SETTING(guid, ConnectionType);
|
||||||
|
|
||||||
GETSET_PROPERTY(hstring, Icon);
|
GETSET_SETTING(hstring, Icon);
|
||||||
|
|
||||||
GETSET_PROPERTY(CloseOnExitMode, CloseOnExit, CloseOnExitMode::Graceful);
|
GETSET_SETTING(CloseOnExitMode, CloseOnExit, CloseOnExitMode::Graceful);
|
||||||
GETSET_PROPERTY(hstring, TabTitle);
|
GETSET_SETTING(hstring, TabTitle);
|
||||||
GETSET_PROPERTY(Windows::Foundation::IReference<Windows::UI::Color>, TabColor);
|
GETSET_NULLABLE_SETTING(Windows::UI::Color, TabColor, nullptr);
|
||||||
GETSET_PROPERTY(bool, SuppressApplicationTitle, false);
|
GETSET_SETTING(bool, SuppressApplicationTitle, false);
|
||||||
|
|
||||||
GETSET_PROPERTY(bool, UseAcrylic, false);
|
GETSET_SETTING(bool, UseAcrylic, false);
|
||||||
GETSET_PROPERTY(double, AcrylicOpacity, 0.5);
|
GETSET_SETTING(double, AcrylicOpacity, 0.5);
|
||||||
GETSET_PROPERTY(Microsoft::Terminal::TerminalControl::ScrollbarState, ScrollState, Microsoft::Terminal::TerminalControl::ScrollbarState::Visible);
|
GETSET_SETTING(Microsoft::Terminal::TerminalControl::ScrollbarState, ScrollState, Microsoft::Terminal::TerminalControl::ScrollbarState::Visible);
|
||||||
|
|
||||||
GETSET_PROPERTY(hstring, FontFace, DEFAULT_FONT_FACE);
|
GETSET_SETTING(hstring, FontFace, DEFAULT_FONT_FACE);
|
||||||
GETSET_PROPERTY(int32_t, FontSize, DEFAULT_FONT_SIZE);
|
GETSET_SETTING(int32_t, FontSize, DEFAULT_FONT_SIZE);
|
||||||
GETSET_PROPERTY(Windows::UI::Text::FontWeight, FontWeight, DEFAULT_FONT_WEIGHT);
|
GETSET_SETTING(Windows::UI::Text::FontWeight, FontWeight, DEFAULT_FONT_WEIGHT);
|
||||||
GETSET_PROPERTY(hstring, Padding, DEFAULT_PADDING);
|
GETSET_SETTING(hstring, Padding, DEFAULT_PADDING);
|
||||||
|
|
||||||
GETSET_PROPERTY(hstring, Commandline, L"cmd.exe");
|
GETSET_SETTING(hstring, Commandline, L"cmd.exe");
|
||||||
GETSET_PROPERTY(hstring, StartingDirectory);
|
GETSET_SETTING(hstring, StartingDirectory);
|
||||||
|
|
||||||
GETSET_PROPERTY(hstring, BackgroundImagePath);
|
GETSET_SETTING(hstring, BackgroundImagePath);
|
||||||
GETSET_PROPERTY(double, BackgroundImageOpacity, 1.0);
|
GETSET_SETTING(double, BackgroundImageOpacity, 1.0);
|
||||||
GETSET_PROPERTY(Windows::UI::Xaml::Media::Stretch, BackgroundImageStretchMode, Windows::UI::Xaml::Media::Stretch::Fill);
|
GETSET_SETTING(Windows::UI::Xaml::Media::Stretch, BackgroundImageStretchMode, Windows::UI::Xaml::Media::Stretch::Fill);
|
||||||
|
|
||||||
GETSET_PROPERTY(Microsoft::Terminal::TerminalControl::TextAntialiasingMode, AntialiasingMode, Microsoft::Terminal::TerminalControl::TextAntialiasingMode::Grayscale);
|
GETSET_SETTING(Microsoft::Terminal::TerminalControl::TextAntialiasingMode, AntialiasingMode, Microsoft::Terminal::TerminalControl::TextAntialiasingMode::Grayscale);
|
||||||
GETSET_PROPERTY(bool, RetroTerminalEffect, false);
|
GETSET_SETTING(bool, RetroTerminalEffect, false);
|
||||||
GETSET_PROPERTY(bool, ForceFullRepaintRendering, false);
|
GETSET_SETTING(bool, ForceFullRepaintRendering, false);
|
||||||
GETSET_PROPERTY(bool, SoftwareRendering, false);
|
GETSET_SETTING(bool, SoftwareRendering, false);
|
||||||
|
|
||||||
GETSET_PROPERTY(hstring, ColorSchemeName, L"Campbell");
|
GETSET_SETTING(hstring, ColorSchemeName, L"Campbell");
|
||||||
GETSET_PROPERTY(Windows::Foundation::IReference<Windows::UI::Color>, Foreground);
|
|
||||||
GETSET_PROPERTY(Windows::Foundation::IReference<Windows::UI::Color>, Background);
|
|
||||||
GETSET_PROPERTY(Windows::Foundation::IReference<Windows::UI::Color>, SelectionBackground);
|
|
||||||
GETSET_PROPERTY(Windows::Foundation::IReference<Windows::UI::Color>, CursorColor);
|
|
||||||
|
|
||||||
GETSET_PROPERTY(int32_t, HistorySize, DEFAULT_HISTORY_SIZE);
|
GETSET_NULLABLE_SETTING(Windows::UI::Color, Foreground, nullptr);
|
||||||
GETSET_PROPERTY(bool, SnapOnInput, true);
|
GETSET_NULLABLE_SETTING(Windows::UI::Color, Background, nullptr);
|
||||||
GETSET_PROPERTY(bool, AltGrAliasing, true);
|
GETSET_NULLABLE_SETTING(Windows::UI::Color, SelectionBackground, nullptr);
|
||||||
|
GETSET_NULLABLE_SETTING(Windows::UI::Color, CursorColor, nullptr);
|
||||||
|
|
||||||
GETSET_PROPERTY(Microsoft::Terminal::TerminalControl::CursorStyle, CursorShape, Microsoft::Terminal::TerminalControl::CursorStyle::Bar);
|
GETSET_SETTING(int32_t, HistorySize, DEFAULT_HISTORY_SIZE);
|
||||||
GETSET_PROPERTY(uint32_t, CursorHeight, DEFAULT_CURSOR_HEIGHT);
|
GETSET_SETTING(bool, SnapOnInput, true);
|
||||||
|
GETSET_SETTING(bool, AltGrAliasing, true);
|
||||||
|
|
||||||
GETSET_PROPERTY(winrt::Microsoft::Terminal::Settings::Model::BellStyle, BellStyle, winrt::Microsoft::Terminal::Settings::Model::BellStyle::Audible);
|
GETSET_SETTING(Microsoft::Terminal::TerminalControl::CursorStyle, CursorShape, Microsoft::Terminal::TerminalControl::CursorStyle::Bar);
|
||||||
|
GETSET_SETTING(uint32_t, CursorHeight, DEFAULT_CURSOR_HEIGHT);
|
||||||
|
|
||||||
|
GETSET_SETTING(Model::BellStyle, BellStyle, BellStyle::Audible);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::optional<winrt::guid> _Guid{ std::nullopt };
|
std::optional<std::tuple<Windows::UI::Xaml::HorizontalAlignment, Windows::UI::Xaml::VerticalAlignment>> _BackgroundImageAlignment{ std::nullopt };
|
||||||
std::optional<winrt::guid> _ConnectionType{ std::nullopt };
|
std::optional<std::tuple<Windows::UI::Xaml::HorizontalAlignment, Windows::UI::Xaml::VerticalAlignment>> _getBackgroundImageAlignmentImpl() const
|
||||||
std::tuple<Windows::UI::Xaml::HorizontalAlignment, Windows::UI::Xaml::VerticalAlignment> _BackgroundImageAlignment{
|
{
|
||||||
Windows::UI::Xaml::HorizontalAlignment::Center,
|
/*return user set value*/
|
||||||
Windows::UI::Xaml::VerticalAlignment::Center
|
if (_BackgroundImageAlignment)
|
||||||
|
{
|
||||||
|
return _BackgroundImageAlignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*user set value was not set*/ /*iterate through parents to find a value*/
|
||||||
|
for (auto parent : _parents)
|
||||||
|
{
|
||||||
|
if (auto val{ parent->_getBackgroundImageAlignmentImpl() })
|
||||||
|
{
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*no value was found*/
|
||||||
|
return std::nullopt;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::wstring EvaluateStartingDirectory(const std::wstring& directory);
|
static std::wstring EvaluateStartingDirectory(const std::wstring& directory);
|
||||||
|
|
||||||
static guid _GenerateGuidForProfile(const hstring& name, const hstring& source) noexcept;
|
static guid _GenerateGuidForProfile(const hstring& name, const hstring& source) noexcept;
|
||||||
|
|
||||||
friend class TerminalAppLocalTests::SettingsTests;
|
friend class SettingsModelLocalTests::DeserializationTests;
|
||||||
friend class TerminalAppLocalTests::ProfileTests;
|
friend class SettingsModelLocalTests::ProfileTests;
|
||||||
friend class TerminalAppUnitTests::JsonTests;
|
friend class SettingsModelLocalTests::ColorSchemeTests;
|
||||||
|
friend class SettingsModelLocalTests::KeyBindingsTests;
|
||||||
friend class TerminalAppUnitTests::DynamicProfileTests;
|
friend class TerminalAppUnitTests::DynamicProfileTests;
|
||||||
|
friend class TerminalAppUnitTests::JsonTests;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,59 +20,157 @@ namespace Microsoft.Terminal.Settings.Model
|
||||||
Profile();
|
Profile();
|
||||||
Profile(Guid guid);
|
Profile(Guid guid);
|
||||||
|
|
||||||
|
Boolean HasName();
|
||||||
|
void ClearName();
|
||||||
String Name;
|
String Name;
|
||||||
|
|
||||||
Boolean HasGuid();
|
Boolean HasGuid();
|
||||||
Guid Guid;
|
Guid Guid;
|
||||||
|
|
||||||
|
Boolean HasSource();
|
||||||
|
void ClearSource();
|
||||||
String Source;
|
String Source;
|
||||||
|
|
||||||
Boolean HasConnectionType();
|
Boolean HasConnectionType();
|
||||||
Guid ConnectionType;
|
Guid ConnectionType;
|
||||||
|
|
||||||
|
Boolean HasHidden();
|
||||||
|
void ClearHidden();
|
||||||
Boolean Hidden;
|
Boolean Hidden;
|
||||||
|
|
||||||
|
Boolean HasIcon();
|
||||||
|
void ClearIcon();
|
||||||
String Icon;
|
String Icon;
|
||||||
|
|
||||||
|
Boolean HasCloseOnExit();
|
||||||
|
void ClearCloseOnExit();
|
||||||
CloseOnExitMode CloseOnExit;
|
CloseOnExitMode CloseOnExit;
|
||||||
|
|
||||||
|
Boolean HasTabTitle();
|
||||||
|
void ClearTabTitle();
|
||||||
String TabTitle;
|
String TabTitle;
|
||||||
|
|
||||||
|
Boolean HasTabColor();
|
||||||
|
void ClearTabColor();
|
||||||
Windows.Foundation.IReference<Windows.UI.Color> TabColor;
|
Windows.Foundation.IReference<Windows.UI.Color> TabColor;
|
||||||
|
|
||||||
|
Boolean HasSuppressApplicationTitle();
|
||||||
|
void ClearSuppressApplicationTitle();
|
||||||
Boolean SuppressApplicationTitle;
|
Boolean SuppressApplicationTitle;
|
||||||
|
|
||||||
|
Boolean HasUseAcrylic();
|
||||||
|
void ClearUseAcrylic();
|
||||||
Boolean UseAcrylic;
|
Boolean UseAcrylic;
|
||||||
|
|
||||||
|
Boolean HasAcrylicOpacity();
|
||||||
|
void ClearAcrylicOpacity();
|
||||||
Double AcrylicOpacity;
|
Double AcrylicOpacity;
|
||||||
|
|
||||||
|
Boolean HasScrollState();
|
||||||
|
void ClearScrollState();
|
||||||
Microsoft.Terminal.TerminalControl.ScrollbarState ScrollState;
|
Microsoft.Terminal.TerminalControl.ScrollbarState ScrollState;
|
||||||
|
|
||||||
|
Boolean HasFontFace();
|
||||||
|
void ClearFontFace();
|
||||||
String FontFace;
|
String FontFace;
|
||||||
|
|
||||||
|
Boolean HasFontSize();
|
||||||
|
void ClearFontSize();
|
||||||
Int32 FontSize;
|
Int32 FontSize;
|
||||||
|
|
||||||
|
Boolean HasFontWeight();
|
||||||
|
void ClearFontWeight();
|
||||||
Windows.UI.Text.FontWeight FontWeight;
|
Windows.UI.Text.FontWeight FontWeight;
|
||||||
|
|
||||||
|
Boolean HasPadding();
|
||||||
|
void ClearPadding();
|
||||||
String Padding;
|
String Padding;
|
||||||
|
|
||||||
|
Boolean HasCommandline();
|
||||||
|
void ClearCommandline();
|
||||||
String Commandline;
|
String Commandline;
|
||||||
|
|
||||||
|
Boolean HasStartingDirectory();
|
||||||
|
void ClearStartingDirectory();
|
||||||
String StartingDirectory;
|
String StartingDirectory;
|
||||||
String EvaluatedStartingDirectory { get; };
|
String EvaluatedStartingDirectory { get; };
|
||||||
|
|
||||||
|
Boolean HasBackgroundImagePath();
|
||||||
|
void ClearBackgroundImagePath();
|
||||||
String BackgroundImagePath;
|
String BackgroundImagePath;
|
||||||
String ExpandedBackgroundImagePath { get; };
|
String ExpandedBackgroundImagePath { get; };
|
||||||
|
|
||||||
|
Boolean HasBackgroundImageOpacity();
|
||||||
|
void ClearBackgroundImageOpacity();
|
||||||
Double BackgroundImageOpacity;
|
Double BackgroundImageOpacity;
|
||||||
|
|
||||||
|
Boolean HasBackgroundImageStretchMode();
|
||||||
|
void ClearBackgroundImageStretchMode();
|
||||||
Windows.UI.Xaml.Media.Stretch BackgroundImageStretchMode;
|
Windows.UI.Xaml.Media.Stretch BackgroundImageStretchMode;
|
||||||
|
|
||||||
|
Boolean HasBackgroundImageAlignment();
|
||||||
|
void ClearBackgroundImageAlignment();
|
||||||
Windows.UI.Xaml.HorizontalAlignment BackgroundImageHorizontalAlignment;
|
Windows.UI.Xaml.HorizontalAlignment BackgroundImageHorizontalAlignment;
|
||||||
Windows.UI.Xaml.VerticalAlignment BackgroundImageVerticalAlignment;
|
Windows.UI.Xaml.VerticalAlignment BackgroundImageVerticalAlignment;
|
||||||
|
|
||||||
|
Boolean HasAntialiasingMode();
|
||||||
|
void ClearAntialiasingMode();
|
||||||
Microsoft.Terminal.TerminalControl.TextAntialiasingMode AntialiasingMode;
|
Microsoft.Terminal.TerminalControl.TextAntialiasingMode AntialiasingMode;
|
||||||
|
|
||||||
|
Boolean HasRetroTerminalEffect();
|
||||||
|
void ClearRetroTerminalEffect();
|
||||||
Boolean RetroTerminalEffect;
|
Boolean RetroTerminalEffect;
|
||||||
|
|
||||||
|
Boolean HasForceFullRepaintRendering();
|
||||||
|
void ClearForceFullRepaintRendering();
|
||||||
Boolean ForceFullRepaintRendering;
|
Boolean ForceFullRepaintRendering;
|
||||||
|
|
||||||
|
Boolean HasSoftwareRendering();
|
||||||
|
void ClearSoftwareRendering();
|
||||||
Boolean SoftwareRendering;
|
Boolean SoftwareRendering;
|
||||||
|
|
||||||
|
Boolean HasColorSchemeName();
|
||||||
|
void ClearColorSchemeName();
|
||||||
String ColorSchemeName;
|
String ColorSchemeName;
|
||||||
|
|
||||||
|
Boolean HasForeground();
|
||||||
|
void ClearForeground();
|
||||||
Windows.Foundation.IReference<Windows.UI.Color> Foreground;
|
Windows.Foundation.IReference<Windows.UI.Color> Foreground;
|
||||||
|
|
||||||
|
Boolean HasBackground();
|
||||||
|
void ClearBackground();
|
||||||
Windows.Foundation.IReference<Windows.UI.Color> Background;
|
Windows.Foundation.IReference<Windows.UI.Color> Background;
|
||||||
|
|
||||||
|
Boolean HasSelectionBackground();
|
||||||
|
void ClearSelectionBackground();
|
||||||
Windows.Foundation.IReference<Windows.UI.Color> SelectionBackground;
|
Windows.Foundation.IReference<Windows.UI.Color> SelectionBackground;
|
||||||
|
|
||||||
|
Boolean HasCursorColor();
|
||||||
|
void ClearCursorColor();
|
||||||
Windows.Foundation.IReference<Windows.UI.Color> CursorColor;
|
Windows.Foundation.IReference<Windows.UI.Color> CursorColor;
|
||||||
|
|
||||||
|
Boolean HasHistorySize();
|
||||||
|
void ClearHistorySize();
|
||||||
Int32 HistorySize;
|
Int32 HistorySize;
|
||||||
|
|
||||||
|
Boolean HasSnapOnInput();
|
||||||
|
void ClearSnapOnInput();
|
||||||
Boolean SnapOnInput;
|
Boolean SnapOnInput;
|
||||||
|
|
||||||
|
Boolean HasAltGrAliasing();
|
||||||
|
void ClearAltGrAliasing();
|
||||||
Boolean AltGrAliasing;
|
Boolean AltGrAliasing;
|
||||||
|
|
||||||
|
Boolean HasCursorShape();
|
||||||
|
void ClearCursorShape();
|
||||||
Microsoft.Terminal.TerminalControl.CursorStyle CursorShape;
|
Microsoft.Terminal.TerminalControl.CursorStyle CursorShape;
|
||||||
|
|
||||||
|
Boolean HasCursorHeight();
|
||||||
|
void ClearCursorHeight();
|
||||||
UInt32 CursorHeight;
|
UInt32 CursorHeight;
|
||||||
|
|
||||||
|
Boolean HasBellStyle();
|
||||||
|
void ClearBellStyle();
|
||||||
BellStyle BellStyle;
|
BellStyle BellStyle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,5 +57,4 @@ namespace til
|
||||||
{
|
{
|
||||||
return t1.has_value() ? t1 : coalesce(std::forward<Ts>(t2)...);
|
return t1.has_value() ? t1 : coalesce(std::forward<Ts>(t2)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue