saving progress...

This commit is contained in:
Leon Liang 2021-09-13 10:04:27 -07:00
parent 387b057c79
commit a6b8d35684
5 changed files with 174 additions and 31 deletions

View file

@ -451,6 +451,9 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// Add the new command to the KeyMap.
// This map directs you to an entry in the ActionMap.
// Action IDs:
// cmd.ExternalID and cmd.Action have a one-to-one relationship.
// Removing Actions from the Command Palette:
// cmd.Name and cmd.Action have a one-to-one relationship.
// If cmd.Name is empty, we must retrieve the old name and remove it.
@ -467,6 +470,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
Model::Command maskingCmd{ nullptr };
_TryUpdateActionMap(cmd, oldCmd, maskingCmd);
_TryUpdateExternalID(cmd, oldCmd, maskingCmd);
_TryUpdateName(cmd, oldCmd, maskingCmd);
_TryUpdateKeyChord(cmd, oldCmd, maskingCmd);
}
@ -481,28 +485,49 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// - maskingAction: the action found in a parent layer, if one already exists
void ActionMap::_TryUpdateActionMap(const Model::Command& cmd, Model::Command& oldCmd, Model::Command& maskingCmd)
{
// Example:
// { "id": "MyAction", "command": "copy", "keys": "ctrl+c" } --> add the action in for the first time
// { "command": "copy", "keys": "ctrl+shift+c" } --> update oldCmd
// { "id": "MyAction", "keys": "ctrl+f" } --> look for the action named "MyAction", update keys.
if (!cmd.ExternalID().empty())
{
const auto action = GetActionByExternalID(cmd.ExternalID());
}
const auto actionID{ Hash(cmd.ActionAndArgs()) };
const auto& actionPair{ _ActionMap.find(actionID) };
if (actionPair == _ActionMap.end())
if (!cmd.ExternalID().empty())
{
// add this action in for the first time
_ActionMap.emplace(actionID, cmd);
const auto& externalPair = _ExternalIDMap.find(cmd.ExternalID());
if (externalPair == _ExternalIDMap.end())
{
_ExternalIDMap.emplace(cmd.ExternalID(), actionID);
if (actionPair == _ActionMap.end())
{
// add this action in for the first time
_ActionMap.emplace(actionID, cmd);
}
else
{
// We're adding an action that already exists in our layer.
// Record it so that we update it with any new information.
oldCmd = actionPair->second;
}
}
else
{
oldCmd = _ActionMap.find(externalPair->second)->second;
}
}
else
{
// We're adding an action that already exists in our layer.
// Record it so that we update it with any new information.
oldCmd = actionPair->second;
// Example:
// { "command": "copy", "keys": "ctrl+c" } --> add the action in for the first time
// { "command": "copy", "keys": "ctrl+shift+c" } --> update oldCmd
if (actionPair == _ActionMap.end())
{
// add this action in for the first time
_ActionMap.emplace(actionID, cmd);
}
else
{
// We're adding an action that already exists in our layer.
// Record it so that we update it with any new information.
oldCmd = actionPair->second;
}
}
// Masking Actions
@ -520,15 +545,37 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
FAIL_FAST_IF(_parents.size() > 1);
for (const auto& parent : _parents)
{
// NOTE: This only checks the layer above us, but that's ok.
// If we had to find one from a layer above that, parent->_MaskingActions
// would have found it, so we inherit it for free!
const auto& inheritedCmd{ parent->_GetActionByID(actionID) };
if (inheritedCmd && *inheritedCmd)
if (!cmd.ExternalID().empty())
{
const auto& inheritedCmdImpl{ get_self<Command>(*inheritedCmd) };
maskingCmd = *inheritedCmdImpl->Copy();
_MaskingActions.emplace(actionID, maskingCmd);
auto inheritedCmdWithID{ parent->GetActionByExternalID(cmd.ExternalID()) };
if (inheritedCmdWithID && *inheritedCmdWithID)
{
// We've found an action in a parent layer that has the same external
// ID as our current layer action. We'll need to overwrite the parent's info.
// Make a copy of inherited, update only the action.
const auto& inheritedCmdImpl{ get_self<Command>(*inheritedCmdWithID) };
const auto inheritedCmdImplCopy{ inheritedCmdImpl->Copy() };
inheritedCmdImplCopy->ActionAndArgs(cmd.ActionAndArgs());
// Adding it to the parent's actions should update all the internal IDs
parent->AddAction(*inheritedCmdImplCopy);
maskingCmd = *inheritedCmdImplCopy;
_MaskingActions.emplace(actionID, maskingCmd);
}
}
else
{
// NOTE: This only checks the layer above us, but that's ok.
// If we had to find one from a layer above that, parent->_MaskingActions
// would have found it, so we inherit it for free!
auto inheritedCmd{ parent->_GetActionByID(actionID) };
if (inheritedCmd && *inheritedCmd)
{
const auto& inheritedCmdImpl{ get_self<Command>(*inheritedCmd) };
maskingCmd = *inheritedCmdImpl->Copy();
_MaskingActions.emplace(actionID, maskingCmd);
}
}
}
}
@ -540,6 +587,87 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
}
}
void ActionMap::_StashIncompleteActions(const Model::Command& cmd)
{
// Stash commands with external IDs so we can combine them
// and AddAction when we know there's no more declarations using the ID.
// Example:
// {
// "id": "customaction",
// "keys": "ctrl+shift+g"
// },
// {
// "id": "customaction",
// "name": "customaction"
// },
// {
// "id": "customaction",
// "command": "copy"
// }
if (!cmd.ExternalID().empty())
{
// Add it to incomplete, or combine it with an existing incomplete.
auto incompletePair{ _IncompleteActions.find(cmd.ExternalID()) };
if (incompletePair == _IncompleteActions.end())
{
_IncompleteActions.emplace(cmd.ExternalID(), cmd);
}
else
{
const auto incompleteImpl{ get_self<Command>(incompletePair->second) };
const auto cmdImpl{ get_self<Command>(cmd) };
if (cmdImpl->HasName())
{
incompleteImpl->Name(cmdImpl->Name());
}
if (cmdImpl->Keys())
{
incompleteImpl->RegisterKey(cmdImpl->Keys());
}
if ((incompleteImpl->ActionAndArgs().Action() == ShortcutAction::Invalid) ||
(cmd.ActionAndArgs().Action() != ShortcutAction::Invalid))
{
incompleteImpl->ActionAndArgs(cmd.ActionAndArgs());
}
}
}
}
void ActionMap::_AddIncompleteActions()
{
for (const auto& [id, cmd]: _IncompleteActions)
{
AddAction(cmd);
}
_IncompleteActions.clear();
}
void ActionMap::_TryUpdateExternalID(const Model::Command& cmd, Model::Command& oldCmd, Model::Command& maskingCmd)
{
if (cmd.ExternalID().empty())
{
return;
}
const auto externalID{ cmd.ExternalID() };
if (oldCmd)
{
if (oldCmd.ExternalID().empty())
{
oldCmd.ExternalID(externalID);
}
}
if (maskingCmd)
{
if (maskingCmd.ExternalID().empty())
{
maskingCmd.ExternalID(externalID);
}
}
}
// Method Description:
// - Update our internal state with the name of the newly registered action
// Arguments:
@ -799,14 +927,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
return nullptr;
}
Model::Command ActionMap::GetActionByExternalID(winrt::hstring const& externalID) const
std::optional<Model::Command> ActionMap::GetActionByExternalID(const winrt::hstring& externalID) const
{
const auto idMapPair{ _ExternalIDMap.find(externalID) };
if (idMapPair != _ExternalIDMap.end())
{
// Really there should be no scenario where an ExternalID mapping to InternalID
// mapping exists but the InternalID doesn't have an action associated to it right?
return _GetActionByID(idMapPair->second).value_or(nullptr);
return _GetActionByID(idMapPair->second);
}
return nullptr;

View file

@ -62,7 +62,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
bool IsKeyChordExplicitlyUnbound(Control::KeyChord const& keys) const;
Control::KeyChord GetKeyBindingForAction(ShortcutAction const& action) const;
Control::KeyChord GetKeyBindingForAction(ShortcutAction const& action, IActionArgs const& actionArgs) const;
Model::Command GetActionByExternalID(winrt::hstring const& externalId) const;
std::optional<Model::Command> GetActionByExternalID(const winrt::hstring& externalId) const;
// population
void AddAction(const Model::Command& cmd);
@ -91,6 +91,9 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
void _TryUpdateActionMap(const Model::Command& cmd, Model::Command& oldCmd, Model::Command& consolidatedCmd);
void _TryUpdateName(const Model::Command& cmd, const Model::Command& oldCmd, const Model::Command& consolidatedCmd);
void _TryUpdateKeyChord(const Model::Command& cmd, const Model::Command& oldCmd, const Model::Command& consolidatedCmd);
void _TryUpdateExternalID(const Model::Command& cmd, Model::Command& oldCmd, Model::Command& consolidatedCmd);
void _AddIncompleteActions();
void _StashIncompleteActions(const Model::Command& cmd);
Windows::Foundation::Collections::IMap<hstring, Model::ActionAndArgs> _AvailableActionsCache{ nullptr };
Windows::Foundation::Collections::IMap<hstring, Model::Command> _NameMapCache{ nullptr };
@ -102,6 +105,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
std::unordered_map<Control::KeyChord, InternalActionID, KeyChordHash, KeyChordEquality> _KeyMap;
std::unordered_map<InternalActionID, Model::Command> _ActionMap;
std::unordered_map<winrt::hstring, InternalActionID> _ExternalIDMap;
std::unordered_map<winrt::hstring, Model::Command> _IncompleteActions;
// Masking Actions:
// These are actions that were introduced in an ancestor,

View file

@ -11,7 +11,7 @@ namespace Microsoft.Terminal.Settings.Model
Boolean IsKeyChordExplicitlyUnbound(Microsoft.Terminal.Control.KeyChord keys);
Command GetActionByKeyChord(Microsoft.Terminal.Control.KeyChord keys);
Command GetActionByExternalID(String externalID);
//Command GetActionByExternalID(String externalID);
Microsoft.Terminal.Control.KeyChord GetKeyBindingForAction(ShortcutAction action);
[method_name("GetKeyBindingForActionWithArgs")] Microsoft.Terminal.Control.KeyChord GetKeyBindingForAction(ShortcutAction action, IActionArgs actionArgs);

View file

@ -50,9 +50,20 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
continue;
}
AddAction(*Command::FromJson(cmdJson, warnings));
const auto& cmd = Command::FromJson(cmdJson, warnings);
if (!cmd->ExternalID().empty())
{
_StashIncompleteActions(*cmd);
}
else
{
AddAction(*cmd);
}
}
_AddIncompleteActions();
return warnings;
}

View file

@ -373,8 +373,8 @@
// Clipboard Integration
{ "command": { "action": "copy", "singleLine": false }, "keys": "ctrl+shift+c" },
{ "command": { "action": "copy", "singleLine": false }, "keys": "ctrl+insert" },
{ "command": "paste", "keys": "ctrl+shift+v" },
{ "command": "paste", "keys": "shift+insert" },
{ "id": "Terminal.Paste", "command": "paste", "keys": "ctrl+shift+v" },
{ "id": "Terminal.Paste", "command": "paste", "keys": "shift+insert" },
// Scrollback
{ "command": "scrollDown", "keys": "ctrl+shift+down" },