From eff61100242532e151c32c83cd8d7c4c924e5bb4 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 31 Dec 2024 11:05:46 +0100 Subject: [PATCH 1/8] Added support for browser rpc --- .../cursorless_everywhere_talon_browser.py | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py diff --git a/cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py b/cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py new file mode 100644 index 0000000000..e2be482fed --- /dev/null +++ b/cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py @@ -0,0 +1,53 @@ +from talon import Context, Module, actions + +from .cursorless_everywhere_types import EditorEdit, EditorState, SelectionOffsets + +mod = Module() + +mod.tag( + "cursorless_everywhere_talon_browser", + desc="Enable RPC to browser extension when using cursorless everywhere in Talon", +) + +ctx = Context() +ctx.matches = r""" +tag: user.cursorless_everywhere_talon_browser +""" + +RPC_COMMAND = "talonCommand" + + +@ctx.action_class("user") +class Actions: + def cursorless_everywhere_get_editor_state() -> EditorState: + command = {"type": "getActiveEditor"} + return actions.user.run_rpc_command_get(RPC_COMMAND, command) + + def cursorless_everywhere_set_selections( + selections: list[SelectionOffsets], # pyright: ignore [reportGeneralTypeIssues] + ): + command = { + "type": "setSelections", + "selections": get_serializable_selections(selections), + } + actions.user.run_rpc_command_and_wait(RPC_COMMAND, command) + + def cursorless_everywhere_edit_text( + edit: EditorEdit, # pyright: ignore [reportGeneralTypeIssues] + ): + command = {"type": "setText", "text": edit["text"]} + actions.user.run_rpc_command_and_wait(RPC_COMMAND, command) + + +# What is passed from cursorless everywhere js is a javascript object, which is not serializable for python. +def get_serializable_selections(selections: list[SelectionOffsets]): + result: list[SelectionOffsets] = [] + for i in range(selections.length): # pyright: ignore [reportAttributeAccessIssue] + selection = selections[i] + result.append( + { + "anchor": selection["anchor"], + "active": selection["active"], + } + ) + return result From 86ff8de37274de704c081e66c9e05915898769f7 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 31 Dec 2024 11:17:07 +0100 Subject: [PATCH 2/8] Enable Cursorless tag when Cursorless everywhere is enabled --- cursorless-everywhere-talon/cursorless_everywhere_talon.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cursorless-everywhere-talon/cursorless_everywhere_talon.py b/cursorless-everywhere-talon/cursorless_everywhere_talon.py index 6af329a51d..5cafb4d8fc 100644 --- a/cursorless-everywhere-talon/cursorless_everywhere_talon.py +++ b/cursorless-everywhere-talon/cursorless_everywhere_talon.py @@ -14,6 +14,8 @@ tag: user.cursorless_everywhere_talon """ +ctx.tags = ["user.cursorless"] + @ctx.action_class("user") class UserActions: From ea4f79a849d08ea1e99cfef676e407e77a2e0237 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 6 Jan 2025 11:57:26 +0100 Subject: [PATCH 3/8] Use fall back --- .../cursorless_everywhere_talon_browser.py | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py b/cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py index e2be482fed..cd5d8028ed 100644 --- a/cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py +++ b/cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py @@ -21,7 +21,10 @@ class Actions: def cursorless_everywhere_get_editor_state() -> EditorState: command = {"type": "getActiveEditor"} - return actions.user.run_rpc_command_get(RPC_COMMAND, command) + res = rpc_get(command) + if use_fallback(res): + return actions.next() + return res def cursorless_everywhere_set_selections( selections: list[SelectionOffsets], # pyright: ignore [reportGeneralTypeIssues] @@ -30,13 +33,25 @@ def cursorless_everywhere_set_selections( "type": "setSelections", "selections": get_serializable_selections(selections), } - actions.user.run_rpc_command_and_wait(RPC_COMMAND, command) + res = rpc_get(command) + if use_fallback(res): + actions.next(selections) def cursorless_everywhere_edit_text( edit: EditorEdit, # pyright: ignore [reportGeneralTypeIssues] ): command = {"type": "setText", "text": edit["text"]} - actions.user.run_rpc_command_and_wait(RPC_COMMAND, command) + res = rpc_get(command) + if use_fallback(res): + actions.next(edit) + + +def rpc_get(command: dict): + return actions.user.run_rpc_command_get(RPC_COMMAND, command) + + +def use_fallback(result: dict) -> bool: + return result.get("fallback", False) # What is passed from cursorless everywhere js is a javascript object, which is not serializable for python. From 1a64801efd989b1f9cac14cf5db9a7a5d8a7b940 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 6 Jan 2025 12:09:16 +0100 Subject: [PATCH 4/8] Clean up --- .../cursorless_everywhere_talon_browser.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py b/cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py index cd5d8028ed..f7f822fc9f 100644 --- a/cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py +++ b/cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py @@ -20,7 +20,9 @@ @ctx.action_class("user") class Actions: def cursorless_everywhere_get_editor_state() -> EditorState: - command = {"type": "getActiveEditor"} + command = { + "type": "getActiveEditor", + } res = rpc_get(command) if use_fallback(res): return actions.next() @@ -40,7 +42,10 @@ def cursorless_everywhere_set_selections( def cursorless_everywhere_edit_text( edit: EditorEdit, # pyright: ignore [reportGeneralTypeIssues] ): - command = {"type": "setText", "text": edit["text"]} + command = { + "type": "setText", + "text": edit["text"], + } res = rpc_get(command) if use_fallback(res): actions.next(edit) From fc80408dceb81f7dfa81d714ab3ec37ef74a7ef4 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 6 Jan 2025 12:12:36 +0100 Subject: [PATCH 5/8] Use get editor state command --- .../cursorless_everywhere_talon_browser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py b/cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py index f7f822fc9f..912404a584 100644 --- a/cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py +++ b/cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py @@ -21,7 +21,7 @@ class Actions: def cursorless_everywhere_get_editor_state() -> EditorState: command = { - "type": "getActiveEditor", + "type": "getEditorState", } res = rpc_get(command) if use_fallback(res): From 6546bf4ba4b3a150285241b285c02c3fc77b58f3 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 6 Jan 2025 12:25:43 +0100 Subject: [PATCH 6/8] Use id instead of type --- .../cursorless_everywhere_talon_browser.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py b/cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py index 912404a584..d1858580cb 100644 --- a/cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py +++ b/cursorless-everywhere-talon/cursorless_everywhere_talon_browser.py @@ -21,7 +21,7 @@ class Actions: def cursorless_everywhere_get_editor_state() -> EditorState: command = { - "type": "getEditorState", + "id": "getEditorState", } res = rpc_get(command) if use_fallback(res): @@ -32,7 +32,7 @@ def cursorless_everywhere_set_selections( selections: list[SelectionOffsets], # pyright: ignore [reportGeneralTypeIssues] ): command = { - "type": "setSelections", + "id": "setSelections", "selections": get_serializable_selections(selections), } res = rpc_get(command) @@ -43,7 +43,7 @@ def cursorless_everywhere_edit_text( edit: EditorEdit, # pyright: ignore [reportGeneralTypeIssues] ): command = { - "type": "setText", + "id": "setText", "text": edit["text"], } res = rpc_get(command) From 10672ece00796956d228785813eb9a31d128bbd7 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 7 Jan 2025 15:08:42 +0100 Subject: [PATCH 7/8] Add the type to module export --- cursorless-everywhere-talon/cursorless_everywhere_talon_win.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cursorless-everywhere-talon/cursorless_everywhere_talon_win.py b/cursorless-everywhere-talon/cursorless_everywhere_talon_win.py index f3e31dc930..e5aabbac0c 100644 --- a/cursorless-everywhere-talon/cursorless_everywhere_talon_win.py +++ b/cursorless-everywhere-talon/cursorless_everywhere_talon_win.py @@ -24,6 +24,9 @@ class Actions: def cursorless_everywhere_get_editor_state() -> EditorState: el = ui.focused_element() + print(el.patterns) + print(el) + if "Text2" not in el.patterns: raise ValueError("Focused element is not a text element") From 40a71a9c9baf7ae73c79bd9a29318c3b54bf9c12 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 7 Jan 2025 15:51:26 +0100 Subject: [PATCH 8/8] Remove debug prints --- cursorless-everywhere-talon/cursorless_everywhere_talon_win.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/cursorless-everywhere-talon/cursorless_everywhere_talon_win.py b/cursorless-everywhere-talon/cursorless_everywhere_talon_win.py index e5aabbac0c..f3e31dc930 100644 --- a/cursorless-everywhere-talon/cursorless_everywhere_talon_win.py +++ b/cursorless-everywhere-talon/cursorless_everywhere_talon_win.py @@ -24,9 +24,6 @@ class Actions: def cursorless_everywhere_get_editor_state() -> EditorState: el = ui.focused_element() - print(el.patterns) - print(el) - if "Text2" not in el.patterns: raise ValueError("Focused element is not a text element")