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

Add support for arbitrary args in keybindings #3391

Merged
merged 21 commits into from
Nov 14, 2019

Conversation

zadjii-msft
Copy link
Member

@zadjii-msft zadjii-msft commented Oct 31, 2019

Summary of the Pull Request

Enables the user to provide arbitrary argument values to shortcut actions through a new args member of keybindings. For some keybindings, like NewTabWithProfile<N>, we previously needed 9 different ShortcutActions, one for each value of Index. If a user wanted to have a NewTabWithProfile11 keybinding, that was simply impossible. Now that the args are in their own separate json object, each binding can accept any number of arbitrary argument values.

So instead of:

        { "command": "newTab", "keys": ["ctrl+shift+t"] },
        { "command": "newTabProfile0", "keys": ["ctrl+shift+1"] },
        { "command": "newTabProfile1", "keys": ["ctrl+shift+2"] },
        { "command": "newTabProfile2", "keys": ["ctrl+shift+3"] },
        { "command": "newTabProfile3", "keys": ["ctrl+shift+4"] },

We can now use:

        { "command": "newTab", "keys": ["ctrl+shift+t"] },
        { "command": { "action": "newTab", "index": 0 }, "keys": ["ctrl+shift+1"] },
        { "command": { "action": "newTab", "index": 1 }, "keys": ["ctrl+shift+2"] },
        { "command": { "action": "newTab", "index": 2 }, "keys": ["ctrl+shift+3"] },

Initially, this does seem more verbose. However, for cases where there are multiple args, or there's a large range of values for the args, this will quickly become a more powerful system of expressing keybindings.

The "legacy" keybindings are left in in this PR. They have helper methods to generate appropriate IActionArgs values. Prior to releasing 1.0, I think we should remove them, if only to remove some code bloat.

References

See the spec for more details.

This is part two of the implementation, part one was #2446

PR Checklist

Validation Steps Performed

  • Ran Tests
  • Removed the legacy keybindings from the defaults.json, everything still works
  • Tried leaving the legacy keybingings in my profiles.json, everything still works.

@DHowett-MSFT
Copy link
Contributor

I hate to suggest this, but.. is args part of command? Should it be? if it is, we could double-parse the command object for the name and the args:

"command": {
    "name": "newTab",
    "index": 4
}

command.name = look up actionargs type, actargs.FromJson(commandObject)?

@DHowett-MSFT
Copy link
Contributor

That might make the model a little easier to understand when we expand it to "command palette", binding menu items to "commands", etc. The command has all the data necessary to act

@zadjii-msft
Copy link
Member Author

@DHowett-MSFT another idea: we just put them right in the root directly.

            { "command": "switchToTab", "keys": [ "alt+shift+1" ], "index": 2 },
            { "command": "splitPane", "keys": [ "alt+shift+|" ], "type": "vertical", "profileGuid": "{etc}" },

@DHowett-MSFT
Copy link
Contributor

Interesting! Will we ever have a command that has a keys?

Like:

{ "command": "sendKeys", "keys": ["alt+left", "ctrl+q"], "keys": ["shift-1"] }

Obviously, activated with Shift+1 and when you activate it it prints Alt+Left,Ctrl+Q into the input buffer. 😁

@zadjii-msft
Copy link
Member Author

Frick. That's a good point. Lets loop back on the previous proposal then:

    "keybindings":
    [
        { "command": "scrollUpPage", "keys": ["ctrl+shift+pgup"] },
        { "command": { "action": "switchToTab", "index": 0 }, "keys": ["ctrl+alt+1"] },
        { "command": { "action": "switchToTab", "index": 1 }, "keys": ["ctrl+alt+2"] },
        { "command": { "action": "sendInput", "keys": ["alt+left", "ctrl+q"] }, "keys": ["shift+1"] }
    ]

If "command" is a string, we'll assume it doesn't have args, and we'll try and parse it as the action.

Otherwise, we'll try and use the "action" property to get the ShortcutAction.

I'm proposing "action" here, because for #2046, commands will need another separate name property that we can use for displaying:

    "commands":
    [
        { 
            "name": "Scroll up a page", 
            "icon":null,
            "command": "scrollUpPage" 
        },
        { 
            "name": "Switch to tab 0", 
            "icon":null,
            "command": { "action": "switchToTab", "index": 0 } 
        },
        { 
            "name": "Switch to the second tab", 
            "icon":null,
            "command": { "action": "switchToTab", "index": 1 } 
        },
        { 
            "name": "Do a send input", 
            "icon":null,
            "command": { "action": "sendInput", "keys": ["alt+left", "ctrl+q"] }
         }
    ]

Oh no. Now I hate myself. Why do commands and keybindings need to be in separate arrays at all? (I'm putting this on in an expando because it's getting long)

    "commands":
    [
        { 
            "name": "Scroll up a page", 
            "icon":null,
            "command": "scrollUpPage",
            "keys": ["ctrl+shift+pgup"]
        },
        { 
            "name": "Switch to tab 0", 
            "icon":null,
            "command": { "action": "switchToTab", "index": 0 },
            "keys": ["ctrl+alt+1"]
        },
        { 
            "name": "Switch to the second tab", 
            "icon":null,
            "command": { "action": "switchToTab", "index": 1 },
            "keys": ["ctrl+alt+2"]
        },
        { 
            "name": "Do a send input", 
            "icon":null,
            "command": { "action": "sendInput", "keys": ["alt+left", "ctrl+q"] },
            "keys": ["shift+1"]
         },
        { 
            // I'm just a keybinding, not a command
            "command": { "action": "sendInput", "keys": ["alt+right", "ctrl+w"] },
            "keys": ["shift+2"]
        },
        { 
            "name": "I'm just a command, unbound", 
            "icon":null,
            "command": { "action": "sendInput", "keys": ["ctrl+left", "ctrl+1"] }
        },
        { 
            "name": { "key": "SomeLocalizedXAMLStringResource"}, 
            "icon":null,
            "command": { "action": "switchToTab", "index": 15 },
            "keys": ["ctrl+alt+5"]
        }
    ]

We'd just have all commands and bindings in a singular array.

@DHowett-MSFT
Copy link
Contributor

I would love to have this followed up with a PR that adds profileGuid to newTab 😁

@zadjii-msft
Copy link
Member Author

Looping back on this - Dustin and I discussed, and the combined commands/keybindings situation is a madhouse, which is part of the reason we're leaving it for 2.0.

However, there was goodness we agreed on, which is the following:


    "keybindings":
    [
        { "command": "scrollUpPage", "keys": ["ctrl+shift+pgup"] },
        { "command": { "action": "switchToTab", "index": 0 }, "keys": ["ctrl+alt+1"] },
        { "command": { "action": "switchToTab", "index": 1 }, "keys": ["ctrl+alt+2"] },
        { "command": { "action": "sendInput", "keys": ["alt+left", "ctrl+q"] }, "keys": ["shift+1"] }
    ]

If "command" is a string, we'll assume it doesn't have args, and we'll try and parse it as the action.

Otherwise, we'll try and use the "action" property to get the ShortcutAction.


…rbitrary-args

# Conflicts:
#	src/cascadia/TerminalApp/AppKeyBindings.idl
#	src/cascadia/TerminalApp/AppKeyBindingsSerialization.cpp
  This is a change to make @DHowett-MSFT happy. Changes the args to be a part
  of the "command" object, as opposed to an object on their own.

  EX:

  ```jsonc

    // Old style
    { "command": "switchToTab0", "keys": ["ctrl+1"] },
    { "command": { "action": "switchToTab", "index": 0 }, "keys": ["ctrl+alt+1"] },

    // new style
    { "command": "switchToTab0", "keys": ["ctrl+1"] },
    { "command": "switchToTab", "args": { "index": 0 } "keys": ["ctrl+alt+1"] },

  ```
@miniksa
Copy link
Member

miniksa commented Nov 6, 2019

The "legacy" keybindings are left in in this PR. They have helper methods to generate appropriate IActionArgs values. Prior to releasing 1.0, I think we should remove them, if only to remove some code bloat.

TODO without work item ID attached.

src/cascadia/TerminalApp/ActionArgs.h Outdated Show resolved Hide resolved
src/cascadia/TerminalApp/ActionArgs.h Outdated Show resolved Hide resolved
src/cascadia/TerminalApp/defaults.json Outdated Show resolved Hide resolved
@ghost ghost added the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Nov 6, 2019
@zadjii-msft
Copy link
Member Author

@zadjii-msft Make sure to update the spec before you submit this PR

@ghost ghost removed the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Nov 8, 2019
  * Add a `Direction::None`
  * LOAD BEARING
  * add some GH ids to TODOs
@zadjii-msft zadjii-msft added Area-Settings Issues related to settings and customizability, for console or terminal Product-Terminal The new Windows Terminal. labels Nov 11, 2019
};

// Possible Direction values
static constexpr std::string_view LeftString{ "left" };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't constant string patterns like this for parsing go wherever the rest of the parsing is for things like dimensions?

Copy link
Member

@miniksa miniksa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per verbal discussion, link todo to make a direction parser later so rando strings aren't floating in a rando file.

Copy link
Member

@carlos-zamora carlos-zamora left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some comments not worth blocking over.

src/cascadia/TerminalApp/AppKeyBindingsSerialization.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalApp/AppKeyBindings.h Outdated Show resolved Hide resolved
src/cascadia/TerminalApp/ActionAndArgs.cpp Outdated Show resolved Hide resolved
@zadjii-msft zadjii-msft merged commit 6a4c737 into master Nov 14, 2019
zadjii-msft added a commit that referenced this pull request Nov 21, 2019
## Summary of the Pull Request

With #3391, I almost certainly regressed the ability for the new tab dropdown to display the keybindings for each profile. This adds them back.

## PR Checklist
* [x] Closes #3603
* [x] I work here
* [ ] Tests added/passed
* [n/a] Requires documentation to be updated

## Detailed Description of the Pull Request / Additional comments

Now, we can lookup keybindings not only for `ShortcutAction`s, but also `ActionAndArgs`s, so we can look up the binding for an action with a particular set of arguments.
---------------------------------------------
* fixes #3603 by searching for ActionAndArgs too

* Apply suggestions from code review

Co-Authored-By: Carlos Zamora <carlos.zamora@microsoft.com>
@ghost
Copy link

ghost commented Nov 26, 2019

🎉Windows Terminal Preview v0.7.3291.0 has been released which incorporates this pull request.:tada:

Handy links:

@zadjii-msft zadjii-msft deleted the dev/migrie/f/1142-arbitrary-args branch January 31, 2020 14:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Settings Issues related to settings and customizability, for console or terminal Product-Terminal The new Windows Terminal.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature Request: Support arbitrary arguments for keybindings
4 participants