serialize and deserialize actions

This commit is contained in:
Mike Griese 2019-07-23 10:55:26 -05:00
parent 999eda3a60
commit 77fc58b7ea
6 changed files with 254 additions and 106 deletions

View file

@ -0,0 +1,87 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "ActionSerialization.h"
#include "KeyChordSerialization.h"
#include "Utils.h"
#include "ShortcutActionSerializationKeys.h"
#include <winrt/Microsoft.Terminal.Settings.h>
using namespace winrt::Microsoft::Terminal::Settings;
using namespace winrt::TerminalApp;
static constexpr std::string_view NameKey{ "name" };
static constexpr std::string_view IconPathKey{ "iconPath" };
static constexpr std::string_view CommandKey{ "command" };
// Method Description:
// - TODO 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 ActionSerialization::ToJson(const winrt::TerminalApp::Action& action)
{
Json::Value jsonObject;
jsonObject[JsonKey(NameKey)] = winrt::to_string(action.Name());
jsonObject[JsonKey(IconPathKey)] = winrt::to_string(action.IconPath());
// Iterate over all the possible actions in the names list, to find the name for our command
for (auto& nameAndAction : commandNames)
{
const auto searchedForName = nameAndAction.first;
const auto searchedForAction = nameAndAction.second;
if (searchedForAction == action.Command())
{
// We found the name, we serialized successfully.
jsonObject[JsonKey(CommandKey)] = searchedForName.data(); //winrt::to_string(action.IconPath());
return jsonObject;
}
}
// We did not find a name, throw an error
throw winrt::hresult_invalid_argument();
}
// 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::Action ActionSerialization::FromJson(const Json::Value& json)
{
winrt::TerminalApp::Action result{};
if (auto name{ json[JsonKey(NameKey)] })
{
result.Name(winrt::to_hstring(name.asString()));
}
if (auto iconPath{ json[JsonKey(IconPathKey)] })
{
result.IconPath(winrt::to_hstring(iconPath.asString()));
}
if (auto commandString{ json[JsonKey(CommandKey)] })
{
// Try matching the command to one we have
const auto found = commandNames.find(commandString.asString());
if (found != commandNames.end())
{
result.Command(found->second);
}
else
{
// We did not find a matching name, throw an error
throw winrt::hresult_invalid_argument();
}
}
return result;
}

View file

@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
//
// Module Name:
// - ActionSerialization.h
//
// Abstract:
// - A couple helper functions for serializing/deserializing an Actions
// to/from json. We need this to exist as external helper functions, rather
// than defining these as methods on the Action class, because
// Action is a winrt type. When we're working with an Action
// object, we only have access to methods defined on the winrt interface (in
// the idl). We don't have access to methods we define on the
// implementation. Since JsonValue is not a winrt type, we can't define any
// methods that operate on it in the idl.
//
// Author(s):
// - Mike Griese - July 2019
#pragma once
#include "Action.h"
class ActionSerialization final
{
public:
static winrt::TerminalApp::Action FromJson(const Json::Value& json);
static Json::Value ToJson(const winrt::TerminalApp::Action& action);
};

View file

@ -5,6 +5,7 @@
#include "AppKeyBindingsSerialization.h"
#include "KeyChordSerialization.h"
#include "Utils.h"
#include "ShortcutActionSerializationKeys.h"
#include <winrt/Microsoft.Terminal.Settings.h>
using namespace winrt::Microsoft::Terminal::Settings;
@ -13,111 +14,6 @@ using namespace winrt::TerminalApp;
static constexpr std::string_view KeysKey{ "keys" };
static constexpr std::string_view CommandKey{ "command" };
static constexpr std::string_view CopyTextKey{ "copy" };
static constexpr std::string_view CopyTextWithoutNewlinesKey{ "copyTextWithoutNewlines" };
static constexpr std::string_view PasteTextKey{ "paste" };
static constexpr std::string_view NewTabKey{ "newTab" };
static constexpr std::string_view DuplicateTabKey{ "duplicateTab" };
static constexpr std::string_view NewTabWithProfile0Key{ "newTabProfile0" };
static constexpr std::string_view NewTabWithProfile1Key{ "newTabProfile1" };
static constexpr std::string_view NewTabWithProfile2Key{ "newTabProfile2" };
static constexpr std::string_view NewTabWithProfile3Key{ "newTabProfile3" };
static constexpr std::string_view NewTabWithProfile4Key{ "newTabProfile4" };
static constexpr std::string_view NewTabWithProfile5Key{ "newTabProfile5" };
static constexpr std::string_view NewTabWithProfile6Key{ "newTabProfile6" };
static constexpr std::string_view NewTabWithProfile7Key{ "newTabProfile7" };
static constexpr std::string_view NewTabWithProfile8Key{ "newTabProfile8" };
static constexpr std::string_view NewWindowKey{ "newWindow" };
static constexpr std::string_view CloseWindowKey{ "closeWindow" };
static constexpr std::string_view CloseTabKey{ "closeTab" };
static constexpr std::string_view ClosePaneKey{ "closePane" };
static constexpr std::string_view SwitchtoTabKey{ "switchToTab" };
static constexpr std::string_view NextTabKey{ "nextTab" };
static constexpr std::string_view PrevTabKey{ "prevTab" };
static constexpr std::string_view IncreaseFontSizeKey{ "increaseFontSize" };
static constexpr std::string_view DecreaseFontSizeKey{ "decreaseFontSize" };
static constexpr std::string_view ScrollupKey{ "scrollUp" };
static constexpr std::string_view ScrolldownKey{ "scrollDown" };
static constexpr std::string_view ScrolluppageKey{ "scrollUpPage" };
static constexpr std::string_view ScrolldownpageKey{ "scrollDownPage" };
static constexpr std::string_view SwitchToTab0Key{ "switchToTab0" };
static constexpr std::string_view SwitchToTab1Key{ "switchToTab1" };
static constexpr std::string_view SwitchToTab2Key{ "switchToTab2" };
static constexpr std::string_view SwitchToTab3Key{ "switchToTab3" };
static constexpr std::string_view SwitchToTab4Key{ "switchToTab4" };
static constexpr std::string_view SwitchToTab5Key{ "switchToTab5" };
static constexpr std::string_view SwitchToTab6Key{ "switchToTab6" };
static constexpr std::string_view SwitchToTab7Key{ "switchToTab7" };
static constexpr std::string_view SwitchToTab8Key{ "switchToTab8" };
static constexpr std::string_view OpenSettingsKey{ "openSettings" };
static constexpr std::string_view SplitHorizontalKey{ "splitHorizontal" };
static constexpr std::string_view SplitVerticalKey{ "splitVertical" };
static constexpr std::string_view ResizePaneLeftKey{ "resizePaneLeft" };
static constexpr std::string_view ResizePaneRightKey{ "resizePaneRight" };
static constexpr std::string_view ResizePaneUpKey{ "resizePaneUp" };
static constexpr std::string_view ResizePaneDownKey{ "resizePaneDown" };
static constexpr std::string_view MoveFocusLeftKey{ "moveFocusLeft" };
static constexpr std::string_view MoveFocusRightKey{ "moveFocusRight" };
static constexpr std::string_view MoveFocusUpKey{ "moveFocusUp" };
static constexpr std::string_view MoveFocusDownKey{ "moveFocusDown" };
// 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:
// These are string_views that are being used as keys. These string_views are
// just pointers to other strings. This could be dangerous, if the map outlived
// the actual strings being pointed to. However, since both these strings and
// the map are all const for the lifetime of the app, we have nothing to worry
// about here.
static const std::map<std::string_view, ShortcutAction, std::less<>> commandNames{
{ CopyTextKey, ShortcutAction::CopyText },
{ CopyTextWithoutNewlinesKey, ShortcutAction::CopyTextWithoutNewlines },
{ PasteTextKey, ShortcutAction::PasteText },
{ NewTabKey, ShortcutAction::NewTab },
{ DuplicateTabKey, ShortcutAction::DuplicateTab },
{ NewTabWithProfile0Key, ShortcutAction::NewTabProfile0 },
{ NewTabWithProfile1Key, ShortcutAction::NewTabProfile1 },
{ NewTabWithProfile2Key, ShortcutAction::NewTabProfile2 },
{ NewTabWithProfile3Key, ShortcutAction::NewTabProfile3 },
{ NewTabWithProfile4Key, ShortcutAction::NewTabProfile4 },
{ NewTabWithProfile5Key, ShortcutAction::NewTabProfile5 },
{ NewTabWithProfile6Key, ShortcutAction::NewTabProfile6 },
{ NewTabWithProfile7Key, ShortcutAction::NewTabProfile7 },
{ NewTabWithProfile8Key, ShortcutAction::NewTabProfile8 },
{ NewWindowKey, ShortcutAction::NewWindow },
{ CloseWindowKey, ShortcutAction::CloseWindow },
{ CloseTabKey, ShortcutAction::CloseTab },
{ ClosePaneKey, ShortcutAction::ClosePane },
{ NextTabKey, ShortcutAction::NextTab },
{ PrevTabKey, ShortcutAction::PrevTab },
{ IncreaseFontSizeKey, ShortcutAction::IncreaseFontSize },
{ DecreaseFontSizeKey, ShortcutAction::DecreaseFontSize },
{ ScrollupKey, ShortcutAction::ScrollUp },
{ ScrolldownKey, ShortcutAction::ScrollDown },
{ ScrolluppageKey, ShortcutAction::ScrollUpPage },
{ ScrolldownpageKey, ShortcutAction::ScrollDownPage },
{ SwitchToTab0Key, ShortcutAction::SwitchToTab0 },
{ SwitchToTab1Key, ShortcutAction::SwitchToTab1 },
{ SwitchToTab2Key, ShortcutAction::SwitchToTab2 },
{ SwitchToTab3Key, ShortcutAction::SwitchToTab3 },
{ SwitchToTab4Key, ShortcutAction::SwitchToTab4 },
{ SwitchToTab5Key, ShortcutAction::SwitchToTab5 },
{ SwitchToTab6Key, ShortcutAction::SwitchToTab6 },
{ SwitchToTab7Key, ShortcutAction::SwitchToTab7 },
{ SwitchToTab8Key, ShortcutAction::SwitchToTab8 },
{ SplitHorizontalKey, ShortcutAction::SplitHorizontal },
{ SplitVerticalKey, ShortcutAction::SplitVertical },
{ ResizePaneLeftKey, ShortcutAction::ResizePaneLeft },
{ ResizePaneRightKey, ShortcutAction::ResizePaneRight },
{ ResizePaneUpKey, ShortcutAction::ResizePaneUp },
{ ResizePaneDownKey, ShortcutAction::ResizePaneDown },
{ MoveFocusLeftKey, ShortcutAction::MoveFocusLeft },
{ MoveFocusRightKey, ShortcutAction::MoveFocusRight },
{ MoveFocusUpKey, ShortcutAction::MoveFocusUp },
{ MoveFocusDownKey, ShortcutAction::MoveFocusDown },
{ OpenSettingsKey, ShortcutAction::OpenSettings },
};
// Function Description:
// - Small helper to create a json value serialization of a single
// KeyBinding->Action maping. The created object is of schema:

View file

@ -6,16 +6,17 @@
#include "../../types/inc/Utils.hpp"
#include "../../inc/DefaultSettings.h"
#include "AppKeyBindingsSerialization.h"
#include "ActionSerialization.h"
#include "Utils.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;
static constexpr std::string_view KeybindingsKey{ "keybindings" };
static constexpr std::string_view ActionsKey{ "actions" };
static constexpr std::string_view DefaultProfileKey{ "defaultProfile" };
static constexpr std::string_view AlwaysShowTabsKey{ "alwaysShowTabs" };
static constexpr std::string_view InitialRowsKey{ "initialRows" };
@ -164,6 +165,17 @@ Json::Value GlobalAppSettings::ToJson() const
jsonObject[JsonKey(RequestedThemeKey)] = winrt::to_string(_SerializeTheme(_requestedTheme));
jsonObject[JsonKey(KeybindingsKey)] = AppKeyBindingsSerialization::ToJson(_keybindings);
Json::Value actionsArrayJson;
for (const auto& action : _actions)
{
try
{
actionsArrayJson.append(ActionSerialization::ToJson(action));
}
CATCH_LOG();
}
jsonObject[JsonKey(ActionsKey)] = actionsArrayJson;
return jsonObject;
}
@ -221,6 +233,21 @@ GlobalAppSettings GlobalAppSettings::FromJson(const Json::Value& json)
result._keybindings = AppKeyBindingsSerialization::FromJson(keybindings);
}
if (auto actionsArray{ json[JsonKey(ActionsKey)] })
{
for (const auto& value : actionsArray)
{
if (value.isObject())
{
try
{
result._actions.push_back(ActionSerialization::FromJson(value));
}
CATCH_LOG();
}
}
}
return result;
}

View file

@ -0,0 +1,107 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
constexpr std::string_view CopyTextKey{ "copy" };
constexpr std::string_view CopyTextWithoutNewlinesKey{ "copyTextWithoutNewlines" };
constexpr std::string_view PasteTextKey{ "paste" };
constexpr std::string_view NewTabKey{ "newTab" };
constexpr std::string_view DuplicateTabKey{ "duplicateTab" };
constexpr std::string_view NewTabWithProfile0Key{ "newTabProfile0" };
constexpr std::string_view NewTabWithProfile1Key{ "newTabProfile1" };
constexpr std::string_view NewTabWithProfile2Key{ "newTabProfile2" };
constexpr std::string_view NewTabWithProfile3Key{ "newTabProfile3" };
constexpr std::string_view NewTabWithProfile4Key{ "newTabProfile4" };
constexpr std::string_view NewTabWithProfile5Key{ "newTabProfile5" };
constexpr std::string_view NewTabWithProfile6Key{ "newTabProfile6" };
constexpr std::string_view NewTabWithProfile7Key{ "newTabProfile7" };
constexpr std::string_view NewTabWithProfile8Key{ "newTabProfile8" };
constexpr std::string_view NewWindowKey{ "newWindow" };
constexpr std::string_view CloseWindowKey{ "closeWindow" };
constexpr std::string_view CloseTabKey{ "closeTab" };
constexpr std::string_view ClosePaneKey{ "closePane" };
constexpr std::string_view SwitchtoTabKey{ "switchToTab" };
constexpr std::string_view NextTabKey{ "nextTab" };
constexpr std::string_view PrevTabKey{ "prevTab" };
constexpr std::string_view IncreaseFontSizeKey{ "increaseFontSize" };
constexpr std::string_view DecreaseFontSizeKey{ "decreaseFontSize" };
constexpr std::string_view ScrollupKey{ "scrollUp" };
constexpr std::string_view ScrolldownKey{ "scrollDown" };
constexpr std::string_view ScrolluppageKey{ "scrollUpPage" };
constexpr std::string_view ScrolldownpageKey{ "scrollDownPage" };
constexpr std::string_view SwitchToTab0Key{ "switchToTab0" };
constexpr std::string_view SwitchToTab1Key{ "switchToTab1" };
constexpr std::string_view SwitchToTab2Key{ "switchToTab2" };
constexpr std::string_view SwitchToTab3Key{ "switchToTab3" };
constexpr std::string_view SwitchToTab4Key{ "switchToTab4" };
constexpr std::string_view SwitchToTab5Key{ "switchToTab5" };
constexpr std::string_view SwitchToTab6Key{ "switchToTab6" };
constexpr std::string_view SwitchToTab7Key{ "switchToTab7" };
constexpr std::string_view SwitchToTab8Key{ "switchToTab8" };
constexpr std::string_view OpenSettingsKey{ "openSettings" };
constexpr std::string_view SplitHorizontalKey{ "splitHorizontal" };
constexpr std::string_view SplitVerticalKey{ "splitVertical" };
constexpr std::string_view ResizePaneLeftKey{ "resizePaneLeft" };
constexpr std::string_view ResizePaneRightKey{ "resizePaneRight" };
constexpr std::string_view ResizePaneUpKey{ "resizePaneUp" };
constexpr std::string_view ResizePaneDownKey{ "resizePaneDown" };
constexpr std::string_view MoveFocusLeftKey{ "moveFocusLeft" };
constexpr std::string_view MoveFocusRightKey{ "moveFocusRight" };
constexpr std::string_view MoveFocusUpKey{ "moveFocusUp" };
constexpr std::string_view MoveFocusDownKey{ "moveFocusDown" };
// 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:
// These are string_views that are being used as keys. These string_views are
// just pointers to other strings. This could be dangerous, if the map outlived
// the actual strings being pointed to. However, since both these strings and
// the map are all const for the lifetime of the app, we have nothing to worry
// about here.
const std::map<std::string_view, winrt::TerminalApp::ShortcutAction, std::less<>> commandNames{
{ CopyTextKey, winrt::TerminalApp::ShortcutAction::CopyText },
{ CopyTextWithoutNewlinesKey, winrt::TerminalApp::ShortcutAction::CopyTextWithoutNewlines },
{ PasteTextKey, winrt::TerminalApp::ShortcutAction::PasteText },
{ NewTabKey, winrt::TerminalApp::ShortcutAction::NewTab },
{ DuplicateTabKey, winrt::TerminalApp::ShortcutAction::DuplicateTab },
{ NewTabWithProfile0Key, winrt::TerminalApp::ShortcutAction::NewTabProfile0 },
{ NewTabWithProfile1Key, winrt::TerminalApp::ShortcutAction::NewTabProfile1 },
{ NewTabWithProfile2Key, winrt::TerminalApp::ShortcutAction::NewTabProfile2 },
{ NewTabWithProfile3Key, winrt::TerminalApp::ShortcutAction::NewTabProfile3 },
{ NewTabWithProfile4Key, winrt::TerminalApp::ShortcutAction::NewTabProfile4 },
{ NewTabWithProfile5Key, winrt::TerminalApp::ShortcutAction::NewTabProfile5 },
{ NewTabWithProfile6Key, winrt::TerminalApp::ShortcutAction::NewTabProfile6 },
{ NewTabWithProfile7Key, winrt::TerminalApp::ShortcutAction::NewTabProfile7 },
{ NewTabWithProfile8Key, winrt::TerminalApp::ShortcutAction::NewTabProfile8 },
{ NewWindowKey, winrt::TerminalApp::ShortcutAction::NewWindow },
{ CloseWindowKey, winrt::TerminalApp::ShortcutAction::CloseWindow },
{ CloseTabKey, winrt::TerminalApp::ShortcutAction::CloseTab },
{ ClosePaneKey, winrt::TerminalApp::ShortcutAction::ClosePane },
{ NextTabKey, winrt::TerminalApp::ShortcutAction::NextTab },
{ PrevTabKey, winrt::TerminalApp::ShortcutAction::PrevTab },
{ IncreaseFontSizeKey, winrt::TerminalApp::ShortcutAction::IncreaseFontSize },
{ DecreaseFontSizeKey, winrt::TerminalApp::ShortcutAction::DecreaseFontSize },
{ ScrollupKey, winrt::TerminalApp::ShortcutAction::ScrollUp },
{ ScrolldownKey, winrt::TerminalApp::ShortcutAction::ScrollDown },
{ ScrolluppageKey, winrt::TerminalApp::ShortcutAction::ScrollUpPage },
{ ScrolldownpageKey, winrt::TerminalApp::ShortcutAction::ScrollDownPage },
{ SwitchToTab0Key, winrt::TerminalApp::ShortcutAction::SwitchToTab0 },
{ SwitchToTab1Key, winrt::TerminalApp::ShortcutAction::SwitchToTab1 },
{ SwitchToTab2Key, winrt::TerminalApp::ShortcutAction::SwitchToTab2 },
{ SwitchToTab3Key, winrt::TerminalApp::ShortcutAction::SwitchToTab3 },
{ SwitchToTab4Key, winrt::TerminalApp::ShortcutAction::SwitchToTab4 },
{ SwitchToTab5Key, winrt::TerminalApp::ShortcutAction::SwitchToTab5 },
{ SwitchToTab6Key, winrt::TerminalApp::ShortcutAction::SwitchToTab6 },
{ SwitchToTab7Key, winrt::TerminalApp::ShortcutAction::SwitchToTab7 },
{ SwitchToTab8Key, winrt::TerminalApp::ShortcutAction::SwitchToTab8 },
{ SplitHorizontalKey, winrt::TerminalApp::ShortcutAction::SplitHorizontal },
{ SplitVerticalKey, winrt::TerminalApp::ShortcutAction::SplitVertical },
{ ResizePaneLeftKey, winrt::TerminalApp::ShortcutAction::ResizePaneLeft },
{ ResizePaneRightKey, winrt::TerminalApp::ShortcutAction::ResizePaneRight },
{ ResizePaneUpKey, winrt::TerminalApp::ShortcutAction::ResizePaneUp },
{ ResizePaneDownKey, winrt::TerminalApp::ShortcutAction::ResizePaneDown },
{ MoveFocusLeftKey, winrt::TerminalApp::ShortcutAction::MoveFocusLeft },
{ MoveFocusRightKey, winrt::TerminalApp::ShortcutAction::MoveFocusRight },
{ MoveFocusUpKey, winrt::TerminalApp::ShortcutAction::MoveFocusUp },
{ MoveFocusDownKey, winrt::TerminalApp::ShortcutAction::MoveFocusDown },
{ OpenSettingsKey, winrt::TerminalApp::ShortcutAction::OpenSettings },
};

View file

@ -66,7 +66,9 @@
<ClInclude Include="../Profile.h" />
<ClInclude Include="../CascadiaSettings.h" />
<ClInclude Include="../AppKeyBindingsSerialization.h" />
<ClInclude Include="../ActionSerialization.h" />
<ClInclude Include="../KeyChordSerialization.h" />
<ClInclude Include="../ShortcutActionSerializationKeys.h" />
<ClInclude Include="../Utils.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="../AppKeyBindings.h" />
@ -100,6 +102,7 @@
<ClCompile Include="../CascadiaSettings.cpp" />
<ClCompile Include="../CascadiaSettingsSerialization.cpp" />
<ClCompile Include="../AppKeyBindingsSerialization.cpp" />
<ClCompile Include="../ActionSerialization.cpp" />
<ClCompile Include="../KeyChordSerialization.cpp" />
<ClCompile Include="../Utils.cpp" />
<ClCompile Include="pch.cpp">