Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions cursorless-talon/src/spoken_forms.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
"NOTE FOR USERS": "Please don't edit this json file; see https://www.cursorless.org/docs/user/customization",
"actions.csv": {
"simple_action": {
"append post": "addSelectionAfter",
"append pre": "addSelectionBefore",
"append": "addSelection",
"bottom": "scrollToBottom",
"break": "breakLine",
"break point": "toggleLineBreakpoint",
"break": "breakLine",
"carve": "cutToClipboard",
"center": "scrollToCenter",
"change": "clearAndSetSelection",
Expand All @@ -22,8 +25,8 @@
"extract": "extractVariable",
"float": "insertEmptyLineAfter",
"fold": "foldRegion",
"follow": "followLink",
"follow split": "followLinkAside",
"follow": "followLink",
"give": "deselect",
"highlight": "highlight",
"hover": "showHover",
Expand All @@ -39,8 +42,8 @@
"reference": "showReferences",
"rename": "rename",
"reverse": "reverseTargets",
"scout": "findInDocument",
"scout all": "findInWorkspace",
"scout": "findInDocument",
"shuffle": "randomizeTargets",
"snippet make": "generateSnippet",
"sort": "sortTargets",
Expand Down
33 changes: 33 additions & 0 deletions data/fixtures/recorded/actions/appendPostWhale.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
languageId: plaintext
command:
version: 7
spokenForm: append post whale
action:
name: addSelectionAfter
target:
type: primitive
mark: {type: decoratedSymbol, symbolColor: default, character: w}
usePrePhraseSnapshot: true
initialState:
documentContents: hello world
selections:
- anchor: {line: 0, character: 0}
active: {line: 0, character: 0}
marks:
default.w:
start: {line: 0, character: 6}
end: {line: 0, character: 11}
finalState:
documentContents: hello world
selections:
- anchor: {line: 0, character: 0}
active: {line: 0, character: 0}
- anchor: {line: 0, character: 11}
active: {line: 0, character: 11}
thatMark:
- type: UntypedTarget
contentRange:
start: {line: 0, character: 6}
end: {line: 0, character: 11}
isReversed: false
hasExplicitRange: false
33 changes: 33 additions & 0 deletions data/fixtures/recorded/actions/appendPreWhale.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
languageId: plaintext
command:
version: 7
spokenForm: append pre whale
action:
name: addSelectionBefore
target:
type: primitive
mark: {type: decoratedSymbol, symbolColor: default, character: w}
usePrePhraseSnapshot: true
initialState:
documentContents: hello world
selections:
- anchor: {line: 0, character: 0}
active: {line: 0, character: 0}
marks:
default.w:
start: {line: 0, character: 6}
end: {line: 0, character: 11}
finalState:
documentContents: hello world
selections:
- anchor: {line: 0, character: 0}
active: {line: 0, character: 0}
- anchor: {line: 0, character: 6}
active: {line: 0, character: 6}
thatMark:
- type: UntypedTarget
contentRange:
start: {line: 0, character: 6}
end: {line: 0, character: 11}
isReversed: false
hasExplicitRange: false
33 changes: 33 additions & 0 deletions data/fixtures/recorded/actions/appendWhale.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
languageId: plaintext
command:
version: 7
spokenForm: append whale
action:
name: addSelection
target:
type: primitive
mark: {type: decoratedSymbol, symbolColor: default, character: w}
usePrePhraseSnapshot: true
initialState:
documentContents: hello world
selections:
- anchor: {line: 0, character: 0}
active: {line: 0, character: 0}
marks:
default.w:
start: {line: 0, character: 6}
end: {line: 0, character: 11}
finalState:
documentContents: hello world
selections:
- anchor: {line: 0, character: 0}
active: {line: 0, character: 0}
- anchor: {line: 0, character: 6}
active: {line: 0, character: 11}
thatMark:
- type: UntypedTarget
contentRange:
start: {line: 0, character: 6}
end: {line: 0, character: 11}
isReversed: false
hasExplicitRange: false
5 changes: 4 additions & 1 deletion packages/common/src/types/command/ActionDescriptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import type { DestinationDescriptor } from "./DestinationDescriptor.types";
* A simple action takes only a single target and no other arguments.
*/
export const simpleActionNames = [
"addSelection",
"addSelectionAfter",
"addSelectionBefore",
"breakLine",
"clearAndSetSelection",
"copyToClipboard",
Expand Down Expand Up @@ -52,9 +55,9 @@ export const simpleActionNames = [
"toggleLineBreakpoint",
"toggleLineComment",
"unfoldRegion",
"private.getTargets",
"private.setKeyboardTarget",
"private.showParseTree",
"private.getTargets",
] as const;

const complexActionNames = [
Expand Down
3 changes: 3 additions & 0 deletions packages/cursorless-engine/src/CommandHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ function sanitizeActionInPlace(action: ActionDescriptor): void {
delete action.options?.commandArgs;
break;

case "addSelection":
case "addSelectionAfter":
case "addSelectionBefore":
case "breakLine":
case "clearAndSetSelection":
case "copyToClipboard":
Expand Down
8 changes: 7 additions & 1 deletion packages/cursorless-engine/src/actions/Actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import GenerateSnippet from "./GenerateSnippet";
import GetTargets from "./GetTargets";
import GetText from "./GetText";
import Highlight from "./Highlight";
import { IndentLine, OutdentLine } from "./IndentLine";
import {
CopyContentAfter as InsertCopyAfter,
CopyContentBefore as InsertCopyBefore,
Expand All @@ -35,13 +36,15 @@ import Replace from "./Replace";
import Rewrap from "./Rewrap";
import { ScrollToBottom, ScrollToCenter, ScrollToTop } from "./Scroll";
import {
AddSelection,
AddSelectionAfter,
AddSelectionBefore,
SetSelection,
SetSelectionAfter,
SetSelectionBefore,
} from "./SetSelection";
import { SetSpecialTarget } from "./SetSpecialTarget";
import ShowParseTree from "./ShowParseTree";
import { IndentLine, OutdentLine } from "./IndentLine";
import {
ExtractVariable,
Fold,
Expand Down Expand Up @@ -73,6 +76,9 @@ export class Actions implements ActionRecord {
private modifierStageFactory: ModifierStageFactory,
) {}

addSelection = new AddSelection();
addSelectionBefore = new AddSelectionBefore();
addSelectionAfter = new AddSelectionAfter();
callAsFunction = new Call(this);
clearAndSetSelection = new Clear(this);
copyToClipboard = new CopyToClipboard(this, this.rangeUpdater);
Expand Down
71 changes: 58 additions & 13 deletions packages/cursorless-engine/src/actions/SetSelection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,23 @@ import type { Target } from "../typings/target.types";
import { ensureSingleEditor } from "../util/targetUtils";
import type { SimpleAction, ActionReturnValue } from "./actions.types";

export class SetSelection implements SimpleAction {
constructor() {
abstract class SetSelectionBase implements SimpleAction {
constructor(
private selectionMode: "set" | "add",
private rangeMode: "content" | "before" | "after",
) {
this.run = this.run.bind(this);
}

protected getSelection(target: Target) {
return target.contentSelection;
}

async run(targets: Target[]): Promise<ActionReturnValue> {
const editor = ensureSingleEditor(targets);
const targetSelections = this.getSelections(targets);

const selections =
this.selectionMode === "add"
? editor.selections.concat(targetSelections)
: targetSelections;

const selections = targets.map(this.getSelection);
await ide()
.getEditableTextEditor(editor)
.setSelections(selections, { focusEditor: true });
Expand All @@ -25,16 +29,57 @@ export class SetSelection implements SimpleAction {
thatTargets: targets,
};
}

private getSelections(targets: Target[]): Selection[] {
switch (this.rangeMode) {
case "content":
return targets.map((target) => target.contentSelection);
case "before":
return targets.map(
(target) =>
new Selection(target.contentRange.start, target.contentRange.start),
);
case "after":
return targets.map(
(target) =>
new Selection(target.contentRange.end, target.contentRange.end),
);
}
}
}

export class SetSelection extends SetSelectionBase {
constructor() {
super("set", "content");
}
}

export class SetSelectionBefore extends SetSelectionBase {
constructor() {
super("set", "before");
}
}

export class SetSelectionAfter extends SetSelectionBase {
constructor() {
super("set", "after");
}
}

export class SetSelectionBefore extends SetSelection {
protected getSelection(target: Target) {
return new Selection(target.contentRange.start, target.contentRange.start);
export class AddSelection extends SetSelectionBase {
constructor() {
super("add", "content");
}
}

export class AddSelectionBefore extends SetSelectionBase {
constructor() {
super("add", "before");
}
}

export class SetSelectionAfter extends SetSelection {
protected getSelection(target: Target) {
return new Selection(target.contentRange.end, target.contentRange.end);
export class AddSelectionAfter extends SetSelectionBase {
constructor() {
super("add", "after");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ export const defaultSpokenFormMapCore: DefaultSpokenFormMapDefinition = {

customRegex: {},
action: {
addSelection: "append",
addSelectionAfter: "append post",
addSelectionBefore: "append pre",
breakLine: "break",
scrollToBottom: "bottom",
toggleLineBreakpoint: "break point",
Expand Down
5 changes: 4 additions & 1 deletion packages/cursorless-org-docs/src/docs/user/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -531,9 +531,12 @@ Despite the name cursorless, some of the most basic commands in cursorless are f

Note that when combined with list targets, `take`/`pre`/`post` commands will result in multiple cursors.

- `"take <TARGET>"`: Selects the given target.
- `"pre <TARGET>"`: Places the cursor before the given target.
- `"post <TARGET>"`: Places the cursor after the given target.
- `"take <TARGET>"`: Selects the given target.
- `"append <TARGET>"`: Selects the given target, while preserving your existing selections.
- `"append pre <TARGET>"`: Adds a new cursor before the given target while preserving your existing selections.
- `"append post <TARGET>"`: Adds a new cursor after the given target, while preserving your existing selections.
- `"give <TARGET>"`: Deselects the given target.

eg:
Expand Down
Loading