Repository: microsoft/terminal
File: src/cascadia/TerminalApp/ShortcutActionDispatch.cpp (C++)

Code before:

#define ACTION_CASE(action)              \
    case ShortcutAction::action:         \
    {                                    \
        action.raise(sender, eventArgs); \
        break;                           \
    }

namespace winrt::TerminalApp::implementation
{
    std::wstring ExtractAction(const ActionAndArgs& actionAndArgs)
    {
        std::wstring id{ actionAndArgs.GenerateID() };
        const auto segment1 = id.find(L'.');
        const auto segment2 = id.find(L'.', segment1 + 1);
        if (segment1 != std::wstring::npos)
        {
            if (segment2 != std::wstring::npos)
            {
                return id.substr(segment1 + 1, segment2 - segment1 - 1);
            }
            else
            {
                return id.substr(segment1 + 1);
            }
        }
        // This shouldn't be possible.
        // GenerateID() returns L"User.{}" unless it's invalid
        return nullptr;
    }

    // Method Description:
    // - Dispatch the appropriate event for the given ActionAndArgs. Constructs
    //   an ActionEventArgs to hold the IActionArgs payload for the event, and
    //   calls the matching handlers for that event.
    // Arguments:
    // - actionAndArgs: the ShortcutAction and associated args to raise an event for.
    // Return Value:
    // - true if we handled the event was handled, else false.
    bool ShortcutActionDispatch::DoAction(const winrt::Windows::Foundation::IInspectable& sender,
                                          const ActionAndArgs& actionAndArgs)
    {
        if (!actionAndArgs)
        {
            return false;
        }

        const auto& action = actionAndArgs.Action();
        const auto& args = actionAndArgs.Args();
        auto eventArgs = args ? ActionEventArgs{ args } :
                                ActionEventArgs{};

Review comment (bug):
I like the deconstruction into find-first-substr-later personally. Because of it however, I stumbled a little over the `segment1 + 1` for the 2nd find, because it may overflow (`npos` is guaranteed to be the max. `size_t` value. `npos + 1 == 0`). But that's fine because then `segment2` will simply be the same as `segment1` (also `npos`).

If you'd like, you can use our `til/string.h` tokenization helper (pseudo-code):
```cpp
const auto id = actionAndArgs.GenerateID();

std::wstring_view remaining{ id };
// Throw away the first word.
std::ignore = til::prefix_split(remaining, L'.');
// Get the 2nd word, i.e. the "foo" in "User.foo".
const auto actionName = til::prefix_split(remaining, L'.');

return { actionName };
```

Code after:

#define ACTION_CASE(action)              \
    case ShortcutAction::action:         \
    {                                    \
        action.raise(sender, eventArgs); \
        break;                           \
    }

namespace winrt::TerminalApp::implementation
{
    // Method Description:
    // - Dispatch the appropriate event for the given ActionAndArgs. Constructs
    //   an ActionEventArgs to hold the IActionArgs payload for the event, and
    //   calls the matching handlers for that event.
    // Arguments:
    // - actionAndArgs: the ShortcutAction and associated args to raise an event for.
    // Return Value:
    // - true if we handled the event was handled, else false.
    bool ShortcutActionDispatch::DoAction(const winrt::Windows::Foundation::IInspectable& sender,
                                          const ActionAndArgs& actionAndArgs)
    {
        if (!actionAndArgs)
        {
            return false;
        }

        const auto& action = actionAndArgs.Action();
        const auto& args = actionAndArgs.Args();
        auto eventArgs = args ? ActionEventArgs{ args } :
                                ActionEventArgs{};

        switch (action)
        {
#define ON_ALL_ACTIONS(id) ACTION_CASE(id);
            ALL_SHORTCUT_ACTIONS
            INTERNAL_SHORTCUT_ACTIONS
#undef ON_ALL_ACTIONS
        default:
            return false;
        }
        const auto handled = eventArgs.Handled();

        if (handled)
        {
            TraceLoggingWrite(
                g_hTerminalAppProvider,
                "ActionDispatched",
                TraceLoggingDescription("Event emitted when an action was successfully performed"),
                TraceLoggingValue(static_cast<int>(actionAndArgs.Action()), "Action"),
                TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
                TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));