Skip to content

Commit 06d2d38

Browse files
committed
Introduce Inheritance Addendum to TSM Spec
1 parent f0b8875 commit 06d2d38

File tree

1 file changed

+83
-2
lines changed

1 file changed

+83
-2
lines changed

doc/specs/#885 - winrt Terminal Settings.md renamed to doc/specs/#885 - Terminal Settings Model.md

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,94 @@ This separation leaves `AppKeyBindings` with the responsibility of detecting and
7878
`KeyMapping` handles the (de)serialization and navigation of the key bindings.
7979

8080

81+
### Fallback Value
82+
83+
Cascading settings allows our settings model to be constructed in layers (i.e. settings.json values override defaults.json values). With the upcoming introduction of the Settings UI and serialization, it is important to know where a setting value comes from. Consider a Settings UI displaying the following information:
84+
```json
85+
// <profile>: <color scheme value>
86+
"defaults": "Solarized", // profiles.defaults
87+
"A": "Raspberry", // profile A
88+
"B": "Tango", // profile B
89+
"C": "Solarized" // profile C
90+
```
91+
If `profiles.defaults` gets changed to `"Tango"` via the Settings UI, it is unclear if profile C's value should be updated as well. We need profile C to record if it's value is inherited from profile.defaults or explicitly set by the user.
92+
93+
To start, each settings object will now have a `Clone()` function. For `GlobalAppSettings`, it will look something like this:
94+
```c++
95+
GlobalAppSettings GlobalAppSettings::Clone() const
96+
{
97+
GlobalAppSettings clone {};
98+
clone._parent = this;
99+
return clone;
100+
}
101+
```
102+
`_parent` serves as a reference for who to ask if a settings value was not provided by the user. `LaunchMode`, for example, will now have a getter/setter that looks similar to this:
103+
```c++
104+
LaunchMode GlobalAppSettings::LaunchMode()
105+
{
106+
// fallback tree:
107+
// - user set value
108+
// - inherited value
109+
// - system set value
110+
return til::coalesce_value(_LaunchMode, _parent.LaunchMode(), LaunchMode::DefaultMode);
111+
}
112+
113+
void GlobalAppSettings::LaunchMode(IReference<LaunchMode> val)
114+
{
115+
// if val is nullptr, we are explicitly saying that we want the inherited value
116+
_LaunchMode = val;
117+
}
118+
```
119+
120+
As `CascadiaSettings` loads the settings model, it will clone each component of the settings model and layer the new values on top of it. Thus, `LayerJson` will look something like this:
121+
```c++
122+
void CascadiaSettings::LayerJson(const Json::Value& json)
123+
{
124+
_globals = _globals.Clone();
125+
_globals->LayerJson(json);
126+
127+
// repeat the same for Profiles/ColorSchemes...
128+
}
129+
```
130+
For `defaults.json`, `_globals` will now hold all of the values set in `defaults.json`. If any settings were omitted from the `defaults.json`, `_globals` will fallback to its parent (a `GlobalAppSettings` consisting purely of system-defined values).
131+
132+
For `settings.json`, `_globals` will only hold the values set in `settings.json`. If any settings were omitted from `settings.json`, `_globals` will fallback to its parent (the `GlobalAppSettings` built from `defaults.json).
133+
134+
This process becomes a bit more complex for `Profile` because it can fallback in the following order:
135+
1. `settings.json` profile
136+
2. `settings.json` `profiles.defaults`
137+
3. (if a dynamic profile) the hardcoded value in the dynamic profile generator
138+
4. `defaults.json` profile
139+
140+
`CascadiaSettings` must do the following...
141+
1. load `defaults.json`
142+
- append newly created profiles to `_profiles` (unchanged)
143+
2. load dynamic profiles
144+
- append newly created profiles to `_profiles` (unchanged)
145+
3. load `settings.json` `profiles.defaults`
146+
- layer `profile.defaults` onto `_profiles` (unchanged)
147+
- construct a `Profile` from `profiles.defaults`. Save as `Profile _profileDefaults`.
148+
4. load `settings.json` `profiles.list`
149+
- if a matching profile exists, clone the matching profile, and layer the json onto the clone.
150+
- otherwise, clone `_profileDefaults`, and layer the json onto the clone.
151+
152+
153+
### Clone vs Copy
154+
155+
Settings objects will have `Clone()` and `Copy()`. `Clone()` is responsible for creating a new settings object that inherits undefined values from its parent. `Copy()` is responsible for recreating the contents of the settings object, including a reference to a copied parent.
156+
157+
The Settings UI will use `Copy()` to get a full copy of `CascadiaSettings` and data bind the UI to that copy. Thus, `Copy()` needs to be exposed in the IDL.
158+
159+
`Clone()` will only be used during (de)serialization to adequately interpret and update the JSON. `Clone()` enables, but is not explicitly used, for retrieving a value from a settings object. It can also be used to enable larger hierarchies for inheritance within the settings model.
160+
161+
81162
### Terminal Settings Model: Serialization and Deserialization
82163

83164
Introducing these `Microsoft.Terminal.Settings.Model` WinRT objects also allow the serialization and deserialization
84165
logic from TerminalApp to be moved to TerminalSettings. `JsonUtils` introduces several quick and easy methods
85-
for setting serialization. This will be moved into the `Microsoft.Terminal.Settings.Model` namespace too.
166+
for setting deserialization. This will be moved into the `Microsoft.Terminal.Settings.Model` namespace too.
86167

87-
Deserialization will be an extension of the existing `JsonUtils` `ConversionTrait` struct template. `ConversionTrait`
168+
Serialization will be an extension of the existing `JsonUtils` `ConversionTrait` struct template. `ConversionTrait`
88169
already includes `FromJson` and `CanConvert`. Serialization would be handled by a `ToJson` function.
89170

90171

0 commit comments

Comments
 (0)