terminal/src/cascadia/TerminalSettingsModel/IInheritable.h

289 lines
18 KiB
C
Raw Normal View History

/*++
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 ClearParents()
{
_parents.clear();
}
void InsertParent(com_ptr<T> parent)
{
Reduce usage of Json::Value throughout Terminal.Settings.Model (#11184) This commit reduces the code surface that interacts with raw JSON data, reducing code complexity and improving maintainability. Files that needed to be changed drastically were additionally cleaned up to remove any code cruft that has accrued over time. In order to facility this the following changes were made: * Move JSON handling from `CascadiaSettings` into `SettingsLoader` This allows us to use STL containers for data model instances. For instance profiles are now added to a hashmap for O(1) lookup. * JSON parsing within `SettingsLoader` doesn't differentiate between user, inbox and fragment JSON data, reducing code complexity and size. It also centralizes common concerns, like profile deduplication and ensuring that all profiles are assigned a GUID. * Direct JSON modification, like the insertion of dynamic profiles into settings.json were removed. This vastly reduces code complexity, but unfortunately removes support for comments in JSON on first start. * `ColorScheme`s cannot be layered. As such its `LayerJson` API was replaced with `FromJson`, allowing us to remove JSON-based color scheme validation. * `Profile`s used to test their wish to layer using `ShouldBeLayered`, which was replaced with a GUID-based hashmap lookup on previously parsed profiles. Further changes were made as improvements upon the previous changes: * Compact the JSON files embedded binary, saving 28kB * Prevent double-initialization of the color table in `ColorScheme` * Making `til::color` getters `constexpr`, allow better optimizations The result is a reduction of: * 48kB binary size for the Settings.Model.dll * 5-10% startup duration * 26% code for the `CascadiaSettings` class * 1% overall code in this project Furthermore this results in the following breaking changes: * The long deprecated "globals" settings object will not be detected and no warning will be created during load. * The initial creation of a new settings.json will not produce helpful comments. Both cases are caused by the removal of manual JSON handling and the move to representing the settings file with model objects instead ## PR Checklist * [x] Closes #5276 * [x] Closes #7421 * [x] I work here * [x] Tests added/passed ## Validation Steps Performed * Out-of-box-experience is identical to before ✔️ (Except for the settings.json file lacking comments.) * Existing user settings load correctly ✔️ * New WSL instances are added to user settings ✔️ * New fragments are added to user settings ✔️ * All profiles are assigned GUIDs ✔️
2021-09-22 18:27:31 +02:00
_parents.emplace_back(std::move(parent));
}
void InsertParent(size_t index, com_ptr<T> parent)
{
auto pos{ _parents.begin() + index };
Reduce usage of Json::Value throughout Terminal.Settings.Model (#11184) This commit reduces the code surface that interacts with raw JSON data, reducing code complexity and improving maintainability. Files that needed to be changed drastically were additionally cleaned up to remove any code cruft that has accrued over time. In order to facility this the following changes were made: * Move JSON handling from `CascadiaSettings` into `SettingsLoader` This allows us to use STL containers for data model instances. For instance profiles are now added to a hashmap for O(1) lookup. * JSON parsing within `SettingsLoader` doesn't differentiate between user, inbox and fragment JSON data, reducing code complexity and size. It also centralizes common concerns, like profile deduplication and ensuring that all profiles are assigned a GUID. * Direct JSON modification, like the insertion of dynamic profiles into settings.json were removed. This vastly reduces code complexity, but unfortunately removes support for comments in JSON on first start. * `ColorScheme`s cannot be layered. As such its `LayerJson` API was replaced with `FromJson`, allowing us to remove JSON-based color scheme validation. * `Profile`s used to test their wish to layer using `ShouldBeLayered`, which was replaced with a GUID-based hashmap lookup on previously parsed profiles. Further changes were made as improvements upon the previous changes: * Compact the JSON files embedded binary, saving 28kB * Prevent double-initialization of the color table in `ColorScheme` * Making `til::color` getters `constexpr`, allow better optimizations The result is a reduction of: * 48kB binary size for the Settings.Model.dll * 5-10% startup duration * 26% code for the `CascadiaSettings` class * 1% overall code in this project Furthermore this results in the following breaking changes: * The long deprecated "globals" settings object will not be detected and no warning will be created during load. * The initial creation of a new settings.json will not produce helpful comments. Both cases are caused by the removal of manual JSON handling and the move to representing the settings file with model objects instead ## PR Checklist * [x] Closes #5276 * [x] Closes #7421 * [x] I work here * [x] Tests added/passed ## Validation Steps Performed * Out-of-box-experience is identical to before ✔️ (Except for the settings.json file lacking comments.) * Existing user settings load correctly ✔️ * New WSL instances are added to user settings ✔️ * New fragments are added to user settings ✔️ * All profiles are assigned GUIDs ✔️
2021-09-22 18:27:31 +02:00
_parents.emplace(pos, std::move(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>
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
using NullableSetting = std::optional<std::optional<T>>;
}
// Use this macro to quickly implement both getters and the setter for an
// inheritable setting property. This is similar to the WINRT_PROPERTY macro, except...
// - Has(): checks if the user explicitly set a value for this setting
Introduce setting override tracking and update SettingContainer (#9079) This PR adds improved override message generation for inheritance in SUI. The settings model now has an `OriginTag` to be able to denote where a `Profile` came from. This tag is used in the `SettingContainer` to generate a more specific override message. ## References #6800 - SUI Epic #8919 - SUI Inheritance PR #8804 - SUI Inheritance (old issue) ## Detailed Description of the Pull Request / Additional comments - **Terminal Settings Model** - Introduced `PROJECTED_SETTING` as a macro to more easily declare the functions for each setting - Introduced `<setting>OverrideSource` which finds the `Profile` that has \<setting\> defined - Introduced `OriginTag Profile::Origin {Custom, InBox, Generated}` to trace where a profile came from - `DefaultProfileUtils` creates profiles for profile generators. So that now sets the `Origin` tag to `Generated` - `CascadiaSettings::LoadDefaults()` tags all profiles created as `InBox`. - The view model had to ingest the API change to be able to interact with `<setting>OverrideSource` - **Override Message Generation** - The reset button now has a more specific tooltip - The reset button now only appears if base layer is being overridden - We use the settings model changes to determine the message to display for the target ## Validation Steps Performed Tested the following cases: - overrides nothing (inherited setting) - overrides value inherited from... - base layer - a profile generator - in-box profile - global settings should not have this feature
2021-02-20 00:50:52 +01:00
// - SourceGetter(): return the object that provides the resolved value
// - 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 INHERITABLE_SETTING(projectedType, type, name, ...) \
public: \
/* Returns true if the user explicitly set the value, false otherwise*/ \
bool Has##name() const \
{ \
return _##name.has_value(); \
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
} \
\
Introduce setting override tracking and update SettingContainer (#9079) This PR adds improved override message generation for inheritance in SUI. The settings model now has an `OriginTag` to be able to denote where a `Profile` came from. This tag is used in the `SettingContainer` to generate a more specific override message. ## References #6800 - SUI Epic #8919 - SUI Inheritance PR #8804 - SUI Inheritance (old issue) ## Detailed Description of the Pull Request / Additional comments - **Terminal Settings Model** - Introduced `PROJECTED_SETTING` as a macro to more easily declare the functions for each setting - Introduced `<setting>OverrideSource` which finds the `Profile` that has \<setting\> defined - Introduced `OriginTag Profile::Origin {Custom, InBox, Generated}` to trace where a profile came from - `DefaultProfileUtils` creates profiles for profile generators. So that now sets the `Origin` tag to `Generated` - `CascadiaSettings::LoadDefaults()` tags all profiles created as `InBox`. - The view model had to ingest the API change to be able to interact with `<setting>OverrideSource` - **Override Message Generation** - The reset button now has a more specific tooltip - The reset button now only appears if base layer is being overridden - We use the settings model changes to determine the message to display for the target ## Validation Steps Performed Tested the following cases: - overrides nothing (inherited setting) - overrides value inherited from... - base layer - a profile generator - in-box profile - global settings should not have this feature
2021-02-20 00:50:52 +01:00
projectedType name##OverrideSource() \
{ \
/*user set value was not set*/ \
/*iterate through parents to find one with a value*/ \
for (auto& parent : _parents) \
{ \
if (auto source{ parent->_get##name##OverrideSourceImpl() }) \
{ \
return source; \
} \
} \
\
/*no value was found*/ \
return nullptr; \
} \
\
/* 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__ }; \
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
} \
\
/* Overwrite the user set value */ \
void name(const type& value) \
{ \
_##name = value; \
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
} \
\
/* Clear the user set value */ \
void Clear##name() \
{ \
_##name = std::nullopt; \
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
} \
\
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 (const auto& parent : _parents) \
{ \
if (auto val{ parent->_get##name##Impl() }) \
{ \
return val; \
} \
} \
\
/*no value was found*/ \
return std::nullopt; \
Introduce setting override tracking and update SettingContainer (#9079) This PR adds improved override message generation for inheritance in SUI. The settings model now has an `OriginTag` to be able to denote where a `Profile` came from. This tag is used in the `SettingContainer` to generate a more specific override message. ## References #6800 - SUI Epic #8919 - SUI Inheritance PR #8804 - SUI Inheritance (old issue) ## Detailed Description of the Pull Request / Additional comments - **Terminal Settings Model** - Introduced `PROJECTED_SETTING` as a macro to more easily declare the functions for each setting - Introduced `<setting>OverrideSource` which finds the `Profile` that has \<setting\> defined - Introduced `OriginTag Profile::Origin {Custom, InBox, Generated}` to trace where a profile came from - `DefaultProfileUtils` creates profiles for profile generators. So that now sets the `Origin` tag to `Generated` - `CascadiaSettings::LoadDefaults()` tags all profiles created as `InBox`. - The view model had to ingest the API change to be able to interact with `<setting>OverrideSource` - **Override Message Generation** - The reset button now has a more specific tooltip - The reset button now only appears if base layer is being overridden - We use the settings model changes to determine the message to display for the target ## Validation Steps Performed Tested the following cases: - overrides nothing (inherited setting) - overrides value inherited from... - base layer - a profile generator - in-box profile - global settings should not have this feature
2021-02-20 00:50:52 +01:00
} \
projectedType _get##name##OverrideSourceImpl() const \
{ \
/*we have a value*/ \
if (_##name) \
{ \
return *this; \
} \
\
/*user set value was not set*/ \
/*iterate through parents to find one with a value*/ \
for (const auto& parent : _parents) \
Introduce setting override tracking and update SettingContainer (#9079) This PR adds improved override message generation for inheritance in SUI. The settings model now has an `OriginTag` to be able to denote where a `Profile` came from. This tag is used in the `SettingContainer` to generate a more specific override message. ## References #6800 - SUI Epic #8919 - SUI Inheritance PR #8804 - SUI Inheritance (old issue) ## Detailed Description of the Pull Request / Additional comments - **Terminal Settings Model** - Introduced `PROJECTED_SETTING` as a macro to more easily declare the functions for each setting - Introduced `<setting>OverrideSource` which finds the `Profile` that has \<setting\> defined - Introduced `OriginTag Profile::Origin {Custom, InBox, Generated}` to trace where a profile came from - `DefaultProfileUtils` creates profiles for profile generators. So that now sets the `Origin` tag to `Generated` - `CascadiaSettings::LoadDefaults()` tags all profiles created as `InBox`. - The view model had to ingest the API change to be able to interact with `<setting>OverrideSource` - **Override Message Generation** - The reset button now has a more specific tooltip - The reset button now only appears if base layer is being overridden - We use the settings model changes to determine the message to display for the target ## Validation Steps Performed Tested the following cases: - overrides nothing (inherited setting) - overrides value inherited from... - base layer - a profile generator - in-box profile - global settings should not have this feature
2021-02-20 00:50:52 +01:00
{ \
if (auto source{ parent->_get##name##OverrideSourceImpl() }) \
{ \
return source; \
} \
} \
\
/*no value was found*/ \
return nullptr; \
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
}
// 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 INHERITABLE_NULLABLE_SETTING(projectedType, type, name, ...) \
public: \
/* Returns true if the user explicitly set the value, false otherwise*/ \
bool Has##name() const \
{ \
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
return _##name.has_value(); \
} \
\
Introduce setting override tracking and update SettingContainer (#9079) This PR adds improved override message generation for inheritance in SUI. The settings model now has an `OriginTag` to be able to denote where a `Profile` came from. This tag is used in the `SettingContainer` to generate a more specific override message. ## References #6800 - SUI Epic #8919 - SUI Inheritance PR #8804 - SUI Inheritance (old issue) ## Detailed Description of the Pull Request / Additional comments - **Terminal Settings Model** - Introduced `PROJECTED_SETTING` as a macro to more easily declare the functions for each setting - Introduced `<setting>OverrideSource` which finds the `Profile` that has \<setting\> defined - Introduced `OriginTag Profile::Origin {Custom, InBox, Generated}` to trace where a profile came from - `DefaultProfileUtils` creates profiles for profile generators. So that now sets the `Origin` tag to `Generated` - `CascadiaSettings::LoadDefaults()` tags all profiles created as `InBox`. - The view model had to ingest the API change to be able to interact with `<setting>OverrideSource` - **Override Message Generation** - The reset button now has a more specific tooltip - The reset button now only appears if base layer is being overridden - We use the settings model changes to determine the message to display for the target ## Validation Steps Performed Tested the following cases: - overrides nothing (inherited setting) - overrides value inherited from... - base layer - a profile generator - in-box profile - global settings should not have this feature
2021-02-20 00:50:52 +01:00
projectedType name##OverrideSource() \
{ \
/*user set value was not set*/ \
/*iterate through parents to find one with a value*/ \
for (const auto& parent : _parents) \
Introduce setting override tracking and update SettingContainer (#9079) This PR adds improved override message generation for inheritance in SUI. The settings model now has an `OriginTag` to be able to denote where a `Profile` came from. This tag is used in the `SettingContainer` to generate a more specific override message. ## References #6800 - SUI Epic #8919 - SUI Inheritance PR #8804 - SUI Inheritance (old issue) ## Detailed Description of the Pull Request / Additional comments - **Terminal Settings Model** - Introduced `PROJECTED_SETTING` as a macro to more easily declare the functions for each setting - Introduced `<setting>OverrideSource` which finds the `Profile` that has \<setting\> defined - Introduced `OriginTag Profile::Origin {Custom, InBox, Generated}` to trace where a profile came from - `DefaultProfileUtils` creates profiles for profile generators. So that now sets the `Origin` tag to `Generated` - `CascadiaSettings::LoadDefaults()` tags all profiles created as `InBox`. - The view model had to ingest the API change to be able to interact with `<setting>OverrideSource` - **Override Message Generation** - The reset button now has a more specific tooltip - The reset button now only appears if base layer is being overridden - We use the settings model changes to determine the message to display for the target ## Validation Steps Performed Tested the following cases: - overrides nothing (inherited setting) - overrides value inherited from... - base layer - a profile generator - in-box profile - global settings should not have this feature
2021-02-20 00:50:52 +01:00
{ \
if (auto source{ parent->_get##name##OverrideSourceImpl() }) \
{ \
return source; \
} \
} \
\
/*no source was found*/ \
return nullptr; \
} \
\
/* 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() }; \
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
if (val) \
{ \
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
if (*val) \
{ \
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
return **val; \
} \
return nullptr; \
} \
return winrt::Windows::Foundation::IReference<type>{ __VA_ARGS__ }; \
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
} \
\
/* Overwrite the user set value */ \
void name(const winrt::Windows::Foundation::IReference<type>& value) \
{ \
if (value) /*set value is different*/ \
{ \
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
_##name = std::optional<type>{ value.Value() }; \
} \
else \
{ \
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
/* note we're setting the _inner_ value */ \
_##name = std::optional<type>{ std::nullopt }; \
} \
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
} \
\
/* Clear the user set value */ \
void Clear##name() \
{ \
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
_##name = std::nullopt; \
} \
\
private: \
NullableSetting<type> _##name{}; \
NullableSetting<type> _get##name##Impl() const \
{ \
/*return user set value*/ \
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
if (_##name) \
{ \
return _##name; \
} \
\
/*user set value was not set*/ \
/*iterate through parents to find a value*/ \
for (const auto& parent : _parents) \
{ \
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
if (auto val{ parent->_get##name##Impl() }) \
{ \
return val; \
} \
} \
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
\
/*no value was found*/ \
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
return std::nullopt; \
Introduce setting override tracking and update SettingContainer (#9079) This PR adds improved override message generation for inheritance in SUI. The settings model now has an `OriginTag` to be able to denote where a `Profile` came from. This tag is used in the `SettingContainer` to generate a more specific override message. ## References #6800 - SUI Epic #8919 - SUI Inheritance PR #8804 - SUI Inheritance (old issue) ## Detailed Description of the Pull Request / Additional comments - **Terminal Settings Model** - Introduced `PROJECTED_SETTING` as a macro to more easily declare the functions for each setting - Introduced `<setting>OverrideSource` which finds the `Profile` that has \<setting\> defined - Introduced `OriginTag Profile::Origin {Custom, InBox, Generated}` to trace where a profile came from - `DefaultProfileUtils` creates profiles for profile generators. So that now sets the `Origin` tag to `Generated` - `CascadiaSettings::LoadDefaults()` tags all profiles created as `InBox`. - The view model had to ingest the API change to be able to interact with `<setting>OverrideSource` - **Override Message Generation** - The reset button now has a more specific tooltip - The reset button now only appears if base layer is being overridden - We use the settings model changes to determine the message to display for the target ## Validation Steps Performed Tested the following cases: - overrides nothing (inherited setting) - overrides value inherited from... - base layer - a profile generator - in-box profile - global settings should not have this feature
2021-02-20 00:50:52 +01:00
} \
projectedType _get##name##OverrideSourceImpl() const \
{ \
/*we have a value*/ \
if (_##name) \
{ \
return *this; \
} \
\
/*user set value was not set*/ \
/*iterate through parents to find one with a value*/ \
for (const auto& parent : _parents) \
Introduce setting override tracking and update SettingContainer (#9079) This PR adds improved override message generation for inheritance in SUI. The settings model now has an `OriginTag` to be able to denote where a `Profile` came from. This tag is used in the `SettingContainer` to generate a more specific override message. ## References #6800 - SUI Epic #8919 - SUI Inheritance PR #8804 - SUI Inheritance (old issue) ## Detailed Description of the Pull Request / Additional comments - **Terminal Settings Model** - Introduced `PROJECTED_SETTING` as a macro to more easily declare the functions for each setting - Introduced `<setting>OverrideSource` which finds the `Profile` that has \<setting\> defined - Introduced `OriginTag Profile::Origin {Custom, InBox, Generated}` to trace where a profile came from - `DefaultProfileUtils` creates profiles for profile generators. So that now sets the `Origin` tag to `Generated` - `CascadiaSettings::LoadDefaults()` tags all profiles created as `InBox`. - The view model had to ingest the API change to be able to interact with `<setting>OverrideSource` - **Override Message Generation** - The reset button now has a more specific tooltip - The reset button now only appears if base layer is being overridden - We use the settings model changes to determine the message to display for the target ## Validation Steps Performed Tested the following cases: - overrides nothing (inherited setting) - overrides value inherited from... - base layer - a profile generator - in-box profile - global settings should not have this feature
2021-02-20 00:50:52 +01:00
{ \
if (auto source{ parent->_get##name##OverrideSourceImpl() }) \
{ \
return source; \
} \
} \
\
/*no value was found*/ \
return nullptr; \
Rework JsonUtils' optional handling to let Converters see null (#8175) The JsonUtils changes in #8018 revealed that we need more robust, configurable optional handling. We learned that there's a class of values that was previously underrepresented in our API: _strings that have an explicit empty value_. The Settings model supports starting directory, icon, background image et al values that are empty. That emptiness _overrides_ a value set in a lower layer, so it is not sufficient to represent the empty value for any one of those fields as an unset optional. There are a couple other settings for which we've implemented a hand-rolled option type (for roughly the same reason): foreground, background, any color fields that override values from the color scheme _or_ the lower layer profile. These requirements are best fulfilled by better optional support in JsonUtils. Where the library would originally detect known types of optional and pre-filter them out during `GetValue` and `SetValue`, it will now defer to another conversion trait. This commit introduces a helper conversion trait and an "option oracle". The conversion trait will use the option oracle to detect emptiness, generate empty option values, and read values out of option types. In so doing, the trait is insulated from the implementation details of any specific option type. Any special logic for handling JSON null and option types has been stripped from GetValue. Due to this, there is an express change in behavior for some converters: * `GetValue<T>(jsonNull)` where `T` is **not** an option type[1] has been upgraded from a silent no-op to an exception. Further, I took the opportunity to replace NullableSetting with std::optional<std::optional<T>>, which accurately represents "setting that the user might explicitly clear". I've added a test to JsonUtilsTests to make sure it can serialize/deserialize double optionals the way we expect it to. Tests (Local, Unit for TerminalApp/SettingsModel): Summary: Total=140, Passed=140, Failed=0, Blocked=0, Not Run=0, Skipped=0 [1]: Explicitly, if `T` is not an option type _and the converter does not support null_.
2020-11-10 00:13:02 +01:00
}