Skip to content

Commit

Permalink
Reduce usage of Json::Value throughout Terminal.Settings.Model (micro…
Browse files Browse the repository at this point in the history
…soft#11184)

This commit reduces the code surface that interacts with raw JSON data,
reducing code complexity and improving maintainability.
Files that needed to be changed drastically were additionally
cleaned up to remove any code cruft that has accrued over time.

In order to facility this the following changes were made:
* Move JSON handling from `CascadiaSettings` into `SettingsLoader`
  This allows us to use STL containers for data model instances.
  For instance profiles are now added to a hashmap for O(1) lookup.
* JSON parsing within `SettingsLoader` doesn't differentiate between user,
  inbox and fragment JSON data, reducing code complexity and size.
  It also centralizes common concerns, like profile deduplication and
  ensuring that all profiles are assigned a GUID.
* Direct JSON modification, like the insertion of dynamic profiles into
  settings.json were removed. This vastly reduces code complexity,
  but unfortunately removes support for comments in JSON on first start.
* `ColorScheme`s cannot be layered. As such its `LayerJson` API was replaced
  with `FromJson`, allowing us to remove JSON-based color scheme validation.
* `Profile`s used to test their wish to layer using `ShouldBeLayered`, which
  was replaced with a GUID-based hashmap lookup on previously parsed profiles.

Further changes were made as improvements upon the previous changes:
* Compact the JSON files embedded binary, saving 28kB
* Prevent double-initialization of the color table in `ColorScheme`
* Making `til::color` getters `constexpr`, allow better optimizations

The result is a reduction of:
* 48kB binary size for the Settings.Model.dll
* 5-10% startup duration
* 26% code for the `CascadiaSettings` class
* 1% overall code in this project

Furthermore this results in the following breaking changes:
* The long deprecated "globals" settings object will not be detected and no
  warning will be created during load.
* The initial creation of a new settings.json will not produce helpful comments.

Both cases are caused by the removal of manual JSON handling and the
move to representing the settings file with model objects instead

## PR Checklist
* [x] Closes microsoft#5276
* [x] Closes microsoft#7421
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed

* Out-of-box-experience is identical to before ✔️
  (Except for the settings.json file lacking comments.)
* Existing user settings load correctly ✔️
* New WSL instances are added to user settings ✔️
* New fragments are added to user settings ✔️
* All profiles are assigned GUIDs ✔️
  • Loading branch information
lhecker authored Sep 22, 2021
1 parent 591a671 commit 168d28b
Show file tree
Hide file tree
Showing 66 changed files with 2,251 additions and 5,456 deletions.
3 changes: 3 additions & 0 deletions .github/actions/spelling/expect/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,7 @@ DECSTR
DECSWL
DECTCEM
Dedupe
deduplicate
deduplicated
DEFAPP
DEFAULTBACKGROUND
Expand Down Expand Up @@ -784,6 +785,7 @@ FINDSTRINGEXACT
FINDUP
FIter
FIXEDCONVERTED
FIXEDFILEINFO
Flg
flyout
fmodern
Expand Down Expand Up @@ -1992,6 +1994,7 @@ resx
retval
rfa
rfc
rfid
rftp
rgb
rgba
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ If you would like to ask a question that you feel doesn't warrant an issue
* You must [enable Developer Mode in the Windows Settings
app](https://docs.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development)
to locally install and run Windows Terminal
* You must have [PowerShell 7 or later](https://github.com/PowerShell/PowerShell/releases/latest) installed
* You must have the [Windows 10 1903
SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk)
installed
Expand Down
532 changes: 244 additions & 288 deletions src/cascadia/LocalTests_SettingsModel/ColorSchemeTests.cpp

Large diffs are not rendered by default.

6 changes: 0 additions & 6 deletions src/cascadia/LocalTests_SettingsModel/CommandTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,6 @@ namespace SettingsModelLocalTests
TEST_METHOD(TestLayerOnAutogeneratedName);

TEST_METHOD(TestGenerateCommandline);

TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
return true;
}
};

void CommandTests::ManyCommandsSameAction()
Expand Down
1,821 changes: 441 additions & 1,380 deletions src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp

Large diffs are not rendered by default.

30 changes: 10 additions & 20 deletions src/cascadia/LocalTests_SettingsModel/JsonTestClass.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,34 @@ Module Name:
Abstract:
- This class is a helper that can be used to quickly create tests that need to
read & parse json data. Test classes that need to read JSON should make sure
to derive from this class, and also make sure to call InitializeJsonReader()
in the TEST_CLASS_SETUP().
read & parse json data.
Author(s):
Mike Griese (migrie) August-2019
--*/

#pragma once

class JsonTestClass
{
public:
void InitializeJsonReader()
{
_reader = std::unique_ptr<Json::CharReader>(Json::CharReaderBuilder::CharReaderBuilder().newCharReader());
};

void InitializeJsonWriter()
static Json::Value VerifyParseSucceeded(const std::string_view& content)
{
_writer = std::unique_ptr<Json::StreamWriter>(Json::StreamWriterBuilder::StreamWriterBuilder().newStreamWriter());
}
static const std::unique_ptr<Json::CharReader> reader{ Json::CharReaderBuilder::CharReaderBuilder().newCharReader() };

Json::Value VerifyParseSucceeded(std::string content)
{
Json::Value root;
std::string errs;
const bool parseResult = _reader->parse(content.c_str(), content.c_str() + content.size(), &root, &errs);
const bool parseResult = reader->parse(content.data(), content.data() + content.size(), &root, &errs);
VERIFY_IS_TRUE(parseResult, winrt::to_hstring(errs).c_str());
return root;
};

std::string toString(const Json::Value& json)
static std::string toString(const Json::Value& json)
{
static const std::unique_ptr<Json::StreamWriter> writer{ Json::StreamWriterBuilder::StreamWriterBuilder().newStreamWriter() };

std::stringstream s;
_writer->write(json, &s);
writer->write(json, &s);
return s.str();
}

protected:
std::unique_ptr<Json::CharReader> _reader;
std::unique_ptr<Json::StreamWriter> _writer;
};
6 changes: 0 additions & 6 deletions src/cascadia/LocalTests_SettingsModel/KeyBindingsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,6 @@ namespace SettingsModelLocalTests

TEST_METHOD(TestGetKeyBindingForAction);
TEST_METHOD(KeybindingsWithoutVkey);

TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
return true;
}
};

void KeyBindingsTests::KeyChords()
Expand Down
Loading

0 comments on commit 168d28b

Please sign in to comment.