8.9 KiB
author | created on | last updated | issue id |
---|---|---|---|
Mike Griese @zadjii-msft | 2020-07-13 | 2020-07-22 | 6899 |
Action IDs
Abstract
This document is intended to serve as an addition to the Command Palette Spec, as well as the New Tab Menu Customization Spec.
As we come to rely more on actions being a mechanism by which the user defines "do something in the Terminal", we'll want to make it even easier for users to re-use the actions that they've already defined, as to reduce duplicated json as much as possible. This spec proposes a mechanism by which actions could be uniquely identifiable, so that the user could refer to bindings in other contexts without needing to replicate an entire json blob.
Solution Design
This spec was largely inspired by the following diagram from @DHowett:
The goal is to introduce an id
parameter by which actions could be uniquely
referred to. If we'd ever like to use an action outside the list of actions
, we
can simply refer to the action's ID, allowing the user to only define the action
once.
We'll start by renaming bindings
to actions
. bindings
was suggested as a
rename for keybindings
in #6532, as a way to make the name more generic.
Discussion with the team lead to the understanding that the name actions
would
be even better, as a way of making the meaning of the "list of actions" more
obvious.
When we're parsing actions
, we'll make three passes:
- The first pass will scan the list for objects with an
id
property. We'll attempt to parse those entries intoActionAndArgs
which we'll store in the globalid->ActionAndArgs
map. If any entry doesn't have anid
set, we'll skip it in this phase. If an entry doesn't have acommand
set, we'll ignore it in this pass. - The second pass will scan for keybindings. Any entries with
keys
set will create aKeyChord->ActionAndArgs
entry in the keybindings map. If the entry has anid
set, then we'll simply re-use the action we've already parsed for theid
, from the action map. If there isn't anid
, then we'll parse the action manually at this time. Entries without akeys
set will be ignored in this pass. - The final pass will be to generate commands. Similar to the keybindings
pass, we'll attempt to lookup actions for entries with an
id
set. If there isn't anid
, then we'll parse the action manually at this time. We'll then get the name for the entry, either from thename
property if it's set, or the action'sGenerateName
method.
For a visual representation, let's assume the user has the following in their
actions
:
We'll first parse the actions
to generate the mapping of id
->Actions
:
Then, we'll parse the actions
to generate the mapping of keys to actions, with
some actions already being defined in the map of id
->Actions
:
When layering actions
, if a later settings file contains an action with the
same id
, it will replace the current value. In this way, users can redefine
actions, or remove default ones (with something like { "id": "Terminal.OpenTab", "command":null }
We'd maintain a large list of default actions, each with unique id
s set. These
are all given id
's with a Terminal.
prefix, to easily identify them as
built-in, default actions. Not all of these actions will be given keys, but they
will all be given id
s.
👉 NOTE: The IDs for the default actions will need to be manually created, not autogenerated. These
id
s are not strings displayed in the user interface, so localization is not a concern.
As we add additional menus to the Terminal, like the customization for the new
tab dropdown, or the tab context menu, or the TermControl
context menu, they
could all refer to these actions by id
, rather than duplicating the same json.
Existing Scenarios
Keybindings will still be stored as a keys->Action
mapping, so the user will
still be able to override default keybindings exactly the same as before.
Similarly, commands in the Command Palette will continue using their existing
name->Action
mapping they're currently using. For a binding like
{ "keys": "ctrl+alt+x", "id": "Terminal.OpenDefaultSettings" },
- We'll bind whatever action is defined as
Terminal.OpenDefaultSettings
to ctrl+alt+x. - We'll use whatever action is defined as
Terminal.OpenDefaultSettings
to generate a name for the command palette.
Future Context Menus
In New Tab Menu Customization Spec, we discuss allowing the user to bind actions to the new tab menu. In that spec, they can do so with something like the following:
{
"newTabMenu": [
{ "type":"action", "command": { "action": "adjustFontSize", "delta": 1 }, }
{ "type":"action", "command": { "action": "adjustFontSize", "delta": -1 }, }
{ "type":"action", "command": "resetFontSize", }
{ "type":"profile", "profile": "cmd" },
{ "type":"profile", "profile": "Windows PowerShell" },
{ "type":"separator" },
{
"type":"folder",
"name": "Settings...",
"icon": "C:\\path\\to\\icon.png",
"entries":[
{ "type":"action", "command": "openSettings" },
{ "type":"action", "command": { "action": "openSettings", "target": "defaultsFile" } },
]
}
]
}
In this example, the user has also exposed the "Increase font size", "Decrease font size", and "Reset font size" actions, as well as the settings files in a submenu. With this proposal, the above could instead be re-written as:
{
"newTabMenu": [
{ "type":"action", "id": "Terminal.IncreaseFontSize" },
{ "type":"action", "id": "Terminal.DecreaseFontSize" },
{ "type":"action", "id": "Terminal.ResetFontSize" },
{ "type":"profile", "profile": "cmd" },
{ "type":"profile", "profile": "Windows PowerShell" },
{ "type":"separator" },
{
"type":"folder",
"name": "Settings...",
"icon": "C:\\path\\to\\icon.png",
"entries":[
{ "type":"action", "id": "Terminal.OpenDefaultSettings" },
{ "type":"action", "id": "Terminal.OpenSettings" },
]
}
]
}
In this example, the actions are looked up from the global map using the id
provided, enabling the user to re-use their existing definitions. If the user
re-defined the Terminal.IncreaseFontSize
action to mean something else, then
the action in the new tab menu will also be automatically updated.
Furthermore, when additional menus are added (such as the tab context menu, or
the TermControl
context menu), these could also leverage a similar syntax to
the above to allow re-use of the id
parameter.
Discussion with the team also suggested that users shouldn't be able to define
actions in these menus at all. The actions should exclusively be defined in
actions
, and other menus should only be able to refer to these actions by
id
.
UI/UX Design
There's not a whole lot of UI for this feature specifically. This is largely behind-the-scenes refactoring of how actions can be defined.
Capabilities
Accessibility
(not applicable)
Security
(no change expected)
Reliability
(no change expected)
Compatibility
(no change expected)
Performance, Power, and Efficiency
(no change expected)
Potential Issues
This won't necessarily play well with iterable commands in the Command Palette, but that's okay. For iterable commands, users will still need to define the actions manually.
Future considerations
- See the following issues for other places where this might be useful: