terminal/src/cascadia/TerminalSettingsModel/CascadiaSettings.h
Leonard Hecker 608a49e817
Allow generated profiles to be deleted (#11007)
Re-enables the delete button for generated profiles in the settings UI.
Additionally fixes "Startup Profiles" to only list active profiles.

Profiles are considered deleted if they're absent from settings.json, but their
GUID has been encountered before. Or in other words, from a user's perspective:
Generated profiles are added to the settings.json automatically only once.
Thus if the user chooses to delete the profile (e.g. using the delete button)
they aren't re-added automatically and thus appear to have been deleted.

Meanwhile those generated profiles are actually only marked as "hidden"
as well as "deleted", but still exist in internal profile lists.
The "hidden" attribute hides them from all existing menus. The "deleted" one
hides them from the settings UI and prevents them from being written to disk.

It would've been preferrable of course to just not generate and
add deleted profile to internal profile lists in the first place.
But this would've required far more wide-reaching changes.
The settings UI for instance requires a list of _all_ profiles in order to
allow a user to re-create previously deleted profiles. Such an approach was
attempted but discarded because of it's current complexity overhead.

## References

* Part of #9997
* A sequel to 5d36e5d

## PR Checklist

* [x] Closes #10960
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed

* "Startup Profiles" doesn't list deleted profiles ✔️
* Manually removing an item from settings.json removes the profile ✔️
* Removing cmd.exe and saving doesn't create empty objects (#10960) ✔️
* "Add a new profile" lists deleted profiles ✔️
* "Duplicate" recreates previously deleted profiles ✔️
* Profiles are always created with GUIDs ✔️
2021-08-23 22:00:08 +00:00

187 lines
7.7 KiB
C++

/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- CascadiaSettings.h
Abstract:
- This class acts as the container for all app settings. It's composed of two
parts: Globals, which are app-wide settings, and Profiles, which contain
a set of settings that apply to a single instance of the terminal.
Also contains the logic for serializing and deserializing this object.
Author(s):
- Mike Griese - March 2019
--*/
#pragma once
#include "CascadiaSettings.g.h"
#include "GlobalAppSettings.h"
#include "TerminalWarnings.h"
#include "IDynamicProfileGenerator.h"
#include "Profile.h"
#include "ColorScheme.h"
// fwdecl unittest classes
namespace SettingsModelLocalTests
{
class SerializationTests;
class DeserializationTests;
class ProfileTests;
class ColorSchemeTests;
class KeyBindingsTests;
};
namespace TerminalAppUnitTests
{
class DynamicProfileTests;
class JsonTests;
};
namespace Microsoft::Terminal::Settings::Model
{
class SettingsTypedDeserializationException;
};
class Microsoft::Terminal::Settings::Model::SettingsTypedDeserializationException final : public std::runtime_error
{
public:
SettingsTypedDeserializationException(const std::string_view description) :
runtime_error(description.data()) {}
};
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{
struct CascadiaSettings : CascadiaSettingsT<CascadiaSettings>
{
public:
CascadiaSettings();
explicit CascadiaSettings(const bool addDynamicProfiles);
CascadiaSettings(hstring json);
Model::CascadiaSettings Copy() const;
static Model::CascadiaSettings LoadDefaults();
static Model::CascadiaSettings LoadAll();
static Model::CascadiaSettings LoadUniversal();
Model::GlobalAppSettings GlobalSettings() const;
Windows::Foundation::Collections::IObservableVector<Model::Profile> AllProfiles() const noexcept;
Windows::Foundation::Collections::IObservableVector<Model::Profile> ActiveProfiles() const noexcept;
Model::ActionMap ActionMap() const noexcept;
static com_ptr<CascadiaSettings> FromJson(const Json::Value& json);
void LayerJson(const Json::Value& json);
void WriteSettingsToDisk() const;
Json::Value ToJson() const;
static hstring SettingsPath();
static hstring DefaultSettingsPath();
Model::Profile ProfileDefaults() const;
static winrt::hstring ApplicationDisplayName();
static winrt::hstring ApplicationVersion();
Model::Profile CreateNewProfile();
Model::Profile FindProfile(const guid& profileGuid) const noexcept;
Model::ColorScheme GetColorSchemeForProfile(const Model::Profile& profile) const;
void UpdateColorSchemeReferences(const hstring oldName, const hstring newName);
Windows::Foundation::Collections::IVectorView<SettingsLoadWarnings> Warnings();
void ClearWarnings();
void AppendWarning(SettingsLoadWarnings warning);
Windows::Foundation::IReference<SettingsLoadErrors> GetLoadingError();
hstring GetSerializationErrorMessage();
Model::Profile GetProfileForArgs(const Model::NewTerminalArgs& newTerminalArgs) const;
Model::Profile DuplicateProfile(const Model::Profile& source);
void RefreshDefaultTerminals();
static bool IsDefaultTerminalAvailable() noexcept;
Windows::Foundation::Collections::IObservableVector<Model::DefaultTerminal> DefaultTerminals() const noexcept;
Model::DefaultTerminal CurrentDefaultTerminal() const noexcept;
void CurrentDefaultTerminal(Model::DefaultTerminal terminal);
private:
com_ptr<GlobalAppSettings> _globals;
Windows::Foundation::Collections::IObservableVector<Model::Profile> _allProfiles;
Windows::Foundation::Collections::IObservableVector<Model::Profile> _activeProfiles;
Windows::Foundation::Collections::IVector<Model::SettingsLoadWarnings> _warnings;
Windows::Foundation::IReference<SettingsLoadErrors> _loadError;
hstring _deserializationErrorMessage;
Windows::Foundation::Collections::IObservableVector<Model::DefaultTerminal> _defaultTerminals;
Model::DefaultTerminal _currentDefaultTerminal;
std::vector<std::unique_ptr<::Microsoft::Terminal::Settings::Model::IDynamicProfileGenerator>> _profileGenerators;
std::string _userSettingsString;
Json::Value _userSettings;
Json::Value _defaultSettings;
winrt::com_ptr<Profile> _userDefaultProfileSettings{ nullptr };
winrt::com_ptr<Profile> _CreateNewProfile(const std::wstring_view& name) const;
void _LayerOrCreateProfile(const Json::Value& profileJson);
winrt::com_ptr<implementation::Profile> _FindMatchingProfile(const Json::Value& profileJson);
std::optional<uint32_t> _FindMatchingProfileIndex(const Json::Value& profileJson);
void _LayerOrCreateColorScheme(const Json::Value& schemeJson);
Json::Value _ParseUtf8JsonString(std::string_view fileData);
winrt::com_ptr<implementation::ColorScheme> _FindMatchingColorScheme(const Json::Value& schemeJson);
void _ParseJsonString(std::string_view fileData, const bool isDefaultSettings);
static const Json::Value& _GetProfilesJsonObject(const Json::Value& json);
static const Json::Value& _GetDisabledProfileSourcesJsonObject(const Json::Value& json);
bool _PrependSchemaDirective();
bool _AppendDynamicProfilesToUserSettings();
std::string _ApplyFirstRunChangesToSettingsTemplate(std::string_view settingsTemplate) const;
void _CopyProfileInheritanceTree(com_ptr<CascadiaSettings>& cloneSettings) const;
void _ApplyDefaultsFromUserSettings();
void _LoadDynamicProfiles();
void _LoadFragmentExtensions();
void _ApplyJsonStubsHelper(const std::wstring_view directory, const std::unordered_set<std::wstring>& ignoredNamespaces);
std::unordered_set<std::string> _AccumulateJsonFilesInDirectory(const std::wstring_view directory);
void _ParseAndLayerFragmentFiles(const std::unordered_set<std::string> files, const winrt::hstring source);
static const std::filesystem::path& _SettingsPath();
static std::optional<std::string> _ReadUserSettings();
std::optional<guid> _GetProfileGuidByName(const hstring) const;
std::optional<guid> _GetProfileGuidByIndex(std::optional<int> index) const;
void _ValidateSettings();
void _ValidateProfilesExist();
void _ValidateDefaultProfileExists();
void _ValidateNoDuplicateProfiles();
void _ResolveDefaultProfile();
void _ReorderProfilesToMatchUserSettingsOrder();
void _UpdateActiveProfiles();
void _ValidateAllSchemesExist();
void _ValidateMediaResources();
void _ValidateKeybindings();
void _ValidateColorSchemesInCommands();
void _ValidateNoGlobalsKey();
bool _HasInvalidColorScheme(const Model::Command& command);
friend class SettingsModelLocalTests::SerializationTests;
friend class SettingsModelLocalTests::DeserializationTests;
friend class SettingsModelLocalTests::ProfileTests;
friend class SettingsModelLocalTests::ColorSchemeTests;
friend class SettingsModelLocalTests::KeyBindingsTests;
friend class TerminalAppUnitTests::DynamicProfileTests;
friend class TerminalAppUnitTests::JsonTests;
};
}
namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation
{
BASIC_FACTORY(CascadiaSettings);
}