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
|
||||
IDirect
|
||||
IExplorer
|
||||
IInheritable
|
||||
IMap
|
||||
IObject
|
||||
IStorage
|
||||
|
|
|
@ -81,6 +81,7 @@ namespace SettingsModelLocalTests
|
|||
TEST_METHOD(TestRebindNestedCommand);
|
||||
|
||||
TEST_METHOD(TestCopy);
|
||||
TEST_METHOD(TestCloneInheritanceTree);
|
||||
|
||||
TEST_CLASS_SETUP(ClassSetup)
|
||||
{
|
||||
|
@ -831,7 +832,7 @@ namespace SettingsModelLocalTests
|
|||
const auto serialized0Profile = profile0->GenerateStub();
|
||||
const auto profile1 = implementation::Profile::FromJson(serialized0Profile);
|
||||
VERIFY_IS_FALSE(profile0->HasGuid());
|
||||
VERIFY_IS_FALSE(profile1->HasGuid());
|
||||
VERIFY_IS_TRUE(profile1->HasGuid());
|
||||
|
||||
auto settings = winrt::make_self<implementation::CascadiaSettings>();
|
||||
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 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 autogeneratedGuid{ implementation::Profile::_GenerateGuidForProfile(name3, L"") };
|
||||
const std::optional<winrt::guid> badGuid{};
|
||||
|
||||
VerifyParseSucceeded(settings0String);
|
||||
|
@ -1366,7 +1368,7 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_ARE_EQUAL(guid0, settings->_GetProfileGuidByName(name0));
|
||||
VERIFY_ARE_EQUAL(guid1, settings->_GetProfileGuidByName(name1));
|
||||
VERIFY_ARE_EQUAL(guid2, settings->_GetProfileGuidByName(name2));
|
||||
VERIFY_ARE_EQUAL(badGuid, settings->_GetProfileGuidByName(name3));
|
||||
VERIFY_ARE_EQUAL(autogeneratedGuid, settings->_GetProfileGuidByName(name3));
|
||||
VERIFY_ARE_EQUAL(badGuid, settings->_GetProfileGuidByName(badName));
|
||||
|
||||
auto prof0{ settings->FindProfile(guid0) };
|
||||
|
@ -1521,9 +1523,9 @@ namespace SettingsModelLocalTests
|
|||
{
|
||||
auto settings = winrt::make_self<implementation::CascadiaSettings>(false);
|
||||
settings->_ParseJsonString(settings0String, false);
|
||||
VERIFY_IS_TRUE(settings->_userDefaultProfileSettings == Json::Value::null);
|
||||
VERIFY_IS_NULL(settings->_userDefaultProfileSettings);
|
||||
settings->_ApplyDefaultsFromUserSettings();
|
||||
VERIFY_IS_FALSE(settings->_userDefaultProfileSettings == Json::Value::null);
|
||||
VERIFY_IS_NOT_NULL(settings->_userDefaultProfileSettings);
|
||||
settings->LayerJson(settings->_userSettings);
|
||||
|
||||
VERIFY_ARE_EQUAL(guid1String, settings->_globals->UnparsedDefaultProfile());
|
||||
|
@ -1573,9 +1575,9 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_ARE_EQUAL(2u, settings->_profiles.Size());
|
||||
|
||||
settings->_ParseJsonString(settings0String, false);
|
||||
VERIFY_IS_TRUE(settings->_userDefaultProfileSettings == Json::Value::null);
|
||||
VERIFY_IS_NULL(settings->_userDefaultProfileSettings);
|
||||
settings->_ApplyDefaultsFromUserSettings();
|
||||
VERIFY_IS_FALSE(settings->_userDefaultProfileSettings == Json::Value::null);
|
||||
VERIFY_IS_NOT_NULL(settings->_userDefaultProfileSettings);
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
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(2).Source());
|
||||
|
||||
VERIFY_IS_TRUE(settings->_profiles.GetAt(0).HasGuid());
|
||||
VERIFY_IS_TRUE(settings->_profiles.GetAt(1).HasGuid());
|
||||
VERIFY_IS_TRUE(settings->_profiles.GetAt(2).HasGuid());
|
||||
|
||||
VERIFY_ARE_EQUAL(guid1, settings->_profiles.GetAt(0).Guid());
|
||||
VERIFY_ARE_EQUAL(guid1, settings->_profiles.GetAt(1).Guid());
|
||||
VERIFY_ARE_EQUAL(guid2, settings->_profiles.GetAt(2).Guid());
|
||||
|
@ -2256,6 +2254,7 @@ namespace SettingsModelLocalTests
|
|||
settings->_ParseJsonString(settings1Json, false);
|
||||
settings->LayerJson(settings->_userSettings);
|
||||
settings->_ValidateSettings();
|
||||
commands = settings->_globals->Commands();
|
||||
_logCommandNames(commands);
|
||||
VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
|
||||
VERIFY_ARE_EQUAL(0u, commands.Size());
|
||||
|
@ -2350,6 +2349,7 @@ namespace SettingsModelLocalTests
|
|||
settings->_ParseJsonString(settings1Json, false);
|
||||
settings->LayerJson(settings->_userSettings);
|
||||
settings->_ValidateSettings();
|
||||
commands = settings->_globals->Commands();
|
||||
_logCommandNames(commands);
|
||||
VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
|
||||
VERIFY_ARE_EQUAL(1u, commands.Size());
|
||||
|
@ -2460,4 +2460,126 @@ namespace SettingsModelLocalTests
|
|||
copyImpl->_globals->WordDelimiters(L"changed value");
|
||||
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?
|
||||
VERIFY_IS_FALSE(profile3->ShouldBeLayered(profile1Json));
|
||||
VERIFY_IS_FALSE(profile3->ShouldBeLayered(profile2Json));
|
||||
VERIFY_IS_FALSE(profile3->ShouldBeLayered(profile3Json));
|
||||
VERIFY_IS_TRUE(profile3->ShouldBeLayered(profile3Json));
|
||||
}
|
||||
|
||||
void ProfileTests::LayerProfileProperties()
|
||||
|
@ -132,39 +132,41 @@ namespace SettingsModelLocalTests
|
|||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"Layering profile1 on top of profile0"));
|
||||
profile0->LayerJson(profile1Json);
|
||||
auto profile1{ profile0->CreateChild() };
|
||||
profile1->LayerJson(profile1Json);
|
||||
|
||||
VERIFY_IS_NOT_NULL(profile0->Foreground());
|
||||
VERIFY_ARE_EQUAL(til::color(2, 2, 2), til::color{ profile0->Foreground().Value() });
|
||||
VERIFY_IS_NOT_NULL(profile1->Foreground());
|
||||
VERIFY_ARE_EQUAL(til::color(2, 2, 2), til::color{ profile1->Foreground().Value() });
|
||||
|
||||
VERIFY_IS_NOT_NULL(profile0->Background());
|
||||
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile0->Background().Value() });
|
||||
VERIFY_IS_NOT_NULL(profile1->Background());
|
||||
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile1->Background().Value() });
|
||||
|
||||
VERIFY_IS_NOT_NULL(profile0->Background());
|
||||
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile0->Background().Value() });
|
||||
VERIFY_IS_NOT_NULL(profile1->Background());
|
||||
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_ARE_EQUAL(L"C:/", profile0->StartingDirectory());
|
||||
VERIFY_IS_FALSE(profile1->StartingDirectory().empty());
|
||||
VERIFY_ARE_EQUAL(L"C:/", profile1->StartingDirectory());
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
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_ARE_EQUAL(til::color(3, 3, 3), til::color{ profile0->Foreground().Value() });
|
||||
VERIFY_IS_NOT_NULL(profile2->Foreground());
|
||||
VERIFY_ARE_EQUAL(til::color(3, 3, 3), til::color{ profile2->Foreground().Value() });
|
||||
|
||||
VERIFY_IS_NOT_NULL(profile0->Background());
|
||||
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile0->Background().Value() });
|
||||
VERIFY_IS_NOT_NULL(profile2->Background());
|
||||
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile2->Background().Value() });
|
||||
|
||||
VERIFY_IS_NOT_NULL(profile0->SelectionBackground());
|
||||
VERIFY_ARE_EQUAL(til::color(2, 2, 2), til::color{ profile0->SelectionBackground().Value() });
|
||||
VERIFY_IS_NOT_NULL(profile2->SelectionBackground());
|
||||
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_ARE_EQUAL(L"C:/", profile0->StartingDirectory());
|
||||
VERIFY_IS_FALSE(profile2->StartingDirectory().empty());
|
||||
VERIFY_ARE_EQUAL(L"C:/", profile2->StartingDirectory());
|
||||
}
|
||||
|
||||
void ProfileTests::LayerProfileIcon()
|
||||
|
|
|
@ -499,6 +499,7 @@ namespace TerminalAppLocalTests
|
|||
|
||||
const std::string settings0String{ R"(
|
||||
{
|
||||
"defaultProfile": "profile5",
|
||||
"profiles": [
|
||||
{
|
||||
"name" : "profile0",
|
||||
|
|
|
@ -756,17 +756,10 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
TerminalConnection::ITerminalConnection connection{ nullptr };
|
||||
|
||||
winrt::guid connectionType{};
|
||||
winrt::guid connectionType = profile.ConnectionType();
|
||||
winrt::guid sessionGuid{};
|
||||
|
||||
const auto hasConnectionType = profile.HasConnectionType();
|
||||
if (hasConnectionType)
|
||||
{
|
||||
connectionType = profile.ConnectionType();
|
||||
}
|
||||
|
||||
if (hasConnectionType &&
|
||||
connectionType == TerminalConnection::AzureConnection::ConnectionType() &&
|
||||
if (connectionType == TerminalConnection::AzureConnection::ConnectionType() &&
|
||||
TerminalConnection::AzureConnection::IsAzureConnectionAvailable())
|
||||
{
|
||||
// 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();
|
||||
|
||||
if (!profile.StartingDirectory().empty())
|
||||
{
|
||||
_StartingDirectory = profile.EvaluatedStartingDirectory();
|
||||
}
|
||||
_StartingDirectory = profile.EvaluatedStartingDirectory();
|
||||
|
||||
// GH#2373: Use the tabTitle as the starting title if it exists, otherwise
|
||||
// use the profile name
|
||||
|
|
|
@ -71,11 +71,6 @@ winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings CascadiaSettings::
|
|||
// dynamic profile generators added by default
|
||||
auto settings{ winrt::make_self<CascadiaSettings>() };
|
||||
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)
|
||||
{
|
||||
settings->_warnings.Append(warning);
|
||||
|
@ -85,10 +80,54 @@ winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings CascadiaSettings::
|
|||
settings->_userSettingsString = _userSettingsString;
|
||||
settings->_userSettings = _userSettings;
|
||||
settings->_defaultSettings = _defaultSettings;
|
||||
settings->_userDefaultProfileSettings = _userDefaultProfileSettings;
|
||||
|
||||
_CopyProfileInheritanceTree(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:
|
||||
// - Finds a profile that matches the given GUID. If there is no profile in this
|
||||
// settings object that matches, returns nullptr.
|
||||
|
|
|
@ -102,10 +102,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
std::string _userSettingsString;
|
||||
Json::Value _userSettings;
|
||||
Json::Value _defaultSettings;
|
||||
Json::Value _userDefaultProfileSettings{ Json::Value::null };
|
||||
winrt::com_ptr<Profile> _userDefaultProfileSettings{ nullptr };
|
||||
|
||||
void _LayerOrCreateProfile(const Json::Value& profileJson);
|
||||
winrt::com_ptr<implementation::Profile> _FindMatchingProfile(const Json::Value& profileJson);
|
||||
std::optional<uint32_t> _FindMatchingProfileIndex(const Json::Value& profileJson);
|
||||
void _LayerOrCreateColorScheme(const Json::Value& schemeJson);
|
||||
winrt::com_ptr<implementation::ColorScheme> _FindMatchingColorScheme(const Json::Value& schemeJson);
|
||||
void _ParseJsonString(std::string_view fileData, const bool isDefaultSettings);
|
||||
|
@ -114,6 +115,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
bool _PrependSchemaDirective();
|
||||
bool _AppendDynamicProfilesToUserSettings();
|
||||
std::string _ApplyFirstRunChangesToSettingsTemplate(std::string_view settingsTemplate) const;
|
||||
void _CopyProfileInheritanceTree(com_ptr<CascadiaSettings>& cloneSettings) const;
|
||||
|
||||
void _ApplyDefaultsFromUserSettings();
|
||||
|
||||
|
|
|
@ -519,20 +519,6 @@ bool CascadiaSettings::_AppendDynamicProfilesToUserSettings()
|
|||
|
||||
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.
|
||||
if (isInJsonObj(profile, _userSettings) || isInJsonObj(profile, _defaultSettings))
|
||||
{
|
||||
|
@ -598,6 +584,8 @@ winrt::com_ptr<CascadiaSettings> CascadiaSettings::FromJson(const Json::Value& j
|
|||
// <none>
|
||||
void CascadiaSettings::LayerJson(const Json::Value& json)
|
||||
{
|
||||
// add a new inheritance layer, and apply json values to child
|
||||
_globals = _globals->CreateChild();
|
||||
_globals->LayerJson(json);
|
||||
|
||||
if (auto schemes{ json[SchemesKey.data()] })
|
||||
|
@ -635,10 +623,28 @@ void CascadiaSettings::LayerJson(const Json::Value& json)
|
|||
void CascadiaSettings::_LayerOrCreateProfile(const Json::Value& profileJson)
|
||||
{
|
||||
// Layer the json on top of an existing profile, if we have one:
|
||||
auto pProfile = _FindMatchingProfile(profileJson);
|
||||
if (pProfile)
|
||||
auto profileIndex{ _FindMatchingProfileIndex(profileJson) };
|
||||
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
|
||||
{
|
||||
|
@ -647,13 +653,13 @@ void CascadiaSettings::_LayerOrCreateProfile(const Json::Value& profileJson)
|
|||
// `source`. Dynamic profiles _must_ be layered on an existing profile.
|
||||
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.
|
||||
if (_userDefaultProfileSettings)
|
||||
{
|
||||
profile->LayerJson(_userDefaultProfileSettings);
|
||||
profile->InsertParent(0, _userDefaultProfileSettings);
|
||||
}
|
||||
|
||||
profile->LayerJson(profileJson);
|
||||
|
@ -675,17 +681,40 @@ void CascadiaSettings::_LayerOrCreateProfile(const Json::Value& profileJson)
|
|||
// profile exists.
|
||||
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);
|
||||
if (profileImpl->ShouldBeLayered(profileJson))
|
||||
{
|
||||
return profileImpl->get_strong();
|
||||
}
|
||||
auto profile{ _profiles.GetAt(*index) };
|
||||
auto profileImpl{ winrt::get_self<Profile>(profile) };
|
||||
return profileImpl->get_strong();
|
||||
}
|
||||
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:
|
||||
// - Finds the "default profile settings" if they exist in the users settings,
|
||||
// and applies them to the existing profiles. The "default profile settings"
|
||||
|
@ -704,7 +733,7 @@ void CascadiaSettings::_ApplyDefaultsFromUserSettings()
|
|||
auto defaultSettings{ Json::Value::null };
|
||||
if (const auto profiles{ _userSettings[JsonKey(ProfilesKey)] })
|
||||
{
|
||||
if (profiles.isObject())
|
||||
if (profiles.isObject() && !profiles[JsonKey(DefaultSettingsKey)].empty())
|
||||
{
|
||||
defaultSettings = profiles[JsonKey(DefaultSettingsKey)];
|
||||
}
|
||||
|
@ -714,16 +743,26 @@ void CascadiaSettings::_ApplyDefaultsFromUserSettings()
|
|||
// from user settings file
|
||||
if (defaultSettings)
|
||||
{
|
||||
_userDefaultProfileSettings = defaultSettings;
|
||||
|
||||
// Remove the `guid` member from the default settings. That'll
|
||||
// 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);
|
||||
profileImpl->LayerJson(_userDefaultProfileSettings);
|
||||
// create a child, so we inherit from the defaults.json layer
|
||||
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,
|
||||
gsl::as_bytes(gsl::make_span(name))) };
|
||||
|
||||
auto newProfile = winrt::make<winrt::Microsoft::Terminal::Settings::Model::implementation::Profile>(profileGuid);
|
||||
newProfile.Name(name);
|
||||
|
||||
|
|
|
@ -16,6 +16,9 @@ Author(s):
|
|||
|
||||
#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}
|
||||
// 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 } };
|
||||
|
|
|
@ -55,7 +55,7 @@ static constexpr bool debugFeaturesDefault{ false };
|
|||
GlobalAppSettings::GlobalAppSettings() :
|
||||
_keymap{ winrt::make_self<KeyMapping>() },
|
||||
_keybindingsWarnings{},
|
||||
_unparsedDefaultProfile{},
|
||||
_validDefaultProfile{ false },
|
||||
_defaultProfile{},
|
||||
_DebugFeaturesEnabled{ debugFeaturesDefault }
|
||||
{
|
||||
|
@ -63,6 +63,25 @@ GlobalAppSettings::GlobalAppSettings() :
|
|||
_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
|
||||
{
|
||||
auto globals{ winrt::make_self<GlobalAppSettings>() };
|
||||
|
@ -91,21 +110,38 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::Copy() const
|
|||
globals->_UseTabSwitcher = _UseTabSwitcher;
|
||||
globals->_DisableAnimations = _DisableAnimations;
|
||||
|
||||
globals->_unparsedDefaultProfile = _unparsedDefaultProfile;
|
||||
globals->_UnparsedDefaultProfile = _UnparsedDefaultProfile;
|
||||
globals->_validDefaultProfile = _validDefaultProfile;
|
||||
globals->_defaultProfile = _defaultProfile;
|
||||
globals->_keymap = _keymap->Copy();
|
||||
if (_keymap)
|
||||
{
|
||||
globals->_keymap = _keymap->Copy();
|
||||
}
|
||||
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()) };
|
||||
globals->_colorSchemes.Insert(kv.Key(), *schemeImpl->Copy());
|
||||
for (auto kv : _colorSchemes)
|
||||
{
|
||||
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()) };
|
||||
globals->_commands.Insert(kv.Key(), *commandImpl->Copy());
|
||||
for (auto kv : _commands)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -115,24 +151,71 @@ winrt::Windows::Foundation::Collections::IMapView<winrt::hstring, winrt::Microso
|
|||
return _colorSchemes.GetView();
|
||||
}
|
||||
|
||||
#pragma region DefaultProfile
|
||||
void GlobalAppSettings::DefaultProfile(const winrt::guid& defaultProfile) noexcept
|
||||
{
|
||||
_unparsedDefaultProfile.clear();
|
||||
_validDefaultProfile = true;
|
||||
_defaultProfile = defaultProfile;
|
||||
}
|
||||
|
||||
winrt::guid GlobalAppSettings::DefaultProfile() const
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
bool GlobalAppSettings::HasUnparsedDefaultProfile() const
|
||||
{
|
||||
return _UnparsedDefaultProfile.has_value();
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
return *_keymap;
|
||||
|
@ -153,7 +236,11 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::FromJson(const Json::Value&
|
|||
|
||||
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);
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ Copyright (c) Microsoft Corporation
|
|||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- CascadiaSettings.hpp
|
||||
- GlobalAppSettings.h
|
||||
|
||||
Abstract:
|
||||
- This class encapsulates all of the settings that are global to the app, and
|
||||
|
@ -16,6 +16,7 @@ Author(s):
|
|||
#pragma once
|
||||
|
||||
#include "GlobalAppSettings.g.h"
|
||||
#include "IInheritable.h"
|
||||
|
||||
#include "KeyMapping.h"
|
||||
#include "Command.h"
|
||||
|
@ -30,10 +31,11 @@ namespace SettingsModelLocalTests
|
|||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
{
|
||||
struct GlobalAppSettings : GlobalAppSettingsT<GlobalAppSettings>
|
||||
struct GlobalAppSettings : GlobalAppSettingsT<GlobalAppSettings>, IInheritable<GlobalAppSettings>
|
||||
{
|
||||
public:
|
||||
GlobalAppSettings();
|
||||
void _FinalizeInheritance() override;
|
||||
com_ptr<GlobalAppSettings> Copy() const;
|
||||
|
||||
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.
|
||||
void DefaultProfile(const guid& defaultProfile) noexcept;
|
||||
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_PROPERTY(int32_t, InitialCols, DEFAULT_COLS);
|
||||
GETSET_PROPERTY(bool, AlwaysShowTabs, true);
|
||||
GETSET_PROPERTY(bool, ShowTitleInTitlebar, true);
|
||||
GETSET_PROPERTY(bool, ConfirmCloseAllTabs, true);
|
||||
GETSET_PROPERTY(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_PROPERTY(bool, ShowTabsInTitlebar, true);
|
||||
GETSET_PROPERTY(hstring, WordDelimiters, DEFAULT_WORD_DELIMITERS);
|
||||
GETSET_PROPERTY(bool, CopyOnSelect, false);
|
||||
GETSET_PROPERTY(winrt::Microsoft::Terminal::TerminalControl::CopyFormat, CopyFormatting, 0);
|
||||
GETSET_PROPERTY(bool, WarnAboutLargePaste, true);
|
||||
GETSET_PROPERTY(bool, WarnAboutMultiLinePaste, true);
|
||||
GETSET_PROPERTY(Model::LaunchPosition, InitialPosition, nullptr, nullptr);
|
||||
GETSET_PROPERTY(Model::LaunchMode, LaunchMode, LaunchMode::DefaultMode);
|
||||
GETSET_PROPERTY(bool, SnapToGridOnResize, true);
|
||||
GETSET_PROPERTY(bool, ForceFullRepaintRendering, false);
|
||||
GETSET_PROPERTY(bool, SoftwareRendering, false);
|
||||
GETSET_PROPERTY(bool, ForceVTInput, false);
|
||||
GETSET_PROPERTY(bool, DebugFeaturesEnabled); // default value set in constructor
|
||||
GETSET_PROPERTY(bool, StartOnUserLogin, false);
|
||||
GETSET_PROPERTY(bool, AlwaysOnTop, false);
|
||||
GETSET_PROPERTY(bool, UseTabSwitcher, true);
|
||||
GETSET_PROPERTY(bool, DisableAnimations, false);
|
||||
GETSET_SETTING(int32_t, InitialRows, DEFAULT_ROWS);
|
||||
GETSET_SETTING(int32_t, InitialCols, DEFAULT_COLS);
|
||||
GETSET_SETTING(bool, AlwaysShowTabs, true);
|
||||
GETSET_SETTING(bool, ShowTitleInTitlebar, true);
|
||||
GETSET_SETTING(bool, ConfirmCloseAllTabs, true);
|
||||
GETSET_SETTING(winrt::Windows::UI::Xaml::ElementTheme, Theme, winrt::Windows::UI::Xaml::ElementTheme::Default);
|
||||
GETSET_SETTING(winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode, TabWidthMode, winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode::Equal);
|
||||
GETSET_SETTING(bool, ShowTabsInTitlebar, true);
|
||||
GETSET_SETTING(hstring, WordDelimiters, DEFAULT_WORD_DELIMITERS);
|
||||
GETSET_SETTING(bool, CopyOnSelect, false);
|
||||
GETSET_SETTING(winrt::Microsoft::Terminal::TerminalControl::CopyFormat, CopyFormatting, 0);
|
||||
GETSET_SETTING(bool, WarnAboutLargePaste, true);
|
||||
GETSET_SETTING(bool, WarnAboutMultiLinePaste, true);
|
||||
GETSET_SETTING(Model::LaunchPosition, InitialPosition, nullptr, nullptr);
|
||||
GETSET_SETTING(Model::LaunchMode, LaunchMode, LaunchMode::DefaultMode);
|
||||
GETSET_SETTING(bool, SnapToGridOnResize, true);
|
||||
GETSET_SETTING(bool, ForceFullRepaintRendering, false);
|
||||
GETSET_SETTING(bool, SoftwareRendering, false);
|
||||
GETSET_SETTING(bool, ForceVTInput, false);
|
||||
GETSET_SETTING(bool, DebugFeaturesEnabled); // default value set in constructor
|
||||
GETSET_SETTING(bool, StartOnUserLogin, false);
|
||||
GETSET_SETTING(bool, AlwaysOnTop, false);
|
||||
GETSET_SETTING(bool, UseTabSwitcher, true);
|
||||
GETSET_SETTING(bool, DisableAnimations, false);
|
||||
|
||||
private:
|
||||
hstring _unparsedDefaultProfile;
|
||||
guid _defaultProfile;
|
||||
std::optional<hstring> _UnparsedDefaultProfile{ std::nullopt };
|
||||
bool _validDefaultProfile;
|
||||
|
||||
com_ptr<KeyMapping> _keymap;
|
||||
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::Command> _commands;
|
||||
|
||||
std::optional<hstring> _getUnparsedDefaultProfileImpl() const;
|
||||
|
||||
friend class SettingsModelLocalTests::DeserializationTests;
|
||||
friend class SettingsModelLocalTests::ColorSchemeTests;
|
||||
};
|
||||
|
|
|
@ -28,31 +28,104 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
|
||||
[default_interface] runtimeclass GlobalAppSettings {
|
||||
Guid DefaultProfile;
|
||||
String UnparsedDefaultProfile();
|
||||
Boolean HasUnparsedDefaultProfile();
|
||||
void ClearUnparsedDefaultProfile();
|
||||
String UnparsedDefaultProfile;
|
||||
|
||||
Boolean HasInitialRows();
|
||||
void ClearInitialRows();
|
||||
Int32 InitialRows;
|
||||
|
||||
Boolean HasInitialCols();
|
||||
void ClearInitialCols();
|
||||
Int32 InitialCols;
|
||||
|
||||
Boolean HasAlwaysShowTabs();
|
||||
void ClearAlwaysShowTabs();
|
||||
Boolean AlwaysShowTabs;
|
||||
|
||||
Boolean HasShowTitleInTitlebar();
|
||||
void ClearShowTitleInTitlebar();
|
||||
Boolean ShowTitleInTitlebar;
|
||||
|
||||
Boolean HasConfirmCloseAllTabs();
|
||||
void ClearConfirmCloseAllTabs();
|
||||
Boolean ConfirmCloseAllTabs;
|
||||
|
||||
Boolean HasTheme();
|
||||
void ClearTheme();
|
||||
Windows.UI.Xaml.ElementTheme Theme;
|
||||
|
||||
Boolean HasTabWidthMode();
|
||||
void ClearTabWidthMode();
|
||||
Microsoft.UI.Xaml.Controls.TabViewWidthMode TabWidthMode;
|
||||
|
||||
Boolean HasShowTabsInTitlebar();
|
||||
void ClearShowTabsInTitlebar();
|
||||
Boolean ShowTabsInTitlebar;
|
||||
|
||||
Boolean HasWordDelimiters();
|
||||
void ClearWordDelimiters();
|
||||
String WordDelimiters;
|
||||
|
||||
Boolean HasCopyOnSelect();
|
||||
void ClearCopyOnSelect();
|
||||
Boolean CopyOnSelect;
|
||||
|
||||
Boolean HasCopyFormatting();
|
||||
void ClearCopyFormatting();
|
||||
Microsoft.Terminal.TerminalControl.CopyFormat CopyFormatting;
|
||||
|
||||
Boolean HasWarnAboutLargePaste();
|
||||
void ClearWarnAboutLargePaste();
|
||||
Boolean WarnAboutLargePaste;
|
||||
|
||||
Boolean HasWarnAboutMultiLinePaste();
|
||||
void ClearWarnAboutMultiLinePaste();
|
||||
Boolean WarnAboutMultiLinePaste;
|
||||
|
||||
Boolean HasInitialPosition();
|
||||
void ClearInitialPosition();
|
||||
LaunchPosition InitialPosition;
|
||||
|
||||
Boolean HasLaunchMode();
|
||||
void ClearLaunchMode();
|
||||
LaunchMode LaunchMode;
|
||||
|
||||
Boolean HasSnapToGridOnResize();
|
||||
void ClearSnapToGridOnResize();
|
||||
Boolean SnapToGridOnResize;
|
||||
|
||||
Boolean HasForceFullRepaintRendering();
|
||||
void ClearForceFullRepaintRendering();
|
||||
Boolean ForceFullRepaintRendering;
|
||||
|
||||
Boolean HasSoftwareRendering();
|
||||
void ClearSoftwareRendering();
|
||||
Boolean SoftwareRendering;
|
||||
|
||||
Boolean HasForceVTInput();
|
||||
void ClearForceVTInput();
|
||||
Boolean ForceVTInput;
|
||||
|
||||
Boolean HasDebugFeaturesEnabled();
|
||||
void ClearDebugFeaturesEnabled();
|
||||
Boolean DebugFeaturesEnabled;
|
||||
|
||||
Boolean HasStartOnUserLogin();
|
||||
void ClearStartOnUserLogin();
|
||||
Boolean StartOnUserLogin;
|
||||
|
||||
Boolean HasAlwaysOnTop();
|
||||
void ClearAlwaysOnTop();
|
||||
Boolean AlwaysOnTop;
|
||||
|
||||
Boolean HasUseTabSwitcher();
|
||||
void ClearUseTabSwitcher();
|
||||
Boolean UseTabSwitcher;
|
||||
|
||||
Boolean HasDisableAnimations();
|
||||
void ClearDisableAnimations();
|
||||
Boolean DisableAnimations;
|
||||
|
||||
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">
|
||||
<DependentUpon>GlobalAppSettings.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IInheritable.h" />
|
||||
<ClInclude Include="IDynamicProfileGenerator.h" />
|
||||
<ClInclude Include="JsonUtils.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>() };
|
||||
profile->_Name = _Name;
|
||||
profile->_Source = _Source;
|
||||
profile->_Hidden = _Hidden;
|
||||
profile->_Icon = _Icon;
|
||||
profile->_CloseOnExit = _CloseOnExit;
|
||||
profile->_TabTitle = _TabTitle;
|
||||
profile->_TabColor = _TabColor;
|
||||
profile->_SuppressApplicationTitle = _SuppressApplicationTitle;
|
||||
profile->_UseAcrylic = _UseAcrylic;
|
||||
profile->_AcrylicOpacity = _AcrylicOpacity;
|
||||
profile->_ScrollState = _ScrollState;
|
||||
profile->_FontFace = _FontFace;
|
||||
profile->_FontSize = _FontSize;
|
||||
profile->_FontWeight = _FontWeight;
|
||||
profile->_Padding = _Padding;
|
||||
profile->_Commandline = _Commandline;
|
||||
profile->_StartingDirectory = _StartingDirectory;
|
||||
profile->_BackgroundImagePath = _BackgroundImagePath;
|
||||
profile->_BackgroundImageOpacity = _BackgroundImageOpacity;
|
||||
profile->_BackgroundImageStretchMode = _BackgroundImageStretchMode;
|
||||
profile->_AntialiasingMode = _AntialiasingMode;
|
||||
profile->_RetroTerminalEffect = _RetroTerminalEffect;
|
||||
profile->_ForceFullRepaintRendering = _ForceFullRepaintRendering;
|
||||
profile->_SoftwareRendering = _SoftwareRendering;
|
||||
profile->_ColorSchemeName = _ColorSchemeName;
|
||||
profile->_Foreground = _Foreground;
|
||||
profile->_Background = _Background;
|
||||
profile->_SelectionBackground = _SelectionBackground;
|
||||
profile->_CursorColor = _CursorColor;
|
||||
profile->_HistorySize = _HistorySize;
|
||||
profile->_SnapOnInput = _SnapOnInput;
|
||||
profile->_AltGrAliasing = _AltGrAliasing;
|
||||
profile->_CursorShape = _CursorShape;
|
||||
profile->_CursorHeight = _CursorHeight;
|
||||
profile->_Guid = _Guid;
|
||||
profile->_ConnectionType = _ConnectionType;
|
||||
profile->_BackgroundImageAlignment = _BackgroundImageAlignment;
|
||||
profile->_Guid = source->_Guid;
|
||||
profile->_Name = source->_Name;
|
||||
profile->_Source = source->_Source;
|
||||
profile->_Hidden = source->_Hidden;
|
||||
profile->_Icon = source->_Icon;
|
||||
profile->_CloseOnExit = source->_CloseOnExit;
|
||||
profile->_TabTitle = source->_TabTitle;
|
||||
profile->_TabColor = source->_TabColor;
|
||||
profile->_SuppressApplicationTitle = source->_SuppressApplicationTitle;
|
||||
profile->_UseAcrylic = source->_UseAcrylic;
|
||||
profile->_AcrylicOpacity = source->_AcrylicOpacity;
|
||||
profile->_ScrollState = source->_ScrollState;
|
||||
profile->_FontFace = source->_FontFace;
|
||||
profile->_FontSize = source->_FontSize;
|
||||
profile->_FontWeight = source->_FontWeight;
|
||||
profile->_Padding = source->_Padding;
|
||||
profile->_Commandline = source->_Commandline;
|
||||
profile->_StartingDirectory = source->_StartingDirectory;
|
||||
profile->_BackgroundImagePath = source->_BackgroundImagePath;
|
||||
profile->_BackgroundImageOpacity = source->_BackgroundImageOpacity;
|
||||
profile->_BackgroundImageStretchMode = source->_BackgroundImageStretchMode;
|
||||
profile->_AntialiasingMode = source->_AntialiasingMode;
|
||||
profile->_RetroTerminalEffect = source->_RetroTerminalEffect;
|
||||
profile->_ForceFullRepaintRendering = source->_ForceFullRepaintRendering;
|
||||
profile->_SoftwareRendering = source->_SoftwareRendering;
|
||||
profile->_ColorSchemeName = source->_ColorSchemeName;
|
||||
profile->_Foreground = source->_Foreground;
|
||||
profile->_Background = source->_Background;
|
||||
profile->_SelectionBackground = source->_SelectionBackground;
|
||||
profile->_CursorColor = source->_CursorColor;
|
||||
profile->_HistorySize = source->_HistorySize;
|
||||
profile->_SnapOnInput = source->_SnapOnInput;
|
||||
profile->_AltGrAliasing = source->_AltGrAliasing;
|
||||
profile->_CursorShape = source->_CursorShape;
|
||||
profile->_CursorHeight = source->_CursorHeight;
|
||||
profile->_BellStyle = source->_BellStyle;
|
||||
profile->_BackgroundImageAlignment = source->_BackgroundImageAlignment;
|
||||
profile->_ConnectionType = source->_ConnectionType;
|
||||
|
||||
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:
|
||||
// - 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.
|
||||
|
@ -129,19 +180,17 @@ Json::Value Profile::GenerateStub() const
|
|||
Json::Value stub;
|
||||
|
||||
///// 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);
|
||||
|
||||
if (!_Source.empty())
|
||||
{
|
||||
stub[JsonKey(SourceKey)] = winrt::to_string(_Source);
|
||||
}
|
||||
|
||||
stub[JsonKey(HiddenKey)] = _Hidden;
|
||||
stub[JsonKey(HiddenKey)] = Hidden();
|
||||
|
||||
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.
|
||||
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
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the other json object didn't have a GUID, we definitely don't want
|
||||
// to layer. We technically might have the same name, and would
|
||||
// auto-generate the same guid, but they should be treated as different
|
||||
// profiles.
|
||||
return false;
|
||||
// If the other json object didn't have a GUID,
|
||||
// check if we auto-generate the same guid using the name and source.
|
||||
const auto otherName{ JsonUtils::GetValueForKey<std::optional<winrt::hstring>>(json, NameKey) };
|
||||
if (Guid() != _GenerateGuidForProfile(otherName ? *otherName : L"Default", otherSource ? *otherSource : L""))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::wstring> otherSource;
|
||||
bool otherHadSource = JsonUtils::GetValueForKey(json, SourceKey, otherSource);
|
||||
|
||||
// For profiles with a `source`, also check the `source` property.
|
||||
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!
|
||||
sourceMatches = *otherSource == _Source;
|
||||
sourceMatches = *otherSource == mySource;
|
||||
}
|
||||
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
|
||||
// of the legacy DPG namespaces. We're looking to see if the other
|
||||
// json object has the same guid, but _no_ "source"
|
||||
if (_Source == WslGeneratorNamespace ||
|
||||
_Source == AzureGeneratorNamespace ||
|
||||
_Source == PowershellCoreGeneratorNamespace)
|
||||
if (mySource == WslGeneratorNamespace ||
|
||||
mySource == AzureGeneratorNamespace ||
|
||||
mySource == PowershellCoreGeneratorNamespace)
|
||||
{
|
||||
sourceMatches = true;
|
||||
}
|
||||
|
@ -247,10 +293,10 @@ void Profile::LayerJson(const Json::Value& json)
|
|||
JsonUtils::GetValueForKey(json, HiddenKey, _Hidden);
|
||||
|
||||
// Core Settings
|
||||
JsonUtils::GetValueForKey(json, ForegroundKey, _Foreground);
|
||||
JsonUtils::GetValueForKey(json, BackgroundKey, _Background);
|
||||
JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _SelectionBackground);
|
||||
JsonUtils::GetValueForKey(json, CursorColorKey, _CursorColor);
|
||||
_Foreground.set = JsonUtils::GetValueForKey(json, ForegroundKey, _Foreground.setting);
|
||||
_Background.set = JsonUtils::GetValueForKey(json, BackgroundKey, _Background.setting);
|
||||
_SelectionBackground.set = JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _SelectionBackground.setting);
|
||||
_CursorColor.set = JsonUtils::GetValueForKey(json, CursorColorKey, _CursorColor.setting);
|
||||
JsonUtils::GetValueForKey(json, ColorSchemeKey, _ColorSchemeName);
|
||||
|
||||
// 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, 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, BackgroundImageKey, _BackgroundImagePath);
|
||||
JsonUtils::GetValueForKey(json, BackgroundImageOpacityKey, _BackgroundImageOpacity);
|
||||
|
@ -286,7 +341,7 @@ void Profile::LayerJson(const Json::Value& json)
|
|||
JsonUtils::GetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect);
|
||||
JsonUtils::GetValueForKey(json, AntialiasingModeKey, _AntialiasingMode);
|
||||
|
||||
JsonUtils::GetValueForKey(json, TabColorKey, _TabColor);
|
||||
_TabColor.set = JsonUtils::GetValueForKey(json, TabColorKey, _TabColor.setting);
|
||||
|
||||
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.
|
||||
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
|
||||
// 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];
|
||||
|
||||
|
@ -322,13 +378,19 @@ winrt::hstring Profile::ExpandedBackgroundImagePath() const
|
|||
}
|
||||
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
|
||||
{
|
||||
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:
|
||||
|
@ -368,11 +430,11 @@ std::wstring Profile::EvaluateStartingDirectory(const std::wstring& directory)
|
|||
// will _not_ change the profile's GUID.
|
||||
void Profile::GenerateGuidIfNecessary() noexcept
|
||||
{
|
||||
if (!_Guid.has_value())
|
||||
if (!_getGuidImpl().has_value())
|
||||
{
|
||||
// Always use the name to generate the temporary GUID. That way, across
|
||||
// reloads, we'll generate the same static GUID.
|
||||
_Guid = Profile::_GenerateGuidForProfile(_Name, _Source);
|
||||
_Guid = Profile::_GenerateGuidForProfile(Name(), Source());
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hSettingsModelProvider,
|
||||
|
@ -438,54 +500,50 @@ winrt::guid Profile::GetGuidOrGenerateForJson(const Json::Value& json) noexcept
|
|||
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
|
||||
{
|
||||
return std::get<HorizontalAlignment>(_BackgroundImageAlignment);
|
||||
const auto val{ _getBackgroundImageAlignmentImpl() };
|
||||
return val ? std::get<HorizontalAlignment>(*val) : HorizontalAlignment::Center;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
return std::get<VerticalAlignment>(_BackgroundImageAlignment);
|
||||
const auto val{ _getBackgroundImageAlignmentImpl() };
|
||||
return val ? std::get<VerticalAlignment>(*val) : VerticalAlignment::Center;
|
||||
}
|
||||
|
||||
void Profile::BackgroundImageVerticalAlignment(const VerticalAlignment& value) noexcept
|
||||
{
|
||||
std::get<VerticalAlignment>(_BackgroundImageAlignment) = value;
|
||||
}
|
||||
|
||||
bool Profile::HasGuid() const noexcept
|
||||
{
|
||||
return _Guid.has_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;
|
||||
if (HasBackgroundImageAlignment())
|
||||
{
|
||||
std::get<VerticalAlignment>(*_BackgroundImageAlignment) = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
_BackgroundImageAlignment = { HorizontalAlignment::Center, value };
|
||||
}
|
||||
}
|
||||
#pragma endregion
|
||||
|
|
|
@ -16,21 +16,24 @@ Author(s):
|
|||
#pragma once
|
||||
|
||||
#include "Profile.g.h"
|
||||
#include "IInheritable.h"
|
||||
|
||||
#include "../inc/cppwinrt_utils.h"
|
||||
#include "JsonUtils.h"
|
||||
#include <DefaultSettings.h>
|
||||
|
||||
// fwdecl unittest classes
|
||||
namespace TerminalAppLocalTests
|
||||
namespace SettingsModelLocalTests
|
||||
{
|
||||
class SettingsTests;
|
||||
class DeserializationTests;
|
||||
class ProfileTests;
|
||||
class ColorSchemeTests;
|
||||
class KeyBindingsTests;
|
||||
};
|
||||
namespace TerminalAppUnitTests
|
||||
{
|
||||
class JsonTests;
|
||||
class DynamicProfileTests;
|
||||
class JsonTests;
|
||||
};
|
||||
|
||||
// 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
|
||||
{
|
||||
struct Profile : ProfileT<Profile>
|
||||
struct Profile : ProfileT<Profile>, IInheritable<Profile>
|
||||
{
|
||||
public:
|
||||
Profile();
|
||||
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;
|
||||
static com_ptr<Profile> FromJson(const Json::Value& json);
|
||||
|
@ -57,83 +61,97 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
void GenerateGuidIfNecessary() 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
|
||||
bool HasBackgroundImageAlignment() const noexcept;
|
||||
void ClearBackgroundImageAlignment() noexcept;
|
||||
const Windows::UI::Xaml::HorizontalAlignment BackgroundImageHorizontalAlignment() const noexcept;
|
||||
void BackgroundImageHorizontalAlignment(const Windows::UI::Xaml::HorizontalAlignment& value) noexcept;
|
||||
const Windows::UI::Xaml::VerticalAlignment BackgroundImageVerticalAlignment() const noexcept;
|
||||
void BackgroundImageVerticalAlignment(const Windows::UI::Xaml::VerticalAlignment& value) noexcept;
|
||||
|
||||
GETSET_PROPERTY(hstring, Name, L"Default");
|
||||
GETSET_PROPERTY(hstring, Source);
|
||||
GETSET_PROPERTY(bool, Hidden, false);
|
||||
GETSET_SETTING(guid, Guid, _GenerateGuidForProfile(Name(), Source()));
|
||||
GETSET_SETTING(hstring, Name, L"Default");
|
||||
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_PROPERTY(hstring, TabTitle);
|
||||
GETSET_PROPERTY(Windows::Foundation::IReference<Windows::UI::Color>, TabColor);
|
||||
GETSET_PROPERTY(bool, SuppressApplicationTitle, false);
|
||||
GETSET_SETTING(CloseOnExitMode, CloseOnExit, CloseOnExitMode::Graceful);
|
||||
GETSET_SETTING(hstring, TabTitle);
|
||||
GETSET_NULLABLE_SETTING(Windows::UI::Color, TabColor, nullptr);
|
||||
GETSET_SETTING(bool, SuppressApplicationTitle, false);
|
||||
|
||||
GETSET_PROPERTY(bool, UseAcrylic, false);
|
||||
GETSET_PROPERTY(double, AcrylicOpacity, 0.5);
|
||||
GETSET_PROPERTY(Microsoft::Terminal::TerminalControl::ScrollbarState, ScrollState, Microsoft::Terminal::TerminalControl::ScrollbarState::Visible);
|
||||
GETSET_SETTING(bool, UseAcrylic, false);
|
||||
GETSET_SETTING(double, AcrylicOpacity, 0.5);
|
||||
GETSET_SETTING(Microsoft::Terminal::TerminalControl::ScrollbarState, ScrollState, Microsoft::Terminal::TerminalControl::ScrollbarState::Visible);
|
||||
|
||||
GETSET_PROPERTY(hstring, FontFace, DEFAULT_FONT_FACE);
|
||||
GETSET_PROPERTY(int32_t, FontSize, DEFAULT_FONT_SIZE);
|
||||
GETSET_PROPERTY(Windows::UI::Text::FontWeight, FontWeight, DEFAULT_FONT_WEIGHT);
|
||||
GETSET_PROPERTY(hstring, Padding, DEFAULT_PADDING);
|
||||
GETSET_SETTING(hstring, FontFace, DEFAULT_FONT_FACE);
|
||||
GETSET_SETTING(int32_t, FontSize, DEFAULT_FONT_SIZE);
|
||||
GETSET_SETTING(Windows::UI::Text::FontWeight, FontWeight, DEFAULT_FONT_WEIGHT);
|
||||
GETSET_SETTING(hstring, Padding, DEFAULT_PADDING);
|
||||
|
||||
GETSET_PROPERTY(hstring, Commandline, L"cmd.exe");
|
||||
GETSET_PROPERTY(hstring, StartingDirectory);
|
||||
GETSET_SETTING(hstring, Commandline, L"cmd.exe");
|
||||
GETSET_SETTING(hstring, StartingDirectory);
|
||||
|
||||
GETSET_PROPERTY(hstring, BackgroundImagePath);
|
||||
GETSET_PROPERTY(double, BackgroundImageOpacity, 1.0);
|
||||
GETSET_PROPERTY(Windows::UI::Xaml::Media::Stretch, BackgroundImageStretchMode, Windows::UI::Xaml::Media::Stretch::Fill);
|
||||
GETSET_SETTING(hstring, BackgroundImagePath);
|
||||
GETSET_SETTING(double, BackgroundImageOpacity, 1.0);
|
||||
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_PROPERTY(bool, RetroTerminalEffect, false);
|
||||
GETSET_PROPERTY(bool, ForceFullRepaintRendering, false);
|
||||
GETSET_PROPERTY(bool, SoftwareRendering, false);
|
||||
GETSET_SETTING(Microsoft::Terminal::TerminalControl::TextAntialiasingMode, AntialiasingMode, Microsoft::Terminal::TerminalControl::TextAntialiasingMode::Grayscale);
|
||||
GETSET_SETTING(bool, RetroTerminalEffect, false);
|
||||
GETSET_SETTING(bool, ForceFullRepaintRendering, false);
|
||||
GETSET_SETTING(bool, SoftwareRendering, false);
|
||||
|
||||
GETSET_PROPERTY(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_SETTING(hstring, ColorSchemeName, L"Campbell");
|
||||
|
||||
GETSET_PROPERTY(int32_t, HistorySize, DEFAULT_HISTORY_SIZE);
|
||||
GETSET_PROPERTY(bool, SnapOnInput, true);
|
||||
GETSET_PROPERTY(bool, AltGrAliasing, true);
|
||||
GETSET_NULLABLE_SETTING(Windows::UI::Color, Foreground, nullptr);
|
||||
GETSET_NULLABLE_SETTING(Windows::UI::Color, Background, nullptr);
|
||||
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_PROPERTY(uint32_t, CursorHeight, DEFAULT_CURSOR_HEIGHT);
|
||||
GETSET_SETTING(int32_t, HistorySize, DEFAULT_HISTORY_SIZE);
|
||||
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:
|
||||
std::optional<winrt::guid> _Guid{ std::nullopt };
|
||||
std::optional<winrt::guid> _ConnectionType{ std::nullopt };
|
||||
std::tuple<Windows::UI::Xaml::HorizontalAlignment, Windows::UI::Xaml::VerticalAlignment> _BackgroundImageAlignment{
|
||||
Windows::UI::Xaml::HorizontalAlignment::Center,
|
||||
Windows::UI::Xaml::VerticalAlignment::Center
|
||||
std::optional<std::tuple<Windows::UI::Xaml::HorizontalAlignment, Windows::UI::Xaml::VerticalAlignment>> _BackgroundImageAlignment{ std::nullopt };
|
||||
std::optional<std::tuple<Windows::UI::Xaml::HorizontalAlignment, Windows::UI::Xaml::VerticalAlignment>> _getBackgroundImageAlignmentImpl() const
|
||||
{
|
||||
/*return user set value*/
|
||||
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 guid _GenerateGuidForProfile(const hstring& name, const hstring& source) noexcept;
|
||||
|
||||
friend class TerminalAppLocalTests::SettingsTests;
|
||||
friend class TerminalAppLocalTests::ProfileTests;
|
||||
friend class TerminalAppUnitTests::JsonTests;
|
||||
friend class SettingsModelLocalTests::DeserializationTests;
|
||||
friend class SettingsModelLocalTests::ProfileTests;
|
||||
friend class SettingsModelLocalTests::ColorSchemeTests;
|
||||
friend class SettingsModelLocalTests::KeyBindingsTests;
|
||||
friend class TerminalAppUnitTests::DynamicProfileTests;
|
||||
friend class TerminalAppUnitTests::JsonTests;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -20,59 +20,157 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
Profile();
|
||||
Profile(Guid guid);
|
||||
|
||||
Boolean HasName();
|
||||
void ClearName();
|
||||
String Name;
|
||||
|
||||
Boolean HasGuid();
|
||||
Guid Guid;
|
||||
|
||||
Boolean HasSource();
|
||||
void ClearSource();
|
||||
String Source;
|
||||
|
||||
Boolean HasConnectionType();
|
||||
Guid ConnectionType;
|
||||
|
||||
Boolean HasHidden();
|
||||
void ClearHidden();
|
||||
Boolean Hidden;
|
||||
|
||||
Boolean HasIcon();
|
||||
void ClearIcon();
|
||||
String Icon;
|
||||
|
||||
Boolean HasCloseOnExit();
|
||||
void ClearCloseOnExit();
|
||||
CloseOnExitMode CloseOnExit;
|
||||
|
||||
Boolean HasTabTitle();
|
||||
void ClearTabTitle();
|
||||
String TabTitle;
|
||||
|
||||
Boolean HasTabColor();
|
||||
void ClearTabColor();
|
||||
Windows.Foundation.IReference<Windows.UI.Color> TabColor;
|
||||
|
||||
Boolean HasSuppressApplicationTitle();
|
||||
void ClearSuppressApplicationTitle();
|
||||
Boolean SuppressApplicationTitle;
|
||||
|
||||
Boolean HasUseAcrylic();
|
||||
void ClearUseAcrylic();
|
||||
Boolean UseAcrylic;
|
||||
|
||||
Boolean HasAcrylicOpacity();
|
||||
void ClearAcrylicOpacity();
|
||||
Double AcrylicOpacity;
|
||||
|
||||
Boolean HasScrollState();
|
||||
void ClearScrollState();
|
||||
Microsoft.Terminal.TerminalControl.ScrollbarState ScrollState;
|
||||
|
||||
Boolean HasFontFace();
|
||||
void ClearFontFace();
|
||||
String FontFace;
|
||||
|
||||
Boolean HasFontSize();
|
||||
void ClearFontSize();
|
||||
Int32 FontSize;
|
||||
|
||||
Boolean HasFontWeight();
|
||||
void ClearFontWeight();
|
||||
Windows.UI.Text.FontWeight FontWeight;
|
||||
|
||||
Boolean HasPadding();
|
||||
void ClearPadding();
|
||||
String Padding;
|
||||
|
||||
Boolean HasCommandline();
|
||||
void ClearCommandline();
|
||||
String Commandline;
|
||||
|
||||
Boolean HasStartingDirectory();
|
||||
void ClearStartingDirectory();
|
||||
String StartingDirectory;
|
||||
String EvaluatedStartingDirectory { get; };
|
||||
|
||||
Boolean HasBackgroundImagePath();
|
||||
void ClearBackgroundImagePath();
|
||||
String BackgroundImagePath;
|
||||
String ExpandedBackgroundImagePath { get; };
|
||||
|
||||
Boolean HasBackgroundImageOpacity();
|
||||
void ClearBackgroundImageOpacity();
|
||||
Double BackgroundImageOpacity;
|
||||
|
||||
Boolean HasBackgroundImageStretchMode();
|
||||
void ClearBackgroundImageStretchMode();
|
||||
Windows.UI.Xaml.Media.Stretch BackgroundImageStretchMode;
|
||||
|
||||
Boolean HasBackgroundImageAlignment();
|
||||
void ClearBackgroundImageAlignment();
|
||||
Windows.UI.Xaml.HorizontalAlignment BackgroundImageHorizontalAlignment;
|
||||
Windows.UI.Xaml.VerticalAlignment BackgroundImageVerticalAlignment;
|
||||
|
||||
Boolean HasAntialiasingMode();
|
||||
void ClearAntialiasingMode();
|
||||
Microsoft.Terminal.TerminalControl.TextAntialiasingMode AntialiasingMode;
|
||||
|
||||
Boolean HasRetroTerminalEffect();
|
||||
void ClearRetroTerminalEffect();
|
||||
Boolean RetroTerminalEffect;
|
||||
|
||||
Boolean HasForceFullRepaintRendering();
|
||||
void ClearForceFullRepaintRendering();
|
||||
Boolean ForceFullRepaintRendering;
|
||||
|
||||
Boolean HasSoftwareRendering();
|
||||
void ClearSoftwareRendering();
|
||||
Boolean SoftwareRendering;
|
||||
|
||||
Boolean HasColorSchemeName();
|
||||
void ClearColorSchemeName();
|
||||
String ColorSchemeName;
|
||||
|
||||
Boolean HasForeground();
|
||||
void ClearForeground();
|
||||
Windows.Foundation.IReference<Windows.UI.Color> Foreground;
|
||||
|
||||
Boolean HasBackground();
|
||||
void ClearBackground();
|
||||
Windows.Foundation.IReference<Windows.UI.Color> Background;
|
||||
|
||||
Boolean HasSelectionBackground();
|
||||
void ClearSelectionBackground();
|
||||
Windows.Foundation.IReference<Windows.UI.Color> SelectionBackground;
|
||||
|
||||
Boolean HasCursorColor();
|
||||
void ClearCursorColor();
|
||||
Windows.Foundation.IReference<Windows.UI.Color> CursorColor;
|
||||
|
||||
Boolean HasHistorySize();
|
||||
void ClearHistorySize();
|
||||
Int32 HistorySize;
|
||||
|
||||
Boolean HasSnapOnInput();
|
||||
void ClearSnapOnInput();
|
||||
Boolean SnapOnInput;
|
||||
|
||||
Boolean HasAltGrAliasing();
|
||||
void ClearAltGrAliasing();
|
||||
Boolean AltGrAliasing;
|
||||
|
||||
Boolean HasCursorShape();
|
||||
void ClearCursorShape();
|
||||
Microsoft.Terminal.TerminalControl.CursorStyle CursorShape;
|
||||
|
||||
Boolean HasCursorHeight();
|
||||
void ClearCursorHeight();
|
||||
UInt32 CursorHeight;
|
||||
|
||||
Boolean HasBellStyle();
|
||||
void ClearBellStyle();
|
||||
BellStyle BellStyle;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,5 +57,4 @@ namespace til
|
|||
{
|
||||
return t1.has_value() ? t1 : coalesce(std::forward<Ts>(t2)...);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue