diff --git a/package.json b/package.json index 1cbaac80..c846e4c0 100644 --- a/package.json +++ b/package.json @@ -1884,6 +1884,11 @@ "title": "Leap or select", "category": "Dance" }, + { + "command": "dance.selections.select.orSneak", + "title": "Leap or select", + "category": "Dance" + }, { "command": "dance.selections.showIndices", "title": "Show selection indices", @@ -1909,6 +1914,11 @@ "title": "Leap or select backward", "category": "Dance" }, + { + "command": "dance.selections.splitLines.orSneak.backward", + "title": "Sneak or select backward", + "category": "Dance" + }, { "command": "dance.selections.toggleIndices", "title": "Toggle selection indices", @@ -2710,6 +2720,10 @@ "command": "dance.selections.select.orLeap", "when": "dance.mode == 'normal'" }, + { + "command": "dance.selections.select.orSneak", + "when": "dance.mode == 'normal'" + }, { "command": "dance.selections.showIndices", "when": "dance.mode == 'normal'" @@ -2730,6 +2744,10 @@ "command": "dance.selections.splitLines.orLeap.backward", "when": "dance.mode == 'normal'" }, + { + "command": "dance.selections.splitLines.orSneak.backward", + "when": "dance.mode == 'normal'" + }, { "command": "dance.selections.toggleIndices", "when": "dance.mode == 'normal'" diff --git a/src/api/data/commands.yaml b/src/api/data/commands.yaml index 372961b6..cdfe76dd 100644 --- a/src/api/data/commands.yaml +++ b/src/api/data/commands.yaml @@ -2477,9 +2477,10 @@ selections.select: #### Variants - | Title | Identifier | Keybinding | Command | - | -------------- | --------------- | --------------------- | ------------------------------------------------------------------------------------------------- | - | Leap or select | `select.orLeap` | `s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { ... }]], otherwise: [[".selections.select", { ... }]] }]` | + | Title | Identifier | Keybinding | Command | + | --------------- | ---------------- | --------------------- | ------------------------------------------------------------------------------------------------------------ | + | Leap or select | `select.orLeap` | `s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { ... }]], otherwise: [[".selections.select", { ... }]] }]` | + | Sneak or select | `select.orSneak` | | `[".ifEmpty", { then: [[".seek", { inputLength: 2, ... }]], otherwise: [[".selections.select", { ... }]] }]` | selections.select.orLeap: title: @@ -2492,6 +2493,16 @@ selections.select.orLeap: qwerty: |- `s` (kakoune: normal) +selections.select.orSneak: + title: + en: Sneak or select + + commands: |- + [".ifEmpty", { then: [[".seek", { inputLength: 2, $exclude: [] }]], otherwise: [[".selections.select", { $exclude: [] }]] }] + + keys: + qwerty: "" + selections.showIndices: title: en: Show selection indices @@ -2530,9 +2541,10 @@ selections.splitLines: #### Variants - | Title | Identifier | Keybinding | Command | - | ----------------------- | ---------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------- | - | Leap or select backward | `splitLines.orLeap.backward` | `a-s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { direction: -1, ... }]], otherwise: [[".selections.splitLines", { ... }]] }]` | + | Title | Identifier | Keybinding | Command | + | ------------------------ | ----------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- | + | Leap or select backward | `splitLines.orLeap.backward` | `a-s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { direction: -1, ... }]], otherwise: [[".selections.splitLines", { ... }]] }]` | + | Sneak or select backward | `splitLines.orSneak.backward` | | `[".ifEmpty", { then: [[".seek", { inputLength: 2, direction: -1, ... }]], otherwise: [[".selections.splitLines", { ... }]] }]` | selections.splitLines.orLeap.backward: title: @@ -2545,6 +2557,16 @@ selections.splitLines.orLeap.backward: qwerty: |- `a-s` (kakoune: normal) +selections.splitLines.orSneak.backward: + title: + en: Sneak or select backward + + commands: |- + [".ifEmpty", { then: [[".seek", { inputLength: 2, direction: -1, $exclude: [] }]], otherwise: [[".selections.splitLines", { $exclude: [] }]] }] + + keys: + qwerty: "" + selections.toggleIndices: title: en: Toggle selection indices diff --git a/src/api/menu.ts b/src/api/menu.ts index 79a594d2..5bcc0df0 100644 --- a/src/api/menu.ts +++ b/src/api/menu.ts @@ -153,7 +153,7 @@ export async function showMenuAfterDelay( timeout = setTimeout(() => cancellationTokenSource.cancel(), delayMs); try { - const key = await keypress(keypressContext); + const key = await keypress({}, keypressContext); clearTimeout(timeout); diff --git a/src/api/prompt.ts b/src/api/prompt.ts index 8ed14390..33d42785 100644 --- a/src/api/prompt.ts +++ b/src/api/prompt.ts @@ -466,9 +466,13 @@ export function notifyPromptActionRequested(action: "next" | "previous" | "clear } /** - * Awaits a keypress from the user and returns the entered key. + * Awaits for one or more keypresses from the user and returns the entered keys. + * + * @param keyCount Determines the number of keypresses to wait for; defaults to 1. */ -export async function keypress(context = Context.current): Promise { +export async function keypress(params: Readonly<{ keyCount?: number }>, + context = Context.current): Promise { + const keyCount = params.keyCount || 1; if (context.cancellationToken.isCancellationRequested) { return Promise.reject(new CancellationError(CancellationError.Reason.CancellationToken)); } @@ -479,12 +483,15 @@ export async function keypress(context = Context.current): Promise { return await new Promise((resolve, reject) => { try { + let keys = ""; const subscriptions = [ vscode.commands.registerCommand("type", ({ text }: { text: string; }) => { - if (subscriptions.length > 0) { + keys += text; + if (subscriptions.length > 0 && keys.length >= keyCount) { subscriptions.splice(0).forEach((s) => s.dispose()); - context.switchToMode(previousMode).then(() => resolve(text)); + context.switchToMode(previousMode) + .then(() => resolve(keys.slice(0, keyCount))); } }), @@ -511,13 +518,13 @@ export async function keypress(context = Context.current): Promise { * Awaits a keypress describing a register and returns the specified register. */ export async function keypressForRegister(context = Context.current) { - const firstKey = await keypress(context); + const firstKey = await keypress({}, context); if (firstKey !== " ") { return context.extension.registers.get(firstKey); } - const secondKey = await keypress(context); + const secondKey = await keypress({}, context); return context.extension.registers.forDocument(context.document).get(secondKey); } diff --git a/src/commands/README.md b/src/commands/README.md index 3d760e56..5de1eac0 100644 --- a/src/commands/README.md +++ b/src/commands/README.md @@ -104,42 +104,42 @@ selections are empty seek.leapLeap forward seek.objectSelect object seek.seekSelect to character (excluded)T (editorTextFocus && dance.mode == 'normal') -seek.askObjectSelect whole objectAlt+A (editorTextFocus && dance.mode == 'normal')Alt+A (editorTextFocus && dance.mode == 'insert') -seek.askObject.endSelect to whole object end] (editorTextFocus && dance.mode == 'normal') -seek.askObject.end.extendExtend to whole object endShift+] (editorTextFocus && dance.mode == 'normal') -seek.askObject.innerSelect inner objectAlt+I (editorTextFocus && dance.mode == 'normal')Alt+I (editorTextFocus && dance.mode == 'insert') -seek.askObject.inner.endSelect to inner object endAlt+] (editorTextFocus && dance.mode == 'normal') -seek.askObject.inner.end.extendExtend to inner object endShift+Alt+] (editorTextFocus && dance.mode == 'normal') -seek.askObject.inner.startSelect to inner object startAlt+[ (editorTextFocus && dance.mode == 'normal') -seek.askObject.inner.start.extendExtend to inner object startShift+Alt+[ (editorTextFocus && dance.mode == 'normal') -seek.askObject.startSelect to whole object start[ (editorTextFocus && dance.mode == 'normal') -seek.askObject.start.extendExtend to whole object startShift+[ (editorTextFocus && dance.mode == 'normal') +seek.askObjectSelect whole objectAlt+A (editorTextFocus && dance.mode == 'normal')Alt+A (editorTextFocus && dance.mode == 'insert') +seek.askObject.endSelect to whole object end] (editorTextFocus && dance.mode == 'normal') +seek.askObject.end.extendExtend to whole object endShift+] (editorTextFocus && dance.mode == 'normal') +seek.askObject.innerSelect inner objectAlt+I (editorTextFocus && dance.mode == 'normal')Alt+I (editorTextFocus && dance.mode == 'insert') +seek.askObject.inner.endSelect to inner object endAlt+] (editorTextFocus && dance.mode == 'normal') +seek.askObject.inner.end.extendExtend to inner object endShift+Alt+] (editorTextFocus && dance.mode == 'normal') +seek.askObject.inner.startSelect to inner object startAlt+[ (editorTextFocus && dance.mode == 'normal') +seek.askObject.inner.start.extendExtend to inner object startShift+Alt+[ (editorTextFocus && dance.mode == 'normal') +seek.askObject.startSelect to whole object start[ (editorTextFocus && dance.mode == 'normal') +seek.askObject.start.extendExtend to whole object startShift+[ (editorTextFocus && dance.mode == 'normal') seek.backwardSelect to character (excluded, backward)Alt+T (editorTextFocus && dance.mode == 'normal') -seek.enclosing.backwardSelect to previous enclosing characterAlt+M (editorTextFocus && dance.mode == 'normal') -seek.enclosing.extendExtend to next enclosing characterShift+M (editorTextFocus && dance.mode == 'normal') -seek.enclosing.extend.backwardExtend to previous enclosing characterShift+Alt+M (editorTextFocus && dance.mode == 'normal') +seek.enclosing.backwardSelect to previous enclosing characterAlt+M (editorTextFocus && dance.mode == 'normal') +seek.enclosing.extendExtend to next enclosing characterShift+M (editorTextFocus && dance.mode == 'normal') +seek.enclosing.extend.backwardExtend to previous enclosing characterShift+Alt+M (editorTextFocus && dance.mode == 'normal') seek.extendExtend to character (excluded)Shift+T (editorTextFocus && dance.mode == 'normal')T (editorTextFocus && dance.mode == 'select') seek.extend.backwardExtend to character (excluded, backward)Shift+Alt+T (editorTextFocus && dance.mode == 'normal')Shift+T (editorTextFocus && dance.mode == 'select') seek.includedSelect to character (included)F (editorTextFocus && dance.mode == 'normal') seek.included.backwardSelect to character (included, backward)Alt+F (editorTextFocus && dance.mode == 'normal') seek.included.extendExtend to character (included)Shift+F (editorTextFocus && dance.mode == 'normal')F (editorTextFocus && dance.mode == 'select') seek.included.extend.backwardExtend to character (included, backward)Shift+Alt+F (editorTextFocus && dance.mode == 'normal')Shift+F (editorTextFocus && dance.mode == 'select') -seek.leap.backwardLeap backward -seek.syntax.child.experimentalSelect child syntax object -seek.syntax.next.experimentalSelect next syntax object -seek.syntax.parent.experimentalSelect parent syntax object -seek.syntax.previous.experimentalSelect previous syntax object -seek.word.backwardSelect to previous word startB (editorTextFocus && dance.mode == 'normal') -seek.word.extendExtend to next word startShift+W (editorTextFocus && dance.mode == 'normal')W (editorTextFocus && dance.mode == 'select') -seek.word.extend.backwardExtend to previous word startShift+B (editorTextFocus && dance.mode == 'normal')B (editorTextFocus && dance.mode == 'select') -seek.word.wsSelect to next non-whitespace word startAlt+W (editorTextFocus && dance.mode == 'normal') -seek.word.ws.backwardSelect to previous non-whitespace word startAlt+B (editorTextFocus && dance.mode == 'normal') -seek.word.ws.extendExtend to next non-whitespace word startShift+Alt+W (editorTextFocus && dance.mode == 'normal')Shift+W (editorTextFocus && dance.mode == 'select') -seek.word.ws.extend.backwardExtend to previous non-whitespace word startShift+Alt+B (editorTextFocus && dance.mode == 'normal')Shift+B (editorTextFocus && dance.mode == 'select') -seek.wordEndSelect to next word endE (editorTextFocus && dance.mode == 'normal') -seek.wordEnd.extendExtend to next word endShift+E (editorTextFocus && dance.mode == 'normal')E (editorTextFocus && dance.mode == 'select') -seek.wordEnd.wsSelect to next non-whitespace word endAlt+E (editorTextFocus && dance.mode == 'normal') -seek.wordEnd.ws.extendExtend to next non-whitespace word endShift+Alt+E (editorTextFocus && dance.mode == 'normal')Shift+E (editorTextFocus && dance.mode == 'select') +seek.leap.backwardLeap backward +seek.syntax.child.experimentalSelect child syntax object +seek.syntax.next.experimentalSelect next syntax object +seek.syntax.parent.experimentalSelect parent syntax object +seek.syntax.previous.experimentalSelect previous syntax object +seek.word.backwardSelect to previous word startB (editorTextFocus && dance.mode == 'normal') +seek.word.extendExtend to next word startShift+W (editorTextFocus && dance.mode == 'normal')W (editorTextFocus && dance.mode == 'select') +seek.word.extend.backwardExtend to previous word startShift+B (editorTextFocus && dance.mode == 'normal')B (editorTextFocus && dance.mode == 'select') +seek.word.wsSelect to next non-whitespace word startAlt+W (editorTextFocus && dance.mode == 'normal') +seek.word.ws.backwardSelect to previous non-whitespace word startAlt+B (editorTextFocus && dance.mode == 'normal') +seek.word.ws.extendExtend to next non-whitespace word startShift+Alt+W (editorTextFocus && dance.mode == 'normal')Shift+W (editorTextFocus && dance.mode == 'select') +seek.word.ws.extend.backwardExtend to previous non-whitespace word startShift+Alt+B (editorTextFocus && dance.mode == 'normal')Shift+B (editorTextFocus && dance.mode == 'select') +seek.wordEndSelect to next word endE (editorTextFocus && dance.mode == 'normal') +seek.wordEnd.extendExtend to next word endShift+E (editorTextFocus && dance.mode == 'normal')E (editorTextFocus && dance.mode == 'select') +seek.wordEnd.wsSelect to next non-whitespace word endAlt+E (editorTextFocus && dance.mode == 'normal') +seek.wordEnd.ws.extendExtend to next non-whitespace word endShift+Alt+E (editorTextFocus && dance.mode == 'normal')Shift+E (editorTextFocus && dance.mode == 'select') seek.syntax.experimentalSelect syntax object seek.wordSelect to next word startW (editorTextFocus && dance.mode == 'normal') selectselect.bufferSelect whole bufferShift+5 (editorTextFocus && dance.mode == 'normal') @@ -183,7 +183,7 @@ selections are empty select.up.jumpJump upK (editorTextFocus && dance.mode == 'normal')Up (editorTextFocus && dance.mode == 'normal') select.toSelect to select.verticallySelect vertically -selectionsselections.changeDirectionChange direction of selectionsAlt+; (editorTextFocus && dance.mode == 'normal') +selectionsselections.changeDirectionChange direction of selectionsAlt+; (editorTextFocus && dance.mode == 'normal') selections.changeOrderReverse selections selections.copyCopy selections belowShift+C (editorTextFocus && dance.mode == 'normal') selections.expandToLinesExpand to linesX (editorTextFocus && dance.mode == 'normal') @@ -199,21 +199,23 @@ selections are empty selections.selectSelect within selections selections.clear.mainClear main selectionsAlt+, (editorTextFocus && dance.mode == 'normal') selections.clear.secondaryClear secondary selections, (editorTextFocus && dance.mode == 'normal') -selections.copy.aboveCopy selections aboveShift+Alt+C (editorTextFocus && dance.mode == 'normal') -selections.faceBackwardBackward selections -selections.faceForwardForward selectionsShift+Alt+; (editorTextFocus && dance.mode == 'normal') +selections.copy.aboveCopy selections aboveShift+Alt+C (editorTextFocus && dance.mode == 'normal') +selections.faceBackwardBackward selections +selections.faceForwardForward selectionsShift+Alt+; (editorTextFocus && dance.mode == 'normal') selections.filter.regexpKeep matching selectionsAlt+K (editorTextFocus && dance.mode == 'normal') selections.filter.regexp.inverseClear matching selectionsShift+Alt+K (editorTextFocus && dance.mode == 'normal') -selections.hideIndicesHide selection indices -selections.orderAscendingOrder selections ascending -selections.orderDescendingOrder selections descending +selections.hideIndicesHide selection indices +selections.orderAscendingOrder selections ascending +selections.orderDescendingOrder selections descending selections.pipe.appendPipe and appendShift+1 (editorTextFocus && dance.mode == 'normal') selections.pipe.prependPipe and prependShift+Alt+1 (editorTextFocus && dance.mode == 'normal') selections.pipe.replacePipe and replaceShift+\ (editorTextFocus && dance.mode == 'normal') -selections.reduce.edgesReduce selections to their endsShift+Alt+S (editorTextFocus && dance.mode == 'normal') +selections.reduce.edgesReduce selections to their endsShift+Alt+S (editorTextFocus && dance.mode == 'normal') selections.select.orLeapLeap or selectS (editorTextFocus && dance.mode == 'normal') -selections.showIndicesShow selection indices -selections.splitLines.orLeap.backwardLeap or select backwardAlt+S (editorTextFocus && dance.mode == 'normal') +selections.select.orSneakLeap or select +selections.showIndicesShow selection indices +selections.splitLines.orLeap.backwardLeap or select backwardAlt+S (editorTextFocus && dance.mode == 'normal') +selections.splitLines.orSneak.backwardSneak or select backward selections.sortSort selections selections.splitSplit selectionsShift+S (editorTextFocus && dance.mode == 'normal') selections.splitLinesSplit selections at line boundaries @@ -1006,7 +1008,7 @@ Update selections based on the text surrounding them. -### [`seek.seek`](./seek.ts#L16-L41) +### [`seek.seek`](./seek.ts#L16-L42) Select to character (excluded). @@ -1026,13 +1028,14 @@ Select to character (excluded). This command: - may be repeated with a given number of repetitions. - takes an argument `include` of type `boolean`. +- takes an argument `inputLength` of type `number`. - takes an input `input` of type `string`. Default keybinding: `t` (kakoune: normal) -### [`seek.enclosing`](./seek.ts#L81-L101) +### [`seek.enclosing`](./seek.ts#L82-L102) Select to next enclosing character. @@ -1053,7 +1056,7 @@ Default keybinding: `m` (kakoune: normal) -### [`seek.word`](./seek.ts#L174-L205) +### [`seek.word`](./seek.ts#L175-L206) Select to next word start. @@ -1085,7 +1088,7 @@ Default keybinding: `w` (kakoune: normal) -### [`seek.object`](./seek.ts#L249-L289) +### [`seek.object`](./seek.ts#L250-L290) Select object. @@ -1125,7 +1128,7 @@ This command: -### [`seek.syntax.experimental`](./seek.ts#L498-L517) +### [`seek.syntax.experimental`](./seek.ts#L499-L518) Select syntax object. @@ -1143,7 +1146,7 @@ This command: -### [`seek.leap`](./seek.ts#L551-L567) +### [`seek.leap`](./seek.ts#L552-L568) Leap forward. @@ -1496,15 +1499,16 @@ Default keybinding: `$` (kakoune: normal) -### [`selections.select`](./selections.ts#L346-L360) +### [`selections.select`](./selections.ts#L346-L361) Select within selections. #### Variants -| Title | Identifier | Keybinding | Command | -| -------------- | --------------- | --------------------- | ------------------------------------------------------------------------------------------------- | -| Leap or select | `select.orLeap` | `s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { ... }]], otherwise: [[".selections.select", { ... }]] }]` | +| Title | Identifier | Keybinding | Command | +| -------------- | ---------------- | --------------------- | ------------------------------------------------------------------------------------------------------------ | +| Leap or select | `select.orLeap` | `s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { ... }]], otherwise: [[".selections.select", { ... }]] }]` | +| Leap or select | `select.orSneak` | | `[".ifEmpty", { then: [[".seek", { inputLength: 2, ... }]], otherwise: [[".selections.select", { ... }]] }]` | This command: - accepts an argument of type `{ re?: string | RegExp }`. @@ -1512,7 +1516,7 @@ This command: -### [`selections.split`](./selections.ts#L379-L390) +### [`selections.split`](./selections.ts#L380-L391) Split selections. @@ -1526,15 +1530,16 @@ Default keybinding: `s-s` (kakoune: normal) -### [`selections.splitLines`](./selections.ts#L415-L431) +### [`selections.splitLines`](./selections.ts#L416-L433) Split selections at line boundaries. #### Variants -| Title | Identifier | Keybinding | Command | -| ----------------------- | ---------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------- | -| Leap or select backward | `splitLines.orLeap.backward` | `a-s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { direction: -1, ... }]], otherwise: [[".selections.splitLines", { ... }]] }]` | +| Title | Identifier | Keybinding | Command | +| ------------------------ | ----------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| Leap or select backward | `splitLines.orLeap.backward` | `a-s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { direction: -1, ... }]], otherwise: [[".selections.splitLines", { ... }]] }]` | +| Sneak or select backward | `splitLines.orSneak.backward` | | `[".ifEmpty", { then: [[".seek", { inputLength: 2, direction: -1, ... }]], otherwise: [[".selections.splitLines", { ... }]] }]` | This command: - may be repeated with a given number of repetitions. @@ -1542,7 +1547,7 @@ This command: -### [`selections.expandToLines`](./selections.ts#L474-L481) +### [`selections.expandToLines`](./selections.ts#L476-L483) Expand to lines. @@ -1554,7 +1559,7 @@ Default keybinding: `x` (kakoune: normal) -### [`selections.trimLines`](./selections.ts#L508-L515) +### [`selections.trimLines`](./selections.ts#L510-L517) Trim lines. @@ -1566,7 +1571,7 @@ Default keybinding: `a-x` (kakoune: normal) -### [`selections.trimWhitespace`](./selections.ts#L540-L547) +### [`selections.trimWhitespace`](./selections.ts#L542-L549) Trim whitespace. @@ -1578,7 +1583,7 @@ Default keybinding: `_` (kakoune: normal) -### [`selections.reduce`](./selections.ts#L566-L585) +### [`selections.reduce`](./selections.ts#L568-L587) Reduce selections to their cursor. @@ -1598,7 +1603,7 @@ Default keybinding: `;` (kakoune: normal) -### [`selections.changeDirection`](./selections.ts#L647-L662) +### [`selections.changeDirection`](./selections.ts#L649-L664) Change direction of selections. @@ -1616,7 +1621,7 @@ Default keybinding: `a-;` (kakoune: normal) -### [`selections.changeOrder`](./selections.ts#L687-L701) +### [`selections.changeOrder`](./selections.ts#L689-L703) Reverse selections. @@ -1630,7 +1635,7 @@ Reverse selections. -### [`selections.sort`](./selections.ts#L714-L726) +### [`selections.sort`](./selections.ts#L716-L728) Sort selections. @@ -1641,7 +1646,7 @@ This command: -### [`selections.copy`](./selections.ts#L799-L817) +### [`selections.copy`](./selections.ts#L801-L819) Copy selections below. @@ -1659,7 +1664,7 @@ Default keybinding: `s-c` (kakoune: normal) -### [`selections.merge`](./selections.ts#L851-L856) +### [`selections.merge`](./selections.ts#L853-L858) Merge contiguous selections. @@ -1669,13 +1674,13 @@ Default keybinding: `a-_` (kakoune: normal) -### [`selections.open`](./selections.ts#L860-L863) +### [`selections.open`](./selections.ts#L862-L865) Open selected file. -### [`selections.toggleIndices`](./selections.ts#L876-L893) +### [`selections.toggleIndices`](./selections.ts#L878-L895) Toggle selection indices. diff --git a/src/commands/edit.ts b/src/commands/edit.ts index 8e76a36f..45a93eb1 100644 --- a/src/commands/edit.ts +++ b/src/commands/edit.ts @@ -232,7 +232,7 @@ export async function replaceCharacters( repetitions: number, inputOr: InputOr<"input", string>, ) { - const input = (await inputOr(() => keypress(_))).repeat(repetitions); + const input = (await inputOr(() => keypress({}, _))).repeat(repetitions); return _.run(() => edit((editBuilder, selections, document) => { for (const selection of selections) { diff --git a/src/commands/layouts/azerty.fr.md b/src/commands/layouts/azerty.fr.md index ab0ef942..ebd070d4 100644 --- a/src/commands/layouts/azerty.fr.md +++ b/src/commands/layouts/azerty.fr.md @@ -89,42 +89,42 @@ selections are empty seek.leapLeap forward seek.objectSelect object seek.seekSelect to character (excluded)T (editorTextFocus && dance.mode == 'normal') -seek.askObjectSelect whole objectAlt+A (editorTextFocus && dance.mode == 'normal')Alt+A (editorTextFocus && dance.mode == 'insert') -seek.askObject.endSelect to whole object end] (editorTextFocus && dance.mode == 'normal') -seek.askObject.end.extendExtend to whole object endShift+] (editorTextFocus && dance.mode == 'normal') -seek.askObject.innerSelect inner objectAlt+I (editorTextFocus && dance.mode == 'normal')Alt+I (editorTextFocus && dance.mode == 'insert') -seek.askObject.inner.endSelect to inner object endAlt+] (editorTextFocus && dance.mode == 'normal') -seek.askObject.inner.end.extendExtend to inner object endShift+Alt+] (editorTextFocus && dance.mode == 'normal') -seek.askObject.inner.startSelect to inner object startAlt+[ (editorTextFocus && dance.mode == 'normal') -seek.askObject.inner.start.extendExtend to inner object startShift+Alt+[ (editorTextFocus && dance.mode == 'normal') -seek.askObject.startSelect to whole object start[ (editorTextFocus && dance.mode == 'normal') -seek.askObject.start.extendExtend to whole object startShift+[ (editorTextFocus && dance.mode == 'normal') +seek.askObjectSelect whole objectAlt+A (editorTextFocus && dance.mode == 'normal')Alt+A (editorTextFocus && dance.mode == 'insert') +seek.askObject.endSelect to whole object end] (editorTextFocus && dance.mode == 'normal') +seek.askObject.end.extendExtend to whole object endShift+] (editorTextFocus && dance.mode == 'normal') +seek.askObject.innerSelect inner objectAlt+I (editorTextFocus && dance.mode == 'normal')Alt+I (editorTextFocus && dance.mode == 'insert') +seek.askObject.inner.endSelect to inner object endAlt+] (editorTextFocus && dance.mode == 'normal') +seek.askObject.inner.end.extendExtend to inner object endShift+Alt+] (editorTextFocus && dance.mode == 'normal') +seek.askObject.inner.startSelect to inner object startAlt+[ (editorTextFocus && dance.mode == 'normal') +seek.askObject.inner.start.extendExtend to inner object startShift+Alt+[ (editorTextFocus && dance.mode == 'normal') +seek.askObject.startSelect to whole object start[ (editorTextFocus && dance.mode == 'normal') +seek.askObject.start.extendExtend to whole object startShift+[ (editorTextFocus && dance.mode == 'normal') seek.backwardSelect to character (excluded, backward)Alt+T (editorTextFocus && dance.mode == 'normal') -seek.enclosing.backwardSelect to previous enclosing characterAlt+M (editorTextFocus && dance.mode == 'normal') -seek.enclosing.extendExtend to next enclosing characterShift+M (editorTextFocus && dance.mode == 'normal') -seek.enclosing.extend.backwardExtend to previous enclosing characterShift+Alt+M (editorTextFocus && dance.mode == 'normal') +seek.enclosing.backwardSelect to previous enclosing characterAlt+M (editorTextFocus && dance.mode == 'normal') +seek.enclosing.extendExtend to next enclosing characterShift+M (editorTextFocus && dance.mode == 'normal') +seek.enclosing.extend.backwardExtend to previous enclosing characterShift+Alt+M (editorTextFocus && dance.mode == 'normal') seek.extendExtend to character (excluded)Shift+T (editorTextFocus && dance.mode == 'normal')T (editorTextFocus && dance.mode == 'select') seek.extend.backwardExtend to character (excluded, backward)Shift+Alt+T (editorTextFocus && dance.mode == 'normal')Shift+T (editorTextFocus && dance.mode == 'select') seek.includedSelect to character (included)F (editorTextFocus && dance.mode == 'normal') seek.included.backwardSelect to character (included, backward)Alt+F (editorTextFocus && dance.mode == 'normal') seek.included.extendExtend to character (included)Shift+F (editorTextFocus && dance.mode == 'normal')F (editorTextFocus && dance.mode == 'select') seek.included.extend.backwardExtend to character (included, backward)Shift+Alt+F (editorTextFocus && dance.mode == 'normal')Shift+F (editorTextFocus && dance.mode == 'select') -seek.leap.backwardLeap backward -seek.syntax.child.experimentalSelect child syntax object -seek.syntax.next.experimentalSelect next syntax object -seek.syntax.parent.experimentalSelect parent syntax object -seek.syntax.previous.experimentalSelect previous syntax object -seek.word.backwardSelect to previous word startB (editorTextFocus && dance.mode == 'normal') -seek.word.extendExtend to next word startShift+W (editorTextFocus && dance.mode == 'normal')W (editorTextFocus && dance.mode == 'select') -seek.word.extend.backwardExtend to previous word startShift+B (editorTextFocus && dance.mode == 'normal')B (editorTextFocus && dance.mode == 'select') -seek.word.wsSelect to next non-whitespace word startAlt+W (editorTextFocus && dance.mode == 'normal') -seek.word.ws.backwardSelect to previous non-whitespace word startAlt+B (editorTextFocus && dance.mode == 'normal') -seek.word.ws.extendExtend to next non-whitespace word startShift+Alt+W (editorTextFocus && dance.mode == 'normal')Shift+W (editorTextFocus && dance.mode == 'select') -seek.word.ws.extend.backwardExtend to previous non-whitespace word startShift+Alt+B (editorTextFocus && dance.mode == 'normal')Shift+B (editorTextFocus && dance.mode == 'select') -seek.wordEndSelect to next word endE (editorTextFocus && dance.mode == 'normal') -seek.wordEnd.extendExtend to next word endShift+E (editorTextFocus && dance.mode == 'normal')E (editorTextFocus && dance.mode == 'select') -seek.wordEnd.wsSelect to next non-whitespace word endAlt+E (editorTextFocus && dance.mode == 'normal') -seek.wordEnd.ws.extendExtend to next non-whitespace word endShift+Alt+E (editorTextFocus && dance.mode == 'normal')Shift+E (editorTextFocus && dance.mode == 'select') +seek.leap.backwardLeap backward +seek.syntax.child.experimentalSelect child syntax object +seek.syntax.next.experimentalSelect next syntax object +seek.syntax.parent.experimentalSelect parent syntax object +seek.syntax.previous.experimentalSelect previous syntax object +seek.word.backwardSelect to previous word startB (editorTextFocus && dance.mode == 'normal') +seek.word.extendExtend to next word startShift+W (editorTextFocus && dance.mode == 'normal')W (editorTextFocus && dance.mode == 'select') +seek.word.extend.backwardExtend to previous word startShift+B (editorTextFocus && dance.mode == 'normal')B (editorTextFocus && dance.mode == 'select') +seek.word.wsSelect to next non-whitespace word startAlt+W (editorTextFocus && dance.mode == 'normal') +seek.word.ws.backwardSelect to previous non-whitespace word startAlt+B (editorTextFocus && dance.mode == 'normal') +seek.word.ws.extendExtend to next non-whitespace word startShift+Alt+W (editorTextFocus && dance.mode == 'normal')Shift+W (editorTextFocus && dance.mode == 'select') +seek.word.ws.extend.backwardExtend to previous non-whitespace word startShift+Alt+B (editorTextFocus && dance.mode == 'normal')Shift+B (editorTextFocus && dance.mode == 'select') +seek.wordEndSelect to next word endE (editorTextFocus && dance.mode == 'normal') +seek.wordEnd.extendExtend to next word endShift+E (editorTextFocus && dance.mode == 'normal')E (editorTextFocus && dance.mode == 'select') +seek.wordEnd.wsSelect to next non-whitespace word endAlt+E (editorTextFocus && dance.mode == 'normal') +seek.wordEnd.ws.extendExtend to next non-whitespace word endShift+Alt+E (editorTextFocus && dance.mode == 'normal')Shift+E (editorTextFocus && dance.mode == 'select') seek.syntax.experimentalSelect syntax object seek.wordSelect to next word startW (editorTextFocus && dance.mode == 'normal') selectselect.bufferSelect whole bufferShift+5 (editorTextFocus && dance.mode == 'normal') @@ -168,7 +168,7 @@ selections are empty select.up.jumpJump upK (editorTextFocus && dance.mode == 'normal')Up (editorTextFocus && dance.mode == 'normal') select.toSelect to select.verticallySelect vertically -selectionsselections.changeDirectionChange direction of selectionsAlt+; (editorTextFocus && dance.mode == 'normal') +selectionsselections.changeDirectionChange direction of selectionsAlt+; (editorTextFocus && dance.mode == 'normal') selections.changeOrderReverse selections selections.copyCopy selections belowShift+C (editorTextFocus && dance.mode == 'normal') selections.expandToLinesExpand to linesX (editorTextFocus && dance.mode == 'normal') @@ -184,21 +184,23 @@ selections are empty selections.selectSelect within selections selections.clear.mainClear main selectionsAlt+, (editorTextFocus && dance.mode == 'normal') selections.clear.secondaryClear secondary selections, (editorTextFocus && dance.mode == 'normal') -selections.copy.aboveCopy selections aboveShift+Alt+C (editorTextFocus && dance.mode == 'normal') -selections.faceBackwardBackward selections -selections.faceForwardForward selectionsShift+Alt+; (editorTextFocus && dance.mode == 'normal') +selections.copy.aboveCopy selections aboveShift+Alt+C (editorTextFocus && dance.mode == 'normal') +selections.faceBackwardBackward selections +selections.faceForwardForward selectionsShift+Alt+; (editorTextFocus && dance.mode == 'normal') selections.filter.regexpKeep matching selectionsAlt+K (editorTextFocus && dance.mode == 'normal') selections.filter.regexp.inverseClear matching selectionsShift+Alt+K (editorTextFocus && dance.mode == 'normal') -selections.hideIndicesHide selection indices -selections.orderAscendingOrder selections ascending -selections.orderDescendingOrder selections descending +selections.hideIndicesHide selection indices +selections.orderAscendingOrder selections ascending +selections.orderDescendingOrder selections descending selections.pipe.appendPipe and appendShift+1 (editorTextFocus && dance.mode == 'normal') selections.pipe.prependPipe and prependShift+Alt+1 (editorTextFocus && dance.mode == 'normal') selections.pipe.replacePipe and replaceShift+\ (editorTextFocus && dance.mode == 'normal') -selections.reduce.edgesReduce selections to their endsShift+Alt+S (editorTextFocus && dance.mode == 'normal') +selections.reduce.edgesReduce selections to their endsShift+Alt+S (editorTextFocus && dance.mode == 'normal') selections.select.orLeapLeap or selectS (editorTextFocus && dance.mode == 'normal') -selections.showIndicesShow selection indices -selections.splitLines.orLeap.backwardLeap or select backwardAlt+S (editorTextFocus && dance.mode == 'normal') +selections.select.orSneakLeap or select +selections.showIndicesShow selection indices +selections.splitLines.orLeap.backwardLeap or select backwardAlt+S (editorTextFocus && dance.mode == 'normal') +selections.splitLines.orSneak.backwardSneak or select backward selections.sortSort selections selections.splitSplit selectionsShift+S (editorTextFocus && dance.mode == 'normal') selections.splitLinesSplit selections at line boundaries @@ -991,7 +993,7 @@ Update selections based on the text surrounding them. -### [`seek.seek`](../seek.ts#L16-L41) +### [`seek.seek`](../seek.ts#L16-L42) Select to character (excluded). @@ -1011,13 +1013,14 @@ Select to character (excluded). This command: - may be repeated with a given number of repetitions. - takes an argument `include` of type `boolean`. +- takes an argument `inputLength` of type `number`. - takes an input `input` of type `string`. Default keybinding: `t` (kakoune: normal) -### [`seek.enclosing`](../seek.ts#L81-L101) +### [`seek.enclosing`](../seek.ts#L82-L102) Select to next enclosing character. @@ -1038,7 +1041,7 @@ Default keybinding: `m` (kakoune: normal) -### [`seek.word`](../seek.ts#L174-L205) +### [`seek.word`](../seek.ts#L175-L206) Select to next word start. @@ -1070,7 +1073,7 @@ Default keybinding: `w` (kakoune: normal) -### [`seek.object`](../seek.ts#L249-L289) +### [`seek.object`](../seek.ts#L250-L290) Select object. @@ -1110,7 +1113,7 @@ This command: -### [`seek.syntax.experimental`](../seek.ts#L498-L517) +### [`seek.syntax.experimental`](../seek.ts#L499-L518) Select syntax object. @@ -1128,7 +1131,7 @@ This command: -### [`seek.leap`](../seek.ts#L551-L567) +### [`seek.leap`](../seek.ts#L552-L568) Leap forward. @@ -1481,15 +1484,16 @@ Default keybinding: `$` (kakoune: normal) -### [`selections.select`](../selections.ts#L346-L360) +### [`selections.select`](../selections.ts#L346-L361) Select within selections. #### Variants -| Title | Identifier | Keybinding | Command | -| -------------- | --------------- | --------------------- | ------------------------------------------------------------------------------------------------- | -| Leap or select | `select.orLeap` | `s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { ... }]], otherwise: [[".selections.select", { ... }]] }]` | +| Title | Identifier | Keybinding | Command | +| -------------- | ---------------- | --------------------- | ------------------------------------------------------------------------------------------------------------ | +| Leap or select | `select.orLeap` | `s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { ... }]], otherwise: [[".selections.select", { ... }]] }]` | +| Leap or select | `select.orSneak` | | `[".ifEmpty", { then: [[".seek", { inputLength: 2, ... }]], otherwise: [[".selections.select", { ... }]] }]` | This command: - accepts an argument of type `{ re?: string | RegExp }`. @@ -1497,7 +1501,7 @@ This command: -### [`selections.split`](../selections.ts#L379-L390) +### [`selections.split`](../selections.ts#L380-L391) Split selections. @@ -1511,15 +1515,16 @@ Default keybinding: `s-s` (kakoune: normal) -### [`selections.splitLines`](../selections.ts#L415-L431) +### [`selections.splitLines`](../selections.ts#L416-L433) Split selections at line boundaries. #### Variants -| Title | Identifier | Keybinding | Command | -| ----------------------- | ---------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------- | -| Leap or select backward | `splitLines.orLeap.backward` | `a-s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { direction: -1, ... }]], otherwise: [[".selections.splitLines", { ... }]] }]` | +| Title | Identifier | Keybinding | Command | +| ------------------------ | ----------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| Leap or select backward | `splitLines.orLeap.backward` | `a-s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { direction: -1, ... }]], otherwise: [[".selections.splitLines", { ... }]] }]` | +| Sneak or select backward | `splitLines.orSneak.backward` | | `[".ifEmpty", { then: [[".seek", { inputLength: 2, direction: -1, ... }]], otherwise: [[".selections.splitLines", { ... }]] }]` | This command: - may be repeated with a given number of repetitions. @@ -1527,7 +1532,7 @@ This command: -### [`selections.expandToLines`](../selections.ts#L474-L481) +### [`selections.expandToLines`](../selections.ts#L476-L483) Expand to lines. @@ -1539,7 +1544,7 @@ Default keybinding: `x` (kakoune: normal) -### [`selections.trimLines`](../selections.ts#L508-L515) +### [`selections.trimLines`](../selections.ts#L510-L517) Trim lines. @@ -1551,7 +1556,7 @@ Default keybinding: `a-x` (kakoune: normal) -### [`selections.trimWhitespace`](../selections.ts#L540-L547) +### [`selections.trimWhitespace`](../selections.ts#L542-L549) Trim whitespace. @@ -1563,7 +1568,7 @@ Default keybinding: `_` (kakoune: normal) -### [`selections.reduce`](../selections.ts#L566-L585) +### [`selections.reduce`](../selections.ts#L568-L587) Reduce selections to their cursor. @@ -1583,7 +1588,7 @@ Default keybinding: `;` (kakoune: normal) -### [`selections.changeDirection`](../selections.ts#L647-L662) +### [`selections.changeDirection`](../selections.ts#L649-L664) Change direction of selections. @@ -1601,7 +1606,7 @@ Default keybinding: `a-;` (kakoune: normal) -### [`selections.changeOrder`](../selections.ts#L687-L701) +### [`selections.changeOrder`](../selections.ts#L689-L703) Reverse selections. @@ -1615,7 +1620,7 @@ Reverse selections. -### [`selections.sort`](../selections.ts#L714-L726) +### [`selections.sort`](../selections.ts#L716-L728) Sort selections. @@ -1626,7 +1631,7 @@ This command: -### [`selections.copy`](../selections.ts#L799-L817) +### [`selections.copy`](../selections.ts#L801-L819) Copy selections below. @@ -1644,7 +1649,7 @@ Default keybinding: `s-c` (kakoune: normal) -### [`selections.merge`](../selections.ts#L851-L856) +### [`selections.merge`](../selections.ts#L853-L858) Merge contiguous selections. @@ -1654,13 +1659,13 @@ Default keybinding: `a-_` (kakoune: normal) -### [`selections.open`](../selections.ts#L860-L863) +### [`selections.open`](../selections.ts#L862-L865) Open selected file. -### [`selections.toggleIndices`](../selections.ts#L876-L893) +### [`selections.toggleIndices`](../selections.ts#L878-L895) Toggle selection indices. diff --git a/src/commands/layouts/qwerty.md b/src/commands/layouts/qwerty.md index 81751aa8..2735999c 100644 --- a/src/commands/layouts/qwerty.md +++ b/src/commands/layouts/qwerty.md @@ -89,42 +89,42 @@ selections are empty seek.leapLeap forward seek.objectSelect object seek.seekSelect to character (excluded)T (editorTextFocus && dance.mode == 'normal') -seek.askObjectSelect whole objectAlt+A (editorTextFocus && dance.mode == 'normal')Alt+A (editorTextFocus && dance.mode == 'insert') -seek.askObject.endSelect to whole object end] (editorTextFocus && dance.mode == 'normal') -seek.askObject.end.extendExtend to whole object endShift+] (editorTextFocus && dance.mode == 'normal') -seek.askObject.innerSelect inner objectAlt+I (editorTextFocus && dance.mode == 'normal')Alt+I (editorTextFocus && dance.mode == 'insert') -seek.askObject.inner.endSelect to inner object endAlt+] (editorTextFocus && dance.mode == 'normal') -seek.askObject.inner.end.extendExtend to inner object endShift+Alt+] (editorTextFocus && dance.mode == 'normal') -seek.askObject.inner.startSelect to inner object startAlt+[ (editorTextFocus && dance.mode == 'normal') -seek.askObject.inner.start.extendExtend to inner object startShift+Alt+[ (editorTextFocus && dance.mode == 'normal') -seek.askObject.startSelect to whole object start[ (editorTextFocus && dance.mode == 'normal') -seek.askObject.start.extendExtend to whole object startShift+[ (editorTextFocus && dance.mode == 'normal') +seek.askObjectSelect whole objectAlt+A (editorTextFocus && dance.mode == 'normal')Alt+A (editorTextFocus && dance.mode == 'insert') +seek.askObject.endSelect to whole object end] (editorTextFocus && dance.mode == 'normal') +seek.askObject.end.extendExtend to whole object endShift+] (editorTextFocus && dance.mode == 'normal') +seek.askObject.innerSelect inner objectAlt+I (editorTextFocus && dance.mode == 'normal')Alt+I (editorTextFocus && dance.mode == 'insert') +seek.askObject.inner.endSelect to inner object endAlt+] (editorTextFocus && dance.mode == 'normal') +seek.askObject.inner.end.extendExtend to inner object endShift+Alt+] (editorTextFocus && dance.mode == 'normal') +seek.askObject.inner.startSelect to inner object startAlt+[ (editorTextFocus && dance.mode == 'normal') +seek.askObject.inner.start.extendExtend to inner object startShift+Alt+[ (editorTextFocus && dance.mode == 'normal') +seek.askObject.startSelect to whole object start[ (editorTextFocus && dance.mode == 'normal') +seek.askObject.start.extendExtend to whole object startShift+[ (editorTextFocus && dance.mode == 'normal') seek.backwardSelect to character (excluded, backward)Alt+T (editorTextFocus && dance.mode == 'normal') -seek.enclosing.backwardSelect to previous enclosing characterAlt+M (editorTextFocus && dance.mode == 'normal') -seek.enclosing.extendExtend to next enclosing characterShift+M (editorTextFocus && dance.mode == 'normal') -seek.enclosing.extend.backwardExtend to previous enclosing characterShift+Alt+M (editorTextFocus && dance.mode == 'normal') +seek.enclosing.backwardSelect to previous enclosing characterAlt+M (editorTextFocus && dance.mode == 'normal') +seek.enclosing.extendExtend to next enclosing characterShift+M (editorTextFocus && dance.mode == 'normal') +seek.enclosing.extend.backwardExtend to previous enclosing characterShift+Alt+M (editorTextFocus && dance.mode == 'normal') seek.extendExtend to character (excluded)Shift+T (editorTextFocus && dance.mode == 'normal')T (editorTextFocus && dance.mode == 'select') seek.extend.backwardExtend to character (excluded, backward)Shift+Alt+T (editorTextFocus && dance.mode == 'normal')Shift+T (editorTextFocus && dance.mode == 'select') seek.includedSelect to character (included)F (editorTextFocus && dance.mode == 'normal') seek.included.backwardSelect to character (included, backward)Alt+F (editorTextFocus && dance.mode == 'normal') seek.included.extendExtend to character (included)Shift+F (editorTextFocus && dance.mode == 'normal')F (editorTextFocus && dance.mode == 'select') seek.included.extend.backwardExtend to character (included, backward)Shift+Alt+F (editorTextFocus && dance.mode == 'normal')Shift+F (editorTextFocus && dance.mode == 'select') -seek.leap.backwardLeap backward -seek.syntax.child.experimentalSelect child syntax object -seek.syntax.next.experimentalSelect next syntax object -seek.syntax.parent.experimentalSelect parent syntax object -seek.syntax.previous.experimentalSelect previous syntax object -seek.word.backwardSelect to previous word startB (editorTextFocus && dance.mode == 'normal') -seek.word.extendExtend to next word startShift+W (editorTextFocus && dance.mode == 'normal')W (editorTextFocus && dance.mode == 'select') -seek.word.extend.backwardExtend to previous word startShift+B (editorTextFocus && dance.mode == 'normal')B (editorTextFocus && dance.mode == 'select') -seek.word.wsSelect to next non-whitespace word startAlt+W (editorTextFocus && dance.mode == 'normal') -seek.word.ws.backwardSelect to previous non-whitespace word startAlt+B (editorTextFocus && dance.mode == 'normal') -seek.word.ws.extendExtend to next non-whitespace word startShift+Alt+W (editorTextFocus && dance.mode == 'normal')Shift+W (editorTextFocus && dance.mode == 'select') -seek.word.ws.extend.backwardExtend to previous non-whitespace word startShift+Alt+B (editorTextFocus && dance.mode == 'normal')Shift+B (editorTextFocus && dance.mode == 'select') -seek.wordEndSelect to next word endE (editorTextFocus && dance.mode == 'normal') -seek.wordEnd.extendExtend to next word endShift+E (editorTextFocus && dance.mode == 'normal')E (editorTextFocus && dance.mode == 'select') -seek.wordEnd.wsSelect to next non-whitespace word endAlt+E (editorTextFocus && dance.mode == 'normal') -seek.wordEnd.ws.extendExtend to next non-whitespace word endShift+Alt+E (editorTextFocus && dance.mode == 'normal')Shift+E (editorTextFocus && dance.mode == 'select') +seek.leap.backwardLeap backward +seek.syntax.child.experimentalSelect child syntax object +seek.syntax.next.experimentalSelect next syntax object +seek.syntax.parent.experimentalSelect parent syntax object +seek.syntax.previous.experimentalSelect previous syntax object +seek.word.backwardSelect to previous word startB (editorTextFocus && dance.mode == 'normal') +seek.word.extendExtend to next word startShift+W (editorTextFocus && dance.mode == 'normal')W (editorTextFocus && dance.mode == 'select') +seek.word.extend.backwardExtend to previous word startShift+B (editorTextFocus && dance.mode == 'normal')B (editorTextFocus && dance.mode == 'select') +seek.word.wsSelect to next non-whitespace word startAlt+W (editorTextFocus && dance.mode == 'normal') +seek.word.ws.backwardSelect to previous non-whitespace word startAlt+B (editorTextFocus && dance.mode == 'normal') +seek.word.ws.extendExtend to next non-whitespace word startShift+Alt+W (editorTextFocus && dance.mode == 'normal')Shift+W (editorTextFocus && dance.mode == 'select') +seek.word.ws.extend.backwardExtend to previous non-whitespace word startShift+Alt+B (editorTextFocus && dance.mode == 'normal')Shift+B (editorTextFocus && dance.mode == 'select') +seek.wordEndSelect to next word endE (editorTextFocus && dance.mode == 'normal') +seek.wordEnd.extendExtend to next word endShift+E (editorTextFocus && dance.mode == 'normal')E (editorTextFocus && dance.mode == 'select') +seek.wordEnd.wsSelect to next non-whitespace word endAlt+E (editorTextFocus && dance.mode == 'normal') +seek.wordEnd.ws.extendExtend to next non-whitespace word endShift+Alt+E (editorTextFocus && dance.mode == 'normal')Shift+E (editorTextFocus && dance.mode == 'select') seek.syntax.experimentalSelect syntax object seek.wordSelect to next word startW (editorTextFocus && dance.mode == 'normal') selectselect.bufferSelect whole bufferShift+5 (editorTextFocus && dance.mode == 'normal') @@ -168,7 +168,7 @@ selections are empty select.up.jumpJump upK (editorTextFocus && dance.mode == 'normal')Up (editorTextFocus && dance.mode == 'normal') select.toSelect to select.verticallySelect vertically -selectionsselections.changeDirectionChange direction of selectionsAlt+; (editorTextFocus && dance.mode == 'normal') +selectionsselections.changeDirectionChange direction of selectionsAlt+; (editorTextFocus && dance.mode == 'normal') selections.changeOrderReverse selections selections.copyCopy selections belowShift+C (editorTextFocus && dance.mode == 'normal') selections.expandToLinesExpand to linesX (editorTextFocus && dance.mode == 'normal') @@ -184,21 +184,23 @@ selections are empty selections.selectSelect within selections selections.clear.mainClear main selectionsAlt+, (editorTextFocus && dance.mode == 'normal') selections.clear.secondaryClear secondary selections, (editorTextFocus && dance.mode == 'normal') -selections.copy.aboveCopy selections aboveShift+Alt+C (editorTextFocus && dance.mode == 'normal') -selections.faceBackwardBackward selections -selections.faceForwardForward selectionsShift+Alt+; (editorTextFocus && dance.mode == 'normal') +selections.copy.aboveCopy selections aboveShift+Alt+C (editorTextFocus && dance.mode == 'normal') +selections.faceBackwardBackward selections +selections.faceForwardForward selectionsShift+Alt+; (editorTextFocus && dance.mode == 'normal') selections.filter.regexpKeep matching selectionsAlt+K (editorTextFocus && dance.mode == 'normal') selections.filter.regexp.inverseClear matching selectionsShift+Alt+K (editorTextFocus && dance.mode == 'normal') -selections.hideIndicesHide selection indices -selections.orderAscendingOrder selections ascending -selections.orderDescendingOrder selections descending +selections.hideIndicesHide selection indices +selections.orderAscendingOrder selections ascending +selections.orderDescendingOrder selections descending selections.pipe.appendPipe and appendShift+1 (editorTextFocus && dance.mode == 'normal') selections.pipe.prependPipe and prependShift+Alt+1 (editorTextFocus && dance.mode == 'normal') selections.pipe.replacePipe and replaceShift+\ (editorTextFocus && dance.mode == 'normal') -selections.reduce.edgesReduce selections to their endsShift+Alt+S (editorTextFocus && dance.mode == 'normal') +selections.reduce.edgesReduce selections to their endsShift+Alt+S (editorTextFocus && dance.mode == 'normal') selections.select.orLeapLeap or selectS (editorTextFocus && dance.mode == 'normal') -selections.showIndicesShow selection indices -selections.splitLines.orLeap.backwardLeap or select backwardAlt+S (editorTextFocus && dance.mode == 'normal') +selections.select.orSneakLeap or select +selections.showIndicesShow selection indices +selections.splitLines.orLeap.backwardLeap or select backwardAlt+S (editorTextFocus && dance.mode == 'normal') +selections.splitLines.orSneak.backwardSneak or select backward selections.sortSort selections selections.splitSplit selectionsShift+S (editorTextFocus && dance.mode == 'normal') selections.splitLinesSplit selections at line boundaries @@ -991,7 +993,7 @@ Update selections based on the text surrounding them. -### [`seek.seek`](../seek.ts#L16-L41) +### [`seek.seek`](../seek.ts#L16-L42) Select to character (excluded). @@ -1011,13 +1013,14 @@ Select to character (excluded). This command: - may be repeated with a given number of repetitions. - takes an argument `include` of type `boolean`. +- takes an argument `inputLength` of type `number`. - takes an input `input` of type `string`. Default keybinding: `t` (kakoune: normal) -### [`seek.enclosing`](../seek.ts#L81-L101) +### [`seek.enclosing`](../seek.ts#L82-L102) Select to next enclosing character. @@ -1038,7 +1041,7 @@ Default keybinding: `m` (kakoune: normal) -### [`seek.word`](../seek.ts#L174-L205) +### [`seek.word`](../seek.ts#L175-L206) Select to next word start. @@ -1070,7 +1073,7 @@ Default keybinding: `w` (kakoune: normal) -### [`seek.object`](../seek.ts#L249-L289) +### [`seek.object`](../seek.ts#L250-L290) Select object. @@ -1110,7 +1113,7 @@ This command: -### [`seek.syntax.experimental`](../seek.ts#L498-L517) +### [`seek.syntax.experimental`](../seek.ts#L499-L518) Select syntax object. @@ -1128,7 +1131,7 @@ This command: -### [`seek.leap`](../seek.ts#L551-L567) +### [`seek.leap`](../seek.ts#L552-L568) Leap forward. @@ -1481,15 +1484,16 @@ Default keybinding: `$` (kakoune: normal) -### [`selections.select`](../selections.ts#L346-L360) +### [`selections.select`](../selections.ts#L346-L361) Select within selections. #### Variants -| Title | Identifier | Keybinding | Command | -| -------------- | --------------- | --------------------- | ------------------------------------------------------------------------------------------------- | -| Leap or select | `select.orLeap` | `s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { ... }]], otherwise: [[".selections.select", { ... }]] }]` | +| Title | Identifier | Keybinding | Command | +| -------------- | ---------------- | --------------------- | ------------------------------------------------------------------------------------------------------------ | +| Leap or select | `select.orLeap` | `s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { ... }]], otherwise: [[".selections.select", { ... }]] }]` | +| Leap or select | `select.orSneak` | | `[".ifEmpty", { then: [[".seek", { inputLength: 2, ... }]], otherwise: [[".selections.select", { ... }]] }]` | This command: - accepts an argument of type `{ re?: string | RegExp }`. @@ -1497,7 +1501,7 @@ This command: -### [`selections.split`](../selections.ts#L379-L390) +### [`selections.split`](../selections.ts#L380-L391) Split selections. @@ -1511,15 +1515,16 @@ Default keybinding: `s-s` (kakoune: normal) -### [`selections.splitLines`](../selections.ts#L415-L431) +### [`selections.splitLines`](../selections.ts#L416-L433) Split selections at line boundaries. #### Variants -| Title | Identifier | Keybinding | Command | -| ----------------------- | ---------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------- | -| Leap or select backward | `splitLines.orLeap.backward` | `a-s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { direction: -1, ... }]], otherwise: [[".selections.splitLines", { ... }]] }]` | +| Title | Identifier | Keybinding | Command | +| ------------------------ | ----------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| Leap or select backward | `splitLines.orLeap.backward` | `a-s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { direction: -1, ... }]], otherwise: [[".selections.splitLines", { ... }]] }]` | +| Sneak or select backward | `splitLines.orSneak.backward` | | `[".ifEmpty", { then: [[".seek", { inputLength: 2, direction: -1, ... }]], otherwise: [[".selections.splitLines", { ... }]] }]` | This command: - may be repeated with a given number of repetitions. @@ -1527,7 +1532,7 @@ This command: -### [`selections.expandToLines`](../selections.ts#L474-L481) +### [`selections.expandToLines`](../selections.ts#L476-L483) Expand to lines. @@ -1539,7 +1544,7 @@ Default keybinding: `x` (kakoune: normal) -### [`selections.trimLines`](../selections.ts#L508-L515) +### [`selections.trimLines`](../selections.ts#L510-L517) Trim lines. @@ -1551,7 +1556,7 @@ Default keybinding: `a-x` (kakoune: normal) -### [`selections.trimWhitespace`](../selections.ts#L540-L547) +### [`selections.trimWhitespace`](../selections.ts#L542-L549) Trim whitespace. @@ -1563,7 +1568,7 @@ Default keybinding: `_` (kakoune: normal) -### [`selections.reduce`](../selections.ts#L566-L585) +### [`selections.reduce`](../selections.ts#L568-L587) Reduce selections to their cursor. @@ -1583,7 +1588,7 @@ Default keybinding: `;` (kakoune: normal) -### [`selections.changeDirection`](../selections.ts#L647-L662) +### [`selections.changeDirection`](../selections.ts#L649-L664) Change direction of selections. @@ -1601,7 +1606,7 @@ Default keybinding: `a-;` (kakoune: normal) -### [`selections.changeOrder`](../selections.ts#L687-L701) +### [`selections.changeOrder`](../selections.ts#L689-L703) Reverse selections. @@ -1615,7 +1620,7 @@ Reverse selections. -### [`selections.sort`](../selections.ts#L714-L726) +### [`selections.sort`](../selections.ts#L716-L728) Sort selections. @@ -1626,7 +1631,7 @@ This command: -### [`selections.copy`](../selections.ts#L799-L817) +### [`selections.copy`](../selections.ts#L801-L819) Copy selections below. @@ -1644,7 +1649,7 @@ Default keybinding: `s-c` (kakoune: normal) -### [`selections.merge`](../selections.ts#L851-L856) +### [`selections.merge`](../selections.ts#L853-L858) Merge contiguous selections. @@ -1654,13 +1659,13 @@ Default keybinding: `a-_` (kakoune: normal) -### [`selections.open`](../selections.ts#L860-L863) +### [`selections.open`](../selections.ts#L862-L865) Open selected file. -### [`selections.toggleIndices`](../selections.ts#L876-L893) +### [`selections.toggleIndices`](../selections.ts#L878-L895) Toggle selection indices. diff --git a/src/commands/load-all.ts b/src/commands/load-all.ts index 73d735d5..3942bf3d 100644 --- a/src/commands/load-all.ts +++ b/src/commands/load-all.ts @@ -30,6 +30,14 @@ function getRegister( return (argument.register = register as any); } +function getInputLength(argument: { inputLength?: number }) { + const len = +(argument.inputLength as any); + if (len > 0 && Number.isInteger(len)) { + return len; + } + throw new ArgumentError('"inputLength" must be positive integer', "inputLength"); +} + function getCount(_: Context.WithoutActiveEditor, argument: { count?: number }) { const count = +(argument.count as any); @@ -468,7 +476,7 @@ export const commands: Commands = function () { ), "dance.seek": new CommandDescriptor( "dance.seek", - (_, argument) => _.runAsync(async (_) => await seek(_, getInputOr("input", argument), getRepetitions(_, argument), getDirection(argument), getShift(argument), argument["include"])), + (_, argument) => _.runAsync(async (_) => await seek(_, getInputOr("input", argument), getRepetitions(_, argument), getDirection(argument), getShift(argument), argument["inputLength"], argument["include"])), CommandDescriptor.Flags.RequiresActiveEditor, ), "dance.seek.enclosing": new CommandDescriptor( @@ -1310,12 +1318,24 @@ export const commands: Commands = function () { CommandDescriptor.Flags.RequiresActiveEditor | CommandDescriptor.Flags.DoNotReplay, [[".ifEmpty", { then: [[".seek.leap", { $exclude: [] }]], otherwise: [[".selections.select", { $exclude: [] }]] }]], ); + describeAdditionalCommand( + commands, + "dance.selections.select.orSneak", + CommandDescriptor.Flags.RequiresActiveEditor | CommandDescriptor.Flags.DoNotReplay, + [[".ifEmpty", { then: [[".seek", { inputLength: 2, $exclude: [] }]], otherwise: [[".selections.select", { $exclude: [] }]] }]], + ); describeAdditionalCommand( commands, "dance.selections.splitLines.orLeap.backward", CommandDescriptor.Flags.RequiresActiveEditor | CommandDescriptor.Flags.DoNotReplay, [[".ifEmpty", { then: [[".seek.leap", { direction: -1, $exclude: [] }]], otherwise: [[".selections.splitLines", { $exclude: [] }]] }]], ); + describeAdditionalCommand( + commands, + "dance.selections.splitLines.orSneak.backward", + CommandDescriptor.Flags.RequiresActiveEditor | CommandDescriptor.Flags.DoNotReplay, + [[".ifEmpty", { then: [[".seek", { inputLength: 2, direction: -1, $exclude: [] }]], otherwise: [[".selections.splitLines", { $exclude: [] }]] }]], + ); describeAdditionalCommand( commands, "dance.selections.reduce.edges", diff --git a/src/commands/seek.ts b/src/commands/seek.ts index 232f5f04..62ecaeeb 100644 --- a/src/commands/seek.ts +++ b/src/commands/seek.ts @@ -37,9 +37,10 @@ export async function seek( repetitions: number, direction = Direction.Forward, shift = Shift.Select, + inputLength: Argument = 1, include: Argument = false, ) { - const input = await inputOr(() => keypress(_)); + const input = await inputOr(() => keypress({ keyCount: inputLength }, _)); Selections.updateByIndex((_, selection, document) => { let position: vscode.Position | undefined = Selections.seekFrom(selection, -direction); @@ -625,7 +626,7 @@ export async function leap( const cutoffPosition = _.mainSelection.active, endPosition = direction === Direction.Forward ? Positions.last(doc) : Positions.zero, allowedRange = new vscode.Range(cutoffPosition, endPosition), - firstChar = await keypress(_), + firstChar = await keypress({}, _), pairSelections = Selections.selectWithin( new RegExp(escapeForRegExp(firstChar) + ".?", "is"), editor.visibleRanges.flatMap((range) => { @@ -663,7 +664,7 @@ export async function leap( try { // Get second character and jump to it. - const secondChar = await keypress(_), + const secondChar = await keypress({}, _), unlabeledSelection = secondCharToUnlabeledSelection[secondChar]; if (unlabeledSelection === undefined) { @@ -707,7 +708,7 @@ export async function leap( let offset = 0; for (;;) { - const labelChar = await keypress(_); + const labelChar = await keypress({}, _); if (labelChar === " ") { // Rotate active labeled selections. diff --git a/src/commands/selections.ts b/src/commands/selections.ts index b5994b12..935f40ec 100644 --- a/src/commands/selections.ts +++ b/src/commands/selections.ts @@ -348,9 +348,10 @@ export function filter( * * #### Variants * - * | Title | Identifier | Keybinding | Command | - * | -------------- | --------------- | --------------------- | ------------------------------------------------------------------------------------------------- | - * | Leap or select | `select.orLeap` | `s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { ... }]], otherwise: [[".selections.select", { ... }]] }]` | + * | Title | Identifier | Keybinding | Command | + * | -------------- | ---------------- | --------------------- | ------------------------------------------------------------------------------------------------------------ | + * | Leap or select | `select.orLeap` | `s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { ... }]], otherwise: [[".selections.select", { ... }]] }]` | + * | Leap or select | `select.orSneak` | | `[".ifEmpty", { then: [[".seek", { inputLength: 2, ... }]], otherwise: [[".selections.select", { ... }]] }]` | */ export function select( _: Context, @@ -417,9 +418,10 @@ export function split( * * #### Variants * - * | Title | Identifier | Keybinding | Command | - * | ----------------------- | ---------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------- | - * | Leap or select backward | `splitLines.orLeap.backward` | `a-s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { direction: -1, ... }]], otherwise: [[".selections.splitLines", { ... }]] }]` | + * | Title | Identifier | Keybinding | Command | + * | ------------------------ | ----------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- | + * | Leap or select backward | `splitLines.orLeap.backward` | `a-s` (kakoune: normal) | `[".ifEmpty", { then: [[".seek.leap", { direction: -1, ... }]], otherwise: [[".selections.splitLines", { ... }]] }]` | + * | Sneak or select backward | `splitLines.orSneak.backward` | | `[".ifEmpty", { then: [[".seek", { inputLength: 2, direction: -1, ... }]], otherwise: [[".selections.splitLines", { ... }]] }]` | */ export function splitLines( _: Context, diff --git a/test/suite/commands/seek.md b/test/suite/commands/seek.md index da3628d9..b4ac4fc1 100644 --- a/test/suite/commands/seek.md +++ b/test/suite/commands/seek.md @@ -250,3 +250,50 @@ ghi jkl mno ``` + +# 4 + +``` +abcabcde abcabcde +| 0 +``` + +## 4 select-to-bc-excluded +[up](#4) + +- .seek { input: "cd" } + +``` +abcabcde abcabcde +^^^^^ 0 +``` +### 4 select-to-bc-excluded select-to +[up](#4-select-to-bc-excluded) + +- .seek { input: "cd" } + +``` +abcabcde abcabcde + ^^^^^^^^^ 0 +``` + +### 4 select-to-bc-excluded to-character +[up](#4-select-to-bc-excluded) + +> behavior <- character + +- .seek { input: "cd" } + +``` +abcabcde abcabcde + ^^^^^^^^^^ 0 +``` + +## 4 select-to-bc-excluded-count-2 +[up](#4) +- .seek { input: "cd", count: 2 } + +``` +abcabcde abcabcde +^^^^^^^^^^^^^^ 0 +``` diff --git a/test/suite/commands/seek.test.ts b/test/suite/commands/seek.test.ts index f790331f..b7366799 100644 --- a/test/suite/commands/seek.test.ts +++ b/test/suite/commands/seek.test.ts @@ -401,5 +401,75 @@ suite("./test/suite/commands/seek.md", function () { `); }); + test("4 > select-to-bc-excluded", async function () { + // Set-up document to be in expected initial state. + await ExpectedDocument.apply(editor, 6, String.raw` + abcabcde abcabcde + | 0 + `); + + // Perform all operations. + await executeCommand("dance.seek", { input: "cd" }); + + // Ensure document is as expected. + ExpectedDocument.assertEquals(editor, "./test/suite/commands/seek.md:261:1", 6, String.raw` + abcabcde abcabcde + ^^^^^ 0 + `); + }); + + test("4 > select-to-bc-excluded > select-to", async function () { + // Set-up document to be in expected initial state. + await ExpectedDocument.apply(editor, 6, String.raw` + abcabcde abcabcde + ^^^^^ 0 + `); + + // Perform all operations. + await executeCommand("dance.seek", { input: "cd" }); + + // Ensure document is as expected. + ExpectedDocument.assertEquals(editor, "./test/suite/commands/seek.md:270:1", 6, String.raw` + abcabcde abcabcde + ^^^^^^^^^ 0 + `); + }); + + test("4 > select-to-bc-excluded > to-character", async function () { + // Set-up document to be in expected initial state. + await ExpectedDocument.apply(editor, 6, String.raw` + abcabcde abcabcde + ^^^^^ 0 + `); + + // Perform all operations. + await executeCommand("dance.dev.setSelectionBehavior", { mode: "normal", value: "character" }); + await executeCommand("dance.seek", { input: "cd" }); + await executeCommand("dance.dev.setSelectionBehavior", { mode: "normal", value: "caret" }); + + // Ensure document is as expected. + ExpectedDocument.assertEquals(editor, "./test/suite/commands/seek.md:280:1", 6, String.raw` + abcabcde abcabcde + ^^^^^^^^^^ 0 + `); + }); + + test("4 > select-to-bc-excluded-count-2", async function () { + // Set-up document to be in expected initial state. + await ExpectedDocument.apply(editor, 6, String.raw` + abcabcde abcabcde + | 0 + `); + + // Perform all operations. + await executeCommand("dance.seek", { input: "cd", count: 2 }); + + // Ensure document is as expected. + ExpectedDocument.assertEquals(editor, "./test/suite/commands/seek.md:292:1", 6, String.raw` + abcabcde abcabcde + ^^^^^^^^^^^^^^ 0 + `); + }); + groupTestsByParentName(this); });