[PR #8175] Rework JsonUtils' optional handling to let Converters see null #27132

Open
opened 2026-01-31 09:20:11 +00:00 by claunia · 0 comments
Owner

Original Pull Request: https://github.com/microsoft/terminal/pull/8175

State: closed
Merged: Yes


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>, 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
.

**Original Pull Request:** https://github.com/microsoft/terminal/pull/8175 **State:** closed **Merged:** Yes --- 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_.
claunia added the pull-request label 2026-01-31 09:20:11 +00:00
Sign in to join this conversation.
No Label pull-request
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#27132