Hide profiles by default if they aren't new (#10910)

Let's say a user doesn't know that they need to write `"hidden": true` in
order to prevent a profile from showing up (and a settings UI doesn't exist).
Naturally they would open settings.json and try to remove the profile object.
This section of code recognizes if a profile was seen before and marks it as
`"hidden": true` by default and thus ensures the behavior the user expects:
Profiles won't show up again after they've been removed from settings.json.

## References

#8324 - Application State

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

## Validation Steps Performed

* settings.json/state.json are created if they don't exist ✔️
* Removing any profile from settings.json doesn't cause it to appear again ✔️
* Hitting save in SUI creates profiles with `"hidden": true` ✔️
* Removing a default profile and hitting save in SUI works 
  An empty object is added instead.
This commit is contained in:
Leonard Hecker 2021-08-16 15:32:05 +02:00 committed by GitHub
parent 0220f71883
commit 5d36e5d2df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 48 additions and 8 deletions

View file

@ -185,8 +185,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
inline bool _IsClosing() const noexcept inline bool _IsClosing() const noexcept
{ {
#ifndef NDEBUG
// _closing isn't atomic and may only be accessed from the main thread. // _closing isn't atomic and may only be accessed from the main thread.
assert(Dispatcher().HasThreadAccess()); if (const auto dispatcher = Dispatcher())
{
assert(dispatcher.HasThreadAccess());
}
#endif
return _closing; return _closing;
} }

View file

@ -155,15 +155,14 @@ winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings CascadiaSettings::
const auto hardcodedDefaultGuid = resultPtr->GlobalSettings().DefaultProfile(); const auto hardcodedDefaultGuid = resultPtr->GlobalSettings().DefaultProfile();
std::optional<std::string> fileData = _ReadUserSettings(); std::optional<std::string> fileData = _ReadUserSettings();
const bool foundFile = fileData.has_value();
// Make sure the file isn't totally empty. If it is, we'll treat the file // Make sure the file isn't totally empty. If it is, we'll treat the file
// like it doesn't exist at all. // like it doesn't exist at all.
const bool fileHasData = foundFile && !fileData.value().empty(); const bool fileHasData = fileData && !fileData->empty();
bool needToWriteFile = false; bool needToWriteFile = false;
if (fileHasData) if (fileHasData)
{ {
resultPtr->_ParseJsonString(fileData.value(), false); resultPtr->_ParseJsonString(*fileData, false);
} }
// Load profiles from dynamic profile generators. _userSettings should be // Load profiles from dynamic profile generators. _userSettings should be
@ -204,6 +203,35 @@ winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings CascadiaSettings::
_CatchRethrowSerializationExceptionWithLocationInfo(resultPtr->_userSettingsString); _CatchRethrowSerializationExceptionWithLocationInfo(resultPtr->_userSettingsString);
} }
// Let's say a user doesn't know that they need to write `"hidden": true` in
// order to prevent a profile from showing up (and a settings UI doesn't exist).
// Naturally they would open settings.json and try to remove the profile object.
// This section of code recognizes if a profile was seen before and marks it as
// `"hidden": true` by default and thus ensures the behavior the user expects:
// Profiles won't show up again after they've been removed from settings.json.
{
const auto state = winrt::get_self<implementation::ApplicationState>(ApplicationState::SharedInstance());
auto generatedProfiles = state->GeneratedProfiles();
bool generatedProfilesChanged = false;
for (auto profile : resultPtr->_allProfiles)
{
if (generatedProfiles.emplace(profile.Guid()).second)
{
generatedProfilesChanged = true;
}
else if (profile.Origin() != OriginTag::User)
{
profile.Hidden(true);
}
}
if (generatedProfilesChanged)
{
state->GeneratedProfiles(generatedProfiles);
}
}
// After layering the user settings, check if there are any new profiles // After layering the user settings, check if there are any new profiles
// that need to be inserted into their user settings file. // that need to be inserted into their user settings file.
needToWriteFile = resultPtr->_AppendDynamicProfilesToUserSettings() || needToWriteFile; needToWriteFile = resultPtr->_AppendDynamicProfilesToUserSettings() || needToWriteFile;
@ -352,7 +380,6 @@ void CascadiaSettings::_LoadDynamicProfiles()
} }
} }
const GUID nullGuid{ 0 };
for (auto& generator : _profileGenerators) for (auto& generator : _profileGenerators)
{ {
const std::wstring generatorNamespace{ generator->GetNamespace() }; const std::wstring generatorNamespace{ generator->GetNamespace() };
@ -711,7 +738,7 @@ bool CascadiaSettings::_AppendDynamicProfilesToUserSettings()
wbuilder.settings_["indentation"] = " "; wbuilder.settings_["indentation"] = " ";
wbuilder.settings_["enableYAMLCompatibility"] = true; // suppress spaces around colons wbuilder.settings_["enableYAMLCompatibility"] = true; // suppress spaces around colons
auto isInJsonObj = [](const auto& profile, const auto& json) { static const auto isInJsonObj = [](const auto& profile, const auto& json) {
for (auto profileJson : _GetProfilesJsonObject(json)) for (auto profileJson : _GetProfilesJsonObject(json))
{ {
if (profileJson.isObject()) if (profileJson.isObject())
@ -745,8 +772,16 @@ bool CascadiaSettings::_AppendDynamicProfilesToUserSettings()
for (const auto& profile : _allProfiles) for (const auto& profile : _allProfiles)
{ {
// Skip profiles that are in the user settings or the default settings. // Skip profiles that are:
if (isInJsonObj(profile, _userSettings) || isInJsonObj(profile, _defaultSettings)) // * hidden
// Because when a user manually removes profiles from settings.json,
// we mark them as hidden in LoadAll(). Adding those profiles right
// back into settings.json would feel confusing, while the
// profile that was just erased is added right back.
// * in the user settings or the default settings
// Because we don't want to add profiles which are already
// in the settings.json (explicitly or implicitly).
if (profile.Hidden() || isInJsonObj(profile, _userSettings) || isInJsonObj(profile, _defaultSettings))
{ {
continue; continue;
} }