Add support for arbitrary args in keybindings (#3391)
## 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 `ShortcutAction`s, 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:
```json
{ "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:
```json
{ "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](https://github.com/microsoft/terminal/blob/master/doc/specs/%231142%20-%20Keybinding%20Arguments.md) for more details.
This is part two of the implementation, part one was #2446
## PR Checklist
* [x] Closes #1142
* [x] I work here
* [x] Tests added/passed
* [x] Schema updated
## 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.
-------------------------------------------------
* this is a start, but there's a weird linker bug if I take the SetKeybinding(ShortcutAction, KeyChord) implementation out, which I don't totally understand
* a good old-fashioned clean will fix that right up
* all these things work
* hey this actually _functionally_ works
* Mostly cleanup and completion of implementation
* Hey I bet we could just make NewTab the handler for NewTabWithProfile
* Start writing tests for Keybinding args
* Add tests
* Revert a bad sln change, and clean out dead code
* Change to include "command" as a single object
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"] },
```
* schemas are hard yo
* Fix the build?
* wonder why my -Wall settings are different than CI...
* this makes me hate things
* Comments from PR
* Add a `Direction::None`
* LOAD BEARING
* add some GH ids to TODOs
* add a comment
* PR nits from carlos
2019-11-14 23:23:40 +01:00
|
|
|
#include "pch.h"
|
2021-05-20 20:44:04 +02:00
|
|
|
#include "AllShortcutActions.h"
|
2020-06-15 15:33:30 +02:00
|
|
|
#include "ActionArgs.h"
|
Add support for arbitrary args in keybindings (#3391)
## 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 `ShortcutAction`s, 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:
```json
{ "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:
```json
{ "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](https://github.com/microsoft/terminal/blob/master/doc/specs/%231142%20-%20Keybinding%20Arguments.md) for more details.
This is part two of the implementation, part one was #2446
## PR Checklist
* [x] Closes #1142
* [x] I work here
* [x] Tests added/passed
* [x] Schema updated
## 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.
-------------------------------------------------
* this is a start, but there's a weird linker bug if I take the SetKeybinding(ShortcutAction, KeyChord) implementation out, which I don't totally understand
* a good old-fashioned clean will fix that right up
* all these things work
* hey this actually _functionally_ works
* Mostly cleanup and completion of implementation
* Hey I bet we could just make NewTab the handler for NewTabWithProfile
* Start writing tests for Keybinding args
* Add tests
* Revert a bad sln change, and clean out dead code
* Change to include "command" as a single object
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"] },
```
* schemas are hard yo
* Fix the build?
* wonder why my -Wall settings are different than CI...
* this makes me hate things
* Comments from PR
* Add a `Direction::None`
* LOAD BEARING
* add some GH ids to TODOs
* add a comment
* PR nits from carlos
2019-11-14 23:23:40 +01:00
|
|
|
#include "ActionAndArgs.h"
|
|
|
|
#include "ActionAndArgs.g.cpp"
|
2020-07-17 03:31:09 +02:00
|
|
|
|
|
|
|
#include "JsonUtils.h"
|
2021-07-03 00:35:55 +02:00
|
|
|
#include "HashUtils.h"
|
2020-07-17 03:31:09 +02:00
|
|
|
|
2020-06-26 22:38:02 +02:00
|
|
|
#include <LibraryResources.h>
|
2020-06-15 15:33:30 +02:00
|
|
|
|
2020-08-20 03:02:10 +02:00
|
|
|
static constexpr std::string_view AdjustFontSizeKey{ "adjustFontSize" };
|
|
|
|
static constexpr std::string_view CloseOtherTabsKey{ "closeOtherTabs" };
|
|
|
|
static constexpr std::string_view ClosePaneKey{ "closePane" };
|
|
|
|
static constexpr std::string_view CloseTabKey{ "closeTab" };
|
|
|
|
static constexpr std::string_view CloseTabsAfterKey{ "closeTabsAfter" };
|
|
|
|
static constexpr std::string_view CloseWindowKey{ "closeWindow" };
|
2020-06-15 15:33:30 +02:00
|
|
|
static constexpr std::string_view CopyTextKey{ "copy" };
|
|
|
|
static constexpr std::string_view DuplicateTabKey{ "duplicateTab" };
|
2020-08-20 03:02:10 +02:00
|
|
|
static constexpr std::string_view ExecuteCommandlineKey{ "wt" };
|
|
|
|
static constexpr std::string_view FindKey{ "find" };
|
|
|
|
static constexpr std::string_view MoveFocusKey{ "moveFocus" };
|
Preliminary work to add Swap Panes functionality (GH Issues 1000, 4922) (#10638)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Add functionality to swap a pane with an adjacent (Up/Down/Left/Right) neighbor.
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
## References
This work potentially touches on: #1000 #2398 and #4922
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes a component of #1000 (partially, comment), #4922 (partially, `SwapPanes` function is added but not hooked up, no detach functionality)
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [x] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
Its been a while since I've written C++ code, and it is my first time working on a Windows application. I hope that I have not made too many mistakes.
Work currently done:
- Add boilerplate/infrastructure for argument parsing, hotkeys, event handling
- Adds the `MovePane` function that finds the focused pane, and then tries to find
a pane that is visually adjacent to according to direction.
- First pass at the `SwapPanes` function that swaps the tree location of two panes
- First working version of helpers `_FindFocusAndNeighbor` and `_FindNeighborFromFocus`
that search the tree for the currently focused pane, and then climbs back up the tree
to try to find a sibling pane that is adjacent to it.
- An `_IsAdjacent' function that tests whether two panes, given their relative offsets, are adjacent to each other according to the direction.
Next steps:
- Once working these functions (`_FindFocusAndNeighbor`, etc) could be utilized to also solve #2398 by updating the `NavigateFocus` function.
- Do we want default hotkeys for the new actions?
<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
At this point, compilation and manual testing of functionality (with hotkeys) by creating panes, adding distinguishers to each pane, and then swapping them around to confirm they went to the right location.
2021-07-22 14:53:03 +02:00
|
|
|
static constexpr std::string_view MovePaneKey{ "movePane" };
|
Move Pane to Tab (GH7075) (#10780)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Add functionality to move a pane to another tab. If the tab index is greater than the number of current tabs a new tab will be created with the pane as its root. Similarly, if the last pane on a tab is moved to another tab, the original tab will be closed.
This is largely complete, but I know that I'm messing around with things that I am unfamiliar with, and would like to avoid footguns where possible.
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
## References
#4587
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #7075
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [x] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
Things done:
- Moving a pane to a new tab appears to work. Moving a pane to an existing tab mostly works. Moving a pane back to its original tab appears to work.
- Set up {Attach,Detach}Pane methods to add or remove a pane from a pane. Detach is slightly different than Close in that we want to persist the tree structure and terminal controls.
- Add `Detached` event on a pane that can be subscribed to to remove other event handlers if desired.
- Added simple WalkTree abstraction for one-off recursion use cases that calls a provided function on each pane in order (and optionally terminates early).
- Fixed an in-prod bug with closing panes. Specifically, if you have a tree (1; 2 3) and close the 1 pane, then 3 will lose its borders because of these lines clearing the border on both children https://github.com/microsoft/terminal/blob/main/src/cascadia/TerminalApp/Pane.cpp#L1197-L1201 .
To do:
- Right now I have `TerminalTab` as a friend class of `Pane` so I can access some extra properties in my `WalkTree` callbacks, but there is probably a better choice for the abstraction boundary.
Next Steps:
- In a future PR Drag & Drop handlers could be added that utilize the Attach/Detach infrastructure to provide a better UI.
- Similarly once this is working, it should be possible to convert an entire tab into a pane on an existing tab (Tab::DetachRoot on original tab followed by Tab::AttachPane on the target tab).
- Its been 10 years, I just really want to use concepts already.
<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Manual testing by creating pane(s), and moving them between tabs and creating new tabs and destroying tabs by moving the last remaining pane.
2021-08-12 18:41:17 +02:00
|
|
|
static constexpr std::string_view SwapPaneKey{ "swapPane" };
|
2020-06-15 15:33:30 +02:00
|
|
|
static constexpr std::string_view NewTabKey{ "newTab" };
|
|
|
|
static constexpr std::string_view NextTabKey{ "nextTab" };
|
2020-08-20 03:02:10 +02:00
|
|
|
static constexpr std::string_view OpenNewTabDropdownKey{ "openNewTabDropdown" };
|
2021-02-24 01:14:13 +01:00
|
|
|
static constexpr std::string_view OpenSettingsKey{ "openSettings" };
|
2020-08-20 03:02:10 +02:00
|
|
|
static constexpr std::string_view OpenTabColorPickerKey{ "openTabColorPicker" };
|
|
|
|
static constexpr std::string_view PasteTextKey{ "paste" };
|
2020-06-15 15:33:30 +02:00
|
|
|
static constexpr std::string_view PrevTabKey{ "prevTab" };
|
2020-08-20 03:02:10 +02:00
|
|
|
static constexpr std::string_view RenameTabKey{ "renameTab" };
|
2020-10-28 20:36:30 +01:00
|
|
|
static constexpr std::string_view OpenTabRenamerKey{ "openTabRenamer" };
|
2020-06-15 15:33:30 +02:00
|
|
|
static constexpr std::string_view ResetFontSizeKey{ "resetFontSize" };
|
2020-08-20 03:02:10 +02:00
|
|
|
static constexpr std::string_view ResizePaneKey{ "resizePane" };
|
2021-05-20 20:44:04 +02:00
|
|
|
static constexpr std::string_view ScrollDownKey{ "scrollDown" };
|
|
|
|
static constexpr std::string_view ScrollDownPageKey{ "scrollDownPage" };
|
|
|
|
static constexpr std::string_view ScrollUpKey{ "scrollUp" };
|
|
|
|
static constexpr std::string_view ScrollUpPageKey{ "scrollUpPage" };
|
2020-12-08 18:28:41 +01:00
|
|
|
static constexpr std::string_view ScrollToTopKey{ "scrollToTop" };
|
|
|
|
static constexpr std::string_view ScrollToBottomKey{ "scrollToBottom" };
|
2020-08-12 15:46:53 +02:00
|
|
|
static constexpr std::string_view SendInputKey{ "sendInput" };
|
2020-08-10 18:21:56 +02:00
|
|
|
static constexpr std::string_view SetColorSchemeKey{ "setColorScheme" };
|
Add `setTabColor` and `openTabColorPicker` actions (#6567)
## Summary of the Pull Request
Adds a pair of `ShortcutAction`s for setting the tab color.
* `setTabColor`: This changes the color of the current tab to the provided color, or can be used to clear the color.
* `openTabColorPicker`: This keybinding immediately activates the tab color picker for the currently focused tab.
## References
## PR Checklist
* [x] scratches my own itch
* [x] I work here
* [x] Tests added/passed
* [x] https://github.com/MicrosoftDocs/terminal/pull/69
## Detailed Description of the Pull Request / Additional comments
## Validation Steps Performed
* hey look there are tests
* Tested with the following:
```json
// { "command": "setTabColor", "keys": [ "alt+c" ] },
{ "keys": "ctrl+alt+c", "command": { "action": "setTabColor", "color": "#123456" } },
{ "keys": "alt+shift+c", "command": { "action": "setTabColor", "color": null} },
{ "keys": "alt+c", "command": "openTabColorPicker" },
```
2020-06-25 15:06:21 +02:00
|
|
|
static constexpr std::string_view SetTabColorKey{ "setTabColor" };
|
2020-08-20 03:02:10 +02:00
|
|
|
static constexpr std::string_view SplitPaneKey{ "splitPane" };
|
|
|
|
static constexpr std::string_view SwitchToTabKey{ "switchToTab" };
|
2020-08-21 17:39:40 +02:00
|
|
|
static constexpr std::string_view TabSearchKey{ "tabSearch" };
|
2020-08-20 03:02:10 +02:00
|
|
|
static constexpr std::string_view ToggleAlwaysOnTopKey{ "toggleAlwaysOnTop" };
|
2020-06-26 22:38:02 +02:00
|
|
|
static constexpr std::string_view ToggleCommandPaletteKey{ "commandPalette" };
|
2020-08-20 03:02:10 +02:00
|
|
|
static constexpr std::string_view ToggleFocusModeKey{ "toggleFocusMode" };
|
|
|
|
static constexpr std::string_view ToggleFullscreenKey{ "toggleFullscreen" };
|
|
|
|
static constexpr std::string_view TogglePaneZoomKey{ "togglePaneZoom" };
|
2021-08-02 23:04:57 +02:00
|
|
|
static constexpr std::string_view ToggleSplitOrientationKey{ "toggleSplitOrientation" };
|
Implement user-specified pixel shaders, redux (#8565)
Co-authored-by: mrange <marten_range@hotmail.com>
I loved the pixel shaders in #7058, but that PR needed a bit of polish
to be ready for ingestion. This PR is almost _exactly_ that PR, with
some small changes.
* It adds a new pre-profile setting `"experimental.pixelShaderPath"`,
which lets the user set a pixel shader to use with the Terminal.
- CHANGED FROM #7058: It does _not_ add any built-in shaders.
- CHANGED FROM #7058: it will _override_
`experimental.retroTerminalEffect`
* It adds a bunch of sample shaders in `samples/shaders`. Included:
- A NOP shader as a base to build from.
- An "invert" shader that inverts the colors, as a simple example
- An "grayscale" shader that converts all colors to grayscale, as a
simple example
- An "raster bars" shader that draws some colored bars on the screen
with a drop shadow, as a more involved example
- The original retro terminal effects, as a more involved example
- It also includes a broken shader, as an example of what heppens
when the shader fails to compile
- CHANGED FROM #7058: It does _not_ add the "retroII" shader we were
all worried about.
* When a shader fails to be found or fails to compile, we'll display an
error dialog to the user with a relevant error message.
- CHANGED FROM #7058: Originally, #7058 would display "error bars"
on the screen. I've removed that, and had the Terminal disable the
shader entirely then.
* Renames the `toggleRetroEffect` action to `toggleShaderEffect`.
(`toggleRetroEffect` is now an alias to `toggleShaderEffect`). This
action will turn the shader OR the retro effects on/off.
`toggleShaderEffect` works the way you'd expect it to, but the mental
math on _how_ is a little weird. The logic is basically:
```
useShader = shaderEffectsEnabled ?
(pixelShaderProvided ?
pixelShader :
(retroEffectEnabled ?
retroEffect : null
)
) :
null
```
and `toggleShaderEffect` toggles `shaderEffectsEnabled`.
* If you've got both a shader and retro enabled, `toggleShaderEffect`
will toggle between the shader on/off.
* If you've got a shader and retro disabled, `toggleShaderEffect` will
toggle between the shader on/off.
References #6191
References #7058
Closes #7013
Closes #3930 "Add setting to retro terminal shader to control blur
radius, color"
Closes #3929 "Add setting to retro terminal shader to enable drawing
scanlines"
- At this point, just roll your own version of the shader.
2020-12-15 21:40:22 +01:00
|
|
|
static constexpr std::string_view LegacyToggleRetroEffectKey{ "toggleRetroEffect" };
|
|
|
|
static constexpr std::string_view ToggleShaderEffectsKey{ "toggleShaderEffects" };
|
2020-11-25 23:09:27 +01:00
|
|
|
static constexpr std::string_view MoveTabKey{ "moveTab" };
|
2020-12-05 00:54:59 +01:00
|
|
|
static constexpr std::string_view BreakIntoDebuggerKey{ "breakIntoDebugger" };
|
Add `findNext`, `findPrev` actions (#8917)
This PR is a resurrection of #8522. @Hegunumo has apparently deleted
their account, but the contribution was still valuable. I'm just here to
get it across the finish line.
This PR adds new action for navigating to the next & previous search
results. These actions are unbound by default. These actions can be used
from directly within the search dialog also, to immediately navigate the
results.
Furthermore, if you have a search started, and close the search box,
then press this keybinding, _it will still perform the search_. So you
can just hit <kbd>F3</kbd> repeatedly with the dialog closed to keep
searching new results. Neat!
If you dispatch the action on the key down, then dismiss a selection on
a key up, we'll end up immediately destroying the selection when you
release the bound key. That's annoying. It also bothers @carlos-zamora
in #3758. However, I _think_ we can just only dismiss the selection on a
key up. I _think_ that's fine. It _seems_ fine so far. We've got an
entire release cycle to futz with it.
## Validation Steps Performed
I've played with it all day and it seems _crisp_.
Closes #7695
Co-authored-by: Kiminori Kaburagi <yukawa_hidenori@icloud.com>
2021-02-18 20:21:35 +01:00
|
|
|
static constexpr std::string_view FindMatchKey{ "findMatch" };
|
2021-02-08 19:03:55 +01:00
|
|
|
static constexpr std::string_view TogglePaneReadOnlyKey{ "toggleReadOnlyMode" };
|
2021-02-20 00:51:30 +01:00
|
|
|
static constexpr std::string_view NewWindowKey{ "newWindow" };
|
2021-03-30 18:08:03 +02:00
|
|
|
static constexpr std::string_view IdentifyWindowKey{ "identifyWindow" };
|
|
|
|
static constexpr std::string_view IdentifyWindowsKey{ "identifyWindows" };
|
Add support for renaming windows (#9662)
## Summary of the Pull Request
This PR adds support for renaming windows.
![window-renaming-000](https://user-images.githubusercontent.com/18356694/113034344-9a30be00-9157-11eb-9443-975f3c294f56.gif)
![window-renaming-001](https://user-images.githubusercontent.com/18356694/113034452-b5033280-9157-11eb-9e35-e5ac80fef0bc.gif)
It does so through two new actions:
* `renameWindow` takes a `name` parameter, and attempts to set the window's name
to the provided name. This is useful if you always want to hit <kbd>F3</kbd>
and rename a window to "foo" (READ: probably not that useful)
* `openWindowRenamer` is more interesting: it opens a `TeachingTip` with a
`TextBox`. When the user hits Ok, it'll request a rename for the provided
value. This lets the user pick a new name for the window at runtime.
In both cases, if there's already a window with that name, then the monarch will
reject the rename, and pop a `Toast` in the window informing the user that the
rename failed. Nifty!
## References
* Builds on the toasts from #9523
* #5000 - process model megathread
## PR Checklist
* [x] Closes https://github.com/microsoft/terminal/projects/5#card-50771747
* [x] I work here
* [x] Tests addded (and pass with the help of #9660)
* [ ] Requires documentation to be updated
## Detailed Description of the Pull Request / Additional comments
I'm sending this PR while finishing up the tests. I figured I'll have time to sneak them in before I get the necessary reviews.
> PAIN: We can't immediately focus the textbox in the TeachingTip. It's
> not technically focusable until it is opened. However, it doesn't
> provide an even tto tell us when it is opened. That's tracked in
> microsoft/microsoft-ui-xaml#1607. So for now, the user _needs_ to
> click on the text box manually.
> We're also not using a ContentDialog for this, because in Xaml
> Islands a text box in a ContentDialog won't recieve _any_ keypresses.
> Fun!
## Validation Steps Performed
I've been playing with
```json
{ "keys": "f1", "command": "identifyWindow" },
{ "keys": "f2", "command": "identifyWindows" },
{ "keys": "f3", "command": "openWindowRenamer" },
{ "keys": "f4", "command": { "action": "renameWindow", "name": "foo" } },
{ "keys": "f5", "command": { "action": "renameWindow", "name": "bar" } },
```
and they seem to work as expected
2021-04-02 18:00:04 +02:00
|
|
|
static constexpr std::string_view RenameWindowKey{ "renameWindow" };
|
|
|
|
static constexpr std::string_view OpenWindowRenamerKey{ "openWindowRenamer" };
|
2021-04-29 00:13:28 +02:00
|
|
|
static constexpr std::string_view GlobalSummonKey{ "globalSummon" };
|
|
|
|
static constexpr std::string_view QuakeModeKey{ "quakeMode" };
|
2021-05-21 23:55:57 +02:00
|
|
|
static constexpr std::string_view FocusPaneKey{ "focusPane" };
|
2021-09-02 16:59:42 +02:00
|
|
|
static constexpr std::string_view ClearBufferKey{ "clearBuffer" };
|
Add action to run multiple actions. (#11045)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Add a new action that can contain multiple other actions.
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
## References
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #3992
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [x] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
Creates a shortcut action that allows a list of actions to be specified as arguments. Steals a bunch of the serialization code from my other pr. Overall, because I had the serialization code written already, this was remarkably easy.
I can't think of any combined action to be added to the defaults, so I think this is just a thing for the documentation unless someone else has a good example. I know there are lot of times when the recommended workaround is "make an action with commandline wt.exe ..." and this could be a good replacement for that, but that is all personalized.
I didn't add this to the command line parsing, since the command line is already a way to run multiple actions.
<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Created a new command, confirmed that "Move right->down" showed up in the command palette, and that running it did the correct behavior (moving right one pane, then down one pane).
```
{
"command": {
"action": "multipleActions",
"name": "Move right->down",
"actions": [
{"action": "moveFocus", "direction": "right" },
{"action": "moveFocus", "direction": "down" },
]
}
}
```
2021-08-31 21:35:51 +02:00
|
|
|
static constexpr std::string_view MultipleActionsKey{ "multipleActions" };
|
2020-06-26 22:38:02 +02:00
|
|
|
|
|
|
|
static constexpr std::string_view ActionKey{ "action" };
|
|
|
|
|
|
|
|
// This key is reserved to remove a keybinding, instead of mapping it to an action.
|
|
|
|
static constexpr std::string_view UnboundKey{ "unbound" };
|
Add support for arbitrary args in keybindings (#3391)
## 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 `ShortcutAction`s, 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:
```json
{ "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:
```json
{ "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](https://github.com/microsoft/terminal/blob/master/doc/specs/%231142%20-%20Keybinding%20Arguments.md) for more details.
This is part two of the implementation, part one was #2446
## PR Checklist
* [x] Closes #1142
* [x] I work here
* [x] Tests added/passed
* [x] Schema updated
## 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.
-------------------------------------------------
* this is a start, but there's a weird linker bug if I take the SetKeybinding(ShortcutAction, KeyChord) implementation out, which I don't totally understand
* a good old-fashioned clean will fix that right up
* all these things work
* hey this actually _functionally_ works
* Mostly cleanup and completion of implementation
* Hey I bet we could just make NewTab the handler for NewTabWithProfile
* Start writing tests for Keybinding args
* Add tests
* Revert a bad sln change, and clean out dead code
* Change to include "command" as a single object
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"] },
```
* schemas are hard yo
* Fix the build?
* wonder why my -Wall settings are different than CI...
* this makes me hate things
* Comments from PR
* Add a `Direction::None`
* LOAD BEARING
* add some GH ids to TODOs
* add a comment
* PR nits from carlos
2019-11-14 23:23:40 +01:00
|
|
|
|
2021-05-20 20:44:04 +02:00
|
|
|
#define KEY_TO_ACTION_PAIR(action) { action##Key, ShortcutAction::action },
|
|
|
|
#define ACTION_TO_KEY_PAIR(action) { ShortcutAction::action, action##Key },
|
|
|
|
#define ACTION_TO_SERIALIZERS_PAIR(action) { ShortcutAction::action, { action##Args::FromJson, action##Args::ToJson } },
|
|
|
|
|
2020-10-06 18:56:59 +02:00
|
|
|
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
Add support for arbitrary args in keybindings (#3391)
## 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 `ShortcutAction`s, 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:
```json
{ "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:
```json
{ "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](https://github.com/microsoft/terminal/blob/master/doc/specs/%231142%20-%20Keybinding%20Arguments.md) for more details.
This is part two of the implementation, part one was #2446
## PR Checklist
* [x] Closes #1142
* [x] I work here
* [x] Tests added/passed
* [x] Schema updated
## 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.
-------------------------------------------------
* this is a start, but there's a weird linker bug if I take the SetKeybinding(ShortcutAction, KeyChord) implementation out, which I don't totally understand
* a good old-fashioned clean will fix that right up
* all these things work
* hey this actually _functionally_ works
* Mostly cleanup and completion of implementation
* Hey I bet we could just make NewTab the handler for NewTabWithProfile
* Start writing tests for Keybinding args
* Add tests
* Revert a bad sln change, and clean out dead code
* Change to include "command" as a single object
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"] },
```
* schemas are hard yo
* Fix the build?
* wonder why my -Wall settings are different than CI...
* this makes me hate things
* Comments from PR
* Add a `Direction::None`
* LOAD BEARING
* add some GH ids to TODOs
* add a comment
* PR nits from carlos
2019-11-14 23:23:40 +01:00
|
|
|
{
|
2020-10-06 18:56:59 +02:00
|
|
|
using namespace ::Microsoft::Terminal::Settings::Model;
|
2020-07-17 03:31:09 +02:00
|
|
|
|
2020-06-15 15:33:30 +02:00
|
|
|
// 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.
|
2020-06-26 22:38:02 +02:00
|
|
|
const std::map<std::string_view, ShortcutAction, std::less<>> ActionAndArgs::ActionKeyNamesMap{
|
2021-05-20 20:44:04 +02:00
|
|
|
#define ON_ALL_ACTIONS(action) KEY_TO_ACTION_PAIR(action)
|
|
|
|
ALL_SHORTCUT_ACTIONS
|
|
|
|
#undef ON_ALL_ACTIONS
|
|
|
|
};
|
|
|
|
|
|
|
|
static const std::map<ShortcutAction, std::string_view, std::less<>> ActionToStringMap{
|
|
|
|
#define ON_ALL_ACTIONS(action) ACTION_TO_KEY_PAIR(action)
|
|
|
|
ALL_SHORTCUT_ACTIONS
|
|
|
|
#undef ON_ALL_ACTIONS
|
2020-06-15 15:33:30 +02:00
|
|
|
};
|
|
|
|
|
2020-10-06 18:56:59 +02:00
|
|
|
using ParseResult = std::tuple<IActionArgs, std::vector<SettingsLoadWarnings>>;
|
2020-06-15 15:33:30 +02:00
|
|
|
using ParseActionFunction = std::function<ParseResult(const Json::Value&)>;
|
2021-05-20 20:44:04 +02:00
|
|
|
using SerializeActionFunction = std::function<Json::Value(IActionArgs)>;
|
2020-06-15 15:33:30 +02:00
|
|
|
|
2021-05-20 20:44:04 +02:00
|
|
|
// This is a map of ShortcutAction->{function<IActionArgs(Json::Value)>, function<Json::Value(IActionArgs)>. It holds
|
|
|
|
// a set of (de)serializer functions that can be used to (de)serialize an IActionArgs
|
2020-06-15 15:33:30 +02:00
|
|
|
// from json. Each type of IActionArgs that can accept arbitrary args should be
|
|
|
|
// placed into this map, with the corresponding deserializer function as the
|
|
|
|
// value.
|
2021-05-20 20:44:04 +02:00
|
|
|
static const std::unordered_map<ShortcutAction, std::pair<ParseActionFunction, SerializeActionFunction>> argSerializerMap{
|
|
|
|
|
|
|
|
// These are special cases.
|
|
|
|
// - QuakeMode: deserializes into a GlobalSummon, so we don't need a serializer
|
|
|
|
// - Invalid: has no args
|
|
|
|
{ ShortcutAction::QuakeMode, { GlobalSummonArgs::QuakeModeFromJson, nullptr } },
|
|
|
|
{ ShortcutAction::Invalid, { nullptr, nullptr } },
|
2020-08-11 16:03:12 +02:00
|
|
|
|
2021-05-20 20:44:04 +02:00
|
|
|
#define ON_ALL_ACTIONS_WITH_ARGS(action) ACTION_TO_SERIALIZERS_PAIR(action)
|
|
|
|
ALL_SHORTCUT_ACTIONS_WITH_ARGS
|
|
|
|
#undef ON_ALL_ACTIONS_WITH_ARGS
|
2020-06-15 15:33:30 +02:00
|
|
|
};
|
|
|
|
|
2021-07-03 00:35:55 +02:00
|
|
|
ActionAndArgs::ActionAndArgs(ShortcutAction action)
|
|
|
|
{
|
|
|
|
// Find the deserializer
|
|
|
|
const auto deserializersIter = argSerializerMap.find(action);
|
|
|
|
if (deserializersIter != argSerializerMap.end())
|
|
|
|
{
|
|
|
|
auto pfn = deserializersIter->second.first;
|
|
|
|
if (pfn)
|
|
|
|
{
|
|
|
|
// Call the deserializer on an empty JSON object.
|
|
|
|
// This ensures that we have a valid ActionArgs
|
|
|
|
std::vector<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings> parseWarnings;
|
|
|
|
std::tie(_Args, parseWarnings) = pfn({});
|
|
|
|
}
|
|
|
|
|
|
|
|
// if an arg parser was registered, but failed,
|
|
|
|
// return the invalid ActionAndArgs we started with.
|
|
|
|
if (pfn && _Args == nullptr)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Either...
|
|
|
|
// (1) we don't have a deserializer, so it's ok for _Args to be null, or
|
|
|
|
// (2) we had one AND it worked, so _Args is set up properly
|
|
|
|
_Action = action;
|
|
|
|
}
|
|
|
|
|
2020-06-15 15:33:30 +02:00
|
|
|
// Function Description:
|
|
|
|
// - Attempts to match a string to a ShortcutAction. If there's no match, then
|
|
|
|
// returns ShortcutAction::Invalid
|
|
|
|
// Arguments:
|
|
|
|
// - actionString: the string to match to a ShortcutAction
|
|
|
|
// Return Value:
|
|
|
|
// - The ShortcutAction corresponding to the given string, if a match exists.
|
|
|
|
static ShortcutAction GetActionFromString(const std::string_view actionString)
|
|
|
|
{
|
|
|
|
// Try matching the command to one we have. If we can't find the
|
|
|
|
// action name in our list of names, let's just unbind that key.
|
2020-06-26 22:38:02 +02:00
|
|
|
const auto found = ActionAndArgs::ActionKeyNamesMap.find(actionString);
|
|
|
|
return found != ActionAndArgs::ActionKeyNamesMap.end() ? found->second : ShortcutAction::Invalid;
|
2020-06-15 15:33:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Deserialize an ActionAndArgs from the provided json object or string `json`.
|
|
|
|
// * If json is a string, we'll attempt to treat it as an action name,
|
|
|
|
// without arguments.
|
|
|
|
// * If json is an object, we'll attempt to retrieve the action name from
|
|
|
|
// its "action" property, and we'll use that name to fine a deserializer
|
|
|
|
// to precess the rest of the arguments in the json object.
|
|
|
|
// - If the action name is null or "unbound", or we don't understand the
|
|
|
|
// action name, or we failed to parse the arguments to this action, we'll
|
|
|
|
// return null. This should indicate to the caller that the action should
|
|
|
|
// be unbound.
|
|
|
|
// - If there were any warnings while parsing arguments for the action,
|
|
|
|
// they'll be appended to the warnings parameter.
|
|
|
|
// Arguments:
|
|
|
|
// - json: The Json::Value to attempt to parse as an ActionAndArgs
|
|
|
|
// - warnings: If there were any warnings during parsing, they'll be
|
|
|
|
// appended to this vector.
|
|
|
|
// Return Value:
|
|
|
|
// - a deserialized ActionAndArgs corresponding to the values in json, or
|
Introduce ActionMap to Terminal Settings Model (#9621)
This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`).
## References
#9428 - Spec
#6900 - Actions page
Closes #7441
## Detailed Description of the Pull Request / Additional comments
The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item.
#9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`.
Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette.
Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller.
The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands.
## Validation Steps Performed
All local tests pass.
2021-05-05 06:50:13 +02:00
|
|
|
// an "invalid" action if we failed to deserialize an action.
|
2020-06-15 15:33:30 +02:00
|
|
|
winrt::com_ptr<ActionAndArgs> ActionAndArgs::FromJson(const Json::Value& json,
|
2020-10-06 18:56:59 +02:00
|
|
|
std::vector<SettingsLoadWarnings>& warnings)
|
2020-06-15 15:33:30 +02:00
|
|
|
{
|
|
|
|
// Invalid is our placeholder that the action was not parsed.
|
|
|
|
ShortcutAction action = ShortcutAction::Invalid;
|
|
|
|
|
|
|
|
// Actions can be serialized in two styles:
|
|
|
|
// "action": "switchToTab0",
|
|
|
|
// "action": { "action": "switchToTab", "index": 0 },
|
|
|
|
// NOTE: For keybindings, the "action" param is actually "command"
|
|
|
|
|
|
|
|
// 1. In the first case, the json is a string, that's the
|
|
|
|
// action name. There are no provided args, so we'll pass
|
|
|
|
// Json::Value::null to the parse function.
|
|
|
|
// 2. In the second case, the json is an object. We'll use the
|
|
|
|
// "action" in that object as the action name. We'll then pass
|
|
|
|
// the json object to the arg parser, for further parsing.
|
|
|
|
|
|
|
|
auto argsVal = Json::Value::null;
|
|
|
|
|
|
|
|
// Only try to parse the action if it's actually a string value.
|
|
|
|
// `null` will not pass this check.
|
|
|
|
if (json.isString())
|
|
|
|
{
|
|
|
|
auto commandString = json.asString();
|
|
|
|
action = GetActionFromString(commandString);
|
|
|
|
}
|
|
|
|
else if (json.isObject())
|
|
|
|
{
|
2020-07-17 03:31:09 +02:00
|
|
|
if (const auto actionString{ JsonUtils::GetValueForKey<std::optional<std::string>>(json, ActionKey) })
|
2020-06-15 15:33:30 +02:00
|
|
|
{
|
2020-07-17 03:31:09 +02:00
|
|
|
action = GetActionFromString(*actionString);
|
2020-06-15 15:33:30 +02:00
|
|
|
argsVal = json;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Some keybindings can accept other arbitrary arguments. If it
|
|
|
|
// does, we'll try to deserialize any "args" that were provided with
|
|
|
|
// the binding.
|
|
|
|
IActionArgs args{ nullptr };
|
2020-10-06 18:56:59 +02:00
|
|
|
std::vector<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings> parseWarnings;
|
2021-05-20 20:44:04 +02:00
|
|
|
const auto deserializersIter = argSerializerMap.find(action);
|
|
|
|
if (deserializersIter != argSerializerMap.end())
|
2020-06-15 15:33:30 +02:00
|
|
|
{
|
2021-05-20 20:44:04 +02:00
|
|
|
auto pfn = deserializersIter->second.first;
|
2020-06-15 15:33:30 +02:00
|
|
|
if (pfn)
|
|
|
|
{
|
|
|
|
std::tie(args, parseWarnings) = pfn(argsVal);
|
|
|
|
}
|
|
|
|
warnings.insert(warnings.end(), parseWarnings.begin(), parseWarnings.end());
|
|
|
|
|
|
|
|
// if an arg parser was registered, but failed, bail
|
|
|
|
if (pfn && args == nullptr)
|
|
|
|
{
|
Introduce ActionMap to Terminal Settings Model (#9621)
This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`).
## References
#9428 - Spec
#6900 - Actions page
Closes #7441
## Detailed Description of the Pull Request / Additional comments
The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item.
#9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`.
Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette.
Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller.
The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands.
## Validation Steps Performed
All local tests pass.
2021-05-05 06:50:13 +02:00
|
|
|
return make_self<ActionAndArgs>();
|
2020-06-15 15:33:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Introduce ActionMap to Terminal Settings Model (#9621)
This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`).
## References
#9428 - Spec
#6900 - Actions page
Closes #7441
## Detailed Description of the Pull Request / Additional comments
The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item.
#9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`.
Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette.
Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller.
The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands.
## Validation Steps Performed
All local tests pass.
2021-05-05 06:50:13 +02:00
|
|
|
// Something like
|
|
|
|
// { name: "foo", action: "unbound" }
|
|
|
|
// will _remove_ the "foo" command, by returning an "invalid" action here.
|
|
|
|
return make_self<ActionAndArgs>(action, args);
|
2020-06-15 15:33:30 +02:00
|
|
|
}
|
|
|
|
|
2021-05-20 20:44:04 +02:00
|
|
|
Json::Value ActionAndArgs::ToJson(const Model::ActionAndArgs& val)
|
|
|
|
{
|
|
|
|
if (val)
|
|
|
|
{
|
|
|
|
// Search for the ShortcutAction
|
|
|
|
const auto shortcutActionIter{ ActionToStringMap.find(val.Action()) };
|
|
|
|
if (shortcutActionIter == ActionToStringMap.end())
|
|
|
|
{
|
|
|
|
// Couldn't find the ShortcutAction,
|
|
|
|
// return... "command": "unbound"
|
|
|
|
return static_cast<std::string>(UnboundKey);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!val.Args())
|
|
|
|
{
|
|
|
|
// No args to serialize,
|
|
|
|
// output something like... "command": "copy"
|
|
|
|
return static_cast<std::string>(shortcutActionIter->second);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Serialize any set args,
|
|
|
|
// output something like... "command": { "action": "copy", "singleLine": false }
|
|
|
|
Json::Value result{ Json::ValueType::objectValue };
|
|
|
|
|
|
|
|
// Set the action args, if any
|
|
|
|
const auto actionArgSerializerIter{ argSerializerMap.find(val.Action()) };
|
|
|
|
if (actionArgSerializerIter != argSerializerMap.end())
|
|
|
|
{
|
|
|
|
auto pfn{ actionArgSerializerIter->second.second };
|
|
|
|
if (pfn)
|
|
|
|
{
|
|
|
|
result = pfn(val.Args());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the "action" part
|
|
|
|
result[static_cast<std::string>(ActionKey)] = static_cast<std::string>(shortcutActionIter->second);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// "command": "unbound"
|
|
|
|
return static_cast<std::string>(UnboundKey);
|
|
|
|
}
|
|
|
|
|
2020-10-17 00:14:11 +02:00
|
|
|
com_ptr<ActionAndArgs> ActionAndArgs::Copy() const
|
|
|
|
{
|
|
|
|
auto copy{ winrt::make_self<ActionAndArgs>() };
|
|
|
|
copy->_Action = _Action;
|
2020-10-23 02:26:54 +02:00
|
|
|
copy->_Args = _Args ? _Args.Copy() : IActionArgs{ nullptr };
|
2020-10-17 00:14:11 +02:00
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
2020-06-26 22:38:02 +02:00
|
|
|
winrt::hstring ActionAndArgs::GenerateName() const
|
|
|
|
{
|
|
|
|
// Use a magic static to initialize this map, because we won't be able
|
|
|
|
// to load the resources at _init_, only at runtime.
|
|
|
|
static const auto GeneratedActionNames = []() {
|
|
|
|
return std::unordered_map<ShortcutAction, winrt::hstring>{
|
2020-08-20 03:02:10 +02:00
|
|
|
{ ShortcutAction::AdjustFontSize, RS_(L"AdjustFontSizeCommandKey") },
|
|
|
|
{ ShortcutAction::CloseOtherTabs, L"" }, // Intentionally omitted, must be generated by GenerateName
|
|
|
|
{ ShortcutAction::ClosePane, RS_(L"ClosePaneCommandKey") },
|
2021-06-25 21:22:52 +02:00
|
|
|
{ ShortcutAction::CloseTab, L"" }, // Intentionally omitted, must be generated by GenerateName
|
2020-08-20 03:02:10 +02:00
|
|
|
{ ShortcutAction::CloseTabsAfter, L"" }, // Intentionally omitted, must be generated by GenerateName
|
|
|
|
{ ShortcutAction::CloseWindow, RS_(L"CloseWindowCommandKey") },
|
2020-06-26 22:38:02 +02:00
|
|
|
{ ShortcutAction::CopyText, RS_(L"CopyTextCommandKey") },
|
|
|
|
{ ShortcutAction::DuplicateTab, RS_(L"DuplicateTabCommandKey") },
|
2020-08-20 03:02:10 +02:00
|
|
|
{ ShortcutAction::ExecuteCommandline, RS_(L"ExecuteCommandlineCommandKey") },
|
|
|
|
{ ShortcutAction::Find, RS_(L"FindCommandKey") },
|
|
|
|
{ ShortcutAction::Invalid, L"" },
|
|
|
|
{ ShortcutAction::MoveFocus, RS_(L"MoveFocusCommandKey") },
|
Preliminary work to add Swap Panes functionality (GH Issues 1000, 4922) (#10638)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Add functionality to swap a pane with an adjacent (Up/Down/Left/Right) neighbor.
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
## References
This work potentially touches on: #1000 #2398 and #4922
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes a component of #1000 (partially, comment), #4922 (partially, `SwapPanes` function is added but not hooked up, no detach functionality)
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [x] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
Its been a while since I've written C++ code, and it is my first time working on a Windows application. I hope that I have not made too many mistakes.
Work currently done:
- Add boilerplate/infrastructure for argument parsing, hotkeys, event handling
- Adds the `MovePane` function that finds the focused pane, and then tries to find
a pane that is visually adjacent to according to direction.
- First pass at the `SwapPanes` function that swaps the tree location of two panes
- First working version of helpers `_FindFocusAndNeighbor` and `_FindNeighborFromFocus`
that search the tree for the currently focused pane, and then climbs back up the tree
to try to find a sibling pane that is adjacent to it.
- An `_IsAdjacent' function that tests whether two panes, given their relative offsets, are adjacent to each other according to the direction.
Next steps:
- Once working these functions (`_FindFocusAndNeighbor`, etc) could be utilized to also solve #2398 by updating the `NavigateFocus` function.
- Do we want default hotkeys for the new actions?
<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
At this point, compilation and manual testing of functionality (with hotkeys) by creating panes, adding distinguishers to each pane, and then swapping them around to confirm they went to the right location.
2021-07-22 14:53:03 +02:00
|
|
|
{ ShortcutAction::MovePane, RS_(L"MovePaneCommandKey") },
|
Move Pane to Tab (GH7075) (#10780)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Add functionality to move a pane to another tab. If the tab index is greater than the number of current tabs a new tab will be created with the pane as its root. Similarly, if the last pane on a tab is moved to another tab, the original tab will be closed.
This is largely complete, but I know that I'm messing around with things that I am unfamiliar with, and would like to avoid footguns where possible.
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
## References
#4587
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #7075
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [x] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
Things done:
- Moving a pane to a new tab appears to work. Moving a pane to an existing tab mostly works. Moving a pane back to its original tab appears to work.
- Set up {Attach,Detach}Pane methods to add or remove a pane from a pane. Detach is slightly different than Close in that we want to persist the tree structure and terminal controls.
- Add `Detached` event on a pane that can be subscribed to to remove other event handlers if desired.
- Added simple WalkTree abstraction for one-off recursion use cases that calls a provided function on each pane in order (and optionally terminates early).
- Fixed an in-prod bug with closing panes. Specifically, if you have a tree (1; 2 3) and close the 1 pane, then 3 will lose its borders because of these lines clearing the border on both children https://github.com/microsoft/terminal/blob/main/src/cascadia/TerminalApp/Pane.cpp#L1197-L1201 .
To do:
- Right now I have `TerminalTab` as a friend class of `Pane` so I can access some extra properties in my `WalkTree` callbacks, but there is probably a better choice for the abstraction boundary.
Next Steps:
- In a future PR Drag & Drop handlers could be added that utilize the Attach/Detach infrastructure to provide a better UI.
- Similarly once this is working, it should be possible to convert an entire tab into a pane on an existing tab (Tab::DetachRoot on original tab followed by Tab::AttachPane on the target tab).
- Its been 10 years, I just really want to use concepts already.
<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Manual testing by creating pane(s), and moving them between tabs and creating new tabs and destroying tabs by moving the last remaining pane.
2021-08-12 18:41:17 +02:00
|
|
|
{ ShortcutAction::SwapPane, RS_(L"SwapPaneCommandKey") },
|
2020-06-26 22:38:02 +02:00
|
|
|
{ ShortcutAction::NewTab, RS_(L"NewTabCommandKey") },
|
|
|
|
{ ShortcutAction::NextTab, RS_(L"NextTabCommandKey") },
|
2020-08-20 03:02:10 +02:00
|
|
|
{ ShortcutAction::OpenNewTabDropdown, RS_(L"OpenNewTabDropdownCommandKey") },
|
2021-02-24 01:14:13 +01:00
|
|
|
{ ShortcutAction::OpenSettings, RS_(L"OpenSettingsUICommandKey") },
|
2020-08-20 03:02:10 +02:00
|
|
|
{ ShortcutAction::OpenTabColorPicker, RS_(L"OpenTabColorPickerCommandKey") },
|
|
|
|
{ ShortcutAction::PasteText, RS_(L"PasteTextCommandKey") },
|
2020-06-26 22:38:02 +02:00
|
|
|
{ ShortcutAction::PrevTab, RS_(L"PrevTabCommandKey") },
|
2020-08-20 03:02:10 +02:00
|
|
|
{ ShortcutAction::RenameTab, RS_(L"ResetTabNameCommandKey") },
|
2020-10-28 20:36:30 +01:00
|
|
|
{ ShortcutAction::OpenTabRenamer, RS_(L"OpenTabRenamerCommandKey") },
|
2020-06-26 22:38:02 +02:00
|
|
|
{ ShortcutAction::ResetFontSize, RS_(L"ResetFontSizeCommandKey") },
|
2020-08-20 03:02:10 +02:00
|
|
|
{ ShortcutAction::ResizePane, RS_(L"ResizePaneCommandKey") },
|
2020-06-26 22:38:02 +02:00
|
|
|
{ ShortcutAction::ScrollDown, RS_(L"ScrollDownCommandKey") },
|
|
|
|
{ ShortcutAction::ScrollDownPage, RS_(L"ScrollDownPageCommandKey") },
|
2020-08-20 03:02:10 +02:00
|
|
|
{ ShortcutAction::ScrollUp, RS_(L"ScrollUpCommandKey") },
|
|
|
|
{ ShortcutAction::ScrollUpPage, RS_(L"ScrollUpPageCommandKey") },
|
2020-12-08 18:28:41 +01:00
|
|
|
{ ShortcutAction::ScrollToTop, RS_(L"ScrollToTopCommandKey") },
|
|
|
|
{ ShortcutAction::ScrollToBottom, RS_(L"ScrollToBottomCommandKey") },
|
2020-08-12 15:46:53 +02:00
|
|
|
{ ShortcutAction::SendInput, L"" },
|
2020-08-10 18:21:56 +02:00
|
|
|
{ ShortcutAction::SetColorScheme, L"" },
|
2020-06-26 22:38:02 +02:00
|
|
|
{ ShortcutAction::SetTabColor, RS_(L"ResetTabColorCommandKey") },
|
2020-08-20 03:02:10 +02:00
|
|
|
{ ShortcutAction::SplitPane, RS_(L"SplitPaneCommandKey") },
|
|
|
|
{ ShortcutAction::SwitchToTab, RS_(L"SwitchToTabCommandKey") },
|
2020-08-21 17:39:40 +02:00
|
|
|
{ ShortcutAction::TabSearch, RS_(L"TabSearchCommandKey") },
|
2020-08-20 03:02:10 +02:00
|
|
|
{ ShortcutAction::ToggleAlwaysOnTop, RS_(L"ToggleAlwaysOnTopCommandKey") },
|
2020-12-03 17:15:31 +01:00
|
|
|
{ ShortcutAction::ToggleCommandPalette, L"" },
|
2020-08-20 03:02:10 +02:00
|
|
|
{ ShortcutAction::ToggleFocusMode, RS_(L"ToggleFocusModeCommandKey") },
|
|
|
|
{ ShortcutAction::ToggleFullscreen, RS_(L"ToggleFullscreenCommandKey") },
|
|
|
|
{ ShortcutAction::TogglePaneZoom, RS_(L"TogglePaneZoomCommandKey") },
|
2021-08-02 23:04:57 +02:00
|
|
|
{ ShortcutAction::ToggleSplitOrientation, RS_(L"ToggleSplitOrientationCommandKey") },
|
Implement user-specified pixel shaders, redux (#8565)
Co-authored-by: mrange <marten_range@hotmail.com>
I loved the pixel shaders in #7058, but that PR needed a bit of polish
to be ready for ingestion. This PR is almost _exactly_ that PR, with
some small changes.
* It adds a new pre-profile setting `"experimental.pixelShaderPath"`,
which lets the user set a pixel shader to use with the Terminal.
- CHANGED FROM #7058: It does _not_ add any built-in shaders.
- CHANGED FROM #7058: it will _override_
`experimental.retroTerminalEffect`
* It adds a bunch of sample shaders in `samples/shaders`. Included:
- A NOP shader as a base to build from.
- An "invert" shader that inverts the colors, as a simple example
- An "grayscale" shader that converts all colors to grayscale, as a
simple example
- An "raster bars" shader that draws some colored bars on the screen
with a drop shadow, as a more involved example
- The original retro terminal effects, as a more involved example
- It also includes a broken shader, as an example of what heppens
when the shader fails to compile
- CHANGED FROM #7058: It does _not_ add the "retroII" shader we were
all worried about.
* When a shader fails to be found or fails to compile, we'll display an
error dialog to the user with a relevant error message.
- CHANGED FROM #7058: Originally, #7058 would display "error bars"
on the screen. I've removed that, and had the Terminal disable the
shader entirely then.
* Renames the `toggleRetroEffect` action to `toggleShaderEffect`.
(`toggleRetroEffect` is now an alias to `toggleShaderEffect`). This
action will turn the shader OR the retro effects on/off.
`toggleShaderEffect` works the way you'd expect it to, but the mental
math on _how_ is a little weird. The logic is basically:
```
useShader = shaderEffectsEnabled ?
(pixelShaderProvided ?
pixelShader :
(retroEffectEnabled ?
retroEffect : null
)
) :
null
```
and `toggleShaderEffect` toggles `shaderEffectsEnabled`.
* If you've got both a shader and retro enabled, `toggleShaderEffect`
will toggle between the shader on/off.
* If you've got a shader and retro disabled, `toggleShaderEffect` will
toggle between the shader on/off.
References #6191
References #7058
Closes #7013
Closes #3930 "Add setting to retro terminal shader to control blur
radius, color"
Closes #3929 "Add setting to retro terminal shader to enable drawing
scanlines"
- At this point, just roll your own version of the shader.
2020-12-15 21:40:22 +01:00
|
|
|
{ ShortcutAction::ToggleShaderEffects, RS_(L"ToggleShaderEffectsCommandKey") },
|
2020-11-25 23:09:27 +01:00
|
|
|
{ ShortcutAction::MoveTab, L"" }, // Intentionally omitted, must be generated by GenerateName
|
2020-12-05 00:54:59 +01:00
|
|
|
{ ShortcutAction::BreakIntoDebugger, RS_(L"BreakIntoDebuggerCommandKey") },
|
Add `findNext`, `findPrev` actions (#8917)
This PR is a resurrection of #8522. @Hegunumo has apparently deleted
their account, but the contribution was still valuable. I'm just here to
get it across the finish line.
This PR adds new action for navigating to the next & previous search
results. These actions are unbound by default. These actions can be used
from directly within the search dialog also, to immediately navigate the
results.
Furthermore, if you have a search started, and close the search box,
then press this keybinding, _it will still perform the search_. So you
can just hit <kbd>F3</kbd> repeatedly with the dialog closed to keep
searching new results. Neat!
If you dispatch the action on the key down, then dismiss a selection on
a key up, we'll end up immediately destroying the selection when you
release the bound key. That's annoying. It also bothers @carlos-zamora
in #3758. However, I _think_ we can just only dismiss the selection on a
key up. I _think_ that's fine. It _seems_ fine so far. We've got an
entire release cycle to futz with it.
## Validation Steps Performed
I've played with it all day and it seems _crisp_.
Closes #7695
Co-authored-by: Kiminori Kaburagi <yukawa_hidenori@icloud.com>
2021-02-18 20:21:35 +01:00
|
|
|
{ ShortcutAction::FindMatch, L"" }, // Intentionally omitted, must be generated by GenerateName
|
2021-02-08 19:03:55 +01:00
|
|
|
{ ShortcutAction::TogglePaneReadOnly, RS_(L"TogglePaneReadOnlyCommandKey") },
|
2021-02-20 00:51:30 +01:00
|
|
|
{ ShortcutAction::NewWindow, RS_(L"NewWindowCommandKey") },
|
2021-03-30 18:08:03 +02:00
|
|
|
{ ShortcutAction::IdentifyWindow, RS_(L"IdentifyWindowCommandKey") },
|
|
|
|
{ ShortcutAction::IdentifyWindows, RS_(L"IdentifyWindowsCommandKey") },
|
Add support for renaming windows (#9662)
## Summary of the Pull Request
This PR adds support for renaming windows.
![window-renaming-000](https://user-images.githubusercontent.com/18356694/113034344-9a30be00-9157-11eb-9443-975f3c294f56.gif)
![window-renaming-001](https://user-images.githubusercontent.com/18356694/113034452-b5033280-9157-11eb-9e35-e5ac80fef0bc.gif)
It does so through two new actions:
* `renameWindow` takes a `name` parameter, and attempts to set the window's name
to the provided name. This is useful if you always want to hit <kbd>F3</kbd>
and rename a window to "foo" (READ: probably not that useful)
* `openWindowRenamer` is more interesting: it opens a `TeachingTip` with a
`TextBox`. When the user hits Ok, it'll request a rename for the provided
value. This lets the user pick a new name for the window at runtime.
In both cases, if there's already a window with that name, then the monarch will
reject the rename, and pop a `Toast` in the window informing the user that the
rename failed. Nifty!
## References
* Builds on the toasts from #9523
* #5000 - process model megathread
## PR Checklist
* [x] Closes https://github.com/microsoft/terminal/projects/5#card-50771747
* [x] I work here
* [x] Tests addded (and pass with the help of #9660)
* [ ] Requires documentation to be updated
## Detailed Description of the Pull Request / Additional comments
I'm sending this PR while finishing up the tests. I figured I'll have time to sneak them in before I get the necessary reviews.
> PAIN: We can't immediately focus the textbox in the TeachingTip. It's
> not technically focusable until it is opened. However, it doesn't
> provide an even tto tell us when it is opened. That's tracked in
> microsoft/microsoft-ui-xaml#1607. So for now, the user _needs_ to
> click on the text box manually.
> We're also not using a ContentDialog for this, because in Xaml
> Islands a text box in a ContentDialog won't recieve _any_ keypresses.
> Fun!
## Validation Steps Performed
I've been playing with
```json
{ "keys": "f1", "command": "identifyWindow" },
{ "keys": "f2", "command": "identifyWindows" },
{ "keys": "f3", "command": "openWindowRenamer" },
{ "keys": "f4", "command": { "action": "renameWindow", "name": "foo" } },
{ "keys": "f5", "command": { "action": "renameWindow", "name": "bar" } },
```
and they seem to work as expected
2021-04-02 18:00:04 +02:00
|
|
|
{ ShortcutAction::RenameWindow, RS_(L"ResetWindowNameCommandKey") },
|
|
|
|
{ ShortcutAction::OpenWindowRenamer, RS_(L"OpenWindowRenamerCommandKey") },
|
2021-04-29 00:13:28 +02:00
|
|
|
{ ShortcutAction::GlobalSummon, L"" }, // Intentionally omitted, must be generated by GenerateName
|
|
|
|
{ ShortcutAction::QuakeMode, RS_(L"QuakeModeCommandKey") },
|
2021-05-21 23:55:57 +02:00
|
|
|
{ ShortcutAction::FocusPane, L"" }, // Intentionally omitted, must be generated by GenerateName
|
2021-09-02 16:59:42 +02:00
|
|
|
{ ShortcutAction::ClearBuffer, L"" }, // Intentionally omitted, must be generated by GenerateName
|
Add action to run multiple actions. (#11045)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Add a new action that can contain multiple other actions.
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
## References
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #3992
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [x] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
Creates a shortcut action that allows a list of actions to be specified as arguments. Steals a bunch of the serialization code from my other pr. Overall, because I had the serialization code written already, this was remarkably easy.
I can't think of any combined action to be added to the defaults, so I think this is just a thing for the documentation unless someone else has a good example. I know there are lot of times when the recommended workaround is "make an action with commandline wt.exe ..." and this could be a good replacement for that, but that is all personalized.
I didn't add this to the command line parsing, since the command line is already a way to run multiple actions.
<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Created a new command, confirmed that "Move right->down" showed up in the command palette, and that running it did the correct behavior (moving right one pane, then down one pane).
```
{
"command": {
"action": "multipleActions",
"name": "Move right->down",
"actions": [
{"action": "moveFocus", "direction": "right" },
{"action": "moveFocus", "direction": "down" },
]
}
}
```
2021-08-31 21:35:51 +02:00
|
|
|
{ ShortcutAction::MultipleActions, L"" }, // Intentionally omitted, must be generated by GenerateName
|
2020-06-26 22:38:02 +02:00
|
|
|
};
|
|
|
|
}();
|
|
|
|
|
|
|
|
if (_Args)
|
|
|
|
{
|
|
|
|
auto nameFromArgs = _Args.GenerateName();
|
|
|
|
if (!nameFromArgs.empty())
|
|
|
|
{
|
|
|
|
return nameFromArgs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto found = GeneratedActionNames.find(_Action);
|
|
|
|
return found != GeneratedActionNames.end() ? found->second : L"";
|
|
|
|
}
|
Add support for arbitrary args in keybindings (#3391)
## 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 `ShortcutAction`s, 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:
```json
{ "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:
```json
{ "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](https://github.com/microsoft/terminal/blob/master/doc/specs/%231142%20-%20Keybinding%20Arguments.md) for more details.
This is part two of the implementation, part one was #2446
## PR Checklist
* [x] Closes #1142
* [x] I work here
* [x] Tests added/passed
* [x] Schema updated
## 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.
-------------------------------------------------
* this is a start, but there's a weird linker bug if I take the SetKeybinding(ShortcutAction, KeyChord) implementation out, which I don't totally understand
* a good old-fashioned clean will fix that right up
* all these things work
* hey this actually _functionally_ works
* Mostly cleanup and completion of implementation
* Hey I bet we could just make NewTab the handler for NewTabWithProfile
* Start writing tests for Keybinding args
* Add tests
* Revert a bad sln change, and clean out dead code
* Change to include "command" as a single object
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"] },
```
* schemas are hard yo
* Fix the build?
* wonder why my -Wall settings are different than CI...
* this makes me hate things
* Comments from PR
* Add a `Direction::None`
* LOAD BEARING
* add some GH ids to TODOs
* add a comment
* PR nits from carlos
2019-11-14 23:23:40 +01:00
|
|
|
}
|