Skip to content

Commit 071739d

Browse files
Flash ranges in Cursorless everywhere (#2722)
When you do actions like copy we flash the ranges in vscode. This updates sends that information to the browser extension. ## Checklist - [/] I have added [tests](https://www.cursorless.org/docs/contributing/test-case-recorder/) - [/] I have updated the [docs](https://github.com/cursorless-dev/cursorless/tree/main/docs) and [cheatsheet](https://github.com/cursorless-dev/cursorless/tree/main/cursorless-talon/src/cheatsheet) - [/] I have not broken the cheatsheet
1 parent 85fd827 commit 071739d

File tree

9 files changed

+94
-8
lines changed

9 files changed

+94
-8
lines changed

cursorless-everywhere-talon/cursorless_everywhere_talon.py

+15-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33

44
from talon import Context, Module, actions
55

6-
from .cursorless_everywhere_types import EditorEdit, EditorState, SelectionOffsets
6+
from .cursorless_everywhere_types import (
7+
EditorEdit,
8+
EditorState,
9+
RangeOffsets,
10+
SelectionOffsets,
11+
)
712

813
mod = Module()
914

@@ -57,6 +62,14 @@ def cursorless_everywhere_edit_text(
5762
):
5863
"""Edit focused element text"""
5964

65+
def cursorless_everywhere_flash_ranges(
66+
ranges: list[RangeOffsets], # pyright: ignore [reportGeneralTypeIssues]
67+
):
68+
"""Flash ranges in focused element"""
69+
actions.skip()
70+
71+
# Private actions
72+
6073
def private_cursorless_talonjs_run_and_wait(
6174
command_id: str, # pyright: ignore [reportGeneralTypeIssues]
6275
arg1: Any = None,
@@ -71,5 +84,5 @@ def private_cursorless_talonjs_run_no_wait(
7184
):
7285
"""Executes a Cursorless command, but does not wait for it to finish, nor return the response"""
7386

74-
def private_cursorless_talonjs_get_response_json() -> str:
87+
def private_cursorless_talonjs_get_response_json() -> str: # pyright: ignore [reportReturnType]
7588
"""Returns the response from the last Cursorless command"""

cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py

+15
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from .cursorless_everywhere_types import (
44
EditorEdit,
55
EditorState,
6+
RangeOffsets,
67
SelectionOffsets,
78
)
89

@@ -61,6 +62,20 @@ def cursorless_everywhere_edit_text(
6162
if use_fallback(res):
6263
actions.next(edit)
6364

65+
def cursorless_everywhere_flash_ranges(
66+
ranges: list[RangeOffsets], # pyright: ignore [reportGeneralTypeIssues]
67+
):
68+
command = {
69+
"id": "flashRanges",
70+
"ranges": [
71+
js_object_to_python_dict(r, ["start", "end"])
72+
for r in js_array_to_python_list(ranges)
73+
],
74+
}
75+
res = rpc_get(command)
76+
if use_fallback(res):
77+
actions.next(ranges)
78+
6479

6580
def rpc_get(command: dict):
6681
return actions.user.run_rpc_command_get(RPC_COMMAND, command)

cursorless-everywhere-talon/cursorless_everywhere_types.py

+5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ class SelectionOffsets(TypedDict):
66
active: int
77

88

9+
class RangeOffsets(TypedDict):
10+
start: int
11+
end: int
12+
13+
914
class EditorState(TypedDict):
1015
text: str
1116
selections: list[SelectionOffsets]

packages/cursorless-everywhere-talon-core/src/ide/TalonJsIDE.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ import { Notifier, type KeyValueStore } from "@cursorless/common";
2424
import { pull } from "lodash-es";
2525
import type { Talon } from "../types/talon.types";
2626
import type { EditorState } from "../types/types";
27+
import { createTextEditor } from "./createTextEditor";
28+
import { flashRanges } from "./flashRanges";
2729
import { TalonJsCapabilities } from "./TalonJsCapabilities";
2830
import { TalonJsClipboard } from "./TalonJsClipboard";
2931
import { TalonJsConfiguration } from "./TalonJsConfiguration";
3032
import { TalonJsEditor } from "./TalonJsEditor";
31-
import { TalonJsMessages } from "./TalonJsMessages";
32-
33-
import { createTextEditor } from "./createTextEditor";
3433
import { TalonJsKeyValueStore } from "./TalonJsKeyValueStore";
34+
import { TalonJsMessages } from "./TalonJsMessages";
3535

3636
export class TalonJsIDE implements IDE {
3737
configuration: Configuration;
@@ -134,8 +134,8 @@ export class TalonJsIDE implements IDE {
134134
throw new Error("executeCommand not implemented.");
135135
}
136136

137-
flashRanges(_flashDescriptors: FlashDescriptor[]): Promise<void> {
138-
return Promise.resolve();
137+
flashRanges(flashDescriptors: FlashDescriptor[]): Promise<void> {
138+
return flashRanges(this.talon, flashDescriptors);
139139
}
140140

141141
setHighlightRanges(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { FlashDescriptor } from "@cursorless/common";
2+
import type { Talon } from "../types/talon.types";
3+
import type { RangeOffsets } from "../types/types";
4+
import { toCharacterRangeOffsets } from "./toCharacterRangeOffsets";
5+
6+
export function flashRanges(
7+
talon: Talon,
8+
flashDescriptors: FlashDescriptor[],
9+
): Promise<void> {
10+
const ranges = flashDescriptors.map(
11+
(descriptor): RangeOffsets =>
12+
toCharacterRangeOffsets(descriptor.editor, descriptor.range),
13+
);
14+
15+
talon.actions.user.cursorless_everywhere_flash_ranges(ranges);
16+
17+
return Promise.resolve();
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import type { GeneralizedRange, TextEditor } from "@cursorless/common";
2+
import type { RangeOffsets } from "../types/types";
3+
4+
export function toCharacterRangeOffsets(
5+
editor: TextEditor,
6+
range: GeneralizedRange,
7+
): RangeOffsets {
8+
if (range.type === "line") {
9+
const startLine = editor.document.lineAt(range.start).range;
10+
const endLine = editor.document.lineAt(range.end).range;
11+
return {
12+
start: editor.document.offsetAt(startLine.start),
13+
end: editor.document.offsetAt(endLine.end),
14+
};
15+
}
16+
return {
17+
start: editor.document.offsetAt(range.start),
18+
end: editor.document.offsetAt(range.end),
19+
};
20+
}

packages/cursorless-everywhere-talon-core/src/types/talon.types.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import type { EditorEdit, EditorState, SelectionOffsets } from "./types";
1+
import type {
2+
RangeOffsets,
3+
EditorEdit,
4+
EditorState,
5+
SelectionOffsets,
6+
} from "./types";
27

38
export type TalonNamespace = "user";
49

@@ -17,6 +22,7 @@ export interface TalonActions {
1722
cursorless_everywhere_get_editor_state(): EditorState;
1823
cursorless_everywhere_set_selections(selections: SelectionOffsets[]): void;
1924
cursorless_everywhere_edit_text(edit: EditorEdit): void;
25+
cursorless_everywhere_flash_ranges(ranges: RangeOffsets[]): void;
2026
};
2127
}
2228

packages/cursorless-everywhere-talon-core/src/types/types.ts

+5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ export interface SelectionOffsets {
1414
active: number;
1515
}
1616

17+
export interface RangeOffsets {
18+
start: number;
19+
end: number;
20+
}
21+
1722
export interface EditorState {
1823
text: string;
1924
languageId?: string;

packages/cursorless-everywhere-talon-e2e/src/talonMock.ts

+4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type {
2+
RangeOffsets,
23
EditorEdit,
34
EditorState,
45
SelectionOffsets,
@@ -53,6 +54,9 @@ const actions: TalonActions = {
5354
}
5455
_finalEditorState.text = edit.text;
5556
},
57+
cursorless_everywhere_flash_ranges(_ranges: RangeOffsets[]): void {
58+
// Do nothing
59+
},
5660
},
5761
};
5862

0 commit comments

Comments
 (0)