Add keyboard interface
See original GitHub issueProposed approach
Everything is done in reverse order of Cursorless spoken forms, and you always move the cursor. So, for example, “chuck funk air” would be executed by running the following in sequence:
- A command that selects “air”
- A command that selects the current function
- A command that deletes the current selection
So we’d basically implement
- Commands to select decorated marks
- Commands to select containing scope type
- Commands to execute action on selection
We’d want to make it so that the delete action knows it’s deleting a function, by having Cursorless keep track of this somehow, probably by storing that information when they select containing scope type. Alternately we could try to infer it from the selection
In terms of keymaps, we could do something like the following. Here’s an example where we have our own mode, so we can use normal keys, but would be easy to replace each of m
, s
, and a
below with control sequences:
- Define
m<color><char>
to select char with colored hat - Define
s<scopeType>
to select a scope type, - Define
a<action>
to execute an action
So for example, to do “chuck state blue air”
, it would be:
mba
to select “blue air”ss
to select containing statementad
to delete (alternately could remap<delete>
when you’re in this mode)
So all told it would be mbassad
. Note that this is actually more verbose than the original proposal below, which would be just dsba
🤷. We could probably shorten a bit by removing the s
and a
prefix from common actions and scope types, respectively, so it would be mbasd
. I guess we could even remove the m
and put the colors at the top level as well, so it would be basd
. There would be a lot of things competing for that top level, though, at that point, but could work. We could just do some juggling to see what makes sense
We could implement ranges by having an action that selects past a decorated mark. Then “chuck funk air past bat” would be
- Select “air”
- Select past “bat”
- Select function
- Delete
List targets (eg "air and “bat”) could be implemented with a command that adds a new selection to the current list of selections
What about “swap”? I guess we could use bookmarking, so you basically mark a target as an argument for the next action
To get the benefits of properly “cursorless” operation, ie where you don’t need to move your cursor, we could have a keyboard version of #190
Alternately, instead of moving cursor, the modifiers and marks could operate on a highlight that indicates the current target. Then for multiple target actions (eg “swap”) there could be a command that switches to creating the next target
Also, given the large number of scope types and actions, we might want a command that pops up a quick input to search for action or scope type rather than memorising a ton of keyboard shortcuts
Proposed top-level keymap
a
: extra actionsb
: [color] bluec
: [scopeType] block (short for “chunk”)d
: [color] defaulte
:f
: [scopeType] functiong
: [color] greenh
:i
:j
:k
:l
: [scopeType] linem
: [action] moven
:o
:p
: [color] pinkq
:r
: [color] reds
: shapet
: extra scope typesu
: [action] bring (short for use)v
:w
:x
: mark current selection as other argument for next multi-arg action, such as “bring”y
: [color] yellowz
:<delete>
: [action] delete
Note that for people that use more shapes than colors, they’d prob want shapes at top level rather than colors
Alternative approach
Capturing ideas from #417:
Without modifier keys
tda
=> “take air” (ie “take default air”)tga
=> “take green air”- ?
tfda
=> “take fox air” (ie “take fox default air”)- or
tsfda
=> “take fox air” (ie “take shape fox default air”)
- or
- ?
tfga
=> “take fox green air” tfda
=> “take funk air”tft
=> “take funk” (ie “take funk this”)- ?
tf<pause>
=> “take funk” tldadbl
-> “take air and bat”- Note that the
l
is used both to start and end a list
- Note that the
trdadb
-> “take air past bat”- Note that the range ends on its own because you’ve defined the start and end
tlrdadbdcl
-> “take air past bat and cap”
To do / think about
- Actions with multiple targets. I think for these you can just treat it kinda like a range target, where you just wait for another target after they’ve specified the first one, and then execute command after they’ve specified both
- Figure out how “character” context works. I don’t think we need an actual map literal for that one, because it woul basically be the identity mapping 😊. But it should prob be a proper context in the sense of the keyboard mapping / vscode thing
- For
toggleList
, note that in case you’re ending a list, you don’t really necessarily transition to atarget
context, because you might have just ended the command (unless it had multiple targets). I don’t think this one is a big deal; implementation will prob just ignore thenextContext
in this case - What to do about multi-char sequences for eg scope types? We won’t be able to have every scope type be one char. So we could either define them as two-char elements in the top-level target map, or have it so that the prefix char for them puts us into a new context where we’re specifying a scope type
Advantage of having context to specify scope type is that then we can use it for “every”, as well as next-gen scope modifiers, eg “first funk”, “last funk”, etc.
- Maybe we should use
l
for “line” instead of “list”. Then need to figure out different key for “list”.
Action context
- Every letter is an action =>
targetContext
Target context
a
:b
:c
:d
: default color =>characterContext
e
:f
:g
: green =>characterContext
h
:i
:j
:k
:l
:m
:n
:o
:p
:q
:r
: red =>characterContext
s
:t
:u
:v
:w
:x
:y
:z
:
With modifier keys
ta
=> “take air”tGa
=> “take green air”
Issue Analytics
- State:
- Created a year ago
- Comments:11 (6 by maintainers)
Top GitHub Comments
Just gave it abother read-through. Yeah I don’t think there’s much here that’s not captured in #989
For posterity’s sake, see the keyboard docs to see where this landed