Skip to content

Commit

Permalink
Merge branch 'main' into fallback
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreasArvidsson committed Feb 21, 2024
2 parents 06edc07 + 76be55e commit d9f6f5a
Show file tree
Hide file tree
Showing 139 changed files with 1,589 additions and 1,369 deletions.
8 changes: 8 additions & 0 deletions changelog/2024-02-addedIncrementAndDecrementActions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
tags: [enhancement]
pullRequest: 2236
---

- Added increment action. Will increment a number. eg `"increment this"` to change `1` to `2`.

- Added decrement action. Will decrement a number. eg `"decrement this"` to change `2` to `1`.
2 changes: 2 additions & 0 deletions cursorless-talon/src/spoken_forms.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"comment": "toggleLineComment",
"copy": "copyToClipboard",
"crown": "scrollToTop",
"decrement": "decrement",
"dedent": "outdentLine",
"define": "revealDefinition",
"drink": "editNewLineBefore",
Expand All @@ -25,6 +26,7 @@
"give": "deselect",
"highlight": "highlight",
"hover": "showHover",
"increment": "increment",
"indent": "indentLine",
"inspect": "showDebugHover",
"join": "joinLines",
Expand Down
5 changes: 5 additions & 0 deletions docs/user/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,11 @@ For example:
- `"indent air"`
- `"dedent funk bat"`

### Increment / decrement

- `"increment <TARGET>"`: increment number target. eg change `1` to `2`.
- `"decrement <TARGET>"`: decrement number target. eg change `2` to `1`.

### Insert empty lines

- `"drink <TARGET>"`: Inserts a new line above the target line, and moves the cursor to the newly created line
Expand Down
2 changes: 1 addition & 1 deletion docs/user/experimental/snippets.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ To define your own snippets, proceed as follows:

### Define snippets in vscode

1. In your VSCode Cursorless settings (say `"cursorless settings"`), set the `cursorless.experimental.snippetsDir` setting to a directory in which you'd like to create your snippets.
1. In your VSCode Cursorless settings (say `"cursorless settings"`), set the `cursorless.experimental.snippetsDir` setting to a directory in which you'd like to create your snippets. You can use the `${userHome}` vairable to refer to your user home directory.
2. Add snippets to the directory in files ending in `.cursorless-snippets`. See the [documentation](snippet-format.md) for the cursorless snippet format.

### 2. Add snippet to spoken forms csvs
Expand Down
2 changes: 2 additions & 0 deletions packages/common/src/scopeSupportFacets/typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ export const typescriptScopeSupport: LanguageScopeSupportFacetMap = {
"type.field": supported,
"type.interface": supported,
"type.alias": supported,
"name.field": supported,
"value.field": supported,
};
2 changes: 2 additions & 0 deletions packages/common/src/types/command/ActionDescriptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const simpleActionNames = [
"clearAndSetSelection",
"copyToClipboard",
"cutToClipboard",
"decrement",
"deselect",
"editNewLineAfter",
"editNewLineBefore",
Expand All @@ -21,6 +22,7 @@ const simpleActionNames = [
"findInWorkspace",
"foldRegion",
"followLink",
"increment",
"indentLine",
"insertCopyAfter",
"insertCopyBefore",
Expand Down
2 changes: 2 additions & 0 deletions packages/cursorless-engine/src/CommandHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ function sanitizeActionInPlace(action: ActionDescriptor): void {
case "clearAndSetSelection":
case "copyToClipboard":
case "cutToClipboard":
case "decrement":
case "deselect":
case "editNewLineAfter":
case "editNewLineBefore":
Expand All @@ -152,6 +153,7 @@ function sanitizeActionInPlace(action: ActionDescriptor): void {
case "findInWorkspace":
case "foldRegion":
case "followLink":
case "increment":
case "indentLine":
case "insertCopyAfter":
case "insertCopyBefore":
Expand Down
5 changes: 4 additions & 1 deletion packages/cursorless-engine/src/actions/Actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ import Remove from "./Remove";
import Replace from "./Replace";
import Rewrap from "./Rewrap";
import { ScrollToBottom, ScrollToCenter, ScrollToTop } from "./Scroll";
import { SetSpecialTarget } from "./SetSpecialTarget";
import {
SetSelection,
SetSelectionAfter,
SetSelectionBefore,
} from "./SetSelection";
import { SetSpecialTarget } from "./SetSpecialTarget";
import ShowParseTree from "./ShowParseTree";
import {
CopyToClipboard,
Expand All @@ -61,6 +61,7 @@ import ToggleBreakpoint from "./ToggleBreakpoint";
import Wrap from "./Wrap";
import WrapWithSnippet from "./WrapWithSnippet";
import { ActionRecord } from "./actions.types";
import { Decrement, Increment } from "./incrementDecrement";

/**
* Keeps a map from action names to objects that implement the given action
Expand All @@ -77,6 +78,7 @@ export class Actions implements ActionRecord {
clearAndSetSelection = new Clear(this);
copyToClipboard = new CopyToClipboard(this.rangeUpdater);
cutToClipboard = new CutToClipboard(this);
decrement = new Decrement(this);
deselect = new Deselect();
editNew = new EditNew(this.rangeUpdater, this);
editNewLineAfter: EditNewAfter = new EditNewAfter(
Expand All @@ -96,6 +98,7 @@ export class Actions implements ActionRecord {
generateSnippet = new GenerateSnippet();
getText = new GetText();
highlight = new Highlight();
increment = new Increment(this);
indentLine = new IndentLine(this.rangeUpdater);
insertCopyAfter = new InsertCopyAfter(
this.rangeUpdater,
Expand Down
110 changes: 110 additions & 0 deletions packages/cursorless-engine/src/actions/incrementDecrement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { Range, TextEditor } from "@cursorless/common";
import { PlainTarget } from "../processTargets/targets";
import { SelectionWithEditor } from "../typings/Types";
import { Destination, Target } from "../typings/target.types";
import { MatchedText, matchText } from "../util/regex";
import { runForEachEditor } from "../util/targetUtils";
import { Actions } from "./Actions";
import { ActionReturnValue } from "./actions.types";

const REGEX = /-?\d+(\.\d+)?/g;

class IncrementDecrement {
constructor(
private actions: Actions,
private isIncrement: boolean,
) {
this.run = this.run.bind(this);
}

async run(targets: Target[]): Promise<ActionReturnValue> {
const thatSelections: SelectionWithEditor[] = [];

await runForEachEditor(
targets,
(target) => target.editor,
async (editor, targets) => {
const selections = await this.runOnEditor(editor, targets);
thatSelections.push(...selections);
},
);

return { thatSelections };
}

private async runOnEditor(
editor: TextEditor,
targets: Target[],
): Promise<SelectionWithEditor[]> {
const { document } = editor;
const destinations: Destination[] = [];
const replaceWith: string[] = [];

for (const target of targets) {
const offset = document.offsetAt(target.contentRange.start);
const text = target.contentText;
const matches = matchText(text, REGEX);

for (const match of matches) {
destinations.push(createDestination(editor, offset, match));
replaceWith.push(updateNumber(this.isIncrement, match.text));
}
}

const { thatSelections } = await this.actions.replace.run(
destinations,
replaceWith,
);

return thatSelections!;
}
}

export class Increment extends IncrementDecrement {
constructor(actions: Actions) {
super(actions, true);
}
}

export class Decrement extends IncrementDecrement {
constructor(actions: Actions) {
super(actions, false);
}
}

function createDestination(
editor: TextEditor,
offset: number,
match: MatchedText,
): Destination {
const target = new PlainTarget({
editor,
isReversed: false,
contentRange: new Range(
editor.document.positionAt(offset + match.index),
editor.document.positionAt(offset + match.index + match.text.length),
),
});
return target.toDestination("to");
}

function updateNumber(isIncrement: boolean, text: string): string {
return text.includes(".")
? updateFloat(isIncrement, text).toString()
: updateInteger(isIncrement, text).toString();
}

function updateInteger(isIncrement: boolean, text: string): number {
const original = parseInt(text);
const diff = 1;
return original + (isIncrement ? diff : -diff);
}

function updateFloat(isIncrement: boolean, text: string): number {
const original = parseFloat(text);
const isPercentage = Math.abs(original) <= 1.0;
const diff = isPercentage ? 0.1 : 1;
const updated = original + (isIncrement ? diff : -diff);
// Remove precision problems that would add a lot of extra digits
return parseFloat(updated.toPrecision(15)) / 1;
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ export const actions = {
deselect: "give",
highlight: "highlight",
showHover: "hover",
increment: "increment",
decrement: "decrement",
indentLine: "indent",
showDebugHover: "inspect",
setSelectionAfter: "post",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,6 @@ const wrapWithSnippetByNameAction: ActionDescriptor = {
variableName: "body",
},
};
const parseTreeAction: ActionDescriptor = {
name: "private.showParseTree",
target: decoratedPrimitiveTarget("a"),
};
const alternateHighlightAirAndBatAction: ActionDescriptor = {
name: "highlight",
target: {
Expand Down
Loading

0 comments on commit d9f6f5a

Please sign in to comment.