Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handling Nullable Profile Settings #7435

Closed
carlos-zamora opened this issue Aug 27, 2020 · 7 comments · Fixed by #7283
Closed

Handling Nullable Profile Settings #7435

carlos-zamora opened this issue Aug 27, 2020 · 7 comments · Fixed by #7283
Labels
Area-Settings Issues related to settings and customizability, for console or terminal Issue-Task It's a feature request, but it doesn't really need a major design. Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting Product-Terminal The new Windows Terminal. Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release.

Comments

@carlos-zamora
Copy link
Member

Windows Terminal version: 1.3.2382.0

Related to...

Some settings in Profile are std::optional and others aren't. This leads to an inconsistent handling of setting the property to null in the JSON. Consider the following examples:

  1. "backgroundImage" (std::optional<std::wstring>)
    • explicitly do not have a background image
  2. "snapOnInput" (bool)
    • fall back to profiles.defaults value
  3. "startingDirectory" (std::optional<std::wstring>)
    • inherit the startingDirectory of the parent process
  4. "commandline" (std::wstring)
    • fall back to profiles.defaults value

From an implementation standpoint, it makes sense. std:optionals treat null as a meaningful value, whereas non-std::optionals treat null as fall back.

The problem here is 2-fold:

  1. The schema does not always accept null as a value, even though we do
    • startingDirectory is particularly an example of this where it has a unique behavior from null but is not in the schema
  2. A user has no way of knowing whether setting a profile setting to null will consistently fallback or set the value.

Proposed Implementation/Solution

Make none of the profile settings nullable. If the user...

  • omits the setting --> fall back
  • sets to null --> validate a potential type mismatch

We should also add a special enum value for startingDirectory to inherit from the process.

From a Settings UI standpoint, it won't be possible to set settings to null either. So we should just purge null-ness as an option, and add specific enums for special behavior. Fallback and other special behavior must be represented in the Settings UI as their own button/option.

@carlos-zamora carlos-zamora added Area-Settings Issues related to settings and customizability, for console or terminal Product-Terminal The new Windows Terminal. Issue-Task It's a feature request, but it doesn't really need a major design. labels Aug 27, 2020
@ghost ghost added the Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting label Aug 27, 2020
@DHowett
Copy link
Member

DHowett commented Aug 27, 2020

NAK on a special magic enum value for startingDirectory. null is that value.

No matter what you name that enum value, if it is a string, somebody could name a directory after it and then wonder, "why does Terminal hate my directory named inherit?"

@DHowett
Copy link
Member

DHowett commented Aug 27, 2020

I disagree with some of these assertions of inconsistent behavior.

  1. "backgroundImage" (std::optional<std::wstring>)
    • explicitly do not have a background image
  2. "snapOnInput" (bool)
    • fall back to profiles.defaults value
  3. "startingDirectory" (std::optional<std::wstring>)
    • inherit the startingDirectory of the parent process
  4. "commandline" (std::wstring)
    • fall back to profiles.defaults value

(2): snapOnInput: null falls back to the compiled-in value (true), and unsets the profiles.defaults value
(4): commandline: null falls back to the compiled-in value (cmd.exe), and unsets the profiles.defaults value

null never falls back to the value in profiles.defaults. That's the point of null.
If you wanted it to fall back to profiles.defaults you omit the setting.

null is an explicit statement that "I DO NOT WANT THE NAMED SETTING TO APPLY HERE". That is distinctly different from falling back.

@carlos-zamora
Copy link
Member Author

Ok, then at least with startingDirectory we're explicitly allowing null to be a value. We just have to better document that it has special meaning.

I tested "commandline" and "snapOnInput". It falls back to profile.defaults. Here's the test JSON:

    "profiles": {
        "defaults": {
            "commandline": "wsl.exe",
            "snapOnInput": false
        },
        "list": [
            {
                "name": "test",
                "commandline": null,
                "snapOnInput": null
            }
        ]
    }

Profile "test" runs wsl.exe and does not snap on input.

We can change the behavior to be that when you set these settings to null, you fall back to the compiled-in value (as you'd expect). But I still think that that's not the right move. A regular person does not know what the compiled-in value is.

The user explicitly set something to null that is not nullable. I feel that that by definition is a type mismatch.

As for "backgroundImage", I'm fine with interpreting that as nullable. That makes sense. The user is explicitly stating that they do not want a background image.

@zadjii-msft
Copy link
Member

I would not treat the schema as the source of truth. We've pretty consistently forgotten to update that with PRs, and we'll often do it half-assedly.

This deserves a longer reply but that's the thoughts off the top of the dome.

The case that's the most curious to me is the snapOnInput one - that's not really an optional. We might be treating null as false in that case (which is why it seems like it reverts to the profiles.defaults value (which is false in the above example))

@zadjii-msft
Copy link
Member

optional<GUID> _guid{ nullopt };
optional<wstring> _source{ nullopt };
optional<GUID> _connectionType;

optional<wstring> _schemeName;

optional<color> _defaultForeground;

optional<color> _defaultBackground;

optional<color> _selectionBackground;

optional<color> _cursorColor;

optional<wstring> _tabTitle;

optional<color> _tabColor;

optional<wstring> _startingDirectory;

optional<wstring> _backgroundImage;
optional<double> _backgroundImageOpacity;
optional<WUX::Media::Stretch> _backgroundImageStretchMode;
optional<tuple<WUX::HorizontalAlignment, WUX::VerticalAlignment>> _backgroundImageAlignment;

optional<TerminalControl::ScrollbarState> _scrollbarState;

optional<wstring> _icon;

optional<bool> _retroTerminalEffect;
Property Hardcoded default What does null mean?
_schemeName "Campbell" I want no scheme??? this doesn't make sense
_defaultForeground nullopt Use the foreground from the scheme
_tabTitle nullopt Use whatever the title from the application is
_tabColor nullopt Use whatever the color from the theme/application is
_startingDirectory nullopt Use the CWD of the terminal itself
_backgroundImage nullopt I don't what an image
_scrollbarState nullopt ?????????? probably "visible"
_icon nullopt I don't want to set an image as the icon
_retroTerminalEffect nullopt Don't enable retro effects

From those, _scrollbarState, _icon, _retroTerminalEffect all don't really make sense as optionals. I suppose we're currently just treating null as "use the hardcoded default value". I suppose _backgroundImage falls into this category as well. When you set that setting to null, you're saying "I want to clear out whatever the current value is".

The ones that do make sense are the ones where there's some other value that the Termianl might use in the absence of a value in the Profile. _tabTitle, _tabColor - For both of them, the absence of a value has meaning. Same with _startingDirectory.


I might be losing the track a bit.

Profile "test" runs wsl.exe and does not snap on input.

That might be a bug in parsing strings with JsonUtils. I'd think that parsing null would set the commandline to null or "", but that seems like we see null and decide "Well that's not a string" and skip processing it, leaving the value from the defaults.

@zadjii-msft
Copy link
Member

Dustin and I discussed that we might be able to fix this with converting almost all optional<string>'s into just strings where "" is "no value", and having null explicitly map to the empty string.

(in addition to getting rid of the aforementioned optionals that aren't really optionals)

@ghost ghost added the In-PR This issue has a related PR label Aug 27, 2020
@ghost ghost closed this as completed in #7283 Aug 28, 2020
ghost pushed a commit that referenced this issue Aug 28, 2020
Profile is now a WinRT object in the TerminalApp project.

As with ColorScheme, all of the serialization logic is not exposed via
the idl. TerminalSetingsModel will handle it when it's all moved over.

I removed the "Get" and "Set" prefixes from all of the Profile
functions. It just makes more sense to use the `GETSET_PROPERTY` macro
to do most of the work for us.

`CloseOnExitMode` is now an enum off of the Profile.idl.

`std::optional<wstring>` got converted to `hstring` (as opposed to
`IReference<hstring>`). `IReference<hstring>` is not valid to MIDL.

## References
#7141 - Profile is a settings object
#885 - this new settings object will be moved to a new TerminalSettingsModel project

## Validation Steps Performed
- [x] Tests passed
- [x] Deployment succeeded

Closes #7435
@ghost ghost added Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release. and removed In-PR This issue has a related PR labels Aug 28, 2020
@ghost
Copy link

ghost commented Sep 22, 2020

🎉This issue was addressed in #7283, which has now been successfully released as Windows Terminal Preview v1.4.2652.0.:tada:

Handy links:

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Settings Issues related to settings and customizability, for console or terminal Issue-Task It's a feature request, but it doesn't really need a major design. Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting Product-Terminal The new Windows Terminal. Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants