Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix fragments that update other profiles #11343

Merged
1 commit merged into from
Sep 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -553,10 +553,12 @@ Model::Profile CascadiaSettings::GetProfileForArgs(const Model::NewTerminalArgs&
FindProfile(GlobalSettings().DefaultProfile()) : FindProfile(GlobalSettings().DefaultProfile()) :
ProfileDefaults(); ProfileDefaults();
} }

else
{
// For compatibility with the stable version's behavior, return the default by GUID in all other cases. // For compatibility with the stable version's behavior, return the default by GUID in all other cases.
return FindProfile(GlobalSettings().DefaultProfile()); return FindProfile(GlobalSettings().DefaultProfile());
} }
}


// Method Description: // Method Description:
// - Helper to get a profile given a name that could be a guid or an actual name. // - Helper to get a profile given a name that could be a guid or an actual name.
Expand Down
3 changes: 1 addition & 2 deletions src/cascadia/TerminalSettingsModel/CascadiaSettings.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -67,9 +67,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
static void _rethrowSerializationExceptionWithLocationInfo(const JsonUtils::DeserializationError& e, const std::string_view& settingsString); static void _rethrowSerializationExceptionWithLocationInfo(const JsonUtils::DeserializationError& e, const std::string_view& settingsString);
static Json::Value _parseJSON(const std::string_view& content); static Json::Value _parseJSON(const std::string_view& content);
static const Json::Value& _getJSONValue(const Json::Value& json, const std::string_view& key) noexcept; static const Json::Value& _getJSONValue(const Json::Value& json, const std::string_view& key) noexcept;
static bool _isValidProfileObject(const Json::Value& profileJson);
gsl::span<const winrt::com_ptr<implementation::Profile>> _getNonUserOriginProfiles() const; gsl::span<const winrt::com_ptr<implementation::Profile>> _getNonUserOriginProfiles() const;
void _parse(const OriginTag origin, const winrt::hstring& source, const std::string_view& content, ParsedSettings& settings); void _parse(const OriginTag origin, const winrt::hstring& source, const std::string_view& content, ParsedSettings& settings, bool updatesKeyAllowed = false);
void _appendProfile(winrt::com_ptr<implementation::Profile>&& profile, ParsedSettings& settings); void _appendProfile(winrt::com_ptr<implementation::Profile>&& profile, ParsedSettings& settings);
static void _addParentProfile(const winrt::com_ptr<implementation::Profile>& profile, ParsedSettings& settings); static void _addParentProfile(const winrt::com_ptr<implementation::Profile>& profile, ParsedSettings& settings);
void _executeGenerator(const IDynamicProfileGenerator& generator); void _executeGenerator(const IDynamicProfileGenerator& generator);
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ void SettingsLoader::FindFragmentsAndMergeIntoUserSettings()
try try
{ {
const auto content = ReadUTF8File(fragmentExt.path()); const auto content = ReadUTF8File(fragmentExt.path());
_parse(OriginTag::Fragment, source, content, fragmentSettings); _parse(OriginTag::Fragment, source, content, fragmentSettings, true);


for (const auto& fragmentProfile : fragmentSettings.profiles) for (const auto& fragmentProfile : fragmentSettings.profiles)
{ {
Expand Down Expand Up @@ -418,17 +418,6 @@ const Json::Value& SettingsLoader::_getJSONValue(const Json::Value& json, const
return Json::Value::nullSingleton(); return Json::Value::nullSingleton();
} }


// Returns true if the given Json::Value looks like a profile.
// We introduced a bug (GH#9962, fixed in GH#9964) that would result in one or
// more nameless, guid-less profiles being emitted into the user's settings file.
// Those profiles would show up in the list as "Default" later.
bool SettingsLoader::_isValidProfileObject(const Json::Value& profileJson)
{
return profileJson.isObject() &&
(profileJson.isMember(NameKey.data(), NameKey.data() + NameKey.size()) || // has a name (can generate a guid)
profileJson.isMember(GuidKey.data(), GuidKey.data() + GuidKey.size())); // or has a guid
}

// We treat userSettings.profiles as an append-only array and will // We treat userSettings.profiles as an append-only array and will
// append profiles into the userSettings as necessary in this function. // append profiles into the userSettings as necessary in this function.
// _userProfileCount stores the number of profiles that were in userJSON during construction. // _userProfileCount stores the number of profiles that were in userJSON during construction.
Expand All @@ -443,7 +432,7 @@ gsl::span<const winrt::com_ptr<Profile>> SettingsLoader::_getNonUserOriginProfil
} }


// Parses the given JSON string ("content") and fills a ParsedSettings instance with it. // Parses the given JSON string ("content") and fills a ParsedSettings instance with it.
void SettingsLoader::_parse(const OriginTag origin, const winrt::hstring& source, const std::string_view& content, ParsedSettings& settings) void SettingsLoader::_parse(const OriginTag origin, const winrt::hstring& source, const std::string_view& content, ParsedSettings& settings, bool updatesKeyAllowed)
{ {
const auto json = content.empty() ? Json::Value{ Json::ValueType::objectValue } : _parseJSON(content); const auto json = content.empty() ? Json::Value{ Json::ValueType::objectValue } : _parseJSON(content);
const auto& profilesObject = _getJSONValue(json, ProfilesKey); const auto& profilesObject = _getJSONValue(json, ProfilesKey);
Expand Down Expand Up @@ -491,8 +480,6 @@ void SettingsLoader::_parse(const OriginTag origin, const winrt::hstring& source
settings.profilesByGuid.reserve(size); settings.profilesByGuid.reserve(size);


for (const auto& profileJson : profilesArray) for (const auto& profileJson : profilesArray)
{
if (_isValidProfileObject(profileJson))
{ {
auto profile = Profile::FromJson(profileJson); auto profile = Profile::FromJson(profileJson);
profile->Origin(origin); profile->Origin(origin);
Expand All @@ -508,15 +495,28 @@ void SettingsLoader::_parse(const OriginTag origin, const winrt::hstring& source
// We want to ensure that every profile has a GUID no matter what, not just to // We want to ensure that every profile has a GUID no matter what, not just to
// cache the value, but also to make them consistently identifiable later on. // cache the value, but also to make them consistently identifiable later on.
if (!profile->HasGuid()) if (!profile->HasGuid())
{
if (profile->HasName())
{ {
profile->Guid(profile->Guid()); profile->Guid(profile->Guid());
} }
else if (!updatesKeyAllowed || profile->Updates() == winrt::guid{})
{
// We introduced a bug (GH#9962, fixed in GH#9964) that would result in one or
// more nameless, guid-less profiles being emitted into the user's settings file.
// Those profiles would show up in the list as "Default" later.
//
// Fragments however can contain an alternative "updates" key, which works similar to the "guid".
// If updatesKeyAllowed is true (see FindFragmentsAndMergeIntoUserSettings) we permit
// such Guid-less, Name-less profiles as long as they have a valid Updates field.
continue;
}
}


_appendProfile(std::move(profile), settings); _appendProfile(std::move(profile), settings);
} }
} }
} }
}


// Adds a profile to the ParsedSettings instance. Takes ownership of the profile. // Adds a profile to the ParsedSettings instance. Takes ownership of the profile.
// It ensures no duplicate GUIDs are added to the ParsedSettings instance. // It ensures no duplicate GUIDs are added to the ParsedSettings instance.
Expand Down