Skip to content

Add keyboard interface #710

@pokey

Description

@pokey

Proposed 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:

  1. A command that selects "air"
  2. A command that selects the current function
  3. 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:

  1. mba to select "blue air"
  2. ss to select containing statement
  3. ad 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

  1. Select "air"
  2. Select past "bat"
  3. Select function
  4. 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 actions
  • b: [color] blue
  • c: [scopeType] block (short for "chunk")
  • d: [color] default
  • e:
  • f: [scopeType] function
  • g: [color] green
  • h:
  • i:
  • j:
  • k:
  • l: [scopeType] line
  • m: [action] move
  • n:
  • o:
  • p: [color] pink
  • q:
  • r: [color] red
  • s: shape
  • t: extra scope types
  • u: [action] bring (short for use)
  • v:
  • w:
  • x: mark current selection as other argument for next multi-arg action, such as "bring"
  • y: [color] yellow
  • z:
  • <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")
  • ? 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
  • 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 a target 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 the nextContext 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"

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions