From 112b42d375cafbcfafed89a0afe073e37182ad1c Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Wed, 3 Jun 2020 00:43:42 -0700 Subject: [PATCH 01/25] [BRIDGE] JsonUtils->JsonUtilsNew --- src/cascadia/TerminalApp/JsonUtils.cpp | 125 ----------------- src/cascadia/TerminalApp/JsonUtils.h | 130 +----------------- .../TerminalApp/lib/TerminalAppLib.vcxproj | 1 - .../lib/TerminalAppLib.vcxproj.filters | 5 +- 4 files changed, 2 insertions(+), 259 deletions(-) delete mode 100644 src/cascadia/TerminalApp/JsonUtils.cpp diff --git a/src/cascadia/TerminalApp/JsonUtils.cpp b/src/cascadia/TerminalApp/JsonUtils.cpp deleted file mode 100644 index f4282097b83..00000000000 --- a/src/cascadia/TerminalApp/JsonUtils.cpp +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -#include "pch.h" -#include "Utils.h" -#include "JsonUtils.h" -#include "../../types/inc/Utils.hpp" - -void TerminalApp::JsonUtils::GetOptionalColor(const Json::Value& json, - std::string_view key, - std::optional& target) -{ - const auto conversionFn = [](const Json::Value& value) -> til::color { - return ::Microsoft::Console::Utils::ColorFromHexString(value.asString()); - }; - GetOptionalValue(json, - key, - target, - conversionFn); -} - -void TerminalApp::JsonUtils::GetOptionalString(const Json::Value& json, - std::string_view key, - std::optional& target) -{ - const auto conversionFn = [](const Json::Value& value) -> std::wstring { - return GetWstringFromJson(value); - }; - GetOptionalValue(json, - key, - target, - conversionFn); -} - -void TerminalApp::JsonUtils::GetOptionalGuid(const Json::Value& json, - std::string_view key, - std::optional& target) -{ - const auto conversionFn = [](const Json::Value& value) -> GUID { - return ::Microsoft::Console::Utils::GuidFromString(GetWstringFromJson(value)); - }; - GetOptionalValue(json, - key, - target, - conversionFn); -} - -void TerminalApp::JsonUtils::GetOptionalDouble(const Json::Value& json, - std::string_view key, - std::optional& target) -{ - const auto conversionFn = [](const Json::Value& value) -> double { - return value.asFloat(); - }; - const auto validationFn = [](const Json::Value& value) -> bool { - return value.isNumeric(); - }; - GetOptionalValue(json, - key, - target, - conversionFn, - validationFn); -} - -void TerminalApp::JsonUtils::GetInt(const Json::Value& json, - std::string_view key, - int& target) -{ - const auto conversionFn = [](const Json::Value& value) -> int { - return value.asInt(); - }; - const auto validationFn = [](const Json::Value& value) -> bool { - return value.isInt(); - }; - GetValue(json, key, target, conversionFn, validationFn); -} - -void TerminalApp::JsonUtils::GetUInt(const Json::Value& json, - std::string_view key, - uint32_t& target) -{ - const auto conversionFn = [](const Json::Value& value) -> uint32_t { - return value.asUInt(); - }; - const auto validationFn = [](const Json::Value& value) -> bool { - return value.isUInt(); - }; - GetValue(json, key, target, conversionFn, validationFn); -} - -void TerminalApp::JsonUtils::GetDouble(const Json::Value& json, - std::string_view key, - double& target) -{ - const auto conversionFn = [](const Json::Value& value) -> double { - return value.asFloat(); - }; - const auto validationFn = [](const Json::Value& value) -> bool { - return value.isNumeric(); - }; - GetValue(json, key, target, conversionFn, validationFn); -} - -void TerminalApp::JsonUtils::GetBool(const Json::Value& json, - std::string_view key, - bool& target) -{ - const auto conversionFn = [](const Json::Value& value) -> bool { - return value.asBool(); - }; - const auto validationFn = [](const Json::Value& value) -> bool { - return value.isBool(); - }; - GetValue(json, key, target, conversionFn, validationFn); -} - -void TerminalApp::JsonUtils::GetWstring(const Json::Value& json, - std::string_view key, - std::wstring& target) -{ - const auto conversionFn = [](const Json::Value& value) -> std::wstring { - return GetWstringFromJson(value); - }; - GetValue(json, key, target, conversionFn, nullptr); -} diff --git a/src/cascadia/TerminalApp/JsonUtils.h b/src/cascadia/TerminalApp/JsonUtils.h index 1845a9d6524..f6b92550463 100644 --- a/src/cascadia/TerminalApp/JsonUtils.h +++ b/src/cascadia/TerminalApp/JsonUtils.h @@ -13,132 +13,4 @@ Author(s): --*/ #pragma once -namespace TerminalApp::JsonUtils -{ - void GetOptionalColor(const Json::Value& json, - std::string_view key, - std::optional& target); - - void GetOptionalString(const Json::Value& json, - std::string_view key, - std::optional& target); - - void GetOptionalGuid(const Json::Value& json, - std::string_view key, - std::optional& target); - - void GetOptionalDouble(const Json::Value& json, - std::string_view key, - std::optional& target); - - // Method Description: - // - Helper that can be used for retrieving an optional value from a json - // object, and parsing it's value to layer on a given target object. - // - If the key we're looking for _doesn't_ exist in the json object, - // we'll leave the target object unmodified. - // - If the key exists in the json object, but is set to `null`, then - // we'll instead set the target back to nullopt. - // - Each caller should provide a conversion function that takes a - // Json::Value and returns an object of the same type as target. - // Arguments: - // - json: The json object to search for the given key - // - key: The key to look for in the json object - // - target: the optional object to receive the value from json - // - conversion: a std::function which can be used to - // convert the Json::Value to the appropriate type. - // - validation: optional, if provided, will be called first to ensure that - // the json::value is of the correct type before attempting to call - // `conversion`. - // Return Value: - // - - template - void GetOptionalValue(const Json::Value& json, - std::string_view key, - std::optional& target, - F&& conversion, - const std::function& validation = nullptr) - { - if (json.isMember(JsonKey(key))) - { - if (auto jsonVal{ json[JsonKey(key)] }) - { - if (validation == nullptr || validation(jsonVal)) - { - target = conversion(jsonVal); - } - } - else - { - // This branch is hit when the json object contained the key, - // but the key was set to `null`. In this case, explicitly clear - // the target. - target = std::nullopt; - } - } - } - - // Method Description: - // - Helper that can be used for retrieving a value from a json - // object, and parsing it's value to set on a given target object. - // - If the key we're looking for _doesn't_ exist in the json object, - // we'll leave the target object unmodified. - // - If the key exists in the json object, we'll use the provided - // `validation` function to ensure that the json value is of the - // correct type. - // - If we successfully validate the json value type (or no validation - // function was provided), then we'll use `conversion` to parse the - // value and place the result into `target` - // - Each caller should provide a conversion function that takes a - // Json::Value and returns an object of the same type as target. - // - Unlike GetOptionalValue, if the key exists but is set to `null`, we'll - // just ignore it. - // Arguments: - // - json: The json object to search for the given key - // - key: The key to look for in the json object - // - target: the optional object to receive the value from json - // - conversion: a std::function which can be used to - // convert the Json::Value to the appropriate type. - // - validation: optional, if provided, will be called first to ensure that - // the json::value is of the correct type before attempting to call - // `conversion`. - // Return Value: - // - - template - void GetValue(const Json::Value& json, - std::string_view key, - T& target, - F&& conversion, - const std::function& validation = nullptr) - { - if (json.isMember(JsonKey(key))) - { - if (auto jsonVal{ json[JsonKey(key)] }) - { - if (validation == nullptr || validation(jsonVal)) - { - target = conversion(jsonVal); - } - } - } - } - - void GetInt(const Json::Value& json, - std::string_view key, - int& target); - - void GetUInt(const Json::Value& json, - std::string_view key, - uint32_t& target); - - void GetDouble(const Json::Value& json, - std::string_view key, - double& target); - - void GetBool(const Json::Value& json, - std::string_view key, - bool& target); - - void GetWstring(const Json::Value& json, - std::string_view key, - std::wstring& target); -}; +#include "JsonUtilsNew.h" diff --git a/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj b/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj index 6c9dc3323b7..8d2655f58a6 100644 --- a/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj +++ b/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj @@ -178,7 +178,6 @@ - diff --git a/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj.filters b/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj.filters index 5f856a6d4a8..8f8f6623bf0 100644 --- a/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj.filters +++ b/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj.filters @@ -50,9 +50,6 @@ json - - json - tab @@ -199,4 +196,4 @@ app - \ No newline at end of file + From 736debe5de6b93f9ea526b5a5d4f0e3940aa2da8 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Sat, 9 May 2020 23:33:51 -0700 Subject: [PATCH 02/25] ColorScheme: Convert to JsonUtilsNew --- src/cascadia/TerminalApp/ColorScheme.cpp | 47 +++++------------------- 1 file changed, 10 insertions(+), 37 deletions(-) diff --git a/src/cascadia/TerminalApp/ColorScheme.cpp b/src/cascadia/TerminalApp/ColorScheme.cpp index 45d4e7748e4..525d8ec95cd 100644 --- a/src/cascadia/TerminalApp/ColorScheme.cpp +++ b/src/cascadia/TerminalApp/ColorScheme.cpp @@ -105,9 +105,9 @@ ColorScheme ColorScheme::FromJson(const Json::Value& json) // - true iff the json object has the same `name` as we do. bool ColorScheme::ShouldBeLayered(const Json::Value& json) const { - if (const auto name{ json[JsonKey(NameKey)] }) + std::wstring nameFromJson{}; + if (JsonUtils::GetValueForKey(json, NameKey, nameFromJson)) { - const auto nameFromJson = GetWstringFromJson(name); return nameFromJson == _schemeName; } return false; @@ -125,39 +125,16 @@ bool ColorScheme::ShouldBeLayered(const Json::Value& json) const // void ColorScheme::LayerJson(const Json::Value& json) { - if (auto name{ json[JsonKey(NameKey)] }) - { - _schemeName = winrt::to_hstring(name.asString()); - } - if (auto fgString{ json[JsonKey(ForegroundKey)] }) - { - const auto color = Utils::ColorFromHexString(fgString.asString()); - _defaultForeground = color; - } - if (auto bgString{ json[JsonKey(BackgroundKey)] }) - { - const auto color = Utils::ColorFromHexString(bgString.asString()); - _defaultBackground = color; - } - if (auto sbString{ json[JsonKey(SelectionBackgroundKey)] }) - { - const auto color = Utils::ColorFromHexString(sbString.asString()); - _selectionBackground = color; - } - if (auto sbString{ json[JsonKey(CursorColorKey)] }) - { - const auto color = Utils::ColorFromHexString(sbString.asString()); - _cursorColor = color; - } + JsonUtils::GetValueForKey(json, NameKey, _schemeName); + JsonUtils::GetValueForKey(json, ForegroundKey, _defaultForeground); + JsonUtils::GetValueForKey(json, BackgroundKey, _defaultBackground); + JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _selectionBackground); + JsonUtils::GetValueForKey(json, CursorColorKey, _cursorColor); int i = 0; for (const auto& current : TableColors) { - if (auto str{ json[JsonKey(current)] }) - { - const auto color = Utils::ColorFromHexString(str.asString()); - _table.at(i) = color; - } + JsonUtils::GetValueForKey(json, current, _table.at(i)); i++; } } @@ -200,11 +177,7 @@ til::color ColorScheme::GetCursorColor() const noexcept // - the name of the color scheme represented by `json` as a std::wstring optional // i.e. the value of the `name` property. // - returns std::nullopt if `json` doesn't have the `name` property -std::optional TerminalApp::ColorScheme::GetNameFromJson(const Json::Value& json) +std::optional ColorScheme::GetNameFromJson(const Json::Value& json) { - if (const auto name{ json[JsonKey(NameKey)] }) - { - return GetWstringFromJson(name); - } - return std::nullopt; + return JsonUtils::GetValueForKey>(json, NameKey); } From f4cb75e093e72b5e00f25dbfb6a799271bc982b9 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Sat, 9 May 2020 23:34:01 -0700 Subject: [PATCH 03/25] Profile: Convert to JsonUtilsNew x include the profile traits? PRO: remove -DH, switch smth to value PRO: remove spaces PCT: non-static PCT --- src/cascadia/TerminalApp/Profile.cpp | 395 +++--------------- src/cascadia/TerminalApp/Profile.h | 16 +- .../TerminalApp/ProfileConversionTraits.cpp | 100 +++++ 3 files changed, 160 insertions(+), 351 deletions(-) create mode 100644 src/cascadia/TerminalApp/ProfileConversionTraits.cpp diff --git a/src/cascadia/TerminalApp/Profile.cpp b/src/cascadia/TerminalApp/Profile.cpp index 5ee40fd27a2..632640a1fa2 100644 --- a/src/cascadia/TerminalApp/Profile.cpp +++ b/src/cascadia/TerminalApp/Profile.cpp @@ -58,15 +58,15 @@ static constexpr std::string_view CloseOnExitGraceful{ "graceful" }; static constexpr std::string_view CloseOnExitNever{ "never" }; // Possible values for Scrollbar state -static constexpr std::wstring_view AlwaysVisible{ L"visible" }; -static constexpr std::wstring_view AlwaysHide{ L"hidden" }; +static constexpr std::string_view AlwaysVisible{ "visible" }; +static constexpr std::string_view AlwaysHide{ "hidden" }; // Possible values for Cursor Shape -static constexpr std::wstring_view CursorShapeVintage{ L"vintage" }; -static constexpr std::wstring_view CursorShapeBar{ L"bar" }; -static constexpr std::wstring_view CursorShapeUnderscore{ L"underscore" }; -static constexpr std::wstring_view CursorShapeFilledbox{ L"filledBox" }; -static constexpr std::wstring_view CursorShapeEmptybox{ L"emptyBox" }; +static constexpr std::string_view CursorShapeVintage{ "vintage" }; +static constexpr std::string_view CursorShapeBar{ "bar" }; +static constexpr std::string_view CursorShapeUnderscore{ "underscore" }; +static constexpr std::string_view CursorShapeFilledbox{ "filledBox" }; +static constexpr std::string_view CursorShapeEmptybox{ "emptyBox" }; // Possible values for Font Weight static constexpr std::string_view FontWeightThin{ "thin" }; @@ -85,7 +85,7 @@ static constexpr std::string_view FontWeightExtraBlack{ "extra-black" }; static constexpr std::string_view ImageStretchModeNone{ "none" }; static constexpr std::string_view ImageStretchModeFill{ "fill" }; static constexpr std::string_view ImageStretchModeUniform{ "uniform" }; -static constexpr std::string_view ImageStretchModeUniformTofill{ "uniformToFill" }; +static constexpr std::string_view ImageStretchModeUniformToFill{ "uniformToFill" }; // Possible values for Image Alignment static constexpr std::string_view ImageAlignmentCenter{ "center" }; @@ -99,9 +99,11 @@ static constexpr std::string_view ImageAlignmentBottomLeft{ "bottomLeft" }; static constexpr std::string_view ImageAlignmentBottomRight{ "bottomRight" }; // Possible values for TextAntialiasingMode -static constexpr std::wstring_view AntialiasingModeGrayscale{ L"grayscale" }; -static constexpr std::wstring_view AntialiasingModeCleartype{ L"cleartype" }; -static constexpr std::wstring_view AntialiasingModeAliased{ L"aliased" }; +static constexpr std::string_view AntialiasingModeGrayscale{ "grayscale" }; +static constexpr std::string_view AntialiasingModeCleartype{ "cleartype" }; +static constexpr std::string_view AntialiasingModeAliased{ "aliased" }; + +#include "ProfileConversionTraits.cpp" Profile::Profile() : Profile(std::nullopt) @@ -248,8 +250,7 @@ TerminalSettings Profile::CreateTerminalSettings(const std::unordered_map>(json, GuidKey) }) { - const auto guid{ json[JsonKey(GuidKey)] }; - const auto otherGuid = Utils::GuidFromString(GetWstringFromJson(guid)); - if (_guid.value() != otherGuid) + if (otherGuid != _guid) // optional compare takes care of this { return false; } @@ -368,16 +367,17 @@ bool Profile::ShouldBeLayered(const Json::Value& json) const return false; } - const auto& otherSource = json.isMember(JsonKey(SourceKey)) ? json[JsonKey(SourceKey)] : Json::Value::null; + std::optional otherSource; + bool otherHadSource = JsonUtils::GetValueForKey(json, SourceKey, otherSource); // For profiles with a `source`, also check the `source` property. bool sourceMatches = false; if (_source.has_value()) { - if (json.isMember(JsonKey(SourceKey))) + if (otherHadSource) { - const auto otherSourceString = GetWstringFromJson(otherSource); - sourceMatches = otherSourceString == _source.value(); + // If we have a source and the other has a source, compare them! + sourceMatches = otherSource == _source; } else { @@ -395,52 +395,13 @@ bool Profile::ShouldBeLayered(const Json::Value& json) const } else { - // We do not have a source. The only way we match is if source is set to null or "". - if (otherSource.isNull() || (otherSource.isString() && otherSource == "")) - { - sourceMatches = true; - } + // We do not have a source. The only way we match is if source is unset or set to "". + sourceMatches = (!otherSource.has_value() || otherSource.value() == L""); } return sourceMatches; } -// Method Description: -// - Helper function to convert a json value into a value of the Stretch enum. -// Calls into ParseImageStretchMode. Used with JsonUtils::GetOptionalValue. -// Arguments: -// - json: the Json::Value object to parse. -// Return Value: -// - An appropriate value from Windows.UI.Xaml.Media.Stretch -Media::Stretch Profile::_ConvertJsonToStretchMode(const Json::Value& json) -{ - return Profile::ParseImageStretchMode(json.asString()); -} - -// Method Description: -// - Helper function to convert a json value into a value of the Stretch enum. -// Calls into ParseImageAlignment. Used with JsonUtils::GetOptionalValue. -// Arguments: -// - json: the Json::Value object to parse. -// Return Value: -// - A pair of HorizontalAlignment and VerticalAlignment -std::tuple Profile::_ConvertJsonToAlignment(const Json::Value& json) -{ - return Profile::ParseImageAlignment(json.asString()); -} - -// Method Description: -// - Helper function to convert a json value into a bool. -// Used with JsonUtils::GetOptionalValue. -// Arguments: -// - json: the Json::Value object to parse. -// Return Value: -// - A bool -bool Profile::_ConvertJsonToBool(const Json::Value& json) -{ - return json.asBool(); -} - // Method Description: // - Layer values from the given json object on top of the existing properties // of this object. For any keys we're expecting to be able to parse in the @@ -456,89 +417,51 @@ bool Profile::_ConvertJsonToBool(const Json::Value& json) void Profile::LayerJson(const Json::Value& json) { // Profile-specific Settings - JsonUtils::GetWstring(json, NameKey, _name); - - JsonUtils::GetOptionalGuid(json, GuidKey, _guid); - - JsonUtils::GetBool(json, HiddenKey, _hidden); + JsonUtils::GetValueForKey(json, NameKey, _name); + JsonUtils::GetValueForKey(json, GuidKey, _guid); + JsonUtils::GetValueForKey(json, HiddenKey, _hidden); // Core Settings - JsonUtils::GetOptionalColor(json, ForegroundKey, _defaultForeground); - - JsonUtils::GetOptionalColor(json, BackgroundKey, _defaultBackground); - - JsonUtils::GetOptionalColor(json, SelectionBackgroundKey, _selectionBackground); - - JsonUtils::GetOptionalColor(json, CursorColorKey, _cursorColor); - - JsonUtils::GetOptionalString(json, ColorSchemeKey, _schemeName); + JsonUtils::GetValueForKey(json, ForegroundKey, _defaultForeground); + JsonUtils::GetValueForKey(json, BackgroundKey, _defaultBackground); + JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _selectionBackground); + JsonUtils::GetValueForKey(json, CursorColorKey, _cursorColor); + JsonUtils::GetValueForKey(json, ColorSchemeKey, _schemeName); // TODO:MSFT:20642297 - Use a sentinel value (-1) for "Infinite scrollback" - JsonUtils::GetInt(json, HistorySizeKey, _historySize); - - JsonUtils::GetBool(json, SnapOnInputKey, _snapOnInput); - - JsonUtils::GetBool(json, AltGrAliasingKey, _altGrAliasing); - - JsonUtils::GetUInt(json, CursorHeightKey, _cursorHeight); - - if (json.isMember(JsonKey(CursorShapeKey))) - { - auto cursorShape{ json[JsonKey(CursorShapeKey)] }; - _cursorShape = _ParseCursorShape(GetWstringFromJson(cursorShape)); - } - JsonUtils::GetOptionalString(json, TabTitleKey, _tabTitle); + JsonUtils::GetValueForKey(json, HistorySizeKey, _historySize); + JsonUtils::GetValueForKey(json, SnapOnInputKey, _snapOnInput); + JsonUtils::GetValueForKey(json, AltGrAliasingKey, _altGrAliasing); + JsonUtils::GetValueForKey(json, CursorHeightKey, _cursorHeight); + JsonUtils::GetValueForKey(json, CursorShapeKey, _cursorShape); + JsonUtils::GetValueForKey(json, TabTitleKey, _tabTitle); // Control Settings - JsonUtils::GetOptionalGuid(json, ConnectionTypeKey, _connectionType); - - JsonUtils::GetWstring(json, CommandlineKey, _commandline); - - JsonUtils::GetWstring(json, FontFaceKey, _fontFace); - - JsonUtils::GetInt(json, FontSizeKey, _fontSize); - + // TODO DH [JU-DH] if (json.isMember(JsonKey(FontWeightKey))) { auto fontWeight{ json[JsonKey(FontWeightKey)] }; _fontWeight = _ParseFontWeight(fontWeight); } - JsonUtils::GetDouble(json, AcrylicTransparencyKey, _acrylicTransparency); - - JsonUtils::GetBool(json, UseAcrylicKey, _useAcrylic); - - JsonUtils::GetBool(json, SuppressApplicationTitleKey, _suppressApplicationTitle); - - if (json.isMember(JsonKey(CloseOnExitKey))) - { - auto closeOnExit{ json[JsonKey(CloseOnExitKey)] }; - _closeOnExitMode = ParseCloseOnExitMode(closeOnExit); - } - - JsonUtils::GetWstring(json, PaddingKey, _padding); - - JsonUtils::GetOptionalString(json, ScrollbarStateKey, _scrollbarState); - - JsonUtils::GetOptionalString(json, StartingDirectoryKey, _startingDirectory); - - JsonUtils::GetOptionalString(json, IconKey, _icon); - - JsonUtils::GetOptionalString(json, BackgroundImageKey, _backgroundImage); - - JsonUtils::GetOptionalDouble(json, BackgroundImageOpacityKey, _backgroundImageOpacity); - - JsonUtils::GetOptionalValue(json, BackgroundImageStretchModeKey, _backgroundImageStretchMode, &Profile::_ConvertJsonToStretchMode); - - JsonUtils::GetOptionalValue(json, BackgroundImageAlignmentKey, _backgroundImageAlignment, &Profile::_ConvertJsonToAlignment); - - JsonUtils::GetOptionalValue(json, RetroTerminalEffectKey, _retroTerminalEffect, Profile::_ConvertJsonToBool); - - if (json.isMember(JsonKey(AntialiasingModeKey))) - { - auto antialiasingMode{ json[JsonKey(AntialiasingModeKey)] }; - _antialiasingMode = ParseTextAntialiasingMode(GetWstringFromJson(antialiasingMode)); - } + JsonUtils::GetValueForKey(json, ConnectionTypeKey, _connectionType); + JsonUtils::GetValueForKey(json, CommandlineKey, _commandline); + JsonUtils::GetValueForKey(json, FontFaceKey, _fontFace); + JsonUtils::GetValueForKey(json, FontSizeKey, _fontSize); + JsonUtils::GetValueForKey(json, AcrylicTransparencyKey, _acrylicTransparency); + JsonUtils::GetValueForKey(json, UseAcrylicKey, _useAcrylic); + JsonUtils::GetValueForKey(json, SuppressApplicationTitleKey, _suppressApplicationTitle); + JsonUtils::GetValueForKey(json, CloseOnExitKey, _closeOnExitMode); + JsonUtils::GetValueForKey(json, PaddingKey, _padding); + JsonUtils::GetValueForKey(json, ScrollbarStateKey, _scrollbarState); + JsonUtils::GetValueForKey(json, StartingDirectoryKey, _startingDirectory); + JsonUtils::GetValueForKey(json, IconKey, _icon); + JsonUtils::GetValueForKey(json, BackgroundImageKey, _backgroundImage); + JsonUtils::GetValueForKey(json, BackgroundImageOpacityKey, _backgroundImageOpacity); + JsonUtils::GetValueForKey(json, BackgroundImageStretchModeKey, _backgroundImageStretchMode); + JsonUtils::GetValueForKey(json, BackgroundImageAlignmentKey, _backgroundImageAlignment); + JsonUtils::GetValueForKey(json, RetroTerminalEffectKey, _retroTerminalEffect); + JsonUtils::GetValueForKey(json, AntialiasingModeKey, _antialiasingMode); } void Profile::SetFontFace(std::wstring fontFace) noexcept @@ -842,177 +765,6 @@ winrt::Windows::UI::Text::FontWeight Profile::_ParseFontWeight(const Json::Value return winrt::Windows::UI::Text::FontWeights::Normal(); } -// Method Description: -// - Helper function for converting a user-specified closeOnExit value to its corresponding enum -// Arguments: -// - The value from the settings.json file -// Return Value: -// - The corresponding enum value which maps to the string provided by the user -CloseOnExitMode Profile::ParseCloseOnExitMode(const Json::Value& json) -{ - if (json.isBool()) - { - return json.asBool() ? CloseOnExitMode::Graceful : CloseOnExitMode::Never; - } - - if (json.isString()) - { - auto closeOnExit = json.asString(); - if (closeOnExit == CloseOnExitAlways) - { - return CloseOnExitMode::Always; - } - else if (closeOnExit == CloseOnExitGraceful) - { - return CloseOnExitMode::Graceful; - } - else if (closeOnExit == CloseOnExitNever) - { - return CloseOnExitMode::Never; - } - } - - return CloseOnExitMode::Graceful; -} - -// Method Description: -// - Helper function for converting a user-specified scrollbar state to its corresponding enum -// Arguments: -// - The value from the settings.json file -// Return Value: -// - The corresponding enum value which maps to the string provided by the user -ScrollbarState Profile::ParseScrollbarState(const std::wstring& scrollbarState) -{ - if (scrollbarState == AlwaysVisible) - { - return ScrollbarState::Visible; - } - else if (scrollbarState == AlwaysHide) - { - return ScrollbarState::Hidden; - } - else - { - return ScrollbarState::Visible; - } -} - -// Method Description: -// - Helper function for converting a user-specified image stretch mode -// to the appropriate enum value -// Arguments: -// - The value from the settings.json file -// Return Value: -// - The corresponding enum value which maps to the string provided by the user -Media::Stretch Profile::ParseImageStretchMode(const std::string_view imageStretchMode) -{ - if (imageStretchMode == ImageStretchModeNone) - { - return Media::Stretch::None; - } - else if (imageStretchMode == ImageStretchModeFill) - { - return Media::Stretch::Fill; - } - else if (imageStretchMode == ImageStretchModeUniform) - { - return Media::Stretch::Uniform; - } - else // Fall through to default behavior - { - return Media::Stretch::UniformToFill; - } -} - -// Method Description: -// - Helper function for converting a user-specified image horizontal and vertical -// alignment to the appropriate enum values tuple -// Arguments: -// - The value from the settings.json file -// Return Value: -// - The corresponding enum values tuple which maps to the string provided by the user -std::tuple Profile::ParseImageAlignment(const std::string_view imageAlignment) -{ - if (imageAlignment == ImageAlignmentTopLeft) - { - return std::make_tuple(HorizontalAlignment::Left, - VerticalAlignment::Top); - } - else if (imageAlignment == ImageAlignmentBottomLeft) - { - return std::make_tuple(HorizontalAlignment::Left, - VerticalAlignment::Bottom); - } - else if (imageAlignment == ImageAlignmentLeft) - { - return std::make_tuple(HorizontalAlignment::Left, - VerticalAlignment::Center); - } - else if (imageAlignment == ImageAlignmentTopRight) - { - return std::make_tuple(HorizontalAlignment::Right, - VerticalAlignment::Top); - } - else if (imageAlignment == ImageAlignmentBottomRight) - { - return std::make_tuple(HorizontalAlignment::Right, - VerticalAlignment::Bottom); - } - else if (imageAlignment == ImageAlignmentRight) - { - return std::make_tuple(HorizontalAlignment::Right, - VerticalAlignment::Center); - } - else if (imageAlignment == ImageAlignmentTop) - { - return std::make_tuple(HorizontalAlignment::Center, - VerticalAlignment::Top); - } - else if (imageAlignment == ImageAlignmentBottom) - { - return std::make_tuple(HorizontalAlignment::Center, - VerticalAlignment::Bottom); - } - else // Fall through to default alignment - { - return std::make_tuple(HorizontalAlignment::Center, - VerticalAlignment::Center); - } -} - -// Method Description: -// - Helper function for converting a user-specified cursor style corresponding -// CursorStyle enum value -// Arguments: -// - cursorShapeString: The string value from the settings file to parse -// Return Value: -// - The corresponding enum value which maps to the string provided by the user -CursorStyle Profile::_ParseCursorShape(const std::wstring& cursorShapeString) -{ - if (cursorShapeString == CursorShapeVintage) - { - return CursorStyle::Vintage; - } - else if (cursorShapeString == CursorShapeBar) - { - return CursorStyle::Bar; - } - else if (cursorShapeString == CursorShapeUnderscore) - { - return CursorStyle::Underscore; - } - else if (cursorShapeString == CursorShapeFilledbox) - { - return CursorStyle::FilledBox; - } - else if (cursorShapeString == CursorShapeEmptybox) - { - return CursorStyle::EmptyBox; - } - // default behavior for invalid data - return CursorStyle::Bar; -} - // Method Description: // - If this profile never had a GUID set for it, generate a runtime GUID for // the profile. If a profile had their guid manually set to {0}, this method @@ -1078,17 +830,13 @@ GUID Profile::_GenerateGuidForProfile(const std::wstring& name, const std::optio // - The json's `guid`, or a guid synthesized for it. GUID Profile::GetGuidOrGenerateForJson(const Json::Value& json) noexcept { - std::optional guid{ std::nullopt }; - - JsonUtils::GetOptionalGuid(json, GuidKey, guid); - if (guid) + if (const auto guid{ JsonUtils::GetValueForKey>(json, GuidKey) }) { return guid.value(); } - const auto name = GetWstringFromJson(json[JsonKey(NameKey)]); - std::optional source{ std::nullopt }; - JsonUtils::GetOptionalString(json, SourceKey, source); + const auto name{ JsonUtils::GetValueForKey(json, NameKey) }; + const auto source{ JsonUtils::GetValueForKey>(json, SourceKey) }; return Profile::_GenerateGuidForProfile(name, source); } @@ -1097,28 +845,3 @@ void Profile::SetRetroTerminalEffect(bool value) noexcept { _retroTerminalEffect = value; } - -// Method Description: -// - Helper function for converting a user-specified antialiasing mode -// corresponding TextAntialiasingMode enum value -// Arguments: -// - antialiasingMode: The string value from the settings file to parse -// Return Value: -// - The corresponding enum value which maps to the string provided by the user -TextAntialiasingMode Profile::ParseTextAntialiasingMode(const std::wstring& antialiasingMode) -{ - if (antialiasingMode == AntialiasingModeCleartype) - { - return TextAntialiasingMode::Cleartype; - } - else if (antialiasingMode == AntialiasingModeAliased) - { - return TextAntialiasingMode::Aliased; - } - else if (antialiasingMode == AntialiasingModeGrayscale) - { - return TextAntialiasingMode::Grayscale; - } - // default behavior for invalid data - return TextAntialiasingMode::Grayscale; -} diff --git a/src/cascadia/TerminalApp/Profile.h b/src/cascadia/TerminalApp/Profile.h index bd48592157c..dc65f9df3e8 100644 --- a/src/cascadia/TerminalApp/Profile.h +++ b/src/cascadia/TerminalApp/Profile.h @@ -107,24 +107,10 @@ class TerminalApp::Profile final private: static std::wstring EvaluateStartingDirectory(const std::wstring& directory); - static winrt::Microsoft::Terminal::Settings::ScrollbarState ParseScrollbarState(const std::wstring& scrollbarState); - static winrt::Windows::UI::Xaml::Media::Stretch ParseImageStretchMode(const std::string_view imageStretchMode); - static winrt::Windows::UI::Xaml::Media::Stretch _ConvertJsonToStretchMode(const Json::Value& json); - static std::tuple ParseImageAlignment(const std::string_view imageAlignment); - static std::tuple _ConvertJsonToAlignment(const Json::Value& json); - static winrt::Windows::UI::Text::FontWeight _ParseFontWeight(const Json::Value& json); - static CloseOnExitMode ParseCloseOnExitMode(const Json::Value& json); - - static winrt::Microsoft::Terminal::Settings::CursorStyle _ParseCursorShape(const std::wstring& cursorShapeString); - - static winrt::Microsoft::Terminal::Settings::TextAntialiasingMode ParseTextAntialiasingMode(const std::wstring& antialiasingMode); - static GUID _GenerateGuidForProfile(const std::wstring& name, const std::optional& source) noexcept; - static bool _ConvertJsonToBool(const Json::Value& json); - std::optional _guid{ std::nullopt }; std::optional _source{ std::nullopt }; std::wstring _name; @@ -159,7 +145,7 @@ class TerminalApp::Profile final std::optional _backgroundImageStretchMode; std::optional> _backgroundImageAlignment; - std::optional _scrollbarState; + std::optional<::winrt::Microsoft::Terminal::Settings::ScrollbarState> _scrollbarState; CloseOnExitMode _closeOnExitMode; std::wstring _padding; diff --git a/src/cascadia/TerminalApp/ProfileConversionTraits.cpp b/src/cascadia/TerminalApp/ProfileConversionTraits.cpp new file mode 100644 index 00000000000..c60dca63489 --- /dev/null +++ b/src/cascadia/TerminalApp/ProfileConversionTraits.cpp @@ -0,0 +1,100 @@ +// Explicit specializations for JSON conversion +template<> +struct JsonUtils::ConversionTrait : public JsonUtils::KeyValueMapper> +{ + static constexpr std::array mappings = { + pair_type{ CursorShapeBar, CursorStyle::Bar }, // DEFAULT + pair_type{ CursorShapeVintage, CursorStyle::Vintage }, + pair_type{ CursorShapeUnderscore, CursorStyle::Underscore }, + pair_type{ CursorShapeFilledbox, CursorStyle::FilledBox }, + pair_type{ CursorShapeEmptybox, CursorStyle::EmptyBox } + }; +}; + +template<> +struct JsonUtils::ConversionTrait : public JsonUtils::KeyValueMapper> +{ + static constexpr std::array mappings = { + pair_type{ ImageStretchModeUniformToFill, Media::Stretch::UniformToFill }, // DEFAULT + pair_type{ ImageStretchModeNone, Media::Stretch::None }, + pair_type{ ImageStretchModeFill, Media::Stretch::Fill }, + pair_type{ ImageStretchModeUniform, Media::Stretch::Uniform } + }; +}; + +template<> +struct JsonUtils::ConversionTrait : public JsonUtils::KeyValueMapper> +{ + static constexpr std::array mappings = { + pair_type{ AlwaysVisible, ScrollbarState::Visible }, // DEFAULT + pair_type{ AlwaysHide, ScrollbarState::Hidden } + }; +}; + +template<> +struct JsonUtils::ConversionTrait> : public JsonUtils::KeyValueMapper, JsonUtils::ConversionTrait>> +{ + static constexpr std::array mappings = { + pair_type{ ImageAlignmentCenter, std::make_tuple(HorizontalAlignment::Center, VerticalAlignment::Center) }, // DEFAULT + pair_type{ ImageAlignmentTopLeft, std::make_tuple(HorizontalAlignment::Left, VerticalAlignment::Top) }, + pair_type{ ImageAlignmentBottomLeft, std::make_tuple(HorizontalAlignment::Left, VerticalAlignment::Bottom) }, + pair_type{ ImageAlignmentLeft, std::make_tuple(HorizontalAlignment::Left, VerticalAlignment::Center) }, + pair_type{ ImageAlignmentTopRight, std::make_tuple(HorizontalAlignment::Right, VerticalAlignment::Top) }, + pair_type{ ImageAlignmentBottomRight, std::make_tuple(HorizontalAlignment::Right, VerticalAlignment::Bottom) }, + pair_type{ ImageAlignmentRight, std::make_tuple(HorizontalAlignment::Right, VerticalAlignment::Center) }, + pair_type{ ImageAlignmentTop, std::make_tuple(HorizontalAlignment::Center, VerticalAlignment::Top) }, + pair_type{ ImageAlignmentBottom, std::make_tuple(HorizontalAlignment::Center, VerticalAlignment::Bottom) } + }; +}; + +template<> +struct JsonUtils::ConversionTrait : public JsonUtils::KeyValueMapper> +{ + static constexpr std::array mappings = { + pair_type{ AntialiasingModeGrayscale, TextAntialiasingMode::Grayscale }, // DEFAULT + pair_type{ AntialiasingModeCleartype, TextAntialiasingMode::Cleartype }, + pair_type{ AntialiasingModeAliased, TextAntialiasingMode::Aliased } + }; +}; + +// Method Description: +// - Helper function for converting a user-specified closeOnExit value to its corresponding enum +// Arguments: +// - The value from the profiles.json file +// Return Value: +// - The corresponding enum value which maps to the string provided by the user +template<> +struct JsonUtils::ConversionTrait +{ + CloseOnExitMode FromJson(const Json::Value& json) + { + if (json.isBool()) + { + return json.asBool() ? CloseOnExitMode::Graceful : CloseOnExitMode::Never; + } + + if (json.isString()) + { + auto closeOnExit = json.asString(); + if (closeOnExit == CloseOnExitAlways) + { + return CloseOnExitMode::Always; + } + else if (closeOnExit == CloseOnExitGraceful) + { + return CloseOnExitMode::Graceful; + } + else if (closeOnExit == CloseOnExitNever) + { + return CloseOnExitMode::Never; + } + } + + return CloseOnExitMode::Graceful; + } + + bool CanConvert(const Json::Value& json) + { + return json.isString() || json.isBool(); + } +}; From 7aeed1c000313fcf527117e55ca12badc565f14c Mon Sep 17 00:00:00 2001 From: Dustin Howett Date: Mon, 11 May 2020 10:36:29 -0700 Subject: [PATCH 04/25] GlobalAppSettings: Convert to JsonUtilsNew GAS: remove -DH GAS: nonstatic GAS --- .../CascadiaSettingsSerialization.cpp | 8 +- .../TerminalApp/GlobalAppSettings.cpp | 226 ++++++++---------- src/cascadia/TerminalApp/GlobalAppSettings.h | 9 - 3 files changed, 100 insertions(+), 143 deletions(-) diff --git a/src/cascadia/TerminalApp/CascadiaSettingsSerialization.cpp b/src/cascadia/TerminalApp/CascadiaSettingsSerialization.cpp index 2ed23f8c770..46bb4df0b10 100644 --- a/src/cascadia/TerminalApp/CascadiaSettingsSerialization.cpp +++ b/src/cascadia/TerminalApp/CascadiaSettingsSerialization.cpp @@ -6,7 +6,7 @@ #include "CascadiaSettings.h" #include "../../types/inc/utils.hpp" #include "utils.h" -#include "JsonUtils.h" +#include "JsonUtils-DH.h" #include #include @@ -249,9 +249,11 @@ void CascadiaSettings::_LoadDynamicProfiles() const auto disabledProfileSources = CascadiaSettings::_GetDisabledProfileSourcesJsonObject(_userSettings); if (disabledProfileSources.isArray()) { - for (const auto& ns : disabledProfileSources) + for (const auto& json : disabledProfileSources) { - ignoredNamespaces.emplace(GetWstringFromJson(ns)); + std::wstring ns{}; + JsonUtils::GetValue(json, ns); + ignoredNamespaces.emplace(std::move(ns)); } } diff --git a/src/cascadia/TerminalApp/GlobalAppSettings.cpp b/src/cascadia/TerminalApp/GlobalAppSettings.cpp index e623634ae7f..c9a4eccb9b3 100644 --- a/src/cascadia/TerminalApp/GlobalAppSettings.cpp +++ b/src/cascadia/TerminalApp/GlobalAppSettings.cpp @@ -44,19 +44,19 @@ static constexpr std::string_view SoftwareRenderingKey{ "experimental.rendering. static constexpr std::string_view ForceVTInputKey{ "experimental.input.forceVT" }; // Launch mode values -static constexpr std::wstring_view DefaultLaunchModeValue{ L"default" }; -static constexpr std::wstring_view MaximizedLaunchModeValue{ L"maximized" }; -static constexpr std::wstring_view FullscreenLaunchModeValue{ L"fullscreen" }; +static constexpr std::string_view DefaultLaunchModeValue{ "default" }; +static constexpr std::string_view MaximizedLaunchModeValue{ "maximized" }; +static constexpr std::string_view FullscreenLaunchModeValue{ "fullscreen" }; // Tab Width Mode values -static constexpr std::wstring_view EqualTabWidthModeValue{ L"equal" }; -static constexpr std::wstring_view TitleLengthTabWidthModeValue{ L"titleLength" }; -static constexpr std::wstring_view TitleLengthCompactModeValue{ L"compact" }; +static constexpr std::string_view EqualTabWidthModeValue{ "equal" }; +static constexpr std::string_view TitleLengthTabWidthModeValue{ "titleLength" }; +static constexpr std::string_view TitleLengthCompactModeValue{ "compact" }; // Theme values -static constexpr std::wstring_view LightThemeValue{ L"light" }; -static constexpr std::wstring_view DarkThemeValue{ L"dark" }; -static constexpr std::wstring_view SystemThemeValue{ L"system" }; +static constexpr std::string_view LightThemeValue{ "light" }; +static constexpr std::string_view DarkThemeValue{ "dark" }; +static constexpr std::string_view SystemThemeValue{ "system" }; #ifdef _DEBUG static constexpr bool debugFeaturesDefault{ true }; @@ -64,6 +64,36 @@ static constexpr bool debugFeaturesDefault{ true }; static constexpr bool debugFeaturesDefault{ false }; #endif +template<> +struct JsonUtils::ConversionTrait : public JsonUtils::KeyValueMapper> +{ + static constexpr std::array mappings = { + pair_type{ SystemThemeValue, ElementTheme::Default }, + pair_type{ LightThemeValue, ElementTheme::Light }, + pair_type{ DarkThemeValue, ElementTheme::Dark }, + }; +}; + +template<> +struct JsonUtils::ConversionTrait : public JsonUtils::KeyValueMapper> +{ + static constexpr std::array mappings = { + pair_type{ DefaultLaunchModeValue, LaunchMode::DefaultMode }, + pair_type{ MaximizedLaunchModeValue, LaunchMode::MaximizedMode }, + pair_type{ FullscreenLaunchModeValue, LaunchMode::FullscreenMode }, + }; +}; + +template<> +struct JsonUtils::ConversionTrait : public JsonUtils::KeyValueMapper> +{ + static constexpr std::array mappings = { + pair_type{ EqualTabWidthModeValue, TabViewWidthMode::Equal }, + pair_type{ TitleLengthTabWidthModeValue, TabViewWidthMode::SizeToContent }, + pair_type{ TitleLengthCompactModeValue, TabViewWidthMode::Compact }, + }; +}; + GlobalAppSettings::GlobalAppSettings() : _keybindings{ winrt::make_self() }, _keybindingsWarnings{}, @@ -148,64 +178,49 @@ GlobalAppSettings GlobalAppSettings::FromJson(const Json::Value& json) void GlobalAppSettings::LayerJson(const Json::Value& json) { - if (auto defaultProfile{ json[JsonKey(DefaultProfileKey)] }) - { - _unparsedDefaultProfile.emplace(GetWstringFromJson(defaultProfile)); - } + JsonUtils::GetValueForKey(json, DefaultProfileKey, _unparsedDefaultProfile); - JsonUtils::GetBool(json, AlwaysShowTabsKey, _AlwaysShowTabs); + JsonUtils::GetValueForKey(json, AlwaysShowTabsKey, _AlwaysShowTabs); - JsonUtils::GetBool(json, ConfirmCloseAllKey, _ConfirmCloseAllTabs); + JsonUtils::GetValueForKey(json, ConfirmCloseAllKey, _ConfirmCloseAllTabs); - JsonUtils::GetInt(json, InitialRowsKey, _InitialRows); + JsonUtils::GetValueForKey(json, InitialRowsKey, _InitialRows); - JsonUtils::GetInt(json, InitialColsKey, _InitialCols); + JsonUtils::GetValueForKey(json, InitialColsKey, _InitialCols); - if (auto initialPosition{ json[JsonKey(InitialPositionKey)] }) - { - _ParseInitialPosition(initialPosition.asString(), _InitialPosition); - } + JsonUtils::GetValueForKey(json, InitialPositionKey, _InitialPosition); - JsonUtils::GetBool(json, ShowTitleInTitlebarKey, _ShowTitleInTitlebar); + JsonUtils::GetValueForKey(json, ShowTitleInTitlebarKey, _ShowTitleInTitlebar); - JsonUtils::GetBool(json, ShowTabsInTitlebarKey, _ShowTabsInTitlebar); + JsonUtils::GetValueForKey(json, ShowTabsInTitlebarKey, _ShowTabsInTitlebar); - JsonUtils::GetWstring(json, WordDelimitersKey, _WordDelimiters); + JsonUtils::GetValueForKey(json, WordDelimitersKey, _WordDelimiters); - JsonUtils::GetBool(json, CopyOnSelectKey, _CopyOnSelect); + JsonUtils::GetValueForKey(json, CopyOnSelectKey, _CopyOnSelect); - JsonUtils::GetBool(json, CopyFormattingKey, _CopyFormatting); + JsonUtils::GetValueForKey(json, CopyFormattingKey, _CopyFormatting); - JsonUtils::GetBool(json, WarnAboutLargePasteKey, _WarnAboutLargePaste); + JsonUtils::GetValueForKey(json, WarnAboutLargePasteKey, _WarnAboutLargePaste); - JsonUtils::GetBool(json, WarnAboutMultiLinePasteKey, _WarnAboutMultiLinePaste); + JsonUtils::GetValueForKey(json, WarnAboutMultiLinePasteKey, _WarnAboutMultiLinePaste); - if (auto launchMode{ json[JsonKey(LaunchModeKey)] }) - { - _LaunchMode = _ParseLaunchMode(GetWstringFromJson(launchMode)); - } + JsonUtils::GetValueForKey(json, LaunchModeKey, _LaunchMode); - if (auto theme{ json[JsonKey(ThemeKey)] }) - { - _Theme = _ParseTheme(GetWstringFromJson(theme)); - } + JsonUtils::GetValueForKey(json, ThemeKey, _Theme); - if (auto tabWidthMode{ json[JsonKey(TabWidthModeKey)] }) - { - _TabWidthMode = _ParseTabWidthMode(GetWstringFromJson(tabWidthMode)); - } + JsonUtils::GetValueForKey(json, TabWidthModeKey, _TabWidthMode); - JsonUtils::GetBool(json, SnapToGridOnResizeKey, _SnapToGridOnResize); + JsonUtils::GetValueForKey(json, SnapToGridOnResizeKey, _SnapToGridOnResize); - JsonUtils::GetBool(json, ForceFullRepaintRenderingKey, _ForceFullRepaintRendering); + // GetValueForKey will only override the current value if the key exists + JsonUtils::GetValueForKey(json, DebugFeaturesKey, _DebugFeaturesEnabled); - JsonUtils::GetBool(json, SoftwareRenderingKey, _SoftwareRendering); - JsonUtils::GetBool(json, ForceVTInputKey, _ForceVTInput); + JsonUtils::GetValueForKey(json, ForceFullRepaintRenderingKey, _ForceFullRepaintRendering); - // GetBool will only override the current value if the key exists - JsonUtils::GetBool(json, DebugFeaturesKey, _DebugFeaturesEnabled); + JsonUtils::GetValueForKey(json, SoftwareRenderingKey, _SoftwareRendering); + JsonUtils::GetValueForKey(json, ForceVTInputKey, _ForceVTInput); - JsonUtils::GetBool(json, EnableStartupTaskKey, _StartOnUserLogin); + JsonUtils::GetValueForKey(json, EnableStartupTaskKey, _StartOnUserLogin); // This is a helper lambda to get the keybindings and commands out of both // and array of objects. We'll use this twice, once on the legacy @@ -233,27 +248,6 @@ void GlobalAppSettings::LayerJson(const Json::Value& json) parseBindings(BindingsKey); } -// Method Description: -// - Helper function for converting a user-specified cursor style corresponding -// CursorStyle enum value -// Arguments: -// - themeString: The string value from the settings file to parse -// Return Value: -// - The corresponding enum value which maps to the string provided by the user -ElementTheme GlobalAppSettings::_ParseTheme(const std::wstring& themeString) noexcept -{ - if (themeString == LightThemeValue) - { - return ElementTheme::Light; - } - else if (themeString == DarkThemeValue) - { - return ElementTheme::Dark; - } - // default behavior for invalid data or SystemThemeValue - return ElementTheme::Default; -} - // Method Description: // - Helper function for converting the initial position string into // 2 coordinate values. We allow users to only provide one coordinate, @@ -265,83 +259,53 @@ ElementTheme GlobalAppSettings::_ParseTheme(const std::wstring& themeString) noe // (100, 100, 100): we only read the first two values, this is equivalent to (100, 100) // Arguments: // - initialPosition: the initial position string from json -// ret: reference to a struct whose optionals will be populated +// initialX: reference to the _initialX member +// initialY: reference to the _initialY member // Return Value: // - None -void GlobalAppSettings::_ParseInitialPosition(const std::string& initialPosition, - LaunchPosition& ret) noexcept +template<> +struct JsonUtils::ConversionTrait { - static constexpr char singleCharDelim = ','; - std::stringstream tokenStream(initialPosition); - std::string token; - uint8_t initialPosIndex = 0; - - // Get initial position values till we run out of delimiter separated values in the stream - // or we hit max number of allowable values (= 2) - // Non-numeral values or empty string will be caught as exception and we do not assign them - for (; std::getline(tokenStream, token, singleCharDelim) && (initialPosIndex < 2); initialPosIndex++) + LaunchPosition FromJson(const Json::Value& json) { - try + LaunchPosition ret; + std::string initialPosition{ json.asString() }; + static constexpr char singleCharDelim = ','; + std::stringstream tokenStream(initialPosition); + std::string token; + uint8_t initialPosIndex = 0; + + // Get initial position values till we run out of delimiter separated values in the stream + // or we hit max number of allowable values (= 2) + // Non-numeral values or empty string will be caught as exception and we do not assign them + for (; std::getline(tokenStream, token, singleCharDelim) && (initialPosIndex < 2); initialPosIndex++) { - int32_t position = std::stoi(token); - if (initialPosIndex == 0) + try { - ret.x.emplace(position); + int32_t position = std::stoi(token); + if (initialPosIndex == 0) + { + ret.x.emplace(position); + } + + if (initialPosIndex == 1) + { + ret.y.emplace(position); + } } - - if (initialPosIndex == 1) + catch (...) { - ret.y.emplace(position); + // Do nothing } } - catch (...) - { - // Do nothing - } + return ret; } -} -// Method Description: -// - Helper function for converting the user-specified launch mode -// to a LaunchMode enum value -// Arguments: -// - launchModeString: The string value from the settings file to parse -// Return Value: -// - The corresponding enum value which maps to the string provided by the user -LaunchMode GlobalAppSettings::_ParseLaunchMode(const std::wstring& launchModeString) noexcept -{ - if (launchModeString == MaximizedLaunchModeValue) - { - return LaunchMode::MaximizedMode; - } - else if (launchModeString == FullscreenLaunchModeValue) + bool CanConvert(const Json::Value& json) { - return LaunchMode::FullscreenMode; + return json.isString(); } - - return LaunchMode::DefaultMode; -} - -// Method Description: -// - Helper function for converting the user-specified tab width -// to a TabViewWidthMode enum value -// Arguments: -// - tabWidthModeString: The string value from the settings file to parse -// Return Value: -// - The corresponding enum value which maps to the string provided by the user -TabViewWidthMode GlobalAppSettings::_ParseTabWidthMode(const std::wstring& tabWidthModeString) noexcept -{ - if (tabWidthModeString == TitleLengthTabWidthModeValue) - { - return TabViewWidthMode::SizeToContent; - } - else if (tabWidthModeString == TitleLengthCompactModeValue) - { - return TabViewWidthMode::Compact; - } - // default behavior for invalid data or EqualTabWidthValue - return TabViewWidthMode::Equal; -} +}; // Method Description: // - Adds the given colorscheme to our map of schemes, using its name as the key. diff --git a/src/cascadia/TerminalApp/GlobalAppSettings.h b/src/cascadia/TerminalApp/GlobalAppSettings.h index 58f8ea5a469..0a37c3c19cb 100644 --- a/src/cascadia/TerminalApp/GlobalAppSettings.h +++ b/src/cascadia/TerminalApp/GlobalAppSettings.h @@ -95,15 +95,6 @@ class TerminalApp::GlobalAppSettings final std::unordered_map _colorSchemes; std::unordered_map _commands; - static winrt::Windows::UI::Xaml::ElementTheme _ParseTheme(const std::wstring& themeString) noexcept; - - static winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode _ParseTabWidthMode(const std::wstring& tabWidthModeString) noexcept; - - static void _ParseInitialPosition(const std::string& initialPosition, - LaunchPosition& ret) noexcept; - - static winrt::TerminalApp::LaunchMode _ParseLaunchMode(const std::wstring& launchModeString) noexcept; - friend class TerminalAppLocalTests::SettingsTests; friend class TerminalAppLocalTests::ColorSchemeTests; }; From 1c02bf29446ed694116620bba2134c53b94ba614 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Tue, 12 May 2020 00:15:49 -0700 Subject: [PATCH 05/25] CSS: Convert to JsonUtilsNew --- src/cascadia/TerminalApp/CascadiaSettingsSerialization.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/cascadia/TerminalApp/CascadiaSettingsSerialization.cpp b/src/cascadia/TerminalApp/CascadiaSettingsSerialization.cpp index 46bb4df0b10..1a8f2b6e71f 100644 --- a/src/cascadia/TerminalApp/CascadiaSettingsSerialization.cpp +++ b/src/cascadia/TerminalApp/CascadiaSettingsSerialization.cpp @@ -6,7 +6,7 @@ #include "CascadiaSettings.h" #include "../../types/inc/utils.hpp" #include "utils.h" -#include "JsonUtils-DH.h" +#include "JsonUtils.h" #include #include @@ -251,9 +251,7 @@ void CascadiaSettings::_LoadDynamicProfiles() { for (const auto& json : disabledProfileSources) { - std::wstring ns{}; - JsonUtils::GetValue(json, ns); - ignoredNamespaces.emplace(std::move(ns)); + ignoredNamespaces.emplace(JsonUtils::GetValue(json)); } } From 372cb9072df5fd2f3cf85ad5ed0a899ca74af646 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Wed, 3 Jun 2020 23:49:33 -0700 Subject: [PATCH 06/25] GAS: move to macro --- src/cascadia/TerminalApp/GlobalAppSettings.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/cascadia/TerminalApp/GlobalAppSettings.cpp b/src/cascadia/TerminalApp/GlobalAppSettings.cpp index c9a4eccb9b3..cb0cafbf352 100644 --- a/src/cascadia/TerminalApp/GlobalAppSettings.cpp +++ b/src/cascadia/TerminalApp/GlobalAppSettings.cpp @@ -64,8 +64,7 @@ static constexpr bool debugFeaturesDefault{ true }; static constexpr bool debugFeaturesDefault{ false }; #endif -template<> -struct JsonUtils::ConversionTrait : public JsonUtils::KeyValueMapper> +JSON_ENUM_MAPPER(ElementTheme) { static constexpr std::array mappings = { pair_type{ SystemThemeValue, ElementTheme::Default }, @@ -74,8 +73,7 @@ struct JsonUtils::ConversionTrait : public JsonUtils::KeyValueMapp }; }; -template<> -struct JsonUtils::ConversionTrait : public JsonUtils::KeyValueMapper> +JSON_ENUM_MAPPER(LaunchMode) { static constexpr std::array mappings = { pair_type{ DefaultLaunchModeValue, LaunchMode::DefaultMode }, @@ -84,8 +82,7 @@ struct JsonUtils::ConversionTrait : public JsonUtils::KeyValueMapper }; }; -template<> -struct JsonUtils::ConversionTrait : public JsonUtils::KeyValueMapper> +JSON_ENUM_MAPPER(TabViewWidthMode) { static constexpr std::array mappings = { pair_type{ EqualTabWidthModeValue, TabViewWidthMode::Equal }, From 8f33d715b2464a8b58ec701202f8701d0331ae62 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Wed, 3 Jun 2020 23:49:44 -0700 Subject: [PATCH 07/25] Profile: move to mapper --- src/cascadia/TerminalApp/Profile.cpp | 2 +- .../TerminalApp/ProfileConversionTraits.cpp | 15 +++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/cascadia/TerminalApp/Profile.cpp b/src/cascadia/TerminalApp/Profile.cpp index 632640a1fa2..71a583086f9 100644 --- a/src/cascadia/TerminalApp/Profile.cpp +++ b/src/cascadia/TerminalApp/Profile.cpp @@ -437,7 +437,7 @@ void Profile::LayerJson(const Json::Value& json) JsonUtils::GetValueForKey(json, TabTitleKey, _tabTitle); // Control Settings - // TODO DH [JU-DH] + // TODO DH [JU-DH] if (json.isMember(JsonKey(FontWeightKey))) { auto fontWeight{ json[JsonKey(FontWeightKey)] }; diff --git a/src/cascadia/TerminalApp/ProfileConversionTraits.cpp b/src/cascadia/TerminalApp/ProfileConversionTraits.cpp index c60dca63489..3abdcae08c2 100644 --- a/src/cascadia/TerminalApp/ProfileConversionTraits.cpp +++ b/src/cascadia/TerminalApp/ProfileConversionTraits.cpp @@ -1,6 +1,5 @@ // Explicit specializations for JSON conversion -template<> -struct JsonUtils::ConversionTrait : public JsonUtils::KeyValueMapper> +JSON_ENUM_MAPPER(CursorStyle) { static constexpr std::array mappings = { pair_type{ CursorShapeBar, CursorStyle::Bar }, // DEFAULT @@ -11,8 +10,7 @@ struct JsonUtils::ConversionTrait : public JsonUtils::KeyValueMappe }; }; -template<> -struct JsonUtils::ConversionTrait : public JsonUtils::KeyValueMapper> +JSON_ENUM_MAPPER(Media::Stretch) { static constexpr std::array mappings = { pair_type{ ImageStretchModeUniformToFill, Media::Stretch::UniformToFill }, // DEFAULT @@ -22,8 +20,7 @@ struct JsonUtils::ConversionTrait : public JsonUtils::KeyValueMa }; }; -template<> -struct JsonUtils::ConversionTrait : public JsonUtils::KeyValueMapper> +JSON_ENUM_MAPPER(ScrollbarState) { static constexpr std::array mappings = { pair_type{ AlwaysVisible, ScrollbarState::Visible }, // DEFAULT @@ -31,8 +28,7 @@ struct JsonUtils::ConversionTrait : public JsonUtils::KeyValueMa }; }; -template<> -struct JsonUtils::ConversionTrait> : public JsonUtils::KeyValueMapper, JsonUtils::ConversionTrait>> +JSON_ENUM_MAPPER(std::tuple) { static constexpr std::array mappings = { pair_type{ ImageAlignmentCenter, std::make_tuple(HorizontalAlignment::Center, VerticalAlignment::Center) }, // DEFAULT @@ -47,8 +43,7 @@ struct JsonUtils::ConversionTrait -struct JsonUtils::ConversionTrait : public JsonUtils::KeyValueMapper> +JSON_ENUM_MAPPER(TextAntialiasingMode) { static constexpr std::array mappings = { pair_type{ AntialiasingModeGrayscale, TextAntialiasingMode::Grayscale }, // DEFAULT From a55198d0b9b493411684c1baec7592d1540a31e9 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Thu, 18 Jun 2020 22:16:15 -0700 Subject: [PATCH 08/25] remove GetWstringFromJson & utils.cpp --- src/cascadia/TerminalApp/Utils.cpp | 18 ------------------ src/cascadia/TerminalApp/Utils.h | 2 -- .../TerminalApp/lib/TerminalAppLib.vcxproj | 1 - .../lib/TerminalAppLib.vcxproj.filters | 1 - 4 files changed, 22 deletions(-) delete mode 100644 src/cascadia/TerminalApp/Utils.cpp diff --git a/src/cascadia/TerminalApp/Utils.cpp b/src/cascadia/TerminalApp/Utils.cpp deleted file mode 100644 index 01fa28dfdd1..00000000000 --- a/src/cascadia/TerminalApp/Utils.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -#include "pch.h" -#include "Utils.h" - -// Method Description: -// - Constructs a wstring from a given Json::Value object. Reads the object as -// a std::string using asString, then builds an hstring from that std::string, -// then converts that hstring into a std::wstring. -// Arguments: -// - json: the Json::Value to parse as a string -// Return Value: -// - the wstring equivalent of the value in json -std::wstring GetWstringFromJson(const Json::Value& json) -{ - return winrt::to_hstring(json.asString()).c_str(); -} diff --git a/src/cascadia/TerminalApp/Utils.h b/src/cascadia/TerminalApp/Utils.h index bba97694282..cb23bac450d 100644 --- a/src/cascadia/TerminalApp/Utils.h +++ b/src/cascadia/TerminalApp/Utils.h @@ -13,8 +13,6 @@ Author(s): --*/ #pragma once -std::wstring GetWstringFromJson(const Json::Value& json); - // Method Description: // - Create a std::string from a string_view. We do this because we can't look // up a key in a Json::Value with a string_view directly, so instead we'll use diff --git a/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj b/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj index 8d2655f58a6..590b0a38e61 100644 --- a/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj +++ b/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj @@ -178,7 +178,6 @@ - diff --git a/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj.filters b/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj.filters index 8f8f6623bf0..74e7e505943 100644 --- a/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj.filters +++ b/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj.filters @@ -8,7 +8,6 @@ - From 163f0f287392c5baefa51213d56c676b9f917320 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Thu, 18 Jun 2020 23:52:15 -0700 Subject: [PATCH 09/25] Some tests are now invalid --- .../KeyBindingsTests.cpp | 24 ++----------------- .../LocalTests_TerminalApp/SettingsTests.cpp | 5 ---- 2 files changed, 2 insertions(+), 27 deletions(-) diff --git a/src/cascadia/LocalTests_TerminalApp/KeyBindingsTests.cpp b/src/cascadia/LocalTests_TerminalApp/KeyBindingsTests.cpp index 760bfd94c8a..0fc9981cf7f 100644 --- a/src/cascadia/LocalTests_TerminalApp/KeyBindingsTests.cpp +++ b/src/cascadia/LocalTests_TerminalApp/KeyBindingsTests.cpp @@ -323,10 +323,8 @@ namespace TerminalAppLocalTests { "keys": ["ctrl+c"], "command": { "action": "splitPane", "split": null } }, { "keys": ["ctrl+d"], "command": { "action": "splitPane", "split": "vertical" } }, { "keys": ["ctrl+e"], "command": { "action": "splitPane", "split": "horizontal" } }, - { "keys": ["ctrl+f"], "command": { "action": "splitPane", "split": "none" } }, { "keys": ["ctrl+g"], "command": { "action": "splitPane" } }, - { "keys": ["ctrl+h"], "command": { "action": "splitPane", "split": "auto" } }, - { "keys": ["ctrl+i"], "command": { "action": "splitPane", "split": "foo" } } + { "keys": ["ctrl+h"], "command": { "action": "splitPane", "split": "auto" } } ])" }; const auto bindings0Json = VerifyParseSucceeded(bindings0String); @@ -335,7 +333,7 @@ namespace TerminalAppLocalTests VERIFY_IS_NOT_NULL(appKeyBindings); VERIFY_ARE_EQUAL(0u, appKeyBindings->_keyShortcuts.size()); appKeyBindings->LayerJson(bindings0Json); - VERIFY_ARE_EQUAL(7u, appKeyBindings->_keyShortcuts.size()); + VERIFY_ARE_EQUAL(5u, appKeyBindings->_keyShortcuts.size()); { KeyChord kc{ true, false, false, static_cast('C') }; @@ -364,15 +362,6 @@ namespace TerminalAppLocalTests // Verify the args have the expected value VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Horizontal, realArgs.SplitStyle()); } - { - KeyChord kc{ true, false, false, static_cast('F') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*appKeyBindings, kc); - VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action()); - const auto& realArgs = actionAndArgs.Args().try_as(); - VERIFY_IS_NOT_NULL(realArgs); - // Verify the args have the expected value - VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle()); - } { KeyChord kc{ true, false, false, static_cast('G') }; auto actionAndArgs = TestUtils::GetActionAndArgs(*appKeyBindings, kc); @@ -391,15 +380,6 @@ namespace TerminalAppLocalTests // Verify the args have the expected value VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle()); } - { - KeyChord kc{ true, false, false, static_cast('I') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*appKeyBindings, kc); - VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action()); - const auto& realArgs = actionAndArgs.Args().try_as(); - VERIFY_IS_NOT_NULL(realArgs); - // Verify the args have the expected value - VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle()); - } } void KeyBindingsTests::TestSetTabColorArgs() diff --git a/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp b/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp index 8aed7e4525d..ecd58743f56 100644 --- a/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp +++ b/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp @@ -1431,10 +1431,6 @@ namespace TerminalAppLocalTests { "name": "profile3", "closeOnExit": null - }, - { - "name": "profile4", - "closeOnExit": { "clearly": "not a string" } } ] })" }; @@ -1449,7 +1445,6 @@ namespace TerminalAppLocalTests // Unknown modes parse as "Graceful" VERIFY_ARE_EQUAL(CloseOnExitMode::Graceful, settings._profiles[3].GetCloseOnExitMode()); - VERIFY_ARE_EQUAL(CloseOnExitMode::Graceful, settings._profiles[4].GetCloseOnExitMode()); } void SettingsTests::TestCloseOnExitCompatibilityShim() { From 32ee8dfb2c2ca7b679a95b5f0c859e043f09a772 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Thu, 18 Jun 2020 23:53:22 -0700 Subject: [PATCH 10/25] GAS: clean up --- src/cascadia/TerminalApp/GlobalAppSettings.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cascadia/TerminalApp/GlobalAppSettings.cpp b/src/cascadia/TerminalApp/GlobalAppSettings.cpp index cb0cafbf352..fd350356664 100644 --- a/src/cascadia/TerminalApp/GlobalAppSettings.cpp +++ b/src/cascadia/TerminalApp/GlobalAppSettings.cpp @@ -66,7 +66,7 @@ static constexpr bool debugFeaturesDefault{ false }; JSON_ENUM_MAPPER(ElementTheme) { - static constexpr std::array mappings = { + JSON_MAPPINGS(3) = { pair_type{ SystemThemeValue, ElementTheme::Default }, pair_type{ LightThemeValue, ElementTheme::Light }, pair_type{ DarkThemeValue, ElementTheme::Dark }, @@ -75,7 +75,7 @@ JSON_ENUM_MAPPER(ElementTheme) JSON_ENUM_MAPPER(LaunchMode) { - static constexpr std::array mappings = { + JSON_MAPPINGS(3) = { pair_type{ DefaultLaunchModeValue, LaunchMode::DefaultMode }, pair_type{ MaximizedLaunchModeValue, LaunchMode::MaximizedMode }, pair_type{ FullscreenLaunchModeValue, LaunchMode::FullscreenMode }, @@ -84,7 +84,7 @@ JSON_ENUM_MAPPER(LaunchMode) JSON_ENUM_MAPPER(TabViewWidthMode) { - static constexpr std::array mappings = { + JSON_MAPPINGS(3) = { pair_type{ EqualTabWidthModeValue, TabViewWidthMode::Equal }, pair_type{ TitleLengthTabWidthModeValue, TabViewWidthMode::SizeToContent }, pair_type{ TitleLengthCompactModeValue, TabViewWidthMode::Compact }, From 73b18f040d5178044728897ab4eae562beebd2f2 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Thu, 18 Jun 2020 23:53:36 -0700 Subject: [PATCH 11/25] Action/Args: Convert --- src/cascadia/TerminalApp/ActionAndArgs.cpp | 12 +- src/cascadia/TerminalApp/ActionArgs.h | 235 +++++++-------------- 2 files changed, 79 insertions(+), 168 deletions(-) diff --git a/src/cascadia/TerminalApp/ActionAndArgs.cpp b/src/cascadia/TerminalApp/ActionAndArgs.cpp index cdb7c61eaa5..8a00b2ea761 100644 --- a/src/cascadia/TerminalApp/ActionAndArgs.cpp +++ b/src/cascadia/TerminalApp/ActionAndArgs.cpp @@ -2,6 +2,9 @@ #include "ActionArgs.h" #include "ActionAndArgs.h" #include "ActionAndArgs.g.cpp" + +#include "JsonUtils.h" + #include static constexpr std::string_view CopyTextKey{ "copy" }; @@ -43,6 +46,8 @@ static constexpr std::string_view UnboundKey{ "unbound" }; namespace winrt::TerminalApp::implementation { + using namespace ::TerminalApp; + // Specifically use a map here over an unordered_map. We want to be able to // iterate over these entries in-order when we're serializing the keybindings. // HERE BE DRAGONS: @@ -181,11 +186,9 @@ namespace winrt::TerminalApp::implementation } else if (json.isObject()) { - const auto actionVal = json[JsonKey(ActionKey)]; - if (actionVal.isString()) + if (const auto actionString{ JsonUtils::GetValueForKey>(json, ActionKey) }) { - auto actionString = actionVal.asString(); - action = GetActionFromString(actionString); + action = GetActionFromString(*actionString); argsVal = json; } } @@ -278,5 +281,4 @@ namespace winrt::TerminalApp::implementation const auto found = GeneratedActionNames.find(_Action); return found != GeneratedActionNames.end() ? found->second : L""; } - } diff --git a/src/cascadia/TerminalApp/ActionArgs.h b/src/cascadia/TerminalApp/ActionArgs.h index eb233b5967a..fa3a267a979 100644 --- a/src/cascadia/TerminalApp/ActionArgs.h +++ b/src/cascadia/TerminalApp/ActionArgs.h @@ -29,8 +29,64 @@ // * ActionEventArgs holds a single IActionArgs. For events that don't need // additional args, this can be nullptr. +// Possible Direction values +// TODO:GH#2550/#3475 - move these to a centralized deserializing place +JSON_ENUM_MAPPER(::winrt::TerminalApp::Direction) +{ + static constexpr std::string_view LeftString{ "left" }; + static constexpr std::string_view RightString{ "right" }; + static constexpr std::string_view UpString{ "up" }; + static constexpr std::string_view DownString{ "down" }; + + JSON_MAPPINGS(4) = { + pair_type{ LeftString, ::winrt::TerminalApp::Direction::Left }, + pair_type{ RightString, ::winrt::TerminalApp::Direction::Right }, + pair_type{ UpString, ::winrt::TerminalApp::Direction::Up }, + pair_type{ DownString, ::winrt::TerminalApp::Direction::Down }, + }; +}; + +// Possible SplitState values +// TODO:GH#2550/#3475 - move these to a centralized deserializing place +JSON_ENUM_MAPPER(::winrt::TerminalApp::SplitState) +{ + static constexpr std::string_view VerticalKey{ "vertical" }; + static constexpr std::string_view HorizontalKey{ "horizontal" }; + static constexpr std::string_view AutomaticKey{ "auto" }; + + JSON_MAPPINGS(3) = { + pair_type{ VerticalKey, ::winrt::TerminalApp::SplitState::Vertical }, + pair_type{ HorizontalKey, ::winrt::TerminalApp::SplitState::Horizontal }, + pair_type{ AutomaticKey, ::winrt::TerminalApp::SplitState::Automatic }, + }; +}; + +// Possible SplitType values +JSON_ENUM_MAPPER(::winrt::TerminalApp::SplitType) +{ + static constexpr std::string_view DuplicateKey{ "duplicate" }; + JSON_MAPPINGS(1) = { + pair_type{ DuplicateKey, ::winrt::TerminalApp::SplitType::Duplicate }, + }; +}; + +JSON_ENUM_MAPPER(::winrt::TerminalApp::SettingsTarget) +{ + // Possible SettingsTarget values + static constexpr std::string_view SettingsFileString{ "settingsFile" }; + static constexpr std::string_view DefaultsFileString{ "defaultsFile" }; + static constexpr std::string_view AllFilesString{ "allFiles" }; + + JSON_MAPPINGS(3) = { + pair_type{ SettingsFileString, ::winrt::TerminalApp::SettingsTarget::SettingsFile }, + pair_type{ DefaultsFileString, ::winrt::TerminalApp::SettingsTarget::DefaultsFile }, + pair_type{ AllFilesString, ::winrt::TerminalApp::SettingsTarget::AllFiles }, + }; +}; + namespace winrt::TerminalApp::implementation { + using namespace ::TerminalApp; using FromJsonResult = std::tuple>; struct ActionEventArgs : public ActionEventArgsT @@ -73,26 +129,11 @@ namespace winrt::TerminalApp::implementation { // LOAD BEARING: Not using make_self here _will_ break you in the future! auto args = winrt::make_self(); - if (auto commandline{ json[JsonKey(CommandlineKey)] }) - { - args->_Commandline = winrt::to_hstring(commandline.asString()); - } - if (auto startingDirectory{ json[JsonKey(StartingDirectoryKey)] }) - { - args->_StartingDirectory = winrt::to_hstring(startingDirectory.asString()); - } - if (auto tabTitle{ json[JsonKey(TabTitleKey)] }) - { - args->_TabTitle = winrt::to_hstring(tabTitle.asString()); - } - if (auto index{ json[JsonKey(ProfileIndexKey)] }) - { - args->_ProfileIndex = index.asInt(); - } - if (auto profile{ json[JsonKey(ProfileKey)] }) - { - args->_Profile = winrt::to_hstring(profile.asString()); - } + JsonUtils::GetValueForKey(json, CommandlineKey, args->_Commandline); + JsonUtils::GetValueForKey(json, StartingDirectoryKey, args->_StartingDirectory); + JsonUtils::GetValueForKey(json, TabTitleKey, args->_TabTitle); + JsonUtils::GetValueForKey(json, ProfileIndexKey, args->_ProfileIndex); + JsonUtils::GetValueForKey(json, ProfileKey, args->_Profile); return *args; } }; @@ -120,10 +161,7 @@ namespace winrt::TerminalApp::implementation { // LOAD BEARING: Not using make_self here _will_ break you in the future! auto args = winrt::make_self(); - if (auto singleLine{ json[JsonKey(SingleLineKey)] }) - { - args->_SingleLine = singleLine.asBool(); - } + JsonUtils::GetValueForKey(json, SingleLineKey, args->_SingleLine); return { *args, {} }; } }; @@ -177,49 +215,11 @@ namespace winrt::TerminalApp::implementation { // LOAD BEARING: Not using make_self here _will_ break you in the future! auto args = winrt::make_self(); - if (auto tabIndex{ json[JsonKey(TabIndexKey)] }) - { - args->_TabIndex = tabIndex.asUInt(); - } + JsonUtils::GetValueForKey(json, TabIndexKey, args->_TabIndex); return { *args, {} }; } }; - // Possible Direction values - // TODO:GH#2550/#3475 - move these to a centralized deserializing place - static constexpr std::string_view LeftString{ "left" }; - static constexpr std::string_view RightString{ "right" }; - static constexpr std::string_view UpString{ "up" }; - static constexpr std::string_view DownString{ "down" }; - - // Function Description: - // - Helper function for parsing a Direction from a string - // Arguments: - // - directionString: the string to attempt to parse - // Return Value: - // - The encoded Direction value, or Direction::None if it was an invalid string - static TerminalApp::Direction ParseDirection(const std::string& directionString) - { - if (directionString == LeftString) - { - return TerminalApp::Direction::Left; - } - else if (directionString == RightString) - { - return TerminalApp::Direction::Right; - } - else if (directionString == UpString) - { - return TerminalApp::Direction::Up; - } - else if (directionString == DownString) - { - return TerminalApp::Direction::Down; - } - // default behavior for invalid data - return TerminalApp::Direction::None; - }; - struct ResizePaneArgs : public ResizePaneArgsT { ResizePaneArgs() = default; @@ -243,10 +243,7 @@ namespace winrt::TerminalApp::implementation { // LOAD BEARING: Not using make_self here _will_ break you in the future! auto args = winrt::make_self(); - if (auto directionString{ json[JsonKey(DirectionKey)] }) - { - args->_Direction = ParseDirection(directionString.asString()); - } + JsonUtils::GetValueForKey(json, DirectionKey, args->_Direction); if (args->_Direction == TerminalApp::Direction::None) { return { nullptr, { ::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter } }; @@ -281,10 +278,7 @@ namespace winrt::TerminalApp::implementation { // LOAD BEARING: Not using make_self here _will_ break you in the future! auto args = winrt::make_self(); - if (auto directionString{ json[JsonKey(DirectionKey)] }) - { - args->_Direction = ParseDirection(directionString.asString()); - } + JsonUtils::GetValueForKey(json, DirectionKey, args->_Direction); if (args->_Direction == TerminalApp::Direction::None) { return { nullptr, { ::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter } }; @@ -319,48 +313,11 @@ namespace winrt::TerminalApp::implementation { // LOAD BEARING: Not using make_self here _will_ break you in the future! auto args = winrt::make_self(); - if (auto jsonDelta{ json[JsonKey(AdjustFontSizeDelta)] }) - { - args->_Delta = jsonDelta.asInt(); - } + JsonUtils::GetValueForKey(json, AdjustFontSizeDelta, args->_Delta); return { *args, {} }; } }; - // Possible SplitState values - // TODO:GH#2550/#3475 - move these to a centralized deserializing place - static constexpr std::string_view VerticalKey{ "vertical" }; - static constexpr std::string_view HorizontalKey{ "horizontal" }; - static constexpr std::string_view AutomaticKey{ "auto" }; - static TerminalApp::SplitState ParseSplitState(const std::string& stateString) - { - if (stateString == VerticalKey) - { - return TerminalApp::SplitState::Vertical; - } - else if (stateString == HorizontalKey) - { - return TerminalApp::SplitState::Horizontal; - } - else if (stateString == AutomaticKey) - { - return TerminalApp::SplitState::Automatic; - } - // default behavior for invalid data - return TerminalApp::SplitState::Automatic; - }; - - // Possible SplitType values - static constexpr std::string_view DuplicateKey{ "duplicate" }; - static TerminalApp::SplitType ParseSplitModeState(const std::string& stateString) - { - if (stateString == DuplicateKey) - { - return TerminalApp::SplitType::Duplicate; - } - return TerminalApp::SplitType::Manual; - } - struct SplitPaneArgs : public SplitPaneArgsT { SplitPaneArgs() = default; @@ -391,48 +348,12 @@ namespace winrt::TerminalApp::implementation // LOAD BEARING: Not using make_self here _will_ break you in the future! auto args = winrt::make_self(); args->_TerminalArgs = NewTerminalArgs::FromJson(json); - if (auto jsonStyle{ json[JsonKey(SplitKey)] }) - { - args->_SplitStyle = ParseSplitState(jsonStyle.asString()); - } - if (auto jsonStyle{ json[JsonKey(SplitModeKey)] }) - { - args->_SplitMode = ParseSplitModeState(jsonStyle.asString()); - } + JsonUtils::GetValueForKey(json, SplitKey, args->_SplitStyle); + JsonUtils::GetValueForKey(json, SplitModeKey, args->_SplitMode); return { *args, {} }; } }; - // Possible SettingsTarget values - // TODO:GH#2550/#3475 - move these to a centralized deserializing place - static constexpr std::string_view SettingsFileString{ "settingsFile" }; - static constexpr std::string_view DefaultsFileString{ "defaultsFile" }; - static constexpr std::string_view AllFilesString{ "allFiles" }; - - // Function Description: - // - Helper function for parsing a SettingsTarget from a string - // Arguments: - // - targetString: the string to attempt to parse - // Return Value: - // - The encoded SettingsTarget value, or SettingsTarget::SettingsFile if it was an invalid string - static TerminalApp::SettingsTarget ParseSettingsTarget(const std::string& targetString) - { - if (targetString == SettingsFileString) - { - return TerminalApp::SettingsTarget::SettingsFile; - } - else if (targetString == DefaultsFileString) - { - return TerminalApp::SettingsTarget::DefaultsFile; - } - else if (targetString == AllFilesString) - { - return TerminalApp::SettingsTarget::AllFiles; - } - // default behavior for invalid data - return TerminalApp::SettingsTarget::SettingsFile; - }; - struct OpenSettingsArgs : public OpenSettingsArgsT { OpenSettingsArgs() = default; @@ -456,10 +377,7 @@ namespace winrt::TerminalApp::implementation { // LOAD BEARING: Not using make_self here _will_ break you in the future! auto args = winrt::make_self(); - if (auto targetString{ json[JsonKey(TargetKey)] }) - { - args->_Target = ParseSettingsTarget(targetString.asString()); - } + JsonUtils::GetValueForKey(json, TargetKey, args->_Target); return { *args, {} }; } }; @@ -487,16 +405,10 @@ namespace winrt::TerminalApp::implementation { // LOAD BEARING: Not using make_self here _will_ break you in the future! auto args = winrt::make_self(); - std::optional temp; - try + if (const auto temp{ JsonUtils::GetValueForKey>(json, ColorKey) }) { - ::TerminalApp::JsonUtils::GetOptionalColor(json, ColorKey, temp); - if (temp.has_value()) - { - args->_TabColor = static_cast(temp.value()); - } + args->_TabColor = static_cast(*temp); } - CATCH_LOG(); return { *args, {} }; } }; @@ -524,10 +436,7 @@ namespace winrt::TerminalApp::implementation { // LOAD BEARING: Not using make_self here _will_ break you in the future! auto args = winrt::make_self(); - if (auto title{ json[JsonKey(TitleKey)] }) - { - args->_Title = winrt::to_hstring(title.asString()); - } + JsonUtils::GetValueForKey(json, TitleKey, args->_Title); return { *args, {} }; } }; From 785f7c044ea549f3bd32bfc872c1cba91c979d45 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Thu, 18 Jun 2020 23:54:16 -0700 Subject: [PATCH 12/25] profile: convert fontweight, move const strings --- src/cascadia/TerminalApp/Profile.cpp | 131 +----------------- .../TerminalApp/ProfileConversionTraits.cpp | 129 ++++++++++++++--- 2 files changed, 107 insertions(+), 153 deletions(-) diff --git a/src/cascadia/TerminalApp/Profile.cpp b/src/cascadia/TerminalApp/Profile.cpp index 71a583086f9..8c6de94e3a4 100644 --- a/src/cascadia/TerminalApp/Profile.cpp +++ b/src/cascadia/TerminalApp/Profile.cpp @@ -52,57 +52,6 @@ static constexpr std::string_view BackgroundImageAlignmentKey{ "backgroundImageA static constexpr std::string_view RetroTerminalEffectKey{ "experimental.retroTerminalEffect" }; static constexpr std::string_view AntialiasingModeKey{ "antialiasingMode" }; -// Possible values for closeOnExit -static constexpr std::string_view CloseOnExitAlways{ "always" }; -static constexpr std::string_view CloseOnExitGraceful{ "graceful" }; -static constexpr std::string_view CloseOnExitNever{ "never" }; - -// Possible values for Scrollbar state -static constexpr std::string_view AlwaysVisible{ "visible" }; -static constexpr std::string_view AlwaysHide{ "hidden" }; - -// Possible values for Cursor Shape -static constexpr std::string_view CursorShapeVintage{ "vintage" }; -static constexpr std::string_view CursorShapeBar{ "bar" }; -static constexpr std::string_view CursorShapeUnderscore{ "underscore" }; -static constexpr std::string_view CursorShapeFilledbox{ "filledBox" }; -static constexpr std::string_view CursorShapeEmptybox{ "emptyBox" }; - -// Possible values for Font Weight -static constexpr std::string_view FontWeightThin{ "thin" }; -static constexpr std::string_view FontWeightExtraLight{ "extra-light" }; -static constexpr std::string_view FontWeightLight{ "light" }; -static constexpr std::string_view FontWeightSemiLight{ "semi-light" }; -static constexpr std::string_view FontWeightNormal{ "normal" }; -static constexpr std::string_view FontWeightMedium{ "medium" }; -static constexpr std::string_view FontWeightSemiBold{ "semi-bold" }; -static constexpr std::string_view FontWeightBold{ "bold" }; -static constexpr std::string_view FontWeightExtraBold{ "extra-bold" }; -static constexpr std::string_view FontWeightBlack{ "black" }; -static constexpr std::string_view FontWeightExtraBlack{ "extra-black" }; - -// Possible values for Image Stretch Mode -static constexpr std::string_view ImageStretchModeNone{ "none" }; -static constexpr std::string_view ImageStretchModeFill{ "fill" }; -static constexpr std::string_view ImageStretchModeUniform{ "uniform" }; -static constexpr std::string_view ImageStretchModeUniformToFill{ "uniformToFill" }; - -// Possible values for Image Alignment -static constexpr std::string_view ImageAlignmentCenter{ "center" }; -static constexpr std::string_view ImageAlignmentLeft{ "left" }; -static constexpr std::string_view ImageAlignmentTop{ "top" }; -static constexpr std::string_view ImageAlignmentRight{ "right" }; -static constexpr std::string_view ImageAlignmentBottom{ "bottom" }; -static constexpr std::string_view ImageAlignmentTopLeft{ "topLeft" }; -static constexpr std::string_view ImageAlignmentTopRight{ "topRight" }; -static constexpr std::string_view ImageAlignmentBottomLeft{ "bottomLeft" }; -static constexpr std::string_view ImageAlignmentBottomRight{ "bottomRight" }; - -// Possible values for TextAntialiasingMode -static constexpr std::string_view AntialiasingModeGrayscale{ "grayscale" }; -static constexpr std::string_view AntialiasingModeCleartype{ "cleartype" }; -static constexpr std::string_view AntialiasingModeAliased{ "aliased" }; - #include "ProfileConversionTraits.cpp" Profile::Profile() : @@ -437,13 +386,7 @@ void Profile::LayerJson(const Json::Value& json) JsonUtils::GetValueForKey(json, TabTitleKey, _tabTitle); // Control Settings - // TODO DH [JU-DH] - if (json.isMember(JsonKey(FontWeightKey))) - { - auto fontWeight{ json[JsonKey(FontWeightKey)] }; - _fontWeight = _ParseFontWeight(fontWeight); - } - + JsonUtils::GetValueForKey(json, FontWeightKey, _fontWeight); JsonUtils::GetValueForKey(json, ConnectionTypeKey, _connectionType); JsonUtils::GetValueForKey(json, CommandlineKey, _commandline); JsonUtils::GetValueForKey(json, FontFaceKey, _fontFace); @@ -693,78 +636,6 @@ std::wstring Profile::EvaluateStartingDirectory(const std::wstring& directory) } } -// Method Description: -// - Helper function for converting a user-specified font weight value to its corresponding enum -// Arguments: -// - The value from the settings.json file -// Return Value: -// - The corresponding value which maps to the string provided by the user -winrt::Windows::UI::Text::FontWeight Profile::_ParseFontWeight(const Json::Value& json) -{ - if (json.isUInt()) - { - winrt::Windows::UI::Text::FontWeight weight; - weight.Weight = static_cast(json.asUInt()); - - // We're only accepting variable values between 100 and 990 so we don't go too crazy. - if (weight.Weight >= 100 && weight.Weight <= 990) - { - return weight; - } - } - - if (json.isString()) - { - auto fontWeight = json.asString(); - if (fontWeight == FontWeightThin) - { - return winrt::Windows::UI::Text::FontWeights::Thin(); - } - else if (fontWeight == FontWeightExtraLight) - { - return winrt::Windows::UI::Text::FontWeights::ExtraLight(); - } - else if (fontWeight == FontWeightLight) - { - return winrt::Windows::UI::Text::FontWeights::Light(); - } - else if (fontWeight == FontWeightSemiLight) - { - return winrt::Windows::UI::Text::FontWeights::SemiLight(); - } - else if (fontWeight == FontWeightNormal) - { - return winrt::Windows::UI::Text::FontWeights::Normal(); - } - else if (fontWeight == FontWeightMedium) - { - return winrt::Windows::UI::Text::FontWeights::Medium(); - } - else if (fontWeight == FontWeightSemiBold) - { - return winrt::Windows::UI::Text::FontWeights::SemiBold(); - } - else if (fontWeight == FontWeightBold) - { - return winrt::Windows::UI::Text::FontWeights::Bold(); - } - else if (fontWeight == FontWeightExtraBold) - { - return winrt::Windows::UI::Text::FontWeights::ExtraBold(); - } - else if (fontWeight == FontWeightBlack) - { - return winrt::Windows::UI::Text::FontWeights::Black(); - } - else if (fontWeight == FontWeightExtraBlack) - { - return winrt::Windows::UI::Text::FontWeights::ExtraBlack(); - } - } - - return winrt::Windows::UI::Text::FontWeights::Normal(); -} - // Method Description: // - If this profile never had a GUID set for it, generate a runtime GUID for // the profile. If a profile had their guid manually set to {0}, this method diff --git a/src/cascadia/TerminalApp/ProfileConversionTraits.cpp b/src/cascadia/TerminalApp/ProfileConversionTraits.cpp index 3abdcae08c2..7b82eafa829 100644 --- a/src/cascadia/TerminalApp/ProfileConversionTraits.cpp +++ b/src/cascadia/TerminalApp/ProfileConversionTraits.cpp @@ -1,8 +1,15 @@ // Explicit specializations for JSON conversion JSON_ENUM_MAPPER(CursorStyle) { + // Possible values for Cursor Shape + static constexpr std::string_view CursorShapeVintage{ "vintage" }; + static constexpr std::string_view CursorShapeBar{ "bar" }; + static constexpr std::string_view CursorShapeUnderscore{ "underscore" }; + static constexpr std::string_view CursorShapeFilledbox{ "filledBox" }; + static constexpr std::string_view CursorShapeEmptybox{ "emptyBox" }; + static constexpr std::array mappings = { - pair_type{ CursorShapeBar, CursorStyle::Bar }, // DEFAULT + pair_type{ CursorShapeBar, CursorStyle::Bar }, pair_type{ CursorShapeVintage, CursorStyle::Vintage }, pair_type{ CursorShapeUnderscore, CursorStyle::Underscore }, pair_type{ CursorShapeFilledbox, CursorStyle::FilledBox }, @@ -12,8 +19,14 @@ JSON_ENUM_MAPPER(CursorStyle) JSON_ENUM_MAPPER(Media::Stretch) { + // Possible values for Image Stretch Mode + static constexpr std::string_view ImageStretchModeNone{ "none" }; + static constexpr std::string_view ImageStretchModeFill{ "fill" }; + static constexpr std::string_view ImageStretchModeUniform{ "uniform" }; + static constexpr std::string_view ImageStretchModeUniformToFill{ "uniformToFill" }; + static constexpr std::array mappings = { - pair_type{ ImageStretchModeUniformToFill, Media::Stretch::UniformToFill }, // DEFAULT + pair_type{ ImageStretchModeUniformToFill, Media::Stretch::UniformToFill }, pair_type{ ImageStretchModeNone, Media::Stretch::None }, pair_type{ ImageStretchModeFill, Media::Stretch::Fill }, pair_type{ ImageStretchModeUniform, Media::Stretch::Uniform } @@ -22,16 +35,31 @@ JSON_ENUM_MAPPER(Media::Stretch) JSON_ENUM_MAPPER(ScrollbarState) { + // Possible values for Scrollbar state + static constexpr std::string_view AlwaysVisible{ "visible" }; + static constexpr std::string_view AlwaysHide{ "hidden" }; + static constexpr std::array mappings = { - pair_type{ AlwaysVisible, ScrollbarState::Visible }, // DEFAULT + pair_type{ AlwaysVisible, ScrollbarState::Visible }, pair_type{ AlwaysHide, ScrollbarState::Hidden } }; }; JSON_ENUM_MAPPER(std::tuple) { + // Possible values for Image Alignment + static constexpr std::string_view ImageAlignmentCenter{ "center" }; + static constexpr std::string_view ImageAlignmentLeft{ "left" }; + static constexpr std::string_view ImageAlignmentTop{ "top" }; + static constexpr std::string_view ImageAlignmentRight{ "right" }; + static constexpr std::string_view ImageAlignmentBottom{ "bottom" }; + static constexpr std::string_view ImageAlignmentTopLeft{ "topLeft" }; + static constexpr std::string_view ImageAlignmentTopRight{ "topRight" }; + static constexpr std::string_view ImageAlignmentBottomLeft{ "bottomLeft" }; + static constexpr std::string_view ImageAlignmentBottomRight{ "bottomRight" }; + static constexpr std::array mappings = { - pair_type{ ImageAlignmentCenter, std::make_tuple(HorizontalAlignment::Center, VerticalAlignment::Center) }, // DEFAULT + pair_type{ ImageAlignmentCenter, std::make_tuple(HorizontalAlignment::Center, VerticalAlignment::Center) }, pair_type{ ImageAlignmentTopLeft, std::make_tuple(HorizontalAlignment::Left, VerticalAlignment::Top) }, pair_type{ ImageAlignmentBottomLeft, std::make_tuple(HorizontalAlignment::Left, VerticalAlignment::Bottom) }, pair_type{ ImageAlignmentLeft, std::make_tuple(HorizontalAlignment::Left, VerticalAlignment::Center) }, @@ -45,8 +73,13 @@ JSON_ENUM_MAPPER(std::tuple) JSON_ENUM_MAPPER(TextAntialiasingMode) { + // Possible values for TextAntialiasingMode + static constexpr std::string_view AntialiasingModeGrayscale{ "grayscale" }; + static constexpr std::string_view AntialiasingModeCleartype{ "cleartype" }; + static constexpr std::string_view AntialiasingModeAliased{ "aliased" }; + static constexpr std::array mappings = { - pair_type{ AntialiasingModeGrayscale, TextAntialiasingMode::Grayscale }, // DEFAULT + pair_type{ AntialiasingModeGrayscale, TextAntialiasingMode::Grayscale }, pair_type{ AntialiasingModeCleartype, TextAntialiasingMode::Cleartype }, pair_type{ AntialiasingModeAliased, TextAntialiasingMode::Aliased } }; @@ -58,38 +91,88 @@ JSON_ENUM_MAPPER(TextAntialiasingMode) // - The value from the profiles.json file // Return Value: // - The corresponding enum value which maps to the string provided by the user -template<> -struct JsonUtils::ConversionTrait +JSON_ENUM_MAPPER(CloseOnExitMode) { + // Possible values for closeOnExit + static constexpr std::string_view CloseOnExitAlways{ "always" }; + static constexpr std::string_view CloseOnExitGraceful{ "graceful" }; + static constexpr std::string_view CloseOnExitNever{ "never" }; + + JSON_MAPPINGS(3) = { + pair_type{ CloseOnExitAlways, CloseOnExitMode::Always }, + pair_type{ CloseOnExitGraceful, CloseOnExitMode::Graceful }, + pair_type{ CloseOnExitNever, CloseOnExitMode::Never }, + }; + + // Override mapping parser to add boolean parsing CloseOnExitMode FromJson(const Json::Value& json) { if (json.isBool()) { return json.asBool() ? CloseOnExitMode::Graceful : CloseOnExitMode::Never; } + return EnumMapper::FromJson(json); + } - if (json.isString()) + bool CanConvert(const Json::Value& json) + { + return EnumMapper::CanConvert(json) || json.isBool(); + } +}; + +template<> +struct JsonUtils::ConversionTrait : public JsonUtils::EnumMapper> +{ + // Possible values for Font Weight + static constexpr std::string_view FontWeightThin{ "thin" }; + static constexpr std::string_view FontWeightExtraLight{ "extra-light" }; + static constexpr std::string_view FontWeightLight{ "light" }; + static constexpr std::string_view FontWeightSemiLight{ "semi-light" }; + static constexpr std::string_view FontWeightNormal{ "normal" }; + static constexpr std::string_view FontWeightMedium{ "medium" }; + static constexpr std::string_view FontWeightSemiBold{ "semi-bold" }; + static constexpr std::string_view FontWeightBold{ "bold" }; + static constexpr std::string_view FontWeightExtraBold{ "extra-bold" }; + static constexpr std::string_view FontWeightBlack{ "black" }; + static constexpr std::string_view FontWeightExtraBlack{ "extra-black" }; + + // The original parser used the font weight getters Bold(), Normal(), etc. + // They were both ugly and *not constant expressions* + JSON_MAPPINGS(11) = { + pair_type{ FontWeightThin, 100u }, + pair_type{ FontWeightExtraLight, 200u }, + pair_type{ FontWeightLight, 300u }, + pair_type{ FontWeightSemiLight, 350u }, + pair_type{ FontWeightNormal, 400u }, + pair_type{ FontWeightMedium, 500u }, + pair_type{ FontWeightSemiBold, 600u }, + pair_type{ FontWeightBold, 700u }, + pair_type{ FontWeightExtraBold, 800u }, + pair_type{ FontWeightBlack, 900u }, + pair_type{ FontWeightExtraBlack, 950u }, + }; + + // Override mapping parser to add boolean parsing + auto FromJson(const Json::Value& json) + { + unsigned int value{ 400 }; + if (json.isUInt()) + { + value = json.asUInt(); + } + else { - auto closeOnExit = json.asString(); - if (closeOnExit == CloseOnExitAlways) - { - return CloseOnExitMode::Always; - } - else if (closeOnExit == CloseOnExitGraceful) - { - return CloseOnExitMode::Graceful; - } - else if (closeOnExit == CloseOnExitNever) - { - return CloseOnExitMode::Never; - } + value = EnumMapper::FromJson(json); } - return CloseOnExitMode::Graceful; + winrt::Windows::UI::Text::FontWeight weight{ + static_cast(std::clamp(value, 100u, 990u)) + }; + return weight; } bool CanConvert(const Json::Value& json) { - return json.isString() || json.isBool(); + return EnumMapper::CanConvert(json) || json.isUInt(); } }; From 373070710a81d105dcd66ddd9c80dc0a3776e34e Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Sun, 12 Jul 2020 16:26:49 -0700 Subject: [PATCH 13/25] Command: update to JU-NEW --- src/cascadia/TerminalApp/Command.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/cascadia/TerminalApp/Command.cpp b/src/cascadia/TerminalApp/Command.cpp index a8e72ec6a84..f3fe1219126 100644 --- a/src/cascadia/TerminalApp/Command.cpp +++ b/src/cascadia/TerminalApp/Command.cpp @@ -7,10 +7,12 @@ #include "Utils.h" #include "ActionAndArgs.h" +#include "JsonUtils.h" #include using namespace winrt::Microsoft::Terminal::Settings; using namespace winrt::TerminalApp; +using namespace ::TerminalApp; static constexpr std::string_view NameKey{ "name" }; static constexpr std::string_view IconPathKey{ "iconPath" }; @@ -35,25 +37,17 @@ namespace winrt::TerminalApp::implementation { if (name.isObject()) { - try + if (const auto resourceKey{ JsonUtils::GetValueForKey>(name, "key") }) { - if (const auto keyJson{ name[JsonKey("key")] }) + if (HasLibraryResourceWithName(*resourceKey)) { - // Make sure the key is present before we try - // loading it. Otherwise we'll crash - const auto resourceKey = GetWstringFromJson(keyJson); - if (HasLibraryResourceWithName(resourceKey)) - { - return GetLibraryResourceString(resourceKey); - } + return GetLibraryResourceString(*resourceKey); } } - CATCH_LOG(); } else if (name.isString()) { - auto nameStr = name.asString(); - return winrt::to_hstring(nameStr); + return JsonUtils::GetValue(name); } } From 16ab0ae6562ab18590ae8e48e01b2bd887a4af09 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Sun, 12 Jul 2020 16:27:16 -0700 Subject: [PATCH 14/25] ProfileConversions: merge constexpr strings w/ map --- .../TerminalApp/ProfileConversionTraits.cpp | 132 ++++++------------ 1 file changed, 42 insertions(+), 90 deletions(-) diff --git a/src/cascadia/TerminalApp/ProfileConversionTraits.cpp b/src/cascadia/TerminalApp/ProfileConversionTraits.cpp index 7b82eafa829..16c50ddf9fe 100644 --- a/src/cascadia/TerminalApp/ProfileConversionTraits.cpp +++ b/src/cascadia/TerminalApp/ProfileConversionTraits.cpp @@ -1,87 +1,54 @@ // Explicit specializations for JSON conversion JSON_ENUM_MAPPER(CursorStyle) { - // Possible values for Cursor Shape - static constexpr std::string_view CursorShapeVintage{ "vintage" }; - static constexpr std::string_view CursorShapeBar{ "bar" }; - static constexpr std::string_view CursorShapeUnderscore{ "underscore" }; - static constexpr std::string_view CursorShapeFilledbox{ "filledBox" }; - static constexpr std::string_view CursorShapeEmptybox{ "emptyBox" }; - static constexpr std::array mappings = { - pair_type{ CursorShapeBar, CursorStyle::Bar }, - pair_type{ CursorShapeVintage, CursorStyle::Vintage }, - pair_type{ CursorShapeUnderscore, CursorStyle::Underscore }, - pair_type{ CursorShapeFilledbox, CursorStyle::FilledBox }, - pair_type{ CursorShapeEmptybox, CursorStyle::EmptyBox } + pair_type{ "bar", CursorStyle::Bar }, + pair_type{ "vintage", CursorStyle::Vintage }, + pair_type{ "underscore", CursorStyle::Underscore }, + pair_type{ "filledBox", CursorStyle::FilledBox }, + pair_type{ "emptyBox", CursorStyle::EmptyBox } }; }; JSON_ENUM_MAPPER(Media::Stretch) { - // Possible values for Image Stretch Mode - static constexpr std::string_view ImageStretchModeNone{ "none" }; - static constexpr std::string_view ImageStretchModeFill{ "fill" }; - static constexpr std::string_view ImageStretchModeUniform{ "uniform" }; - static constexpr std::string_view ImageStretchModeUniformToFill{ "uniformToFill" }; - static constexpr std::array mappings = { - pair_type{ ImageStretchModeUniformToFill, Media::Stretch::UniformToFill }, - pair_type{ ImageStretchModeNone, Media::Stretch::None }, - pair_type{ ImageStretchModeFill, Media::Stretch::Fill }, - pair_type{ ImageStretchModeUniform, Media::Stretch::Uniform } + pair_type{ "uniformToFill", Media::Stretch::UniformToFill }, + pair_type{ "none", Media::Stretch::None }, + pair_type{ "fill", Media::Stretch::Fill }, + pair_type{ "uniform", Media::Stretch::Uniform } }; }; JSON_ENUM_MAPPER(ScrollbarState) { - // Possible values for Scrollbar state - static constexpr std::string_view AlwaysVisible{ "visible" }; - static constexpr std::string_view AlwaysHide{ "hidden" }; - static constexpr std::array mappings = { - pair_type{ AlwaysVisible, ScrollbarState::Visible }, - pair_type{ AlwaysHide, ScrollbarState::Hidden } + pair_type{ "visible", ScrollbarState::Visible }, + pair_type{ "hidden", ScrollbarState::Hidden } }; }; JSON_ENUM_MAPPER(std::tuple) { - // Possible values for Image Alignment - static constexpr std::string_view ImageAlignmentCenter{ "center" }; - static constexpr std::string_view ImageAlignmentLeft{ "left" }; - static constexpr std::string_view ImageAlignmentTop{ "top" }; - static constexpr std::string_view ImageAlignmentRight{ "right" }; - static constexpr std::string_view ImageAlignmentBottom{ "bottom" }; - static constexpr std::string_view ImageAlignmentTopLeft{ "topLeft" }; - static constexpr std::string_view ImageAlignmentTopRight{ "topRight" }; - static constexpr std::string_view ImageAlignmentBottomLeft{ "bottomLeft" }; - static constexpr std::string_view ImageAlignmentBottomRight{ "bottomRight" }; - static constexpr std::array mappings = { - pair_type{ ImageAlignmentCenter, std::make_tuple(HorizontalAlignment::Center, VerticalAlignment::Center) }, - pair_type{ ImageAlignmentTopLeft, std::make_tuple(HorizontalAlignment::Left, VerticalAlignment::Top) }, - pair_type{ ImageAlignmentBottomLeft, std::make_tuple(HorizontalAlignment::Left, VerticalAlignment::Bottom) }, - pair_type{ ImageAlignmentLeft, std::make_tuple(HorizontalAlignment::Left, VerticalAlignment::Center) }, - pair_type{ ImageAlignmentTopRight, std::make_tuple(HorizontalAlignment::Right, VerticalAlignment::Top) }, - pair_type{ ImageAlignmentBottomRight, std::make_tuple(HorizontalAlignment::Right, VerticalAlignment::Bottom) }, - pair_type{ ImageAlignmentRight, std::make_tuple(HorizontalAlignment::Right, VerticalAlignment::Center) }, - pair_type{ ImageAlignmentTop, std::make_tuple(HorizontalAlignment::Center, VerticalAlignment::Top) }, - pair_type{ ImageAlignmentBottom, std::make_tuple(HorizontalAlignment::Center, VerticalAlignment::Bottom) } + pair_type{ "center", std::make_tuple(HorizontalAlignment::Center, VerticalAlignment::Center) }, + pair_type{ "topLeft", std::make_tuple(HorizontalAlignment::Left, VerticalAlignment::Top) }, + pair_type{ "bottomLeft", std::make_tuple(HorizontalAlignment::Left, VerticalAlignment::Bottom) }, + pair_type{ "left", std::make_tuple(HorizontalAlignment::Left, VerticalAlignment::Center) }, + pair_type{ "topRight", std::make_tuple(HorizontalAlignment::Right, VerticalAlignment::Top) }, + pair_type{ "bottomRight", std::make_tuple(HorizontalAlignment::Right, VerticalAlignment::Bottom) }, + pair_type{ "right", std::make_tuple(HorizontalAlignment::Right, VerticalAlignment::Center) }, + pair_type{ "top", std::make_tuple(HorizontalAlignment::Center, VerticalAlignment::Top) }, + pair_type{ "bottom", std::make_tuple(HorizontalAlignment::Center, VerticalAlignment::Bottom) } }; }; JSON_ENUM_MAPPER(TextAntialiasingMode) { - // Possible values for TextAntialiasingMode - static constexpr std::string_view AntialiasingModeGrayscale{ "grayscale" }; - static constexpr std::string_view AntialiasingModeCleartype{ "cleartype" }; - static constexpr std::string_view AntialiasingModeAliased{ "aliased" }; - static constexpr std::array mappings = { - pair_type{ AntialiasingModeGrayscale, TextAntialiasingMode::Grayscale }, - pair_type{ AntialiasingModeCleartype, TextAntialiasingMode::Cleartype }, - pair_type{ AntialiasingModeAliased, TextAntialiasingMode::Aliased } + pair_type{ "grayscale", TextAntialiasingMode::Grayscale }, + pair_type{ "cleartype", TextAntialiasingMode::Cleartype }, + pair_type{ "aliased", TextAntialiasingMode::Aliased } }; }; @@ -93,15 +60,10 @@ JSON_ENUM_MAPPER(TextAntialiasingMode) // - The corresponding enum value which maps to the string provided by the user JSON_ENUM_MAPPER(CloseOnExitMode) { - // Possible values for closeOnExit - static constexpr std::string_view CloseOnExitAlways{ "always" }; - static constexpr std::string_view CloseOnExitGraceful{ "graceful" }; - static constexpr std::string_view CloseOnExitNever{ "never" }; - JSON_MAPPINGS(3) = { - pair_type{ CloseOnExitAlways, CloseOnExitMode::Always }, - pair_type{ CloseOnExitGraceful, CloseOnExitMode::Graceful }, - pair_type{ CloseOnExitNever, CloseOnExitMode::Never }, + pair_type{ "always", CloseOnExitMode::Always }, + pair_type{ "graceful", CloseOnExitMode::Graceful }, + pair_type{ "never", CloseOnExitMode::Never }, }; // Override mapping parser to add boolean parsing @@ -120,36 +82,26 @@ JSON_ENUM_MAPPER(CloseOnExitMode) } }; +// This specialization isn't using JSON_ENUM_MAPPER because we need to have a different +// value type (unsinged int) and return type (FontWeight struct). JSON_ENUM_MAPPER +// expects that the value type _is_ the return type. template<> struct JsonUtils::ConversionTrait : public JsonUtils::EnumMapper> { - // Possible values for Font Weight - static constexpr std::string_view FontWeightThin{ "thin" }; - static constexpr std::string_view FontWeightExtraLight{ "extra-light" }; - static constexpr std::string_view FontWeightLight{ "light" }; - static constexpr std::string_view FontWeightSemiLight{ "semi-light" }; - static constexpr std::string_view FontWeightNormal{ "normal" }; - static constexpr std::string_view FontWeightMedium{ "medium" }; - static constexpr std::string_view FontWeightSemiBold{ "semi-bold" }; - static constexpr std::string_view FontWeightBold{ "bold" }; - static constexpr std::string_view FontWeightExtraBold{ "extra-bold" }; - static constexpr std::string_view FontWeightBlack{ "black" }; - static constexpr std::string_view FontWeightExtraBlack{ "extra-black" }; - // The original parser used the font weight getters Bold(), Normal(), etc. // They were both ugly and *not constant expressions* JSON_MAPPINGS(11) = { - pair_type{ FontWeightThin, 100u }, - pair_type{ FontWeightExtraLight, 200u }, - pair_type{ FontWeightLight, 300u }, - pair_type{ FontWeightSemiLight, 350u }, - pair_type{ FontWeightNormal, 400u }, - pair_type{ FontWeightMedium, 500u }, - pair_type{ FontWeightSemiBold, 600u }, - pair_type{ FontWeightBold, 700u }, - pair_type{ FontWeightExtraBold, 800u }, - pair_type{ FontWeightBlack, 900u }, - pair_type{ FontWeightExtraBlack, 950u }, + pair_type{ "thin", 100u }, + pair_type{ "extra-light", 200u }, + pair_type{ "light", 300u }, + pair_type{ "semi-light", 350u }, + pair_type{ "normal", 400u }, + pair_type{ "medium", 500u }, + pair_type{ "semi-bold", 600u }, + pair_type{ "bold", 700u }, + pair_type{ "extra-bold", 800u }, + pair_type{ "black", 900u }, + pair_type{ "extra-black", 950u }, }; // Override mapping parser to add boolean parsing @@ -162,7 +114,7 @@ struct JsonUtils::ConversionTrait : public } else { - value = EnumMapper::FromJson(json); + value = BaseEnumMapper::FromJson(json); } winrt::Windows::UI::Text::FontWeight weight{ @@ -173,6 +125,6 @@ struct JsonUtils::ConversionTrait : public bool CanConvert(const Json::Value& json) { - return EnumMapper::CanConvert(json) || json.isUInt(); + return BaseEnumMapper::CanConvert(json) || json.isUInt(); } }; From 627ede22ee0487b431d4790dc4ea60d1d3fb98ce Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Tue, 14 Jul 2020 01:11:27 -0700 Subject: [PATCH 15/25] Add TermSettingsSerHelpers, move all settings traits into it Move all settings types out of globalapp/profile into SettingsTypes. **EVENTUALLY** they will become exported types from the Terminal Settings Model library. This is a temporary stopgap. I added a ValueType convenience helper to EnumMapper so you don't have to repeat a really obscenely long fully-qualified namespace name for every mapped value. --- .../TerminalApp/GlobalAppSettings.cpp | 103 +------- src/cascadia/TerminalApp/GlobalAppSettings.h | 7 +- src/cascadia/TerminalApp/JsonUtilsNew.h | 1 + src/cascadia/TerminalApp/Profile.cpp | 3 +- src/cascadia/TerminalApp/Profile.h | 10 +- .../TerminalApp/ProfileConversionTraits.cpp | 130 --------- src/cascadia/TerminalApp/SettingsTypes.h | 28 ++ .../TerminalSettingsSerializationHelpers.h | 246 ++++++++++++++++++ 8 files changed, 280 insertions(+), 248 deletions(-) delete mode 100644 src/cascadia/TerminalApp/ProfileConversionTraits.cpp create mode 100644 src/cascadia/TerminalApp/SettingsTypes.h create mode 100644 src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h diff --git a/src/cascadia/TerminalApp/GlobalAppSettings.cpp b/src/cascadia/TerminalApp/GlobalAppSettings.cpp index fd350356664..95752d3928e 100644 --- a/src/cascadia/TerminalApp/GlobalAppSettings.cpp +++ b/src/cascadia/TerminalApp/GlobalAppSettings.cpp @@ -7,11 +7,11 @@ #include "../../inc/DefaultSettings.h" #include "Utils.h" #include "JsonUtils.h" +#include "TerminalSettingsSerializationHelpers.h" using namespace TerminalApp; using namespace winrt::Microsoft::Terminal::Settings; using namespace winrt::TerminalApp; -using namespace winrt::Windows::Data::Json; using namespace winrt::Windows::UI::Xaml; using namespace ::Microsoft::Console; using namespace winrt::Microsoft::UI::Xaml::Controls; @@ -43,54 +43,12 @@ static constexpr std::string_view ForceFullRepaintRenderingKey{ "experimental.re static constexpr std::string_view SoftwareRenderingKey{ "experimental.rendering.software" }; static constexpr std::string_view ForceVTInputKey{ "experimental.input.forceVT" }; -// Launch mode values -static constexpr std::string_view DefaultLaunchModeValue{ "default" }; -static constexpr std::string_view MaximizedLaunchModeValue{ "maximized" }; -static constexpr std::string_view FullscreenLaunchModeValue{ "fullscreen" }; - -// Tab Width Mode values -static constexpr std::string_view EqualTabWidthModeValue{ "equal" }; -static constexpr std::string_view TitleLengthTabWidthModeValue{ "titleLength" }; -static constexpr std::string_view TitleLengthCompactModeValue{ "compact" }; - -// Theme values -static constexpr std::string_view LightThemeValue{ "light" }; -static constexpr std::string_view DarkThemeValue{ "dark" }; -static constexpr std::string_view SystemThemeValue{ "system" }; - #ifdef _DEBUG static constexpr bool debugFeaturesDefault{ true }; #else static constexpr bool debugFeaturesDefault{ false }; #endif -JSON_ENUM_MAPPER(ElementTheme) -{ - JSON_MAPPINGS(3) = { - pair_type{ SystemThemeValue, ElementTheme::Default }, - pair_type{ LightThemeValue, ElementTheme::Light }, - pair_type{ DarkThemeValue, ElementTheme::Dark }, - }; -}; - -JSON_ENUM_MAPPER(LaunchMode) -{ - JSON_MAPPINGS(3) = { - pair_type{ DefaultLaunchModeValue, LaunchMode::DefaultMode }, - pair_type{ MaximizedLaunchModeValue, LaunchMode::MaximizedMode }, - pair_type{ FullscreenLaunchModeValue, LaunchMode::FullscreenMode }, - }; -}; - -JSON_ENUM_MAPPER(TabViewWidthMode) -{ - JSON_MAPPINGS(3) = { - pair_type{ EqualTabWidthModeValue, TabViewWidthMode::Equal }, - pair_type{ TitleLengthTabWidthModeValue, TabViewWidthMode::SizeToContent }, - pair_type{ TitleLengthCompactModeValue, TabViewWidthMode::Compact }, - }; -}; - GlobalAppSettings::GlobalAppSettings() : _keybindings{ winrt::make_self() }, _keybindingsWarnings{}, @@ -245,65 +203,6 @@ void GlobalAppSettings::LayerJson(const Json::Value& json) parseBindings(BindingsKey); } -// Method Description: -// - Helper function for converting the initial position string into -// 2 coordinate values. We allow users to only provide one coordinate, -// thus, we use comma as the separator: -// (100, 100): standard input string -// (, 100), (100, ): if a value is missing, we set this value as a default -// (,): both x and y are set to default -// (abc, 100): if a value is not valid, we treat it as default -// (100, 100, 100): we only read the first two values, this is equivalent to (100, 100) -// Arguments: -// - initialPosition: the initial position string from json -// initialX: reference to the _initialX member -// initialY: reference to the _initialY member -// Return Value: -// - None -template<> -struct JsonUtils::ConversionTrait -{ - LaunchPosition FromJson(const Json::Value& json) - { - LaunchPosition ret; - std::string initialPosition{ json.asString() }; - static constexpr char singleCharDelim = ','; - std::stringstream tokenStream(initialPosition); - std::string token; - uint8_t initialPosIndex = 0; - - // Get initial position values till we run out of delimiter separated values in the stream - // or we hit max number of allowable values (= 2) - // Non-numeral values or empty string will be caught as exception and we do not assign them - for (; std::getline(tokenStream, token, singleCharDelim) && (initialPosIndex < 2); initialPosIndex++) - { - try - { - int32_t position = std::stoi(token); - if (initialPosIndex == 0) - { - ret.x.emplace(position); - } - - if (initialPosIndex == 1) - { - ret.y.emplace(position); - } - } - catch (...) - { - // Do nothing - } - } - return ret; - } - - bool CanConvert(const Json::Value& json) - { - return json.isString(); - } -}; - // Method Description: // - Adds the given colorscheme to our map of schemes, using its name as the key. // Arguments: diff --git a/src/cascadia/TerminalApp/GlobalAppSettings.h b/src/cascadia/TerminalApp/GlobalAppSettings.h index 0a37c3c19cb..96bea93acb9 100644 --- a/src/cascadia/TerminalApp/GlobalAppSettings.h +++ b/src/cascadia/TerminalApp/GlobalAppSettings.h @@ -17,6 +17,7 @@ Author(s): #include "AppKeyBindings.h" #include "ColorScheme.h" #include "Command.h" +#include "SettingsTypes.h" // fwdecl unittest classes namespace TerminalAppLocalTests @@ -28,12 +29,6 @@ namespace TerminalAppLocalTests namespace TerminalApp { class GlobalAppSettings; - - struct LaunchPosition - { - std::optional x; - std::optional y; - }; }; class TerminalApp::GlobalAppSettings final diff --git a/src/cascadia/TerminalApp/JsonUtilsNew.h b/src/cascadia/TerminalApp/JsonUtilsNew.h index 03e9826f4b2..b98ade1da9d 100644 --- a/src/cascadia/TerminalApp/JsonUtilsNew.h +++ b/src/cascadia/TerminalApp/JsonUtilsNew.h @@ -285,6 +285,7 @@ namespace TerminalApp::JsonUtils struct EnumMapper { using BaseEnumMapper = EnumMapper; + using ValueType = T; using pair_type = std::pair; T FromJson(const Json::Value& json) { diff --git a/src/cascadia/TerminalApp/Profile.cpp b/src/cascadia/TerminalApp/Profile.cpp index 8c6de94e3a4..7cd80a65b11 100644 --- a/src/cascadia/TerminalApp/Profile.cpp +++ b/src/cascadia/TerminalApp/Profile.cpp @@ -9,6 +9,7 @@ #include #include "LegacyProfileGeneratorNamespaces.h" +#include "TerminalSettingsSerializationHelpers.h" using namespace TerminalApp; using namespace winrt::Microsoft::Terminal::Settings; @@ -52,8 +53,6 @@ static constexpr std::string_view BackgroundImageAlignmentKey{ "backgroundImageA static constexpr std::string_view RetroTerminalEffectKey{ "experimental.retroTerminalEffect" }; static constexpr std::string_view AntialiasingModeKey{ "antialiasingMode" }; -#include "ProfileConversionTraits.cpp" - Profile::Profile() : Profile(std::nullopt) { diff --git a/src/cascadia/TerminalApp/Profile.h b/src/cascadia/TerminalApp/Profile.h index dc65f9df3e8..d01d5255d59 100644 --- a/src/cascadia/TerminalApp/Profile.h +++ b/src/cascadia/TerminalApp/Profile.h @@ -15,6 +15,7 @@ Author(s): --*/ #pragma once #include "ColorScheme.h" +#include "SettingsTypes.h" // fwdecl unittest classes namespace TerminalAppLocalTests @@ -35,14 +36,7 @@ constexpr GUID RUNTIME_GENERATED_PROFILE_NAMESPACE_GUID = { 0xf65ddb7e, 0x706b, namespace TerminalApp { class Profile; - - enum class CloseOnExitMode - { - Never = 0, - Graceful, - Always - }; -}; +} class TerminalApp::Profile final { diff --git a/src/cascadia/TerminalApp/ProfileConversionTraits.cpp b/src/cascadia/TerminalApp/ProfileConversionTraits.cpp deleted file mode 100644 index 16c50ddf9fe..00000000000 --- a/src/cascadia/TerminalApp/ProfileConversionTraits.cpp +++ /dev/null @@ -1,130 +0,0 @@ -// Explicit specializations for JSON conversion -JSON_ENUM_MAPPER(CursorStyle) -{ - static constexpr std::array mappings = { - pair_type{ "bar", CursorStyle::Bar }, - pair_type{ "vintage", CursorStyle::Vintage }, - pair_type{ "underscore", CursorStyle::Underscore }, - pair_type{ "filledBox", CursorStyle::FilledBox }, - pair_type{ "emptyBox", CursorStyle::EmptyBox } - }; -}; - -JSON_ENUM_MAPPER(Media::Stretch) -{ - static constexpr std::array mappings = { - pair_type{ "uniformToFill", Media::Stretch::UniformToFill }, - pair_type{ "none", Media::Stretch::None }, - pair_type{ "fill", Media::Stretch::Fill }, - pair_type{ "uniform", Media::Stretch::Uniform } - }; -}; - -JSON_ENUM_MAPPER(ScrollbarState) -{ - static constexpr std::array mappings = { - pair_type{ "visible", ScrollbarState::Visible }, - pair_type{ "hidden", ScrollbarState::Hidden } - }; -}; - -JSON_ENUM_MAPPER(std::tuple) -{ - static constexpr std::array mappings = { - pair_type{ "center", std::make_tuple(HorizontalAlignment::Center, VerticalAlignment::Center) }, - pair_type{ "topLeft", std::make_tuple(HorizontalAlignment::Left, VerticalAlignment::Top) }, - pair_type{ "bottomLeft", std::make_tuple(HorizontalAlignment::Left, VerticalAlignment::Bottom) }, - pair_type{ "left", std::make_tuple(HorizontalAlignment::Left, VerticalAlignment::Center) }, - pair_type{ "topRight", std::make_tuple(HorizontalAlignment::Right, VerticalAlignment::Top) }, - pair_type{ "bottomRight", std::make_tuple(HorizontalAlignment::Right, VerticalAlignment::Bottom) }, - pair_type{ "right", std::make_tuple(HorizontalAlignment::Right, VerticalAlignment::Center) }, - pair_type{ "top", std::make_tuple(HorizontalAlignment::Center, VerticalAlignment::Top) }, - pair_type{ "bottom", std::make_tuple(HorizontalAlignment::Center, VerticalAlignment::Bottom) } - }; -}; - -JSON_ENUM_MAPPER(TextAntialiasingMode) -{ - static constexpr std::array mappings = { - pair_type{ "grayscale", TextAntialiasingMode::Grayscale }, - pair_type{ "cleartype", TextAntialiasingMode::Cleartype }, - pair_type{ "aliased", TextAntialiasingMode::Aliased } - }; -}; - -// Method Description: -// - Helper function for converting a user-specified closeOnExit value to its corresponding enum -// Arguments: -// - The value from the profiles.json file -// Return Value: -// - The corresponding enum value which maps to the string provided by the user -JSON_ENUM_MAPPER(CloseOnExitMode) -{ - JSON_MAPPINGS(3) = { - pair_type{ "always", CloseOnExitMode::Always }, - pair_type{ "graceful", CloseOnExitMode::Graceful }, - pair_type{ "never", CloseOnExitMode::Never }, - }; - - // Override mapping parser to add boolean parsing - CloseOnExitMode FromJson(const Json::Value& json) - { - if (json.isBool()) - { - return json.asBool() ? CloseOnExitMode::Graceful : CloseOnExitMode::Never; - } - return EnumMapper::FromJson(json); - } - - bool CanConvert(const Json::Value& json) - { - return EnumMapper::CanConvert(json) || json.isBool(); - } -}; - -// This specialization isn't using JSON_ENUM_MAPPER because we need to have a different -// value type (unsinged int) and return type (FontWeight struct). JSON_ENUM_MAPPER -// expects that the value type _is_ the return type. -template<> -struct JsonUtils::ConversionTrait : public JsonUtils::EnumMapper> -{ - // The original parser used the font weight getters Bold(), Normal(), etc. - // They were both ugly and *not constant expressions* - JSON_MAPPINGS(11) = { - pair_type{ "thin", 100u }, - pair_type{ "extra-light", 200u }, - pair_type{ "light", 300u }, - pair_type{ "semi-light", 350u }, - pair_type{ "normal", 400u }, - pair_type{ "medium", 500u }, - pair_type{ "semi-bold", 600u }, - pair_type{ "bold", 700u }, - pair_type{ "extra-bold", 800u }, - pair_type{ "black", 900u }, - pair_type{ "extra-black", 950u }, - }; - - // Override mapping parser to add boolean parsing - auto FromJson(const Json::Value& json) - { - unsigned int value{ 400 }; - if (json.isUInt()) - { - value = json.asUInt(); - } - else - { - value = BaseEnumMapper::FromJson(json); - } - - winrt::Windows::UI::Text::FontWeight weight{ - static_cast(std::clamp(value, 100u, 990u)) - }; - return weight; - } - - bool CanConvert(const Json::Value& json) - { - return BaseEnumMapper::CanConvert(json) || json.isUInt(); - } -}; diff --git a/src/cascadia/TerminalApp/SettingsTypes.h b/src/cascadia/TerminalApp/SettingsTypes.h new file mode 100644 index 00000000000..66903ab41a4 --- /dev/null +++ b/src/cascadia/TerminalApp/SettingsTypes.h @@ -0,0 +1,28 @@ +/*++ +Copyright (c) Microsoft Corporation +Licensed under the MIT license. + +Module Name: +- SettingsTypes.h + +Abstract: +- Types used in the settings model (non-exported) +--*/ + +#pragma once + +namespace TerminalApp +{ + enum class CloseOnExitMode + { + Never = 0, + Graceful, + Always + }; + + struct LaunchPosition + { + std::optional x; + std::optional y; + }; +}; diff --git a/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h b/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h new file mode 100644 index 00000000000..90098c1e12c --- /dev/null +++ b/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h @@ -0,0 +1,246 @@ +/*++ +Copyright (c) Microsoft Corporation +Licensed under the MIT license. + +Module Name: +- TerminalSettingsSerializationHelpers.h + +Abstract: +- Specializations of the JsonUtils helpers for things that might end up in a + settings document. + +--*/ + +#pragma once + +#include "pch.h" + +#include "JsonUtils.h" +#include "SettingsTypes.h" + +#include +#include + +// Explicit specializations for JSON conversion +JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::CursorStyle) +{ + static constexpr std::array mappings = { + pair_type{ "bar", ValueType::Bar }, + pair_type{ "vintage", ValueType::Vintage }, + pair_type{ "underscore", ValueType::Underscore }, + pair_type{ "filledBox", ValueType::FilledBox }, + pair_type{ "emptyBox", ValueType::EmptyBox } + }; +}; + +JSON_ENUM_MAPPER(::winrt::Windows::UI::Xaml::Media::Stretch) +{ + static constexpr std::array mappings = { + pair_type{ "uniformToFill", ValueType::UniformToFill }, + pair_type{ "none", ValueType::None }, + pair_type{ "fill", ValueType::Fill }, + pair_type{ "uniform", ValueType::Uniform } + }; +}; + +JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::ScrollbarState) +{ + static constexpr std::array mappings = { + pair_type{ "visible", ValueType::Visible }, + pair_type{ "hidden", ValueType::Hidden } + }; +}; + +JSON_ENUM_MAPPER(std::tuple<::winrt::Windows::UI::Xaml::HorizontalAlignment, ::winrt::Windows::UI::Xaml::VerticalAlignment>) +{ + // reduce repetition + using HA = ::winrt::Windows::UI::Xaml::HorizontalAlignment; + using VA = ::winrt::Windows::UI::Xaml::VerticalAlignment; + static constexpr std::array mappings = { + pair_type{ "center", std::make_tuple(HA::Center, VA::Center) }, + pair_type{ "topLeft", std::make_tuple(HA::Left, VA::Top) }, + pair_type{ "bottomLeft", std::make_tuple(HA::Left, VA::Bottom) }, + pair_type{ "left", std::make_tuple(HA::Left, VA::Center) }, + pair_type{ "topRight", std::make_tuple(HA::Right, VA::Top) }, + pair_type{ "bottomRight", std::make_tuple(HA::Right, VA::Bottom) }, + pair_type{ "right", std::make_tuple(HA::Right, VA::Center) }, + pair_type{ "top", std::make_tuple(HA::Center, VA::Top) }, + pair_type{ "bottom", std::make_tuple(HA::Center, VA::Bottom) } + }; +}; + +JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::TextAntialiasingMode) +{ + static constexpr std::array mappings = { + pair_type{ "grayscale", ValueType::Grayscale }, + pair_type{ "cleartype", ValueType::Cleartype }, + pair_type{ "aliased", ValueType::Aliased } + }; +}; + +// Method Description: +// - Helper function for converting a user-specified closeOnExit value to its corresponding enum +// Arguments: +// - The value from the profiles.json file +// Return Value: +// - The corresponding enum value which maps to the string provided by the user +JSON_ENUM_MAPPER(::TerminalApp::CloseOnExitMode) +{ + JSON_MAPPINGS(3) = { + pair_type{ "always", ValueType::Always }, + pair_type{ "graceful", ValueType::Graceful }, + pair_type{ "never", ValueType::Never }, + }; + + // Override mapping parser to add boolean parsing + CloseOnExitMode FromJson(const Json::Value& json) + { + if (json.isBool()) + { + return json.asBool() ? ValueType::Graceful : ValueType::Never; + } + return EnumMapper::FromJson(json); + } + + bool CanConvert(const Json::Value& json) + { + return EnumMapper::CanConvert(json) || json.isBool(); + } +}; + +// This specialization isn't using JSON_ENUM_MAPPER because we need to have a different +// value type (unsinged int) and return type (FontWeight struct). JSON_ENUM_MAPPER +// expects that the value type _is_ the return type. +template<> +struct ::TerminalApp::JsonUtils::ConversionTrait<::winrt::Windows::UI::Text::FontWeight> : + public ::TerminalApp::JsonUtils::EnumMapper< + unsigned int, + ::TerminalApp::JsonUtils::ConversionTrait<::winrt::Windows::UI::Text::FontWeight>> +{ + // The original parser used the font weight getters Bold(), Normal(), etc. + // They were both cumbersome and *not constant expressions* + JSON_MAPPINGS(11) = { + pair_type{ "thin", 100u }, + pair_type{ "extra-light", 200u }, + pair_type{ "light", 300u }, + pair_type{ "semi-light", 350u }, + pair_type{ "normal", 400u }, + pair_type{ "medium", 500u }, + pair_type{ "semi-bold", 600u }, + pair_type{ "bold", 700u }, + pair_type{ "extra-bold", 800u }, + pair_type{ "black", 900u }, + pair_type{ "extra-black", 950u }, + }; + + // Override mapping parser to add boolean parsing + auto FromJson(const Json::Value& json) + { + unsigned int value{ 400 }; + if (json.isUInt()) + { + value = json.asUInt(); + } + else + { + value = BaseEnumMapper::FromJson(json); + } + + ::winrt::Windows::UI::Text::FontWeight weight{ + static_cast(std::clamp(value, 100u, 990u)) + }; + return weight; + } + + bool CanConvert(const Json::Value& json) + { + return BaseEnumMapper::CanConvert(json) || json.isUInt(); + } +}; + +JSON_ENUM_MAPPER(::winrt::Windows::UI::Xaml::ElementTheme) +{ + JSON_MAPPINGS(3) = { + pair_type{ "system", ValueType::Default }, + pair_type{ "light", ValueType::Light }, + pair_type{ "dark", ValueType::Dark }, + }; +}; + +JSON_ENUM_MAPPER(::winrt::TerminalApp::LaunchMode) +{ + JSON_MAPPINGS(3) = { + pair_type{ "default", ValueType::DefaultMode }, + pair_type{ "maximized", ValueType::MaximizedMode }, + pair_type{ "fullscreen", ValueType::FullscreenMode }, + }; +}; + +JSON_ENUM_MAPPER(::winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode) +{ + JSON_MAPPINGS(3) = { + pair_type{ "equal", ValueType::Equal }, + pair_type{ "titleLength", ValueType::SizeToContent }, + pair_type{ "compact", ValueType::Compact }, + }; +}; + +// Type Description: +// - Helper for converting the initial position string into +// 2 coordinate values. We allow users to only provide one coordinate, +// thus, we use comma as the separator: +// (100, 100): standard input string +// (, 100), (100, ): if a value is missing, we set this value as a default +// (,): both x and y are set to default +// (abc, 100): if a value is not valid, we treat it as default +// (100, 100, 100): we only read the first two values, this is equivalent to (100, 100) +// Arguments: +// - initialPosition: the initial position string from json +// initialX: reference to the _initialX member +// initialY: reference to the _initialY member +// Return Value: +// - None +template<> +struct JsonUtils::ConversionTrait +{ + LaunchPosition FromJson(const Json::Value& json) + { + LaunchPosition ret; + std::string initialPosition{ json.asString() }; + static constexpr char singleCharDelim = ','; + std::stringstream tokenStream(initialPosition); + std::string token; + uint8_t initialPosIndex = 0; + + // Get initial position values till we run out of delimiter separated values in the stream + // or we hit max number of allowable values (= 2) + // Non-numeral values or empty string will be caught as exception and we do not assign them + for (; std::getline(tokenStream, token, singleCharDelim) && (initialPosIndex < 2); initialPosIndex++) + { + try + { + int32_t position = std::stoi(token); + if (initialPosIndex == 0) + { + ret.x.emplace(position); + } + + if (initialPosIndex == 1) + { + ret.y.emplace(position); + } + } + catch (...) + { + // Do nothing + } + } + return ret; + } + + bool CanConvert(const Json::Value& json) + { + return json.isString(); + } +}; + From 05b31a6ae39a36e5f58517d858d05ce4c7bb9cc0 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Tue, 14 Jul 2020 01:15:28 -0700 Subject: [PATCH 16/25] remove dead line --- src/cascadia/TerminalApp/Profile.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/cascadia/TerminalApp/Profile.h b/src/cascadia/TerminalApp/Profile.h index d01d5255d59..17edad98bb6 100644 --- a/src/cascadia/TerminalApp/Profile.h +++ b/src/cascadia/TerminalApp/Profile.h @@ -101,8 +101,6 @@ class TerminalApp::Profile final private: static std::wstring EvaluateStartingDirectory(const std::wstring& directory); - static winrt::Windows::UI::Text::FontWeight _ParseFontWeight(const Json::Value& json); - static GUID _GenerateGuidForProfile(const std::wstring& name, const std::optional& source) noexcept; std::optional _guid{ std::nullopt }; From 5d1fd5a6e637d9e52c7b23d351916190d2804962 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Tue, 14 Jul 2020 01:19:33 -0700 Subject: [PATCH 17/25] code format --- src/cascadia/TerminalApp/ActionArgs.h | 2 +- src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cascadia/TerminalApp/ActionArgs.h b/src/cascadia/TerminalApp/ActionArgs.h index fa3a267a979..cfad15152be 100644 --- a/src/cascadia/TerminalApp/ActionArgs.h +++ b/src/cascadia/TerminalApp/ActionArgs.h @@ -405,7 +405,7 @@ namespace winrt::TerminalApp::implementation { // LOAD BEARING: Not using make_self here _will_ break you in the future! auto args = winrt::make_self(); - if (const auto temp{ JsonUtils::GetValueForKey>(json, ColorKey) }) + if (const auto temp{ JsonUtils::GetValueForKey>(json, ColorKey) }) { args->_TabColor = static_cast(*temp); } diff --git a/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h b/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h index 90098c1e12c..ec752a5555e 100644 --- a/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h +++ b/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h @@ -243,4 +243,3 @@ struct JsonUtils::ConversionTrait return json.isString(); } }; - From 5dbe10446da202e7c209042ae88149cd0eb248b8 Mon Sep 17 00:00:00 2001 From: Dustin Howett Date: Tue, 14 Jul 2020 11:39:34 -0700 Subject: [PATCH 18/25] move strings/actargs helpers --- src/cascadia/TerminalApp/ActionArgs.h | 57 +------------------ .../TerminalSettingsSerializationHelpers.h | 39 +++++++++++++ .../TerminalApp/lib/TerminalAppLib.vcxproj | 1 + .../lib/TerminalAppLib.vcxproj.filters | 3 + 4 files changed, 45 insertions(+), 55 deletions(-) diff --git a/src/cascadia/TerminalApp/ActionArgs.h b/src/cascadia/TerminalApp/ActionArgs.h index cfad15152be..93e2b5baf3e 100644 --- a/src/cascadia/TerminalApp/ActionArgs.h +++ b/src/cascadia/TerminalApp/ActionArgs.h @@ -23,67 +23,14 @@ #include "JsonUtils.h" #include "TerminalWarnings.h" +#include "TerminalSettingsSerializationHelpers.h" + // Notes on defining ActionArgs and ActionEventArgs: // * All properties specific to an action should be defined as an ActionArgs // class that implements IActionArgs // * ActionEventArgs holds a single IActionArgs. For events that don't need // additional args, this can be nullptr. -// Possible Direction values -// TODO:GH#2550/#3475 - move these to a centralized deserializing place -JSON_ENUM_MAPPER(::winrt::TerminalApp::Direction) -{ - static constexpr std::string_view LeftString{ "left" }; - static constexpr std::string_view RightString{ "right" }; - static constexpr std::string_view UpString{ "up" }; - static constexpr std::string_view DownString{ "down" }; - - JSON_MAPPINGS(4) = { - pair_type{ LeftString, ::winrt::TerminalApp::Direction::Left }, - pair_type{ RightString, ::winrt::TerminalApp::Direction::Right }, - pair_type{ UpString, ::winrt::TerminalApp::Direction::Up }, - pair_type{ DownString, ::winrt::TerminalApp::Direction::Down }, - }; -}; - -// Possible SplitState values -// TODO:GH#2550/#3475 - move these to a centralized deserializing place -JSON_ENUM_MAPPER(::winrt::TerminalApp::SplitState) -{ - static constexpr std::string_view VerticalKey{ "vertical" }; - static constexpr std::string_view HorizontalKey{ "horizontal" }; - static constexpr std::string_view AutomaticKey{ "auto" }; - - JSON_MAPPINGS(3) = { - pair_type{ VerticalKey, ::winrt::TerminalApp::SplitState::Vertical }, - pair_type{ HorizontalKey, ::winrt::TerminalApp::SplitState::Horizontal }, - pair_type{ AutomaticKey, ::winrt::TerminalApp::SplitState::Automatic }, - }; -}; - -// Possible SplitType values -JSON_ENUM_MAPPER(::winrt::TerminalApp::SplitType) -{ - static constexpr std::string_view DuplicateKey{ "duplicate" }; - JSON_MAPPINGS(1) = { - pair_type{ DuplicateKey, ::winrt::TerminalApp::SplitType::Duplicate }, - }; -}; - -JSON_ENUM_MAPPER(::winrt::TerminalApp::SettingsTarget) -{ - // Possible SettingsTarget values - static constexpr std::string_view SettingsFileString{ "settingsFile" }; - static constexpr std::string_view DefaultsFileString{ "defaultsFile" }; - static constexpr std::string_view AllFilesString{ "allFiles" }; - - JSON_MAPPINGS(3) = { - pair_type{ SettingsFileString, ::winrt::TerminalApp::SettingsTarget::SettingsFile }, - pair_type{ DefaultsFileString, ::winrt::TerminalApp::SettingsTarget::DefaultsFile }, - pair_type{ AllFilesString, ::winrt::TerminalApp::SettingsTarget::AllFiles }, - }; -}; - namespace winrt::TerminalApp::implementation { using namespace ::TerminalApp; diff --git a/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h b/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h index ec752a5555e..db1f46f9453 100644 --- a/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h +++ b/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h @@ -243,3 +243,42 @@ struct JsonUtils::ConversionTrait return json.isString(); } }; + +// Possible Direction values +JSON_ENUM_MAPPER(::winrt::TerminalApp::Direction) +{ + JSON_MAPPINGS(4) = { + pair_type{ "left", ::winrt::TerminalApp::Direction::Left }, + pair_type{ "right", ::winrt::TerminalApp::Direction::Right }, + pair_type{ "up", ::winrt::TerminalApp::Direction::Up }, + pair_type{ "down", ::winrt::TerminalApp::Direction::Down }, + }; +}; + +// Possible SplitState values +JSON_ENUM_MAPPER(::winrt::TerminalApp::SplitState) +{ + JSON_MAPPINGS(3) = { + pair_type{ "vertical", ::winrt::TerminalApp::SplitState::Vertical }, + pair_type{ "horizontal", ::winrt::TerminalApp::SplitState::Horizontal }, + pair_type{ "auto", ::winrt::TerminalApp::SplitState::Automatic }, + }; +}; + +// Possible SplitType values +JSON_ENUM_MAPPER(::winrt::TerminalApp::SplitType) +{ + JSON_MAPPINGS(1) = { + pair_type{ "duplicate", ::winrt::TerminalApp::SplitType::Duplicate }, + }; +}; + +JSON_ENUM_MAPPER(::winrt::TerminalApp::SettingsTarget) +{ + JSON_MAPPINGS(3) = { + pair_type{ "settingsFile", ::winrt::TerminalApp::SettingsTarget::SettingsFile }, + pair_type{ "defaultsFile", ::winrt::TerminalApp::SettingsTarget::DefaultsFile }, + pair_type{ "allFiles", ::winrt::TerminalApp::SettingsTarget::AllFiles }, + }; +}; + diff --git a/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj b/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj index 590b0a38e61..0fb6b823c4c 100644 --- a/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj +++ b/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj @@ -109,6 +109,7 @@ + diff --git a/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj.filters b/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj.filters index 74e7e505943..d716860a4af 100644 --- a/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj.filters +++ b/src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj.filters @@ -88,6 +88,9 @@ settings + + settings + settings From d040df4a765320e394f86ab7c51734df0500fc22 Mon Sep 17 00:00:00 2001 From: Dustin Howett Date: Tue, 14 Jul 2020 11:44:35 -0700 Subject: [PATCH 19/25] fode cormat --- src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h b/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h index db1f46f9453..488efdd2b4e 100644 --- a/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h +++ b/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h @@ -281,4 +281,3 @@ JSON_ENUM_MAPPER(::winrt::TerminalApp::SettingsTarget) pair_type{ "allFiles", ::winrt::TerminalApp::SettingsTarget::AllFiles }, }; }; - From 59e54d1239ca2d77be53780d5d19b4af7a3e4e58 Mon Sep 17 00:00:00 2001 From: Dustin Howett Date: Tue, 14 Jul 2020 11:58:33 -0700 Subject: [PATCH 20/25] clean --- .../TerminalSettingsSerializationHelpers.h | 43 +++++++------------ 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h b/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h index 488efdd2b4e..9b399563e57 100644 --- a/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h +++ b/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h @@ -21,7 +21,6 @@ Module Name: #include #include -// Explicit specializations for JSON conversion JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::CursorStyle) { static constexpr std::array mappings = { @@ -78,12 +77,8 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::TextAntialiasingMode) }; }; -// Method Description: -// - Helper function for converting a user-specified closeOnExit value to its corresponding enum -// Arguments: -// - The value from the profiles.json file -// Return Value: -// - The corresponding enum value which maps to the string provided by the user +// Type Description: +// - Helper for converting a user-specified closeOnExit value to its corresponding enum JSON_ENUM_MAPPER(::TerminalApp::CloseOnExitMode) { JSON_MAPPINGS(3) = { @@ -194,18 +189,12 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode) // (,): both x and y are set to default // (abc, 100): if a value is not valid, we treat it as default // (100, 100, 100): we only read the first two values, this is equivalent to (100, 100) -// Arguments: -// - initialPosition: the initial position string from json -// initialX: reference to the _initialX member -// initialY: reference to the _initialY member -// Return Value: -// - None template<> -struct JsonUtils::ConversionTrait +struct ::TerminalApp::JsonUtils::ConversionTrait<::TerminalApp::LaunchPosition> { - LaunchPosition FromJson(const Json::Value& json) + ::TerminalApp::LaunchPosition FromJson(const Json::Value& json) { - LaunchPosition ret; + ::TerminalApp::LaunchPosition ret; std::string initialPosition{ json.asString() }; static constexpr char singleCharDelim = ','; std::stringstream tokenStream(initialPosition); @@ -248,10 +237,10 @@ struct JsonUtils::ConversionTrait JSON_ENUM_MAPPER(::winrt::TerminalApp::Direction) { JSON_MAPPINGS(4) = { - pair_type{ "left", ::winrt::TerminalApp::Direction::Left }, - pair_type{ "right", ::winrt::TerminalApp::Direction::Right }, - pair_type{ "up", ::winrt::TerminalApp::Direction::Up }, - pair_type{ "down", ::winrt::TerminalApp::Direction::Down }, + pair_type{ "left", TargetType::Left }, + pair_type{ "right", TargetType::Right }, + pair_type{ "up", TargetType::Up }, + pair_type{ "down", TargetType::Down }, }; }; @@ -259,9 +248,9 @@ JSON_ENUM_MAPPER(::winrt::TerminalApp::Direction) JSON_ENUM_MAPPER(::winrt::TerminalApp::SplitState) { JSON_MAPPINGS(3) = { - pair_type{ "vertical", ::winrt::TerminalApp::SplitState::Vertical }, - pair_type{ "horizontal", ::winrt::TerminalApp::SplitState::Horizontal }, - pair_type{ "auto", ::winrt::TerminalApp::SplitState::Automatic }, + pair_type{ "vertical", TargetType::Vertical }, + pair_type{ "horizontal", TargetType::Horizontal }, + pair_type{ "auto", TargetType::Automatic }, }; }; @@ -269,15 +258,15 @@ JSON_ENUM_MAPPER(::winrt::TerminalApp::SplitState) JSON_ENUM_MAPPER(::winrt::TerminalApp::SplitType) { JSON_MAPPINGS(1) = { - pair_type{ "duplicate", ::winrt::TerminalApp::SplitType::Duplicate }, + pair_type{ "duplicate", TargetType::Duplicate }, }; }; JSON_ENUM_MAPPER(::winrt::TerminalApp::SettingsTarget) { JSON_MAPPINGS(3) = { - pair_type{ "settingsFile", ::winrt::TerminalApp::SettingsTarget::SettingsFile }, - pair_type{ "defaultsFile", ::winrt::TerminalApp::SettingsTarget::DefaultsFile }, - pair_type{ "allFiles", ::winrt::TerminalApp::SettingsTarget::AllFiles }, + pair_type{ "settingsFile", TargetType::SettingsFile }, + pair_type{ "defaultsFile", TargetType::DefaultsFile }, + pair_type{ "allFiles", TargetType::AllFiles }, }; }; From 9801aa62fd7d0a4b4f4b7e2bdd881f86ec0ea701 Mon Sep 17 00:00:00 2001 From: Dustin Howett Date: Tue, 14 Jul 2020 12:05:26 -0700 Subject: [PATCH 21/25] git is mad, push an empty commit From a23bc5196ec82c95e5cfa53b6d610640de2f5ded Mon Sep 17 00:00:00 2001 From: Dustin Howett Date: Tue, 14 Jul 2020 17:37:48 -0700 Subject: [PATCH 22/25] Fixup after merge --- src/cascadia/TerminalApp/GlobalAppSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cascadia/TerminalApp/GlobalAppSettings.cpp b/src/cascadia/TerminalApp/GlobalAppSettings.cpp index dfb2fcd6433..c214c04896d 100644 --- a/src/cascadia/TerminalApp/GlobalAppSettings.cpp +++ b/src/cascadia/TerminalApp/GlobalAppSettings.cpp @@ -178,7 +178,7 @@ void GlobalAppSettings::LayerJson(const Json::Value& json) JsonUtils::GetValueForKey(json, EnableStartupTaskKey, _StartOnUserLogin); - JsonUtils::GetBool(json, AlwaysOnTopKey, _AlwaysOnTop); + JsonUtils::GetValueForKey(json, AlwaysOnTopKey, _AlwaysOnTop); // This is a helper lambda to get the keybindings and commands out of both // and array of objects. We'll use this twice, once on the legacy From f18374e200f769e68e30820f88337035adfe56df Mon Sep 17 00:00:00 2001 From: Dustin Howett Date: Tue, 14 Jul 2020 17:50:35 -0700 Subject: [PATCH 23/25] rename JU-NEW, fix an Oops in TargetType/ValueType --- src/cascadia/TerminalApp/JsonUtils.h | 479 ++++++++++++++++- src/cascadia/TerminalApp/JsonUtilsNew.h | 491 ------------------ .../TerminalSettingsSerializationHelpers.h | 22 +- 3 files changed, 488 insertions(+), 504 deletions(-) delete mode 100644 src/cascadia/TerminalApp/JsonUtilsNew.h diff --git a/src/cascadia/TerminalApp/JsonUtils.h b/src/cascadia/TerminalApp/JsonUtils.h index f6b92550463..b98ade1da9d 100644 --- a/src/cascadia/TerminalApp/JsonUtils.h +++ b/src/cascadia/TerminalApp/JsonUtils.h @@ -9,8 +9,483 @@ Module Name: - Helpers for the TerminalApp project Author(s): - Mike Griese - August 2019 - +- Dustin Howett - January 2020 --*/ + #pragma once -#include "JsonUtilsNew.h" +#include + +#include "../types/inc/utils.hpp" + +namespace winrt +{ + // If we don't use winrt, nobody will include the ConversionTraits for winrt stuff. + // If nobody includes it, these forward declarations will suffice. + struct guid; + struct hstring; + namespace Windows::Foundation + { + template + struct IReference; + } +} + +namespace TerminalApp::JsonUtils +{ + namespace Detail + { + // Function Description: + // - Returns a string_view to a Json::Value's internal string storage, + // hopefully without copying it. + __declspec(noinline) inline const std::string_view GetStringView(const Json::Value& json) + { + const char* begin{ nullptr }; + const char* end{ nullptr }; + json.getString(&begin, &end); + const std::string_view zeroCopyString{ begin, gsl::narrow_cast(end - begin) }; + return zeroCopyString; + } + + template + struct DeduceOptional + { + using Type = typename std::decay::type; + static constexpr bool IsOptional = false; + }; + + template + struct DeduceOptional> + { + using Type = typename std::decay::type; + static constexpr bool IsOptional = true; + }; + + template + struct DeduceOptional<::winrt::Windows::Foundation::IReference> + { + using Type = typename std::decay::type; + static constexpr bool IsOptional = true; + }; + } + + // These exceptions cannot use localized messages, as we do not have + // guaranteed access to the resource loader. + class TypeMismatchException : public std::runtime_error + { + public: + TypeMismatchException() : + runtime_error("unexpected data type") {} + }; + + class KeyedException : public std::runtime_error + { + public: + KeyedException(const std::string_view key, std::exception_ptr exception) : + runtime_error(fmt::format("error parsing \"{0}\"", key).c_str()), + _key{ key }, + _innerException{ std::move(exception) } {} + + std::string GetKey() const + { + return _key; + } + + [[noreturn]] void RethrowInner() const + { + std::rethrow_exception(_innerException); + } + + private: + std::string _key; + std::exception_ptr _innerException; + }; + + class UnexpectedValueException : public std::runtime_error + { + public: + UnexpectedValueException(const std::string_view value) : + runtime_error(fmt::format("unexpected value \"{0}\"", value).c_str()), + _value{ value } {} + + std::string GetValue() const + { + return _value; + } + + private: + std::string _value; + }; + + template + struct ConversionTrait + { + // Forward-declare these so the linker can pick up specializations from elsewhere! + T FromJson(const Json::Value&); + bool CanConvert(const Json::Value& json); + }; + + template<> + struct ConversionTrait + { + std::string FromJson(const Json::Value& json) + { + return json.asString(); + } + + bool CanConvert(const Json::Value& json) + { + return json.isString(); + } + }; + + template<> + struct ConversionTrait + { + std::wstring FromJson(const Json::Value& json) + { + return til::u8u16(Detail::GetStringView(json)); + } + + bool CanConvert(const Json::Value& json) + { + return json.isString(); + } + }; + +#ifdef WINRT_BASE_H + template<> + struct ConversionTrait : public ConversionTrait + { + // Leverage the wstring converter's validation + winrt::hstring FromJson(const Json::Value& json) + { + return winrt::hstring{ til::u8u16(Detail::GetStringView(json)) }; + } + }; +#endif + + template<> + struct ConversionTrait + { + bool FromJson(const Json::Value& json) + { + return json.asBool(); + } + + bool CanConvert(const Json::Value& json) + { + return json.isBool(); + } + }; + + template<> + struct ConversionTrait + { + int FromJson(const Json::Value& json) + { + return json.asInt(); + } + + bool CanConvert(const Json::Value& json) + { + return json.isInt(); + } + }; + + template<> + struct ConversionTrait + { + unsigned int FromJson(const Json::Value& json) + { + return json.asUInt(); + } + + bool CanConvert(const Json::Value& json) + { + return json.isUInt(); + } + }; + + template<> + struct ConversionTrait + { + float FromJson(const Json::Value& json) + { + return json.asFloat(); + } + + bool CanConvert(const Json::Value& json) + { + return json.isNumeric(); + } + }; + + template<> + struct ConversionTrait + { + double FromJson(const Json::Value& json) + { + return json.asDouble(); + } + + bool CanConvert(const Json::Value& json) + { + return json.isNumeric(); + } + }; + + template<> + struct ConversionTrait + { + GUID FromJson(const Json::Value& json) + { + return ::Microsoft::Console::Utils::GuidFromString(til::u8u16(Detail::GetStringView(json))); + } + + bool CanConvert(const Json::Value& json) + { + if (!json.isString()) + { + return false; + } + + const auto string{ Detail::GetStringView(json) }; + return string.length() == 38 && string.front() == '{' && string.back() == '}'; + } + }; + + // (GUID and winrt::guid are mutually convertible!) + template<> + struct ConversionTrait : public ConversionTrait + { + }; + + template<> + struct ConversionTrait + { + til::color FromJson(const Json::Value& json) + { + return ::Microsoft::Console::Utils::ColorFromHexString(Detail::GetStringView(json)); + } + + bool CanConvert(const Json::Value& json) + { + if (!json.isString()) + { + return false; + } + + const auto string{ Detail::GetStringView(json) }; + return (string.length() == 7 || string.length() == 4) && string.front() == '#'; + } + }; + + template + struct EnumMapper + { + using BaseEnumMapper = EnumMapper; + using ValueType = T; + using pair_type = std::pair; + T FromJson(const Json::Value& json) + { + const auto name{ Detail::GetStringView(json) }; + for (const auto& pair : TBase::mappings) + { + if (pair.first == name) + { + return pair.second; + } + } + + throw UnexpectedValueException{ name }; + } + + bool CanConvert(const Json::Value& json) + { + return json.isString(); + } + }; + + // FlagMapper is EnumMapper, but it works for bitfields. + // It supports a string (single flag) or an array of strings. + // Does an O(n*m) search; meant for small search spaces! + // + // Cleverly leverage EnumMapper to do the heavy lifting. + template + struct FlagMapper : public EnumMapper + { + private: + // Hide BaseEnumMapper so FlagMapper's consumers cannot see + // it. + using BaseEnumMapper = EnumMapper::BaseEnumMapper; + + public: + using BaseFlagMapper = FlagMapper; + static constexpr T AllSet{ static_cast(~0u) }; + static constexpr T AllClear{ static_cast(0u) }; + + T FromJson(const Json::Value& json) + { + if (json.isString()) + { + return BaseEnumMapper::FromJson(json); + } + else if (json.isArray()) + { + unsigned int seen{ 0 }; + T value{}; + for (const auto& element : json) + { + const auto newFlag{ BaseEnumMapper::FromJson(element) }; + if (++seen > 1 && + ((newFlag == AllClear && value != AllClear) || + (value == AllClear && newFlag != AllClear))) + { + // attempt to combine AllClear (explicitly) with anything else + throw UnexpectedValueException{ element.asString() }; + } + value |= newFlag; + } + return value; + } + + // We'll only get here if CanConvert has failed us. + return AllClear; + } + + bool CanConvert(const Json::Value& json) + { + return BaseEnumMapper::CanConvert(json) || json.isArray(); + } + }; + + // Method Description: + // - Helper that will populate a reference with a value converted from a json object. + // Arguments: + // - json: the json object to convert + // - target: the value to populate with the converted result + // Return Value: + // - a boolean indicating whether the value existed (in this case, was non-null) + // + // GetValue, type-deduced, manual converter + template + bool GetValue(const Json::Value& json, T& target, Converter&& conv) + { + if constexpr (Detail::DeduceOptional::IsOptional) + { + // FOR OPTION TYPES + // - If the json object is set to `null`, then + // we'll instead set the target back to the empty optional. + if (json.isNull()) + { + target = T{}; // zero-construct an empty optional + return true; + } + } + + if (json) + { + if (!conv.CanConvert(json)) + { + throw TypeMismatchException{}; + } + + target = conv.FromJson(json); + return true; + } + return false; + } + + // GetValue, forced return type, manual converter + template + std::decay_t GetValue(const Json::Value& json, Converter&& conv) + { + std::decay_t local{}; + GetValue(json, local, std::forward(conv)); + return local; // returns zero-initialized or value + } + + // GetValueForKey, type-deduced, manual converter + template + bool GetValueForKey(const Json::Value& json, std::string_view key, T& target, Converter&& conv) + { + if (auto found{ json.find(&*key.cbegin(), (&*key.cbegin()) + key.size()) }) + { + try + { + return GetValue(*found, target, std::forward(conv)); + } + catch (...) + { + // Wrap any caught exceptions in one that preserves context. + throw KeyedException(key, std::current_exception()); + } + } + return false; + } + + // GetValueForKey, forced return type, manual converter + template + std::decay_t GetValueForKey(const Json::Value& json, std::string_view key, Converter&& conv) + { + std::decay_t local{}; + GetValueForKey(json, key, local, std::forward(conv)); + return local; // returns zero-initialized? + } + + // GetValue, type-deduced, with automatic converter + template + bool GetValue(const Json::Value& json, T& target) + { + return GetValue(json, target, ConversionTrait::Type>{}); + } + + // GetValue, forced return type, with automatic converter + template + std::decay_t GetValue(const Json::Value& json) + { + std::decay_t local{}; + GetValue(json, local, ConversionTrait::Type>{}); + return local; // returns zero-initialized or value + } + + // GetValueForKey, type-deduced, with automatic converter + template + bool GetValueForKey(const Json::Value& json, std::string_view key, T& target) + { + return GetValueForKey(json, key, target, ConversionTrait::Type>{}); + } + + // GetValueForKey, forced return type, with automatic converter + template + std::decay_t GetValueForKey(const Json::Value& json, std::string_view key) + { + return GetValueForKey(json, key, ConversionTrait::Type>{}); + } + + // Get multiple values for keys (json, k, &v, k, &v, k, &v, ...). + // Uses the default converter for each v. + // Careful: this can cause a template explosion. + constexpr void GetValuesForKeys(const Json::Value& /*json*/) {} + + template + void GetValuesForKeys(const Json::Value& json, std::string_view key1, T&& val1, Args&&... args) + { + GetValueForKey(json, key1, val1); + GetValuesForKeys(json, std::forward(args)...); + } +}; + +#define JSON_ENUM_MAPPER(...) \ + template<> \ + struct ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__> : \ + public ::TerminalApp::JsonUtils::EnumMapper<__VA_ARGS__, ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__>> + +#define JSON_FLAG_MAPPER(...) \ + template<> \ + struct ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__> : \ + public ::TerminalApp::JsonUtils::FlagMapper<__VA_ARGS__, ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__>> + +#define JSON_MAPPINGS(Count) \ + static constexpr std::array mappings diff --git a/src/cascadia/TerminalApp/JsonUtilsNew.h b/src/cascadia/TerminalApp/JsonUtilsNew.h deleted file mode 100644 index b98ade1da9d..00000000000 --- a/src/cascadia/TerminalApp/JsonUtilsNew.h +++ /dev/null @@ -1,491 +0,0 @@ -/*++ -Copyright (c) Microsoft Corporation -Licensed under the MIT license. - -Module Name: -- JsonUtils.h - -Abstract: -- Helpers for the TerminalApp project -Author(s): -- Mike Griese - August 2019 -- Dustin Howett - January 2020 ---*/ - -#pragma once - -#include - -#include "../types/inc/utils.hpp" - -namespace winrt -{ - // If we don't use winrt, nobody will include the ConversionTraits for winrt stuff. - // If nobody includes it, these forward declarations will suffice. - struct guid; - struct hstring; - namespace Windows::Foundation - { - template - struct IReference; - } -} - -namespace TerminalApp::JsonUtils -{ - namespace Detail - { - // Function Description: - // - Returns a string_view to a Json::Value's internal string storage, - // hopefully without copying it. - __declspec(noinline) inline const std::string_view GetStringView(const Json::Value& json) - { - const char* begin{ nullptr }; - const char* end{ nullptr }; - json.getString(&begin, &end); - const std::string_view zeroCopyString{ begin, gsl::narrow_cast(end - begin) }; - return zeroCopyString; - } - - template - struct DeduceOptional - { - using Type = typename std::decay::type; - static constexpr bool IsOptional = false; - }; - - template - struct DeduceOptional> - { - using Type = typename std::decay::type; - static constexpr bool IsOptional = true; - }; - - template - struct DeduceOptional<::winrt::Windows::Foundation::IReference> - { - using Type = typename std::decay::type; - static constexpr bool IsOptional = true; - }; - } - - // These exceptions cannot use localized messages, as we do not have - // guaranteed access to the resource loader. - class TypeMismatchException : public std::runtime_error - { - public: - TypeMismatchException() : - runtime_error("unexpected data type") {} - }; - - class KeyedException : public std::runtime_error - { - public: - KeyedException(const std::string_view key, std::exception_ptr exception) : - runtime_error(fmt::format("error parsing \"{0}\"", key).c_str()), - _key{ key }, - _innerException{ std::move(exception) } {} - - std::string GetKey() const - { - return _key; - } - - [[noreturn]] void RethrowInner() const - { - std::rethrow_exception(_innerException); - } - - private: - std::string _key; - std::exception_ptr _innerException; - }; - - class UnexpectedValueException : public std::runtime_error - { - public: - UnexpectedValueException(const std::string_view value) : - runtime_error(fmt::format("unexpected value \"{0}\"", value).c_str()), - _value{ value } {} - - std::string GetValue() const - { - return _value; - } - - private: - std::string _value; - }; - - template - struct ConversionTrait - { - // Forward-declare these so the linker can pick up specializations from elsewhere! - T FromJson(const Json::Value&); - bool CanConvert(const Json::Value& json); - }; - - template<> - struct ConversionTrait - { - std::string FromJson(const Json::Value& json) - { - return json.asString(); - } - - bool CanConvert(const Json::Value& json) - { - return json.isString(); - } - }; - - template<> - struct ConversionTrait - { - std::wstring FromJson(const Json::Value& json) - { - return til::u8u16(Detail::GetStringView(json)); - } - - bool CanConvert(const Json::Value& json) - { - return json.isString(); - } - }; - -#ifdef WINRT_BASE_H - template<> - struct ConversionTrait : public ConversionTrait - { - // Leverage the wstring converter's validation - winrt::hstring FromJson(const Json::Value& json) - { - return winrt::hstring{ til::u8u16(Detail::GetStringView(json)) }; - } - }; -#endif - - template<> - struct ConversionTrait - { - bool FromJson(const Json::Value& json) - { - return json.asBool(); - } - - bool CanConvert(const Json::Value& json) - { - return json.isBool(); - } - }; - - template<> - struct ConversionTrait - { - int FromJson(const Json::Value& json) - { - return json.asInt(); - } - - bool CanConvert(const Json::Value& json) - { - return json.isInt(); - } - }; - - template<> - struct ConversionTrait - { - unsigned int FromJson(const Json::Value& json) - { - return json.asUInt(); - } - - bool CanConvert(const Json::Value& json) - { - return json.isUInt(); - } - }; - - template<> - struct ConversionTrait - { - float FromJson(const Json::Value& json) - { - return json.asFloat(); - } - - bool CanConvert(const Json::Value& json) - { - return json.isNumeric(); - } - }; - - template<> - struct ConversionTrait - { - double FromJson(const Json::Value& json) - { - return json.asDouble(); - } - - bool CanConvert(const Json::Value& json) - { - return json.isNumeric(); - } - }; - - template<> - struct ConversionTrait - { - GUID FromJson(const Json::Value& json) - { - return ::Microsoft::Console::Utils::GuidFromString(til::u8u16(Detail::GetStringView(json))); - } - - bool CanConvert(const Json::Value& json) - { - if (!json.isString()) - { - return false; - } - - const auto string{ Detail::GetStringView(json) }; - return string.length() == 38 && string.front() == '{' && string.back() == '}'; - } - }; - - // (GUID and winrt::guid are mutually convertible!) - template<> - struct ConversionTrait : public ConversionTrait - { - }; - - template<> - struct ConversionTrait - { - til::color FromJson(const Json::Value& json) - { - return ::Microsoft::Console::Utils::ColorFromHexString(Detail::GetStringView(json)); - } - - bool CanConvert(const Json::Value& json) - { - if (!json.isString()) - { - return false; - } - - const auto string{ Detail::GetStringView(json) }; - return (string.length() == 7 || string.length() == 4) && string.front() == '#'; - } - }; - - template - struct EnumMapper - { - using BaseEnumMapper = EnumMapper; - using ValueType = T; - using pair_type = std::pair; - T FromJson(const Json::Value& json) - { - const auto name{ Detail::GetStringView(json) }; - for (const auto& pair : TBase::mappings) - { - if (pair.first == name) - { - return pair.second; - } - } - - throw UnexpectedValueException{ name }; - } - - bool CanConvert(const Json::Value& json) - { - return json.isString(); - } - }; - - // FlagMapper is EnumMapper, but it works for bitfields. - // It supports a string (single flag) or an array of strings. - // Does an O(n*m) search; meant for small search spaces! - // - // Cleverly leverage EnumMapper to do the heavy lifting. - template - struct FlagMapper : public EnumMapper - { - private: - // Hide BaseEnumMapper so FlagMapper's consumers cannot see - // it. - using BaseEnumMapper = EnumMapper::BaseEnumMapper; - - public: - using BaseFlagMapper = FlagMapper; - static constexpr T AllSet{ static_cast(~0u) }; - static constexpr T AllClear{ static_cast(0u) }; - - T FromJson(const Json::Value& json) - { - if (json.isString()) - { - return BaseEnumMapper::FromJson(json); - } - else if (json.isArray()) - { - unsigned int seen{ 0 }; - T value{}; - for (const auto& element : json) - { - const auto newFlag{ BaseEnumMapper::FromJson(element) }; - if (++seen > 1 && - ((newFlag == AllClear && value != AllClear) || - (value == AllClear && newFlag != AllClear))) - { - // attempt to combine AllClear (explicitly) with anything else - throw UnexpectedValueException{ element.asString() }; - } - value |= newFlag; - } - return value; - } - - // We'll only get here if CanConvert has failed us. - return AllClear; - } - - bool CanConvert(const Json::Value& json) - { - return BaseEnumMapper::CanConvert(json) || json.isArray(); - } - }; - - // Method Description: - // - Helper that will populate a reference with a value converted from a json object. - // Arguments: - // - json: the json object to convert - // - target: the value to populate with the converted result - // Return Value: - // - a boolean indicating whether the value existed (in this case, was non-null) - // - // GetValue, type-deduced, manual converter - template - bool GetValue(const Json::Value& json, T& target, Converter&& conv) - { - if constexpr (Detail::DeduceOptional::IsOptional) - { - // FOR OPTION TYPES - // - If the json object is set to `null`, then - // we'll instead set the target back to the empty optional. - if (json.isNull()) - { - target = T{}; // zero-construct an empty optional - return true; - } - } - - if (json) - { - if (!conv.CanConvert(json)) - { - throw TypeMismatchException{}; - } - - target = conv.FromJson(json); - return true; - } - return false; - } - - // GetValue, forced return type, manual converter - template - std::decay_t GetValue(const Json::Value& json, Converter&& conv) - { - std::decay_t local{}; - GetValue(json, local, std::forward(conv)); - return local; // returns zero-initialized or value - } - - // GetValueForKey, type-deduced, manual converter - template - bool GetValueForKey(const Json::Value& json, std::string_view key, T& target, Converter&& conv) - { - if (auto found{ json.find(&*key.cbegin(), (&*key.cbegin()) + key.size()) }) - { - try - { - return GetValue(*found, target, std::forward(conv)); - } - catch (...) - { - // Wrap any caught exceptions in one that preserves context. - throw KeyedException(key, std::current_exception()); - } - } - return false; - } - - // GetValueForKey, forced return type, manual converter - template - std::decay_t GetValueForKey(const Json::Value& json, std::string_view key, Converter&& conv) - { - std::decay_t local{}; - GetValueForKey(json, key, local, std::forward(conv)); - return local; // returns zero-initialized? - } - - // GetValue, type-deduced, with automatic converter - template - bool GetValue(const Json::Value& json, T& target) - { - return GetValue(json, target, ConversionTrait::Type>{}); - } - - // GetValue, forced return type, with automatic converter - template - std::decay_t GetValue(const Json::Value& json) - { - std::decay_t local{}; - GetValue(json, local, ConversionTrait::Type>{}); - return local; // returns zero-initialized or value - } - - // GetValueForKey, type-deduced, with automatic converter - template - bool GetValueForKey(const Json::Value& json, std::string_view key, T& target) - { - return GetValueForKey(json, key, target, ConversionTrait::Type>{}); - } - - // GetValueForKey, forced return type, with automatic converter - template - std::decay_t GetValueForKey(const Json::Value& json, std::string_view key) - { - return GetValueForKey(json, key, ConversionTrait::Type>{}); - } - - // Get multiple values for keys (json, k, &v, k, &v, k, &v, ...). - // Uses the default converter for each v. - // Careful: this can cause a template explosion. - constexpr void GetValuesForKeys(const Json::Value& /*json*/) {} - - template - void GetValuesForKeys(const Json::Value& json, std::string_view key1, T&& val1, Args&&... args) - { - GetValueForKey(json, key1, val1); - GetValuesForKeys(json, std::forward(args)...); - } -}; - -#define JSON_ENUM_MAPPER(...) \ - template<> \ - struct ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__> : \ - public ::TerminalApp::JsonUtils::EnumMapper<__VA_ARGS__, ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__>> - -#define JSON_FLAG_MAPPER(...) \ - template<> \ - struct ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__> : \ - public ::TerminalApp::JsonUtils::FlagMapper<__VA_ARGS__, ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__>> - -#define JSON_MAPPINGS(Count) \ - static constexpr std::array mappings diff --git a/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h b/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h index 9b399563e57..40de89d2258 100644 --- a/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h +++ b/src/cascadia/TerminalApp/TerminalSettingsSerializationHelpers.h @@ -237,10 +237,10 @@ struct ::TerminalApp::JsonUtils::ConversionTrait<::TerminalApp::LaunchPosition> JSON_ENUM_MAPPER(::winrt::TerminalApp::Direction) { JSON_MAPPINGS(4) = { - pair_type{ "left", TargetType::Left }, - pair_type{ "right", TargetType::Right }, - pair_type{ "up", TargetType::Up }, - pair_type{ "down", TargetType::Down }, + pair_type{ "left", ValueType::Left }, + pair_type{ "right", ValueType::Right }, + pair_type{ "up", ValueType::Up }, + pair_type{ "down", ValueType::Down }, }; }; @@ -248,9 +248,9 @@ JSON_ENUM_MAPPER(::winrt::TerminalApp::Direction) JSON_ENUM_MAPPER(::winrt::TerminalApp::SplitState) { JSON_MAPPINGS(3) = { - pair_type{ "vertical", TargetType::Vertical }, - pair_type{ "horizontal", TargetType::Horizontal }, - pair_type{ "auto", TargetType::Automatic }, + pair_type{ "vertical", ValueType::Vertical }, + pair_type{ "horizontal", ValueType::Horizontal }, + pair_type{ "auto", ValueType::Automatic }, }; }; @@ -258,15 +258,15 @@ JSON_ENUM_MAPPER(::winrt::TerminalApp::SplitState) JSON_ENUM_MAPPER(::winrt::TerminalApp::SplitType) { JSON_MAPPINGS(1) = { - pair_type{ "duplicate", TargetType::Duplicate }, + pair_type{ "duplicate", ValueType::Duplicate }, }; }; JSON_ENUM_MAPPER(::winrt::TerminalApp::SettingsTarget) { JSON_MAPPINGS(3) = { - pair_type{ "settingsFile", TargetType::SettingsFile }, - pair_type{ "defaultsFile", TargetType::DefaultsFile }, - pair_type{ "allFiles", TargetType::AllFiles }, + pair_type{ "settingsFile", ValueType::SettingsFile }, + pair_type{ "defaultsFile", ValueType::DefaultsFile }, + pair_type{ "allFiles", ValueType::AllFiles }, }; }; From e6c229a82cfdc7d20292a46755d115e08ff65442 Mon Sep 17 00:00:00 2001 From: Dustin Howett Date: Tue, 14 Jul 2020 18:28:51 -0700 Subject: [PATCH 24/25] update test for rename --- src/cascadia/ut_app/JsonUtilsTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cascadia/ut_app/JsonUtilsTests.cpp b/src/cascadia/ut_app/JsonUtilsTests.cpp index 1016fb282a1..f3f3c7c5b2c 100644 --- a/src/cascadia/ut_app/JsonUtilsTests.cpp +++ b/src/cascadia/ut_app/JsonUtilsTests.cpp @@ -3,7 +3,7 @@ #include "precomp.h" -#include "../TerminalApp/JsonUtilsNew.h" +#include "../TerminalApp/JsonUtils.h" using namespace Microsoft::Console; using namespace WEX::Logging; From a8841d477c4b0d3d8a151a0b333d2326a05c54fe Mon Sep 17 00:00:00 2001 From: Dustin Howett Date: Tue, 14 Jul 2020 18:29:07 -0700 Subject: [PATCH 25/25] remove more tests that explicitly parsed bad values --- .../LocalTests_TerminalApp/CommandTests.cpp | 26 +-------- .../KeyBindingsTests.cpp | 12 +--- src/cascadia/ut_app/JsonTests.cpp | 56 ------------------- 3 files changed, 3 insertions(+), 91 deletions(-) diff --git a/src/cascadia/LocalTests_TerminalApp/CommandTests.cpp b/src/cascadia/LocalTests_TerminalApp/CommandTests.cpp index 129e2469182..1babcf6a2c8 100644 --- a/src/cascadia/LocalTests_TerminalApp/CommandTests.cpp +++ b/src/cascadia/LocalTests_TerminalApp/CommandTests.cpp @@ -147,10 +147,8 @@ namespace TerminalAppLocalTests { "name": "command0", "command": { "action": "splitPane", "split": null } }, { "name": "command1", "command": { "action": "splitPane", "split": "vertical" } }, { "name": "command2", "command": { "action": "splitPane", "split": "horizontal" } }, - { "name": "command3", "command": { "action": "splitPane", "split": "none" } }, { "name": "command4", "command": { "action": "splitPane" } }, - { "name": "command5", "command": { "action": "splitPane", "split": "auto" } }, - { "name": "command6", "command": { "action": "splitPane", "split": "foo" } } + { "name": "command5", "command": { "action": "splitPane", "split": "auto" } } ])" }; const auto commands0Json = VerifyParseSucceeded(commands0String); @@ -159,7 +157,7 @@ namespace TerminalAppLocalTests VERIFY_ARE_EQUAL(0u, commands.size()); auto warnings = implementation::Command::LayerJson(commands, commands0Json); VERIFY_ARE_EQUAL(0u, warnings.size()); - VERIFY_ARE_EQUAL(7u, commands.size()); + VERIFY_ARE_EQUAL(5u, commands.size()); { auto command = commands.at(L"command0"); @@ -191,16 +189,6 @@ namespace TerminalAppLocalTests // Verify the args have the expected value VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Horizontal, realArgs.SplitStyle()); } - { - auto command = commands.at(L"command3"); - VERIFY_IS_NOT_NULL(command); - VERIFY_IS_NOT_NULL(command.Action()); - VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.Action().Action()); - const auto& realArgs = command.Action().Args().try_as(); - VERIFY_IS_NOT_NULL(realArgs); - // Verify the args have the expected value - VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle()); - } { auto command = commands.at(L"command4"); VERIFY_IS_NOT_NULL(command); @@ -221,16 +209,6 @@ namespace TerminalAppLocalTests // Verify the args have the expected value VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle()); } - { - auto command = commands.at(L"command6"); - VERIFY_IS_NOT_NULL(command); - VERIFY_IS_NOT_NULL(command.Action()); - VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.Action().Action()); - const auto& realArgs = command.Action().Args().try_as(); - VERIFY_IS_NOT_NULL(realArgs); - // Verify the args have the expected value - VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle()); - } } void CommandTests::TestResourceKeyName() { diff --git a/src/cascadia/LocalTests_TerminalApp/KeyBindingsTests.cpp b/src/cascadia/LocalTests_TerminalApp/KeyBindingsTests.cpp index 0fc9981cf7f..ad51cf8269b 100644 --- a/src/cascadia/LocalTests_TerminalApp/KeyBindingsTests.cpp +++ b/src/cascadia/LocalTests_TerminalApp/KeyBindingsTests.cpp @@ -387,7 +387,6 @@ namespace TerminalAppLocalTests const std::string bindings0String{ R"([ { "keys": ["ctrl+c"], "command": { "action": "setTabColor", "color": null } }, { "keys": ["ctrl+d"], "command": { "action": "setTabColor", "color": "#123456" } }, - { "keys": ["ctrl+e"], "command": { "action": "setTabColor", "color": "thisStringObviouslyWontWork" } }, { "keys": ["ctrl+f"], "command": "setTabColor" }, ])" }; @@ -397,7 +396,7 @@ namespace TerminalAppLocalTests VERIFY_IS_NOT_NULL(appKeyBindings); VERIFY_ARE_EQUAL(0u, appKeyBindings->_keyShortcuts.size()); appKeyBindings->LayerJson(bindings0Json); - VERIFY_ARE_EQUAL(4u, appKeyBindings->_keyShortcuts.size()); + VERIFY_ARE_EQUAL(3u, appKeyBindings->_keyShortcuts.size()); { KeyChord kc{ true, false, false, static_cast('C') }; @@ -419,15 +418,6 @@ namespace TerminalAppLocalTests // Remember that COLORREFs are actually BBGGRR order, while the string is in #RRGGBB order VERIFY_ARE_EQUAL(static_cast(til::color(0x563412)), realArgs.TabColor().Value()); } - { - KeyChord kc{ true, false, false, static_cast('E') }; - auto actionAndArgs = TestUtils::GetActionAndArgs(*appKeyBindings, kc); - VERIFY_ARE_EQUAL(ShortcutAction::SetTabColor, actionAndArgs.Action()); - const auto& realArgs = actionAndArgs.Args().try_as(); - VERIFY_IS_NOT_NULL(realArgs); - // Verify the args have the expected value - VERIFY_IS_NULL(realArgs.TabColor()); - } { KeyChord kc{ true, false, false, static_cast('F') }; auto actionAndArgs = TestUtils::GetActionAndArgs(*appKeyBindings, kc); diff --git a/src/cascadia/ut_app/JsonTests.cpp b/src/cascadia/ut_app/JsonTests.cpp index 9fd573134f7..1afbeaeddff 100644 --- a/src/cascadia/ut_app/JsonTests.cpp +++ b/src/cascadia/ut_app/JsonTests.cpp @@ -28,8 +28,6 @@ namespace TerminalAppUnitTests TEST_METHOD(ParseSimpleColorScheme); TEST_METHOD(ProfileGeneratesGuid); - TEST_METHOD(TestWrongValueType); - TEST_CLASS_SETUP(ClassSetup) { InitializeJsonReader(); @@ -169,58 +167,4 @@ namespace TerminalAppUnitTests VERIFY_ARE_EQUAL(profile3.GetGuid(), nullGuid); VERIFY_ARE_EQUAL(profile4.GetGuid(), cmdGuid); } - - void JsonTests::TestWrongValueType() - { - // This json blob has a whole bunch of settings with the wrong value - // types - strings for int values, ints for strings, floats for ints, - // etc. When we encounter data that's the wrong data type, we should - // gracefully ignore it, as opposed to throwing an exception, causing us - // to fail to load the settings at all. - - const std::string settings0String{ R"( - { - "defaultProfile" : "{00000000-1111-0000-0000-000000000000}", - "profiles": [ - { - "guid" : "{00000000-1111-0000-0000-000000000000}", - "acrylicOpacity" : "0.5", - "closeOnExit" : "true", - "fontSize" : "10", - "historySize" : 1234.5678, - "padding" : 20, - "snapOnInput" : "false", - "icon" : 4, - "backgroundImageOpacity": false, - "useAcrylic" : 14 - } - ] - })" }; - - const auto settings0Json = VerifyParseSucceeded(settings0String); - - CascadiaSettings settings; - - settings._ParseJsonString(settings0String, false); - // We should not throw an exception trying to parse the settings here. - settings.LayerJson(settings._userSettings); - - VERIFY_ARE_EQUAL(1u, settings._profiles.size()); - auto& profile = settings._profiles.at(0); - Profile defaults{}; - - VERIFY_ARE_EQUAL(defaults._acrylicTransparency, profile._acrylicTransparency); - VERIFY_ARE_EQUAL(defaults._closeOnExitMode, profile._closeOnExitMode); - VERIFY_ARE_EQUAL(defaults._fontSize, profile._fontSize); - VERIFY_ARE_EQUAL(defaults._historySize, profile._historySize); - // A 20 as an int can still be treated as a json string - VERIFY_ARE_EQUAL(L"20", profile._padding); - VERIFY_ARE_EQUAL(defaults._snapOnInput, profile._snapOnInput); - // 4 is a valid string value - VERIFY_ARE_EQUAL(L"4", profile._icon); - // false is not a valid optional - VERIFY_IS_FALSE(profile._backgroundImageOpacity.has_value()); - VERIFY_ARE_EQUAL(defaults._useAcrylic, profile._useAcrylic); - } - }