Add Serializer to CascadiaSettings (#8018)
## Summary of the Pull Request This adds `ToJson` functions to `Profile`, `GlobalAppSettings`, and `ColorScheme`. They are used in `CascadiaSettings` to completely serialize an instance of the settings model. Thanks to #7923, all of the settings are `std::optional`, and `JsonUtils` only writes out values that are actually populated. `CascadiaSettings::WriteSettingsToDisk` serializes the current settings and writes them to the settings.json. A backup file is created with your old contents. #### Limitations: - all of the color schemes are serialized regardless of them coming from defaults.json or settings.json - keybindings/actions are copied/pasted ## References #1564 - Settings UI TSM Specs (#6904 and #7876) ## PR Checklist * [x] Tests added/passed
This commit is contained in:
parent
77a204b765
commit
6b503ba887
|
@ -34,6 +34,7 @@ IObject
|
|||
IStorage
|
||||
LCID
|
||||
llabs
|
||||
localtime
|
||||
lround
|
||||
LSHIFT
|
||||
msappx
|
||||
|
|
|
@ -418872,6 +418872,7 @@ time-shrouded
|
|||
time-space
|
||||
time-spirit
|
||||
timestamp
|
||||
timestamped
|
||||
timestamps
|
||||
timet
|
||||
time-table
|
||||
|
|
|
@ -884,7 +884,7 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
|
||||
VERIFY_ARE_EQUAL(2u, settings->_allProfiles.Size());
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(0).HasGuid());
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(1).HasGuid());
|
||||
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(1).HasGuid());
|
||||
}
|
||||
|
||||
void DeserializationTests::TestReorderWithNullGuids()
|
||||
|
@ -935,7 +935,7 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
|
||||
VERIFY_ARE_EQUAL(4u, settings->_allProfiles.Size());
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(0).HasGuid());
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(1).HasGuid());
|
||||
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(1).HasGuid());
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(2).HasGuid());
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(3).HasGuid());
|
||||
VERIFY_ARE_EQUAL(L"profile0", settings->_allProfiles.GetAt(0).Name());
|
||||
|
@ -1036,7 +1036,7 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_ARE_EQUAL(0u, settings->_warnings.Size());
|
||||
VERIFY_ARE_EQUAL(4u, settings->_allProfiles.Size());
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(0).HasGuid());
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(1).HasGuid());
|
||||
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(1).HasGuid());
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(2).HasGuid());
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(3).HasGuid());
|
||||
VERIFY_ARE_EQUAL(L"Command Prompt", settings->_allProfiles.GetAt(0).Name());
|
||||
|
@ -1190,8 +1190,8 @@ namespace SettingsModelLocalTests
|
|||
|
||||
VERIFY_ARE_EQUAL(5u, settings->_allProfiles.Size());
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(0).HasGuid());
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(1).HasGuid());
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(2).HasGuid());
|
||||
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(1).HasGuid());
|
||||
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(2).HasGuid());
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(3).HasGuid());
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(4).HasGuid());
|
||||
VERIFY_ARE_EQUAL(L"ThisProfileIsGood", settings->_allProfiles.GetAt(0).Name());
|
||||
|
|
|
@ -22,6 +22,12 @@ public:
|
|||
{
|
||||
_reader = std::unique_ptr<Json::CharReader>(Json::CharReaderBuilder::CharReaderBuilder().newCharReader());
|
||||
};
|
||||
|
||||
void InitializeJsonWriter()
|
||||
{
|
||||
_writer = std::unique_ptr<Json::StreamWriter>(Json::StreamWriterBuilder::StreamWriterBuilder().newStreamWriter());
|
||||
}
|
||||
|
||||
Json::Value VerifyParseSucceeded(std::string content)
|
||||
{
|
||||
Json::Value root;
|
||||
|
@ -31,6 +37,14 @@ public:
|
|||
return root;
|
||||
};
|
||||
|
||||
std::string toString(const Json::Value& json)
|
||||
{
|
||||
std::stringstream s;
|
||||
_writer->write(json, &s);
|
||||
return s.str();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<Json::CharReader> _reader;
|
||||
std::unique_ptr<Json::StreamWriter> _writer;
|
||||
};
|
||||
|
|
295
src/cascadia/LocalTests_SettingsModel/SerializationTests.cpp
Normal file
295
src/cascadia/LocalTests_SettingsModel/SerializationTests.cpp
Normal file
|
@ -0,0 +1,295 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include "../TerminalSettingsModel/ColorScheme.h"
|
||||
#include "../TerminalSettingsModel/CascadiaSettings.h"
|
||||
#include "JsonTestClass.h"
|
||||
#include "TestUtils.h"
|
||||
#include <defaults.h>
|
||||
#include "../ut_app/TestDynamicProfileGenerator.h"
|
||||
|
||||
using namespace Microsoft::Console;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::TestExecution;
|
||||
using namespace WEX::Common;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
using namespace winrt::Microsoft::Terminal::TerminalControl;
|
||||
|
||||
namespace SettingsModelLocalTests
|
||||
{
|
||||
// TODO:microsoft/terminal#3838:
|
||||
// Unfortunately, these tests _WILL NOT_ work in our CI. We're waiting for
|
||||
// an updated TAEF that will let us install framework packages when the test
|
||||
// package is deployed. Until then, these tests won't deploy in CI.
|
||||
|
||||
class SerializationTests : public JsonTestClass
|
||||
{
|
||||
// Use a custom AppxManifest to ensure that we can activate winrt types
|
||||
// from our test. This property will tell taef to manually use this as
|
||||
// the AppxManifest for this test class.
|
||||
// This does not yet work for anything XAML-y. See TabTests.cpp for more
|
||||
// details on that.
|
||||
BEGIN_TEST_CLASS(SerializationTests)
|
||||
TEST_CLASS_PROPERTY(L"RunAs", L"UAP")
|
||||
TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml")
|
||||
END_TEST_CLASS()
|
||||
|
||||
TEST_METHOD(GlobalSettings);
|
||||
TEST_METHOD(Profile);
|
||||
TEST_METHOD(ColorScheme);
|
||||
TEST_METHOD(CascadiaSettings);
|
||||
|
||||
TEST_CLASS_SETUP(ClassSetup)
|
||||
{
|
||||
InitializeJsonReader();
|
||||
InitializeJsonWriter();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// Method Description:
|
||||
// - deserializes and reserializes a json string representing a settings object model of type T
|
||||
// - verifies that the generated json string matches the provided one
|
||||
// Template Types:
|
||||
// - <T>: The type of Settings Model object to generate (must be impl type)
|
||||
// Arguments:
|
||||
// - jsonString - JSON string we're performing the test on
|
||||
// Return Value:
|
||||
// - the JsonObject representing this instance
|
||||
template<typename T>
|
||||
void RoundtripTest(const std::string& jsonString)
|
||||
{
|
||||
const auto json{ VerifyParseSucceeded(jsonString) };
|
||||
const auto settings{ T::FromJson(json) };
|
||||
const auto result{ settings->ToJson() };
|
||||
|
||||
// Compare toString(json) instead of jsonString here.
|
||||
// The toString writes the json out alphabetically.
|
||||
// This trick allows jsonString to _not_ have to be
|
||||
// written alphabetically.
|
||||
VERIFY_ARE_EQUAL(toString(json), toString(result));
|
||||
}
|
||||
};
|
||||
|
||||
void SerializationTests::GlobalSettings()
|
||||
{
|
||||
const std::string globalsString{ R"(
|
||||
{
|
||||
"defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
|
||||
|
||||
"initialRows": 30,
|
||||
"initialCols": 120,
|
||||
"initialPosition": ",",
|
||||
"launchMode": "default",
|
||||
"alwaysOnTop": false,
|
||||
|
||||
"copyOnSelect": false,
|
||||
"copyFormatting": "all",
|
||||
"wordDelimiters": " /\\()\"'-.,:;<>~!@#$%^&*|+=[]{}~?\u2502",
|
||||
|
||||
"alwaysShowTabs": true,
|
||||
"showTabsInTitlebar": true,
|
||||
"showTerminalTitleInTitlebar": true,
|
||||
"tabWidthMode": "equal",
|
||||
"tabSwitcherMode": "mru",
|
||||
|
||||
"startOnUserLogin": false,
|
||||
"theme": "system",
|
||||
"snapToGridOnResize": true,
|
||||
"disableAnimations": false,
|
||||
|
||||
"confirmCloseAllTabs": true,
|
||||
"largePasteWarning": true,
|
||||
"multiLinePasteWarning": true,
|
||||
|
||||
"experimental.input.forceVT": false,
|
||||
"experimental.rendering.forceFullRepaint": false,
|
||||
"experimental.rendering.software": false
|
||||
})" };
|
||||
|
||||
const std::string smallGlobalsString{ R"(
|
||||
{
|
||||
"defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}"
|
||||
})" };
|
||||
|
||||
RoundtripTest<implementation::GlobalAppSettings>(globalsString);
|
||||
RoundtripTest<implementation::GlobalAppSettings>(smallGlobalsString);
|
||||
}
|
||||
|
||||
void SerializationTests::Profile()
|
||||
{
|
||||
const std::string profileString{ R"(
|
||||
{
|
||||
"name": "Windows PowerShell",
|
||||
"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
|
||||
|
||||
"commandline": "%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
|
||||
"startingDirectory": "%USERPROFILE%",
|
||||
|
||||
"icon": "ms-appx:///ProfileIcons/{61c54bbd-c2c6-5271-96e7-009a87ff44bf}.png",
|
||||
"hidden": false,
|
||||
|
||||
"tabTitle": "Cool Tab",
|
||||
"suppressApplicationTitle": false,
|
||||
|
||||
"fontFace": "Cascadia Mono",
|
||||
"fontSize": 12,
|
||||
"fontWeight": "normal",
|
||||
"padding": "8, 8, 8, 8",
|
||||
"antialiasingMode": "grayscale",
|
||||
|
||||
"cursorShape": "bar",
|
||||
"cursorColor": "#CCBBAA",
|
||||
"cursorHeight": 10,
|
||||
|
||||
"altGrAliasing": true,
|
||||
|
||||
"colorScheme": "Campbell",
|
||||
"tabColor": "#0C0C0C",
|
||||
"foreground": "#AABBCC",
|
||||
"background": "#BBCCAA",
|
||||
"selectionBackground": "#CCAABB",
|
||||
|
||||
"useAcrylic": false,
|
||||
"acrylicOpacity": 0.5,
|
||||
|
||||
"backgroundImage": "made_you_look.jpeg",
|
||||
"backgroundImageStretchMode": "uniformToFill",
|
||||
"backgroundImageAlignment": "center",
|
||||
"backgroundImageOpacity": 1.0,
|
||||
|
||||
"scrollbarState": "visible",
|
||||
"snapOnInput": true,
|
||||
"historySize": 9001,
|
||||
|
||||
"closeOnExit": "graceful",
|
||||
"experimental.retroTerminalEffect": false
|
||||
})" };
|
||||
|
||||
const std::string smallProfileString{ R"(
|
||||
{
|
||||
"name": "Custom Profile"
|
||||
})" };
|
||||
|
||||
// Setting "tabColor" to null tests two things:
|
||||
// - null should count as an explicit user-set value, not falling back to the parent's value
|
||||
// - null should be acceptable even though we're working with colors
|
||||
const std::string weirdProfileString{ R"(
|
||||
{
|
||||
"name": "Weird Profile",
|
||||
"tabColor": null,
|
||||
"foreground": null,
|
||||
"source": "local"
|
||||
})" };
|
||||
|
||||
RoundtripTest<implementation::Profile>(profileString);
|
||||
RoundtripTest<implementation::Profile>(smallProfileString);
|
||||
RoundtripTest<implementation::Profile>(weirdProfileString);
|
||||
}
|
||||
|
||||
void SerializationTests::ColorScheme()
|
||||
{
|
||||
const std::string schemeString{ R"({
|
||||
"name": "Campbell",
|
||||
|
||||
"cursorColor": "#FFFFFF",
|
||||
"selectionBackground": "#131313",
|
||||
|
||||
"background": "#0C0C0C",
|
||||
"foreground": "#F2F2F2",
|
||||
|
||||
"black": "#0C0C0C",
|
||||
"blue": "#0037DA",
|
||||
"cyan": "#3A96DD",
|
||||
"green": "#13A10E",
|
||||
"purple": "#881798",
|
||||
"red": "#C50F1F",
|
||||
"white": "#CCCCCC",
|
||||
"yellow": "#C19C00",
|
||||
"brightBlack": "#767676",
|
||||
"brightBlue": "#3B78FF",
|
||||
"brightCyan": "#61D6D6",
|
||||
"brightGreen": "#16C60C",
|
||||
"brightPurple": "#B4009E",
|
||||
"brightRed": "#E74856",
|
||||
"brightWhite": "#F2F2F2",
|
||||
"brightYellow": "#F9F1A5"
|
||||
})" };
|
||||
|
||||
RoundtripTest<implementation::ColorScheme>(schemeString);
|
||||
}
|
||||
|
||||
void SerializationTests::CascadiaSettings()
|
||||
{
|
||||
const std::string settingsString{ R"({
|
||||
"$schema": "https://aka.ms/terminal-profiles-schema",
|
||||
"defaultProfile": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
|
||||
|
||||
"profiles": {
|
||||
"defaults": {
|
||||
"fontFace": "Zamora Code"
|
||||
},
|
||||
"list": [
|
||||
{
|
||||
"fontFace": "Cascadia Code",
|
||||
"guid": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
|
||||
"name": "HowettShell"
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "BhojwaniShell"
|
||||
},
|
||||
{
|
||||
"antialiasingMode": "aliased",
|
||||
"name": "NiksaShell"
|
||||
}
|
||||
]
|
||||
},
|
||||
"schemes": [
|
||||
{
|
||||
"name": "Cinnamon Roll",
|
||||
|
||||
"cursorColor": "#FFFFFD",
|
||||
"selectionBackground": "#FFFFFF",
|
||||
|
||||
"background": "#3C0315",
|
||||
"foreground": "#FFFFFD",
|
||||
|
||||
"black": "#282A2E",
|
||||
"blue": "#0170C5",
|
||||
"cyan": "#3F8D83",
|
||||
"green": "#76AB23",
|
||||
"purple": "#7D498F",
|
||||
"red": "#BD0940",
|
||||
"white": "#FFFFFD",
|
||||
"yellow": "#E0DE48",
|
||||
"brightBlack": "#676E7A",
|
||||
"brightBlue": "#5C98C5",
|
||||
"brightCyan": "#8ABEB7",
|
||||
"brightGreen": "#B5D680",
|
||||
"brightPurple": "#AC79BB",
|
||||
"brightRed": "#BD6D85",
|
||||
"brightWhite": "#FFFFFD",
|
||||
"brightYellow": "#FFFD76"
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
{"command": { "action": "renameTab","input": "Liang Tab" },"keys": "ctrl+t" }
|
||||
],
|
||||
"keybindings": [
|
||||
{ "command": { "action": "sendInput","input": "VT Griese Mode" },"keys": "ctrl+k" }
|
||||
]
|
||||
})" };
|
||||
|
||||
auto settings{ winrt::make_self<implementation::CascadiaSettings>(false) };
|
||||
settings->_ParseJsonString(settingsString, false);
|
||||
settings->_ApplyDefaultsFromUserSettings();
|
||||
settings->LayerJson(settings->_userSettings);
|
||||
settings->_ValidateSettings();
|
||||
|
||||
const auto result{ settings->ToJson() };
|
||||
VERIFY_ARE_EQUAL(toString(settings->_userSettings), toString(result));
|
||||
}
|
||||
}
|
|
@ -39,6 +39,7 @@
|
|||
<ClCompile Include="KeyBindingsTests.cpp" />
|
||||
<ClCompile Include="CommandTests.cpp" />
|
||||
<ClCompile Include="DeserializationTests.cpp" />
|
||||
<ClCompile Include="SerializationTests.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
|
|
|
@ -247,11 +247,6 @@ void CascadiaSettings::_ValidateSettings()
|
|||
// Make sure to check that profiles exists at all first and foremost:
|
||||
_ValidateProfilesExist();
|
||||
|
||||
// Verify all profiles actually had a GUID specified, otherwise generate a
|
||||
// GUID for them. Make sure to do this before de-duping profiles and
|
||||
// checking that the default profile is set.
|
||||
_ValidateProfilesHaveGuid();
|
||||
|
||||
// Re-order profiles so that all profiles from the user's settings appear
|
||||
// before profiles that _weren't_ in the user profiles.
|
||||
_ReorderProfilesToMatchUserSettingsOrder();
|
||||
|
@ -308,19 +303,6 @@ void CascadiaSettings::_ValidateProfilesExist()
|
|||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Walks through each profile, and ensures that they had a GUID set at some
|
||||
// point. If the profile did _not_ have a GUID ever set for it, generate a
|
||||
// temporary runtime GUID for it. This validation does not add any warnings.
|
||||
void CascadiaSettings::_ValidateProfilesHaveGuid()
|
||||
{
|
||||
for (auto profile : _allProfiles)
|
||||
{
|
||||
auto profileImpl = winrt::get_self<implementation::Profile>(profile);
|
||||
profileImpl->GenerateGuidIfNecessary();
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Resolves the "defaultProfile", which can be a profile name, to a GUID
|
||||
// and stores it back to the globals.
|
||||
|
@ -509,7 +491,8 @@ void CascadiaSettings::_ValidateAllSchemesExist()
|
|||
const auto schemeName = profile.ColorSchemeName();
|
||||
if (!_globals->ColorSchemes().HasKey(schemeName))
|
||||
{
|
||||
profile.ColorSchemeName({ L"Campbell" });
|
||||
// Clear the user set color scheme. We'll just fallback instead.
|
||||
profile.ClearColorSchemeName();
|
||||
foundInvalidScheme = true;
|
||||
}
|
||||
}
|
||||
|
@ -727,7 +710,8 @@ void CascadiaSettings::_ValidateKeybindings()
|
|||
// we find any invalid background images.
|
||||
void CascadiaSettings::_ValidateNoGlobalsKey()
|
||||
{
|
||||
if (auto oldGlobalsProperty{ _userSettings["globals"] })
|
||||
// use isMember here. If you use [], you're actually injecting "globals": null.
|
||||
if (_userSettings.isMember("globals"))
|
||||
{
|
||||
_warnings.Append(SettingsLoadWarnings::LegacyGlobalsProperty);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ Author(s):
|
|||
// fwdecl unittest classes
|
||||
namespace SettingsModelLocalTests
|
||||
{
|
||||
class SerializationTests;
|
||||
class DeserializationTests;
|
||||
class ProfileTests;
|
||||
class ColorSchemeTests;
|
||||
|
@ -74,6 +75,9 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
static com_ptr<CascadiaSettings> FromJson(const Json::Value& json);
|
||||
void LayerJson(const Json::Value& json);
|
||||
|
||||
void WriteSettingsToDisk() const;
|
||||
Json::Value ToJson() const;
|
||||
|
||||
static hstring SettingsPath();
|
||||
static hstring DefaultSettingsPath();
|
||||
|
||||
|
@ -124,7 +128,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
void _LoadDynamicProfiles();
|
||||
|
||||
static bool _IsPackaged();
|
||||
static void _WriteSettings(const std::string_view content);
|
||||
static void _WriteSettings(std::string_view content, const hstring filepath);
|
||||
static std::optional<std::string> _ReadUserSettings();
|
||||
static std::optional<std::string> _ReadFile(HANDLE hFile);
|
||||
|
||||
|
@ -133,7 +137,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
|
||||
void _ValidateSettings();
|
||||
void _ValidateProfilesExist();
|
||||
void _ValidateProfilesHaveGuid();
|
||||
void _ValidateDefaultProfileExists();
|
||||
void _ValidateNoDuplicateProfiles();
|
||||
void _ResolveDefaultProfile();
|
||||
|
@ -144,6 +147,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
void _ValidateKeybindings();
|
||||
void _ValidateNoGlobalsKey();
|
||||
|
||||
friend class SettingsModelLocalTests::SerializationTests;
|
||||
friend class SettingsModelLocalTests::DeserializationTests;
|
||||
friend class SettingsModelLocalTests::ProfileTests;
|
||||
friend class SettingsModelLocalTests::ColorSchemeTests;
|
||||
|
|
|
@ -11,6 +11,8 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
CascadiaSettings(String json);
|
||||
CascadiaSettings Copy();
|
||||
|
||||
void WriteSettingsToDisk();
|
||||
|
||||
static CascadiaSettings LoadDefaults();
|
||||
static CascadiaSettings LoadAll();
|
||||
static CascadiaSettings LoadUniversal();
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "JsonUtils.h"
|
||||
#include <appmodel.h>
|
||||
#include <shlobj.h>
|
||||
#include <fmt/chrono.h>
|
||||
|
||||
// defaults.h is a file containing the default json settings in a std::string_view
|
||||
#include "defaults.h"
|
||||
|
@ -28,10 +29,12 @@ static constexpr std::wstring_view UnpackagedSettingsFolderName{ L"Microsoft\\Wi
|
|||
static constexpr std::wstring_view DefaultsFilename{ L"defaults.json" };
|
||||
|
||||
static constexpr std::string_view SchemaKey{ "$schema" };
|
||||
static constexpr std::string_view SchemaValue{ "https://aka.ms/terminal-profiles-schema" };
|
||||
static constexpr std::string_view ProfilesKey{ "profiles" };
|
||||
static constexpr std::string_view DefaultSettingsKey{ "defaults" };
|
||||
static constexpr std::string_view ProfilesListKey{ "list" };
|
||||
static constexpr std::string_view KeybindingsKey{ "keybindings" };
|
||||
static constexpr std::string_view LegacyKeybindingsKey{ "keybindings" };
|
||||
static constexpr std::string_view ActionsKey{ "actions" };
|
||||
static constexpr std::string_view SchemesKey{ "schemes" };
|
||||
|
||||
static constexpr std::string_view DisabledProfileSourcesKey{ "disabledProfileSources" };
|
||||
|
@ -188,7 +191,7 @@ winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings CascadiaSettings::
|
|||
|
||||
try
|
||||
{
|
||||
_WriteSettings(resultPtr->_userSettingsString);
|
||||
_WriteSettings(resultPtr->_userSettingsString, CascadiaSettings::SettingsPath());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
@ -221,7 +224,7 @@ winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings CascadiaSettings::
|
|||
}
|
||||
|
||||
// If the user had keybinding settings preferences, we want to learn from them to make better defaults
|
||||
auto userKeybindings = resultPtr->_userSettings[JsonKey(KeybindingsKey)];
|
||||
auto userKeybindings = resultPtr->_userSettings[JsonKey(LegacyKeybindingsKey)];
|
||||
if (!userKeybindings.empty())
|
||||
{
|
||||
// If there are custom key bindings, let's understand what they are because maybe the defaults aren't good enough
|
||||
|
@ -366,8 +369,6 @@ void CascadiaSettings::_LoadDynamicProfiles()
|
|||
auto profiles = generator->GenerateProfiles();
|
||||
for (auto& profile : profiles)
|
||||
{
|
||||
// If the profile did not have a GUID when it was generated,
|
||||
// we'll synthesize a GUID for it in _ValidateProfilesHaveGuid
|
||||
profile.Source(generatorNamespace);
|
||||
|
||||
_allProfiles.Append(profile);
|
||||
|
@ -829,7 +830,7 @@ bool CascadiaSettings::_IsPackaged()
|
|||
}
|
||||
|
||||
// Method Description:
|
||||
// - Writes the given content in UTF-8 to our settings file using the Win32 APIS's.
|
||||
// - Writes the given content in UTF-8 to a settings file using the Win32 APIS's.
|
||||
// Will overwrite any existing content in the file.
|
||||
// Arguments:
|
||||
// - content: the given string of content to write to the file.
|
||||
|
@ -837,11 +838,9 @@ bool CascadiaSettings::_IsPackaged()
|
|||
// - <none>
|
||||
// This can throw an exception if we fail to open the file for writing, or we
|
||||
// fail to write the file
|
||||
void CascadiaSettings::_WriteSettings(const std::string_view content)
|
||||
void CascadiaSettings::_WriteSettings(const std::string_view content, const hstring filepath)
|
||||
{
|
||||
auto pathToSettingsFile{ CascadiaSettings::SettingsPath() };
|
||||
|
||||
wil::unique_hfile hOut{ CreateFileW(pathToSettingsFile.c_str(),
|
||||
wil::unique_hfile hOut{ CreateFileW(filepath.c_str(),
|
||||
GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
nullptr,
|
||||
|
@ -1039,3 +1038,83 @@ const Json::Value& CascadiaSettings::_GetDisabledProfileSourcesJsonObject(const
|
|||
}
|
||||
return json[JsonKey(DisabledProfileSourcesKey)];
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Write the current state of CascadiaSettings to our settings file
|
||||
// - Create a backup file with the current contents, if one does not exist
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void CascadiaSettings::WriteSettingsToDisk() const
|
||||
{
|
||||
const auto settingsPath{ CascadiaSettings::SettingsPath() };
|
||||
|
||||
try
|
||||
{
|
||||
// create a timestamped backup file
|
||||
const auto clock{ std::chrono::system_clock() };
|
||||
const auto timeStamp{ clock.to_time_t(clock.now()) };
|
||||
const winrt::hstring backupSettingsPath{ fmt::format(L"{}.{:%Y-%m-%dT%H-%M-%S}.backup", settingsPath, fmt::localtime(timeStamp)) };
|
||||
_WriteSettings(_userSettingsString, backupSettingsPath);
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
// write current settings to current settings file
|
||||
Json::StreamWriterBuilder wbuilder;
|
||||
wbuilder.settings_["indentation"] = " ";
|
||||
wbuilder.settings_["enableYAMLCompatibility"] = true; // suppress spaces around colons
|
||||
|
||||
const auto styledString{ Json::writeString(wbuilder, ToJson()) };
|
||||
_WriteSettings(styledString, settingsPath);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Create a new serialized JsonObject from an instance of this class
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// the JsonObject representing this instance
|
||||
Json::Value CascadiaSettings::ToJson() const
|
||||
{
|
||||
// top-level json object
|
||||
// directly inject "globals" and "$schema" into here
|
||||
Json::Value json{ _globals->ToJson() };
|
||||
JsonUtils::SetValueForKey(json, SchemaKey, JsonKey(SchemaValue));
|
||||
|
||||
// "profiles" will always be serialized as an object
|
||||
Json::Value profiles{ Json::ValueType::objectValue };
|
||||
profiles[JsonKey(DefaultSettingsKey)] = _userDefaultProfileSettings ? _userDefaultProfileSettings->ToJson() :
|
||||
Json::ValueType::objectValue;
|
||||
Json::Value profilesList{ Json::ValueType::arrayValue };
|
||||
for (const auto& entry : _allProfiles)
|
||||
{
|
||||
const auto prof{ winrt::get_self<implementation::Profile>(entry) };
|
||||
profilesList.append(prof->ToJson());
|
||||
}
|
||||
profiles[JsonKey(ProfilesListKey)] = profilesList;
|
||||
json[JsonKey(ProfilesKey)] = profiles;
|
||||
|
||||
// TODO GH#8100:
|
||||
// "schemes" will be an accumulation of _all_ the color schemes
|
||||
// including all of the ones from defaults.json
|
||||
Json::Value schemes{ Json::ValueType::arrayValue };
|
||||
for (const auto& entry : _globals->ColorSchemes())
|
||||
{
|
||||
const auto scheme{ winrt::get_self<implementation::ColorScheme>(entry.Value()) };
|
||||
schemes.append(scheme->ToJson());
|
||||
}
|
||||
json[JsonKey(SchemesKey)] = schemes;
|
||||
|
||||
// "actions"/"keybindings" will be whatever blob we had in the file
|
||||
if (_userSettings.isMember(JsonKey(LegacyKeybindingsKey)))
|
||||
{
|
||||
json[JsonKey(LegacyKeybindingsKey)] = _userSettings[JsonKey(LegacyKeybindingsKey)];
|
||||
}
|
||||
if (_userSettings.isMember(JsonKey(ActionsKey)))
|
||||
{
|
||||
json[JsonKey(ActionsKey)] = _userSettings[JsonKey(ActionsKey)];
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
|
|
@ -129,8 +129,8 @@ void ColorScheme::LayerJson(const Json::Value& json)
|
|||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// <none>
|
||||
Json::Value ColorScheme::ToJson()
|
||||
// - the JsonObject representing this instance
|
||||
Json::Value ColorScheme::ToJson() const
|
||||
{
|
||||
Json::Value json{ Json::ValueType::objectValue };
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
bool ShouldBeLayered(const Json::Value& json) const;
|
||||
void LayerJson(const Json::Value& json);
|
||||
|
||||
Json::Value ToJson();
|
||||
Json::Value ToJson() const;
|
||||
|
||||
static std::optional<std::wstring> GetNameFromJson(const Json::Value& json);
|
||||
|
||||
|
|
|
@ -53,12 +53,16 @@ static constexpr bool debugFeaturesDefault{ true };
|
|||
static constexpr bool debugFeaturesDefault{ false };
|
||||
#endif
|
||||
|
||||
bool GlobalAppSettings::_getDefaultDebugFeaturesValue()
|
||||
{
|
||||
return debugFeaturesDefault;
|
||||
}
|
||||
|
||||
GlobalAppSettings::GlobalAppSettings() :
|
||||
_keymap{ winrt::make_self<KeyMapping>() },
|
||||
_keybindingsWarnings{},
|
||||
_validDefaultProfile{ false },
|
||||
_defaultProfile{},
|
||||
_DebugFeaturesEnabled{ debugFeaturesDefault }
|
||||
_defaultProfile{}
|
||||
{
|
||||
_commands = winrt::single_threaded_map<winrt::hstring, Model::Command>();
|
||||
_colorSchemes = winrt::single_threaded_map<winrt::hstring, Model::ColorScheme>();
|
||||
|
@ -347,3 +351,49 @@ winrt::Windows::Foundation::Collections::IMapView<winrt::hstring, winrt::Microso
|
|||
{
|
||||
return _commands.GetView();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Create a new serialized JsonObject from an instance of this class
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - the JsonObject representing this instance
|
||||
Json::Value GlobalAppSettings::ToJson() const
|
||||
{
|
||||
Json::Value json{ Json::ValueType::objectValue };
|
||||
|
||||
// clang-format off
|
||||
JsonUtils::SetValueForKey(json, DefaultProfileKey, _UnparsedDefaultProfile);
|
||||
JsonUtils::SetValueForKey(json, AlwaysShowTabsKey, _AlwaysShowTabs);
|
||||
JsonUtils::SetValueForKey(json, ConfirmCloseAllKey, _ConfirmCloseAllTabs);
|
||||
JsonUtils::SetValueForKey(json, InitialRowsKey, _InitialRows);
|
||||
JsonUtils::SetValueForKey(json, InitialColsKey, _InitialCols);
|
||||
JsonUtils::SetValueForKey(json, InitialPositionKey, _InitialPosition);
|
||||
JsonUtils::SetValueForKey(json, ShowTitleInTitlebarKey, _ShowTitleInTitlebar);
|
||||
JsonUtils::SetValueForKey(json, ShowTabsInTitlebarKey, _ShowTabsInTitlebar);
|
||||
JsonUtils::SetValueForKey(json, WordDelimitersKey, _WordDelimiters);
|
||||
JsonUtils::SetValueForKey(json, CopyOnSelectKey, _CopyOnSelect);
|
||||
JsonUtils::SetValueForKey(json, CopyFormattingKey, _CopyFormatting);
|
||||
JsonUtils::SetValueForKey(json, WarnAboutLargePasteKey, _WarnAboutLargePaste);
|
||||
JsonUtils::SetValueForKey(json, WarnAboutMultiLinePasteKey, _WarnAboutMultiLinePaste);
|
||||
JsonUtils::SetValueForKey(json, LaunchModeKey, _LaunchMode);
|
||||
JsonUtils::SetValueForKey(json, ThemeKey, _Theme);
|
||||
JsonUtils::SetValueForKey(json, TabWidthModeKey, _TabWidthMode);
|
||||
JsonUtils::SetValueForKey(json, SnapToGridOnResizeKey, _SnapToGridOnResize);
|
||||
JsonUtils::SetValueForKey(json, DebugFeaturesKey, _DebugFeaturesEnabled);
|
||||
JsonUtils::SetValueForKey(json, ForceFullRepaintRenderingKey, _ForceFullRepaintRendering);
|
||||
JsonUtils::SetValueForKey(json, SoftwareRenderingKey, _SoftwareRendering);
|
||||
JsonUtils::SetValueForKey(json, ForceVTInputKey, _ForceVTInput);
|
||||
JsonUtils::SetValueForKey(json, EnableStartupTaskKey, _StartOnUserLogin);
|
||||
JsonUtils::SetValueForKey(json, AlwaysOnTopKey, _AlwaysOnTop);
|
||||
JsonUtils::SetValueForKey(json, TabSwitcherModeKey, _TabSwitcherMode);
|
||||
JsonUtils::SetValueForKey(json, DisableAnimationsKey, _DisableAnimations);
|
||||
// clang-format on
|
||||
|
||||
// TODO GH#8100: keymap needs to be serialized here
|
||||
// For deserialization, we iterate over each action in the Json and interpret it as a keybinding, then as a command.
|
||||
// Converting this back to JSON is a problem because we have no way to know if a Command and Keybinding come from
|
||||
// the same entry.
|
||||
|
||||
return json;
|
||||
}
|
||||
|
|
|
@ -46,6 +46,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
static com_ptr<GlobalAppSettings> FromJson(const Json::Value& json);
|
||||
void LayerJson(const Json::Value& json);
|
||||
|
||||
Json::Value ToJson() const;
|
||||
|
||||
std::vector<SettingsLoadWarnings> KeybindingsWarnings() const;
|
||||
|
||||
Windows::Foundation::Collections::IMapView<hstring, Model::Command> Commands() noexcept;
|
||||
|
@ -78,7 +80,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
GETSET_SETTING(bool, ForceFullRepaintRendering, false);
|
||||
GETSET_SETTING(bool, SoftwareRendering, false);
|
||||
GETSET_SETTING(bool, ForceVTInput, false);
|
||||
GETSET_SETTING(bool, DebugFeaturesEnabled); // default value set in constructor
|
||||
GETSET_SETTING(bool, DebugFeaturesEnabled, _getDefaultDebugFeaturesValue());
|
||||
GETSET_SETTING(bool, StartOnUserLogin, false);
|
||||
GETSET_SETTING(bool, AlwaysOnTop, false);
|
||||
GETSET_SETTING(Model::TabSwitcherMode, TabSwitcherMode, Model::TabSwitcherMode::MostRecentlyUsed);
|
||||
|
@ -96,6 +98,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
Windows::Foundation::Collections::IMap<hstring, Model::Command> _commands;
|
||||
|
||||
std::optional<hstring> _getUnparsedDefaultProfileImpl() const;
|
||||
static bool _getDefaultDebugFeaturesValue();
|
||||
|
||||
friend class SettingsModelLocalTests::DeserializationTests;
|
||||
friend class SettingsModelLocalTests::ColorSchemeTests;
|
||||
|
|
|
@ -88,6 +88,13 @@ namespace Microsoft::Terminal::Settings::Model::JsonUtils
|
|||
static constexpr auto&& Value(const ::winrt::Windows::Foundation::IReference<T>& o) { return o.Value(); }
|
||||
};
|
||||
|
||||
class SerializationError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
SerializationError() :
|
||||
runtime_error("failed to serialize") {}
|
||||
};
|
||||
|
||||
class DeserializationError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
|
@ -517,7 +524,7 @@ namespace Microsoft::Terminal::Settings::Model::JsonUtils
|
|||
return { pair.first.data() };
|
||||
}
|
||||
}
|
||||
FAIL_FAST();
|
||||
throw SerializationError{};
|
||||
}
|
||||
|
||||
std::string TypeDescription() const
|
||||
|
|
|
@ -291,6 +291,7 @@ void Profile::LayerJson(const Json::Value& json)
|
|||
JsonUtils::GetValueForKey(json, NameKey, _Name);
|
||||
JsonUtils::GetValueForKey(json, GuidKey, _Guid);
|
||||
JsonUtils::GetValueForKey(json, HiddenKey, _Hidden);
|
||||
JsonUtils::GetValueForKey(json, SourceKey, _Source);
|
||||
|
||||
// Core Settings
|
||||
JsonUtils::GetValueForKey(json, ForegroundKey, _Foreground);
|
||||
|
@ -417,27 +418,6 @@ std::wstring Profile::EvaluateStartingDirectory(const std::wstring& directory)
|
|||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// will _not_ change the profile's GUID.
|
||||
void Profile::GenerateGuidIfNecessary() noexcept
|
||||
{
|
||||
if (!_getGuidImpl().has_value())
|
||||
{
|
||||
// Always use the name to generate the temporary GUID. That way, across
|
||||
// reloads, we'll generate the same static GUID.
|
||||
_Guid = Profile::_GenerateGuidForProfile(Name(), Source());
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hSettingsModelProvider,
|
||||
"SynthesizedGuidForProfile",
|
||||
TraceLoggingDescription("Event emitted when a profile is deserialized without a GUID"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
}
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Returns true if the given JSON object represents a dynamic profile object.
|
||||
// If it is a dynamic profile object, we should make sure to only layer the
|
||||
|
@ -540,3 +520,63 @@ void Profile::BackgroundImageVerticalAlignment(const VerticalAlignment& value) n
|
|||
}
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
// Method Description:
|
||||
// - Create a new serialized JsonObject from an instance of this class
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - the JsonObject representing this instance
|
||||
Json::Value Profile::ToJson() const
|
||||
{
|
||||
Json::Value json{ Json::ValueType::objectValue };
|
||||
|
||||
// Profile-specific Settings
|
||||
JsonUtils::SetValueForKey(json, NameKey, _Name);
|
||||
JsonUtils::SetValueForKey(json, GuidKey, _Guid);
|
||||
JsonUtils::SetValueForKey(json, HiddenKey, _Hidden);
|
||||
JsonUtils::SetValueForKey(json, SourceKey, _Source);
|
||||
|
||||
// Core Settings
|
||||
JsonUtils::SetValueForKey(json, ForegroundKey, _Foreground);
|
||||
JsonUtils::SetValueForKey(json, BackgroundKey, _Background);
|
||||
JsonUtils::SetValueForKey(json, SelectionBackgroundKey, _SelectionBackground);
|
||||
JsonUtils::SetValueForKey(json, CursorColorKey, _CursorColor);
|
||||
JsonUtils::SetValueForKey(json, ColorSchemeKey, _ColorSchemeName);
|
||||
|
||||
// TODO:MSFT:20642297 - Use a sentinel value (-1) for "Infinite scrollback"
|
||||
JsonUtils::SetValueForKey(json, HistorySizeKey, _HistorySize);
|
||||
JsonUtils::SetValueForKey(json, SnapOnInputKey, _SnapOnInput);
|
||||
JsonUtils::SetValueForKey(json, AltGrAliasingKey, _AltGrAliasing);
|
||||
JsonUtils::SetValueForKey(json, CursorHeightKey, _CursorHeight);
|
||||
JsonUtils::SetValueForKey(json, CursorShapeKey, _CursorShape);
|
||||
JsonUtils::SetValueForKey(json, TabTitleKey, _TabTitle);
|
||||
|
||||
// Control Settings
|
||||
JsonUtils::SetValueForKey(json, FontWeightKey, _FontWeight);
|
||||
JsonUtils::SetValueForKey(json, ConnectionTypeKey, _ConnectionType);
|
||||
JsonUtils::SetValueForKey(json, CommandlineKey, _Commandline);
|
||||
JsonUtils::SetValueForKey(json, FontFaceKey, _FontFace);
|
||||
JsonUtils::SetValueForKey(json, FontSizeKey, _FontSize);
|
||||
JsonUtils::SetValueForKey(json, AcrylicTransparencyKey, _AcrylicOpacity);
|
||||
JsonUtils::SetValueForKey(json, UseAcrylicKey, _UseAcrylic);
|
||||
JsonUtils::SetValueForKey(json, SuppressApplicationTitleKey, _SuppressApplicationTitle);
|
||||
JsonUtils::SetValueForKey(json, CloseOnExitKey, _CloseOnExit);
|
||||
|
||||
// PermissiveStringConverter is unnecessary for serialization
|
||||
JsonUtils::SetValueForKey(json, PaddingKey, _Padding);
|
||||
|
||||
JsonUtils::SetValueForKey(json, ScrollbarStateKey, _ScrollState);
|
||||
JsonUtils::SetValueForKey(json, StartingDirectoryKey, _StartingDirectory);
|
||||
JsonUtils::SetValueForKey(json, IconKey, _Icon);
|
||||
JsonUtils::SetValueForKey(json, BackgroundImageKey, _BackgroundImagePath);
|
||||
JsonUtils::SetValueForKey(json, BackgroundImageOpacityKey, _BackgroundImageOpacity);
|
||||
JsonUtils::SetValueForKey(json, BackgroundImageStretchModeKey, _BackgroundImageStretchMode);
|
||||
JsonUtils::SetValueForKey(json, BackgroundImageAlignmentKey, _BackgroundImageAlignment);
|
||||
JsonUtils::SetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect);
|
||||
JsonUtils::SetValueForKey(json, AntialiasingModeKey, _AntialiasingMode);
|
||||
JsonUtils::SetValueForKey(json, TabColorKey, _TabColor);
|
||||
JsonUtils::SetValueForKey(json, BellStyleKey, _BellStyle);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
|
|
@ -55,10 +55,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
bool ShouldBeLayered(const Json::Value& json) const;
|
||||
void LayerJson(const Json::Value& json);
|
||||
static bool IsDynamicProfileObject(const Json::Value& json);
|
||||
Json::Value ToJson() const;
|
||||
|
||||
hstring EvaluatedStartingDirectory() const;
|
||||
hstring ExpandedBackgroundImagePath() const;
|
||||
void GenerateGuidIfNecessary() noexcept;
|
||||
static guid GetGuidOrGenerateForJson(const Json::Value& json) noexcept;
|
||||
|
||||
// BackgroundImageAlignment is 1 setting saved as 2 separate values
|
||||
|
|
|
@ -154,6 +154,19 @@ struct ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait<::winr
|
|||
return weight;
|
||||
}
|
||||
|
||||
Json::Value ToJson(const ::winrt::Windows::UI::Text::FontWeight& val)
|
||||
{
|
||||
const auto weight{ val.Weight };
|
||||
try
|
||||
{
|
||||
return BaseEnumMapper::ToJson(weight);
|
||||
}
|
||||
catch (SerializationError&)
|
||||
{
|
||||
return weight;
|
||||
}
|
||||
}
|
||||
|
||||
bool CanConvert(const Json::Value& json)
|
||||
{
|
||||
return BaseEnumMapper::CanConvert(json) || json.isUInt();
|
||||
|
|
|
@ -110,8 +110,7 @@ namespace TerminalAppUnitTests
|
|||
|
||||
void DynamicProfileTests::TestGenGuidsForProfiles()
|
||||
{
|
||||
// We'll generate GUIDs during
|
||||
// CascadiaSettings::_ValidateProfilesHaveGuid. We should make sure that
|
||||
// We'll generate GUIDs in the Profile::Guid getter. We should make sure that
|
||||
// the GUID generated for a dynamic profile (with a source) is different
|
||||
// than that of a profile without a source.
|
||||
|
||||
|
@ -167,14 +166,6 @@ namespace TerminalAppUnitTests
|
|||
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(4).HasGuid());
|
||||
VERIFY_IS_FALSE(settings->_allProfiles.GetAt(4).Source().empty());
|
||||
|
||||
settings->_ValidateProfilesHaveGuid();
|
||||
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(0).HasGuid());
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(1).HasGuid());
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(2).HasGuid());
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(3).HasGuid());
|
||||
VERIFY_IS_TRUE(settings->_allProfiles.GetAt(4).HasGuid());
|
||||
|
||||
VERIFY_ARE_NOT_EQUAL(settings->_allProfiles.GetAt(0).Guid(),
|
||||
settings->_allProfiles.GetAt(1).Guid());
|
||||
VERIFY_ARE_NOT_EQUAL(settings->_allProfiles.GetAt(0).Guid(),
|
||||
|
|
|
@ -120,7 +120,7 @@ namespace TerminalAppUnitTests
|
|||
{
|
||||
// Parse some profiles without guids. We should NOT generate new guids
|
||||
// for them. If a profile doesn't have a GUID, we'll leave its _guid
|
||||
// set to nullopt. CascadiaSettings::_ValidateProfilesHaveGuid will
|
||||
// set to nullopt. The Profile::Guid() getter will
|
||||
// ensure all profiles have a GUID that's actually set.
|
||||
// The null guid _is_ a valid guid, so we won't re-generate that
|
||||
// guid. null is _not_ a valid guid, so we'll leave that nullopt
|
||||
|
|
Loading…
Reference in a new issue