diff --git a/packages/cursorless-vscode-e2e/src/suite/keyboard/basic.vscode.test.ts b/packages/cursorless-vscode-e2e/src/suite/keyboard/basic.vscode.test.ts index c216316019..b6a50dbc91 100644 --- a/packages/cursorless-vscode-e2e/src/suite/keyboard/basic.vscode.test.ts +++ b/packages/cursorless-vscode-e2e/src/suite/keyboard/basic.vscode.test.ts @@ -62,6 +62,13 @@ const testCases: TestCase[] = [ keySequence: ["dw", "wj", "c"], finalContent: "a + + b", }, + { + name: "inside", + initialContent: "(aaa)", + // change inside air + keySequence: ["da", "mi", "c"], + finalContent: "()", + }, { name: "wrap", initialContent: "a", diff --git a/packages/cursorless-vscode/src/keyboard/TokenTypes.ts b/packages/cursorless-vscode/src/keyboard/TokenTypes.ts index 7355e34132..43ab7ce428 100644 --- a/packages/cursorless-vscode/src/keyboard/TokenTypes.ts +++ b/packages/cursorless-vscode/src/keyboard/TokenTypes.ts @@ -20,7 +20,7 @@ export interface SectionTypes { vscodeCommand: ModalVscodeCommandDescriptor; modifier: ModifierType; } -type ModifierType = "nextPrev" | "every"; +type ModifierType = "nextPrev" | "every" | "interiorOnly" | "excludeInterior"; export type MiscValue = | "combineColorAndShape" | "makeRange" @@ -65,6 +65,7 @@ export interface TokenTypeValueMap { // modifier config section nextPrev: "nextPrev"; every: "every"; + simpleModifier: "interiorOnly" | "excludeInterior"; digit: number; } diff --git a/packages/cursorless-vscode/src/keyboard/getTokenTypeKeyMaps.ts b/packages/cursorless-vscode/src/keyboard/getTokenTypeKeyMaps.ts index 1edfc765d9..b333f1daab 100644 --- a/packages/cursorless-vscode/src/keyboard/getTokenTypeKeyMaps.ts +++ b/packages/cursorless-vscode/src/keyboard/getTokenTypeKeyMaps.ts @@ -68,6 +68,11 @@ export function getTokenTypeKeyMaps( // modifier config section every: config.getTokenKeyMap("every", "modifier", only("every")), nextPrev: config.getTokenKeyMap("nextPrev", "modifier", only("nextPrev")), + simpleModifier: config.getTokenKeyMap( + "simpleModifier", + "modifier", + only("interiorOnly", "excludeInterior"), + ), digit: Object.fromEntries( range(10).map((value) => [ diff --git a/packages/cursorless-vscode/src/keyboard/grammar/generated/grammar.ts b/packages/cursorless-vscode/src/keyboard/grammar/generated/grammar.ts index 7c23f4f672..0add1c5b76 100644 --- a/packages/cursorless-vscode/src/keyboard/grammar/generated/grammar.ts +++ b/packages/cursorless-vscode/src/keyboard/grammar/generated/grammar.ts @@ -9,6 +9,7 @@ declare var simpleAction: any; declare var wrap: any; declare var pairedDelimiter: any; declare var vscodeCommand: any; +declare var simpleModifier: any; declare var every: any; declare var nextPrev: any; declare var simpleScopeTypeType: any; @@ -69,6 +70,7 @@ const grammar: Grammar = { command("performWrapActionOnTarget", ["actionDescriptor", "delimiter"]) }, {"name": "main", "symbols": [(keyboardLexer.has("vscodeCommand") ? {type: "vscodeCommand"} : vscodeCommand)], "postprocess": command("vscodeCommand", ["command"])}, + {"name": "modifier", "symbols": [(keyboardLexer.has("simpleModifier") ? {type: "simpleModifier"} : simpleModifier)], "postprocess": capture({ type: $0 })}, {"name": "modifier", "symbols": ["scopeType"], "postprocess": capture({ type: "containingScope", scopeType: $0 })}, {"name": "modifier", "symbols": [(keyboardLexer.has("every") ? {type: "every"} : every), "scopeType"], "postprocess": capture({ type: "everyScope", scopeType: $1 })}, {"name": "modifier$ebnf$1", "symbols": ["offset"], "postprocess": id}, diff --git a/packages/cursorless-vscode/src/keyboard/grammar/grammar.ne b/packages/cursorless-vscode/src/keyboard/grammar/grammar.ne index f5f0d3fba0..ae1aa5abd2 100644 --- a/packages/cursorless-vscode/src/keyboard/grammar/grammar.ne +++ b/packages/cursorless-vscode/src/keyboard/grammar/grammar.ne @@ -47,6 +47,9 @@ main -> %vscodeCommand {% command("vscodeCommand", ["command"]) %} # --------------------------- Modifiers --------------------------- +# "inside", "bounds" +modifier -> %simpleModifier {% capture({ type: $0 }) %} + # "funk" modifier -> scopeType {% capture({ type: "containingScope", scopeType: $0 }) %} diff --git a/packages/cursorless-vscode/src/keyboard/grammar/grammar.test.ts b/packages/cursorless-vscode/src/keyboard/grammar/grammar.test.ts index 8a9a0729b1..005c7273a4 100644 --- a/packages/cursorless-vscode/src/keyboard/grammar/grammar.test.ts +++ b/packages/cursorless-vscode/src/keyboard/grammar/grammar.test.ts @@ -128,6 +128,17 @@ const testCases: TestCase[] = [ type: "modifyTarget", }, }, + { + tokens: [{ type: "simpleModifier", value: "excludeInterior" }], + expected: { + arg: { + modifier: { + type: "excludeInterior", + }, + }, + type: "modifyTarget", + }, + }, { tokens: [ { diff --git a/packages/cursorless-vscode/src/keyboard/keyboard-config.fixture.json b/packages/cursorless-vscode/src/keyboard/keyboard-config.fixture.json index 2466a6f4b5..76ba57a76e 100644 --- a/packages/cursorless-vscode/src/keyboard/keyboard-config.fixture.json +++ b/packages/cursorless-vscode/src/keyboard/keyboard-config.fixture.json @@ -67,7 +67,9 @@ }, "cursorless.experimental.keyboard.modal.keybindings.modifier": { "n": "nextPrev", - "*": "every" + "*": "every", + "mi": "interiorOnly", + "mb": "excludeInterior" }, "cursorless.experimental.keyboard.modal.keybindings.vscodeCommand": { "va": "editor.action.addCommentLine",