Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Switch to jsoncpp as our json library #1005

Merged
merged 33 commits into from
Jun 4, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
d0121a1
start work on an error dialog
zadjii-msft May 7, 2019
effefeb
Continue work on an error dialog
zadjii-msft May 8, 2019
00a8da4
This unfortunately didn't work
zadjii-msft May 15, 2019
643a177
Merge remote-tracking branch 'origin/master' into dev/migrie/f/gh-err…
zadjii-msft May 15, 2019
b51d03f
I'm just committing all of this, even though I really don't need most…
zadjii-msft May 20, 2019
c1d17f6
Cleanup for PR
zadjii-msft May 20, 2019
cb55215
Merge remote-tracking branch 'origin/master' into dev/migrie/f/gh-err…
zadjii-msft May 20, 2019
809a180
Include jsoncpp in the solution
zadjii-msft May 21, 2019
e8f5fb8
Merge branch 'master' into dev/migrie/f/gh-error-dialog
zadjii-msft May 21, 2019
5547ca5
PR feedback
zadjii-msft May 21, 2019
86e92c0
Merge branch 'dev/migrie/f/gh-error-dialog' into dev/migrie/f/jsoncpp
zadjii-msft May 21, 2019
dae4213
Serialize just colorschemes
zadjii-msft May 21, 2019
c88f69f
Serialize Profiles
zadjii-msft May 21, 2019
c84b8b3
Serialize the keybindings
zadjii-msft May 21, 2019
d2d8df6
Start work on parsing the json with jsoncpp
zadjii-msft May 22, 2019
4b8fcd1
Serialize Colorschemes
zadjii-msft May 22, 2019
96f49ac
Deserialize profiles
zadjii-msft May 22, 2019
a8a1bba
AppKeyBindings deserialization
zadjii-msft May 23, 2019
87b795a
Roundtrip the everything
zadjii-msft May 23, 2019
ddbbc12
Remove all the old serialization code
zadjii-msft May 23, 2019
72aef95
Merge branch 'master' into dev/migrie/f/jsoncpp
zadjii-msft May 24, 2019
6c268a0
gah serialize the starting directory too
zadjii-msft May 24, 2019
a2aa9db
Remove all the `_2`'s
zadjii-msft May 24, 2019
f60bfb3
throw a proper exception
zadjii-msft May 24, 2019
aeec8f5
My PR nits
zadjii-msft May 28, 2019
459d86c
Load as UTF-8 without rounttripping through an hstring
zadjii-msft May 28, 2019
3ebb504
Write the json content as utf-8 w/o roundtripping through an hstring
zadjii-msft May 28, 2019
5769a62
Remaining PR feedback
zadjii-msft May 28, 2019
511a66c
Merge remote-tracking branch 'origin/master' into dev/migrie/f/jsoncpp
zadjii-msft May 30, 2019
c4b2eef
Remaining PR nits
zadjii-msft May 30, 2019
097b7dd
Merge remote-tracking branch 'origin/master' into dev/migrie/f/jsoncpp
zadjii-msft May 30, 2019
63e0a23
Change the case of all the keys to PascalCase
zadjii-msft May 31, 2019
a68a9bb
Add a NOTICES file
DHowett May 31, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 75 additions & 50 deletions src/cascadia/TerminalApp/AppKeyBindingsSerialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,44 +13,44 @@ using namespace winrt::TerminalApp;
static constexpr std::string_view KEYS_KEY{ "keys" };
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
static constexpr std::string_view COMMAND_KEY{ "command" };

static constexpr std::wstring_view COPYTEXT_KEY{ L"copy" };
static constexpr std::wstring_view PASTETEXT_KEY{ L"paste" };
static constexpr std::wstring_view NEWTAB_KEY{ L"newTab" };
static constexpr std::wstring_view NEWTABWITHPROFILE0_KEY{ L"newTabProfile0" };
static constexpr std::wstring_view NEWTABWITHPROFILE1_KEY{ L"newTabProfile1" };
static constexpr std::wstring_view NEWTABWITHPROFILE2_KEY{ L"newTabProfile2" };
static constexpr std::wstring_view NEWTABWITHPROFILE3_KEY{ L"newTabProfile3" };
static constexpr std::wstring_view NEWTABWITHPROFILE4_KEY{ L"newTabProfile4" };
static constexpr std::wstring_view NEWTABWITHPROFILE5_KEY{ L"newTabProfile5" };
static constexpr std::wstring_view NEWTABWITHPROFILE6_KEY{ L"newTabProfile6" };
static constexpr std::wstring_view NEWTABWITHPROFILE7_KEY{ L"newTabProfile7" };
static constexpr std::wstring_view NEWTABWITHPROFILE8_KEY{ L"newTabProfile8" };
static constexpr std::wstring_view NEWWINDOW_KEY{ L"newWindow" };
static constexpr std::wstring_view CLOSEWINDOW_KEY{ L"closeWindow" };
static constexpr std::wstring_view CLOSETAB_KEY{ L"closeTab" };
static constexpr std::wstring_view SWITCHTOTAB_KEY{ L"switchToTab" };
static constexpr std::wstring_view NEXTTAB_KEY{ L"nextTab" };
static constexpr std::wstring_view PREVTAB_KEY{ L"prevTab" };
static constexpr std::wstring_view INCREASEFONTSIZE_KEY{ L"increaseFontSize" };
static constexpr std::wstring_view DECREASEFONTSIZE_KEY{ L"decreaseFontSize" };
static constexpr std::wstring_view SCROLLUP_KEY{ L"scrollUp" };
static constexpr std::wstring_view SCROLLDOWN_KEY{ L"scrollDown" };
static constexpr std::wstring_view SCROLLUPPAGE_KEY{ L"scrollUpPage" };
static constexpr std::wstring_view SCROLLDOWNPAGE_KEY{ L"scrollDownPage" };
static constexpr std::wstring_view SWITCHTOTAB0_KEY{ L"switchToTab0" };
static constexpr std::wstring_view SWITCHTOTAB1_KEY{ L"switchToTab1" };
static constexpr std::wstring_view SWITCHTOTAB2_KEY{ L"switchToTab2" };
static constexpr std::wstring_view SWITCHTOTAB3_KEY{ L"switchToTab3" };
static constexpr std::wstring_view SWITCHTOTAB4_KEY{ L"switchToTab4" };
static constexpr std::wstring_view SWITCHTOTAB5_KEY{ L"switchToTab5" };
static constexpr std::wstring_view SWITCHTOTAB6_KEY{ L"switchToTab6" };
static constexpr std::wstring_view SWITCHTOTAB7_KEY{ L"switchToTab7" };
static constexpr std::wstring_view SWITCHTOTAB8_KEY{ L"switchToTab8" };
static constexpr std::wstring_view OPENSETTINGS_KEY{ L"openSettings" };
static constexpr std::string_view COPYTEXT_KEY{ "copy" };
static constexpr std::string_view PASTETEXT_KEY{ "paste" };
static constexpr std::string_view NEWTAB_KEY{ "newTab" };
static constexpr std::string_view NEWTABWITHPROFILE0_KEY{ "newTabProfile0" };
static constexpr std::string_view NEWTABWITHPROFILE1_KEY{ "newTabProfile1" };
static constexpr std::string_view NEWTABWITHPROFILE2_KEY{ "newTabProfile2" };
static constexpr std::string_view NEWTABWITHPROFILE3_KEY{ "newTabProfile3" };
static constexpr std::string_view NEWTABWITHPROFILE4_KEY{ "newTabProfile4" };
static constexpr std::string_view NEWTABWITHPROFILE5_KEY{ "newTabProfile5" };
static constexpr std::string_view NEWTABWITHPROFILE6_KEY{ "newTabProfile6" };
static constexpr std::string_view NEWTABWITHPROFILE7_KEY{ "newTabProfile7" };
static constexpr std::string_view NEWTABWITHPROFILE8_KEY{ "newTabProfile8" };
static constexpr std::string_view NEWWINDOW_KEY{ "newWindow" };
static constexpr std::string_view CLOSEWINDOW_KEY{ "closeWindow" };
static constexpr std::string_view CLOSETAB_KEY{ "closeTab" };
static constexpr std::string_view SWITCHTOTAB_KEY{ "switchToTab" };
static constexpr std::string_view NEXTTAB_KEY{ "nextTab" };
static constexpr std::string_view PREVTAB_KEY{ "prevTab" };
static constexpr std::string_view INCREASEFONTSIZE_KEY{ "increaseFontSize" };
static constexpr std::string_view DECREASEFONTSIZE_KEY{ "decreaseFontSize" };
static constexpr std::string_view SCROLLUP_KEY{ "scrollUp" };
static constexpr std::string_view SCROLLDOWN_KEY{ "scrollDown" };
static constexpr std::string_view SCROLLUPPAGE_KEY{ "scrollUpPage" };
static constexpr std::string_view SCROLLDOWNPAGE_KEY{ "scrollDownPage" };
static constexpr std::string_view SWITCHTOTAB0_KEY{ "switchToTab0" };
static constexpr std::string_view SWITCHTOTAB1_KEY{ "switchToTab1" };
static constexpr std::string_view SWITCHTOTAB2_KEY{ "switchToTab2" };
static constexpr std::string_view SWITCHTOTAB3_KEY{ "switchToTab3" };
static constexpr std::string_view SWITCHTOTAB4_KEY{ "switchToTab4" };
static constexpr std::string_view SWITCHTOTAB5_KEY{ "switchToTab5" };
static constexpr std::string_view SWITCHTOTAB6_KEY{ "switchToTab6" };
static constexpr std::string_view SWITCHTOTAB7_KEY{ "switchToTab7" };
static constexpr std::string_view SWITCHTOTAB8_KEY{ "switchToTab8" };
static constexpr std::string_view OPENSETTINGS_KEY{ "openSettings" };

// 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.
static const std::map<std::wstring_view, ShortcutAction> commandNames {
static const std::map<std::string_view, ShortcutAction> commandNames {
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
{ COPYTEXT_KEY, ShortcutAction::CopyText },
{ PASTETEXT_KEY, ShortcutAction::PasteText },
{ NEWTAB_KEY, ShortcutAction::NewTab },
Expand Down Expand Up @@ -86,32 +86,42 @@ static const std::map<std::wstring_view, ShortcutAction> commandNames {
};

// Function Description:
// - Small helper to insert a given KeyChord, ShortcutAction pair into the
// given json array
// - Small helper to create a json value serialization of a single
// KeyBinding->Action maping. The created object is of schema:
// {
// keys:[String],
// command:String
// }
// Arguments:
// - bindingsArray: The JsonArray to insert the object into.
// - chord: The KeyChord to serailize and place in the json array
// - chord: The KeyChord to serialize
// - actionName: the name of the ShortcutAction to use with this KeyChord
static void _AddShortcutToJsonArray2(Json::Value& bindingsArray,
const KeyChord& chord,
const std::wstring_view& actionName)
// Return Value:
// - a Json::Value which is an equivalent serialization of this object.
static Json::Value _ShortcutAsJsonObject(const KeyChord& chord,
const std::string_view& actionName)
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
{
const auto keyString = KeyChordSerialization::ToString(chord);
if (keyString == L"")
{
return;
return nullptr;
}

Json::Value jsonObject;
Json::Value keysArray;
keysArray.append(winrt::to_string(keyString));

jsonObject[KEYS_KEY.data()] = keysArray;
jsonObject[COMMAND_KEY.data()] = winrt::to_string(actionName);
jsonObject[JsonKey(KEYS_KEY)] = keysArray;
jsonObject[JsonKey(COMMAND_KEY)] = actionName.data();

bindingsArray.append(jsonObject);
return jsonObject;
}

// Method Description:
// - Serialize this AppKeyBindings to a json array of objects. Each object in
// the array represents a single keybinding, mapping a KeyChord to a
// ShortcutAction.
// Return Value:
// - a Json::Value which is an equivalent serialization of this object.
Json::Value AppKeyBindingsSerialization::ToJson(const winrt::TerminalApp::AppKeyBindings& bindings)
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
{
Json::Value bindingsArray;
Expand All @@ -125,13 +135,28 @@ Json::Value AppKeyBindingsSerialization::ToJson(const winrt::TerminalApp::AppKey
const auto chord = bindings.GetKeyBinding(searchedForAction);
if (chord)
{
_AddShortcutToJsonArray2(bindingsArray, chord, searchedForName);
const auto serialization = _ShortcutAsJsonObject(chord, searchedForName);
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
if (serialization)
{
bindingsArray.append(serialization);
}
}
}

return bindingsArray;
}

// Method Description:
// - Deserialize an AppKeyBindings from the key mappings that are in the array
// `json`. The json array should contain an array of objects with both a
// `command` string and a `keys` array, where `command` is one of the names
// listed in `commandNames`, and `keys` is an array of keypresses. Currently,
// the array should contain a single string, which can be deserialized into a
// KeyChord.
// Arguments:
// - json: and array of JsonObject's to deserialize into our _keyShortcuts mapping.
// Return Value:
// - the newly constructed AppKeyBindings object.
winrt::TerminalApp::AppKeyBindings AppKeyBindingsSerialization::FromJson(const Json::Value& json)
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
{
winrt::TerminalApp::AppKeyBindings newBindings{};
Expand All @@ -140,8 +165,8 @@ winrt::TerminalApp::AppKeyBindings AppKeyBindingsSerialization::FromJson(const J
{
if (value.isObject())
{
const auto commandString = value[COMMAND_KEY.data()];
const auto keys = value[KEYS_KEY.data()];
const auto commandString = value[JsonKey(COMMAND_KEY)];
const auto keys = value[JsonKey(KEYS_KEY)];

if (commandString && keys)
{
Expand All @@ -153,7 +178,7 @@ winrt::TerminalApp::AppKeyBindings AppKeyBindingsSerialization::FromJson(const J
ShortcutAction action;

// Try matching the command to one we have
auto found = commandNames.find(GetWstringFromJson(commandString));
auto found = commandNames.find(commandString.asString());
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
if (found != commandNames.end())
{
action = found->second;
Expand Down
8 changes: 4 additions & 4 deletions src/cascadia/TerminalApp/CascadiaSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ class TerminalApp::CascadiaSettings final
void _CreateDefaultProfiles();

static bool _IsPackaged();
static void _SaveAsPackagedApp(const winrt::hstring content);
static void _SaveAsUnpackagedApp(const winrt::hstring content);
static void _SaveAsPackagedApp(const std::string content);
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
static void _SaveAsUnpackagedApp(const std::string content);
static std::wstring _GetFullPathToUnpackagedSettingsFile();
static winrt::hstring _GetPackagedSettingsPath();
static std::optional<winrt::hstring> _LoadAsPackagedApp();
static std::optional<winrt::hstring> _LoadAsUnpackagedApp();
static std::optional<std::string> _LoadAsPackagedApp();
static std::optional<std::string> _LoadAsUnpackagedApp();
static bool _isPowerShellCoreInstalledInPath(const std::wstring_view programFileEnv, std::filesystem::path& cmdline);
static bool _isPowerShellCoreInstalled(std::filesystem::path& cmdline);
static std::wstring ExpandEnvironmentVariableString(std::wstring_view source);
Expand Down
59 changes: 29 additions & 30 deletions src/cascadia/TerminalApp/CascadiaSettingsSerialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ static constexpr std::string_view SCHEMES_KEY{ "schemes" };
std::unique_ptr<CascadiaSettings> CascadiaSettings::LoadAll(const bool saveOnLoad)
{
std::unique_ptr<CascadiaSettings> resultPtr;
std::optional<winrt::hstring> fileData = _IsPackaged() ?
_LoadAsPackagedApp() : _LoadAsUnpackagedApp();
std::optional<std::string> fileData = _IsPackaged() ?
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
_LoadAsPackagedApp() : _LoadAsUnpackagedApp();

const bool foundFile = fileData.has_value();
if (foundFile)
Expand All @@ -52,11 +52,10 @@ std::unique_ptr<CascadiaSettings> CascadiaSettings::LoadAll(const bool saveOnLoa
// Parse the json data.
Json::Value root;
std::unique_ptr<Json::CharReader> reader{ Json::CharReaderBuilder::CharReaderBuilder().newCharReader() };
const auto raw = winrt::to_string(actualData);
std::string errs; // This string will recieve any error text from failing to parse.

// `parse` will return false if it fails.
if (!reader->parse(raw.c_str(), raw.c_str() + raw.size(), &root, &errs))
if (!reader->parse(actualData.c_str(), actualData.c_str() + actualData.size(), &root, &errs))
{
// TODO:GH#990 display this exception text to the user, in a
// copy-pasteable way.
Expand Down Expand Up @@ -98,19 +97,19 @@ std::unique_ptr<CascadiaSettings> CascadiaSettings::LoadAll(const bool saveOnLoa
// - <none>
void CascadiaSettings::SaveAll() const
{
const auto json2 = ToJson();
const auto json = ToJson();
Json::StreamWriterBuilder wbuilder;
// Use 4 spaces to indent instead of \t
wbuilder.settings_["indentation"] = " ";
const auto s = winrt::to_hstring(Json::writeString(wbuilder, json2));
const auto serializedString = Json::writeString(wbuilder, json);

if (_IsPackaged())
{
_SaveAsPackagedApp(s);
_SaveAsPackagedApp(serializedString);
}
else
{
_SaveAsUnpackagedApp(s);
_SaveAsUnpackagedApp(serializedString);
}
}

Expand All @@ -123,10 +122,6 @@ void CascadiaSettings::SaveAll() const
Json::Value CascadiaSettings::ToJson() const
{
Json::Value root;
// TODO: Globals

// TODO: put the keybindings in the globals (now that the order doesn't
// really matter).

Json::Value profilesArray;
for (const auto& profile : _profiles)
Expand Down Expand Up @@ -243,7 +238,7 @@ bool CascadiaSettings::_IsPackaged()
// - content: the given string of content to write to the file.
// Return Value:
// - <none>
void CascadiaSettings::_SaveAsPackagedApp(const winrt::hstring content)
void CascadiaSettings::_SaveAsPackagedApp(const std::string content)
{
auto curr = ApplicationData::Current();
auto folder = curr.RoamingFolder();
Expand All @@ -254,11 +249,13 @@ void CascadiaSettings::_SaveAsPackagedApp(const winrt::hstring content)
auto file = file_async.get();

DataWriter dw = DataWriter();

// DataWriter will convert UTF-16 string to UTF-8 (expected settings file encoding)
dw.UnicodeEncoding(UnicodeEncoding::Utf8);

dw.WriteString(content);
const char* firstChar = content.c_str();
const char* lastChar = firstChar + content.size();
// Manually cast to a uint8_t*, because the compiler is unhappy with a static_cast here.
const uint8_t* firstByte = (const uint8_t*)firstChar;
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
const uint8_t* lastByte = (const uint8_t*)lastChar;
winrt::array_view<const uint8_t> bytes{ firstByte, lastByte };
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
dw.WriteBytes(bytes);

FileIO::WriteBufferAsync(file, dw.DetachBuffer()).get();
}
Expand All @@ -272,11 +269,8 @@ void CascadiaSettings::_SaveAsPackagedApp(const winrt::hstring content)
// - <none>
// This can throw an exception if we fail to open the file for writing, or we
// fail to write the file
void CascadiaSettings::_SaveAsUnpackagedApp(const winrt::hstring content)
void CascadiaSettings::_SaveAsUnpackagedApp(const std::string content)
{
// convert UTF-16 to UTF-8
auto contentString = winrt::to_string(content);

// Get path to output file
// In this scenario, the settings file will end up under e.g. C:\Users\admin\AppData\Roaming\Microsoft\Windows Terminal\profiles.json
std::wstring pathToSettingsFile = CascadiaSettings::_GetFullPathToUnpackagedSettingsFile();
Expand All @@ -286,7 +280,7 @@ void CascadiaSettings::_SaveAsUnpackagedApp(const winrt::hstring content)
{
THROW_LAST_ERROR();
}
THROW_LAST_ERROR_IF(!WriteFile(hOut, contentString.c_str(), gsl::narrow<DWORD>(contentString.length()), 0, 0));
THROW_LAST_ERROR_IF(!WriteFile(hOut, content.c_str(), gsl::narrow<DWORD>(content.length()), 0, 0));
CloseHandle(hOut);
}

Expand Down Expand Up @@ -328,7 +322,7 @@ std::wstring CascadiaSettings::_GetFullPathToUnpackagedSettingsFile()
// Return Value:
// - an optional with the content of the file if we were able to open it,
// otherwise the optional will be empty
std::optional<winrt::hstring> CascadiaSettings::_LoadAsPackagedApp()
std::optional<std::string> CascadiaSettings::_LoadAsPackagedApp()
{
auto curr = ApplicationData::Current();
auto folder = curr.RoamingFolder();
Expand All @@ -342,7 +336,15 @@ std::optional<winrt::hstring> CascadiaSettings::_LoadAsPackagedApp()
const auto storageFile = file.as<StorageFile>();

// settings file is UTF-8 without BOM
return { FileIO::ReadTextAsync(storageFile, UnicodeEncoding::Utf8).get() };
auto buffer = FileIO::ReadBufferAsync(storageFile).get();
auto bufferData = buffer.data();
std::string resultString;
resultString.reserve(buffer.Length());
for (size_t i = 0; i < buffer.Length(); i++)
{
resultString.push_back(bufferData[i]);
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
}
return { resultString };
}


Expand All @@ -355,7 +357,7 @@ std::optional<winrt::hstring> CascadiaSettings::_LoadAsPackagedApp()
// otherwise the optional will be empty.
// If the file exists, but we fail to read it, this can throw an exception
// from reading the file
std::optional<winrt::hstring> CascadiaSettings::_LoadAsUnpackagedApp()
std::optional<std::string> CascadiaSettings::_LoadAsUnpackagedApp()
{
std::wstring pathToSettingsFile = CascadiaSettings::_GetFullPathToUnpackagedSettingsFile();
const auto hFile = CreateFileW(pathToSettingsFile.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
Expand All @@ -380,10 +382,7 @@ std::optional<winrt::hstring> CascadiaSettings::_LoadAsUnpackagedApp()
// convert buffer to UTF-8 string
std::string utf8string(utf8buffer.get(), fileSize);

// UTF-8 to UTF-16
const winrt::hstring fileData = winrt::to_hstring(utf8string);

return { fileData };
return { utf8string };
}

// function Description:
Expand Down
Loading