from talon import Context, Module, actions, app is_mac = app.platform == "mac" ctx = Context() mac_ctx = Context() mod = Module() mod.apps.vscode = """ os: mac and app.bundle: com.microsoft.VSCode os: mac and app.bundle: com.microsoft.VSCodeInsiders os: mac and app.bundle: com.visualstudio.code.oss os: mac and app.bundle: com.todesktop.230313mzl4w4u92 """ mod.apps.vscode = """ os: linux and app.name: Code os: linux and app.name: code-oss os: linux and app.name: code-insiders os: linux and app.name: VSCodium os: linux and app.name: Codium os: linux and app.name: Cursor """ mod.apps.vscode = r""" os: windows and app.name: Visual Studio Code os: windows and app.name: Visual Studio Code Insiders os: windows and app.name: Visual Studio Code - Insiders os: windows and app.exe: /^code\.exe$/i os: windows and app.exe: /^code-insiders\.exe$/i os: windows and app.name: VSCodium os: windows and app.exe: /^vscodium\.exe$/i os: windows and app.name: Azure Data Studio os: windows and app.exe: /^azuredatastudio\.exe$/i """ ctx.matches = r""" app: vscode """ mac_ctx.matches = r""" os: mac app: vscode """ @ctx.action_class("app") class AppActions: # talon app actions def tab_open(): actions.user.vscode("workbench.action.files.newUntitledFile") def tab_close(): actions.user.vscode("workbench.action.closeActiveEditor") def tab_next(): actions.user.vscode("workbench.action.nextEditorInGroup") def tab_previous(): actions.user.vscode("workbench.action.previousEditorInGroup") def tab_reopen(): actions.user.vscode("workbench.action.reopenClosedEditor") def window_close(): actions.user.vscode("workbench.action.closeWindow") def window_open(): actions.user.vscode("workbench.action.newWindow") @ctx.action_class("code") class CodeActions: # talon code actions def toggle_comment(): actions.user.vscode("editor.action.commentLine") @ctx.action_class("edit") class EditActions: # talon edit actions def indent_more(): actions.user.vscode("editor.action.indentLines") def indent_less(): actions.user.vscode("editor.action.outdentLines") def save_all(): actions.user.vscode("workbench.action.files.saveAll") def find_next(): actions.user.vscode("editor.action.nextMatchFindAction") def find_previous(): actions.user.vscode("editor.action.previousMatchFindAction") def line_swap_up(): actions.key("alt-up") def line_swap_down(): actions.key("alt-down") def line_clone(): actions.key("shift-alt-down") def line_insert_down(): actions.user.vscode("editor.action.insertLineAfter") def line_insert_up(): actions.user.vscode("editor.action.insertLineBefore") def jump_line(n: int): actions.user.vscode("workbench.action.gotoLine") actions.insert(str(n)) actions.key("enter") actions.edit.line_start() def zoom_reset(): actions.user.vscode("workbench.action.zoomReset") @ctx.action_class("win") class WinActions: def filename(): title = actions.win.title() # this doesn't seem to be necessary on VSCode for Mac # if title == "": # title = ui.active_window().doc if is_mac: result = title.split(" — ")[0] else: result = title.split(" - ")[0] if "." in result: return result return "" @mod.action_class class Actions: def vscode_terminal(number: int): """Activate a terminal by number""" actions.user.vscode(f"workbench.action.terminal.focusAtIndex{number}") def command_palette(): """Show command palette""" actions.key("ctrl-shift-p") @mac_ctx.action_class("edit") class MacEditActions: def find(text: str = None): actions.key("cmd-f") if text: actions.insert(text) @mac_ctx.action_class("user") class MacUserActions: def command_palette(): actions.key("cmd-shift-p") @ctx.action_class("user") class UserActions: # splits.py support begin def split_clear_all(): actions.user.vscode("workbench.action.editorLayoutSingle") def split_clear(): actions.user.vscode("workbench.action.joinTwoGroups") def split_flip(): actions.user.vscode("workbench.action.toggleEditorGroupLayout") def split_maximize(): actions.user.vscode("workbench.action.toggleMaximizeEditorGroup") def split_reset(): actions.user.vscode("workbench.action.evenEditorWidths") def split_last(): actions.user.vscode("workbench.action.focusLeftGroup") def split_next(): actions.user.vscode_and_wait("workbench.action.focusRightGroup") def split_window_down(): actions.user.vscode("workbench.action.moveEditorToBelowGroup") def split_window_horizontally(): actions.user.vscode("workbench.action.splitEditorOrthogonal") def split_window_left(): actions.user.vscode("workbench.action.moveEditorToLeftGroup") def split_window_right(): actions.user.vscode("workbench.action.moveEditorToRightGroup") def split_window_up(): actions.user.vscode("workbench.action.moveEditorToAboveGroup") def split_window_vertically(): actions.user.vscode("workbench.action.splitEditor") def split_window(): actions.user.vscode("workbench.action.splitEditor") def split_number(index: int): supported_ordinals = [ "First", "Second", "Third", "Fourth", "Fifth", "Sixth", "Seventh", "Eighth", ] if 0 <= index - 1 < len(supported_ordinals): actions.user.vscode( f"workbench.action.focus{supported_ordinals[index - 1]}EditorGroup" ) # splits.py support end # multiple_cursor.py support begin # note: vscode has no explicit mode for multiple cursors def multi_cursor_add_above(): actions.user.vscode("editor.action.insertCursorAbove") def multi_cursor_add_below(): actions.user.vscode("editor.action.insertCursorBelow") def multi_cursor_add_to_line_ends(): actions.user.vscode("editor.action.insertCursorAtEndOfEachLineSelected") def multi_cursor_disable(): actions.key("escape") def multi_cursor_enable(): actions.skip() def multi_cursor_select_all_occurrences(): actions.user.vscode("editor.action.selectHighlights") def multi_cursor_select_fewer_occurrences(): actions.user.vscode("cursorUndo") def multi_cursor_select_more_occurrences(): actions.user.vscode("editor.action.addSelectionToNextFindMatch") def multi_cursor_skip_occurrence(): actions.user.vscode("editor.action.moveSelectionToNextFindMatch") # multiple_cursor.py support end def command_search(command: str = ""): actions.user.vscode("workbench.action.showCommands") if command != "": actions.insert(command) # tabs.py support begin def tab_jump(number: int): if number < 10: if is_mac: actions.user.vscode_with_plugin( f"workbench.action.openEditorAtIndex{number}" ) else: actions.key(f"alt-{number}") else: actions.user.vscode_with_plugin( "workbench.action.openEditorAtIndex", number ) def tab_final(): if is_mac: actions.user.vscode("workbench.action.lastEditorInGroup") else: actions.key("alt-0") def tab_duplicate(): # Duplicates the current tab into a new tab group # vscode does not allow duplicate tabs in the same tab group, and so is implemented through splits actions.user.split_window_vertically() # tabs.py support end # find_and_replace.py support begin def find_everywhere(text: str): """Triggers find across project""" if is_mac: actions.key("cmd-shift-f") else: actions.key("ctrl-shift-f") if text: actions.insert(text) def find_toggle_match_by_case(): """Toggles find match by case sensitivity""" if is_mac: actions.key("alt-cmd-c") else: actions.key("alt-c") def find_toggle_match_by_word(): """Toggles find match by whole words""" if is_mac: actions.key("cmd-alt-w") else: actions.key("alt-w") def find_toggle_match_by_regex(): """Toggles find match by regex""" if is_mac: actions.key("cmd-alt-r") else: actions.key("alt-r") def replace(text: str): """Search and replaces in the active editor""" if is_mac: actions.key("alt-cmd-f") else: actions.key("ctrl-h") if text: actions.insert(text) def replace_everywhere(text: str): """Search and replaces in the entire project""" if is_mac: actions.key("cmd-shift-h") else: actions.key("ctrl-shift-h") if text: actions.insert(text) def replace_confirm(): """Confirm replace at current position""" if is_mac: actions.key("shift-cmd-1") else: actions.key("ctrl-shift-1") def replace_confirm_all(): """Confirm replace all""" if is_mac: actions.key("cmd-enter") else: actions.key("ctrl-alt-enter") def select_previous_occurrence(text: str): actions.edit.find(text) actions.sleep("100ms") actions.key("shift-enter esc") def select_next_occurrence(text: str): actions.edit.find(text) actions.sleep("100ms") actions.key("esc") def insert_snippet(body: str): actions.user.run_rpc_command("editor.action.insertSnippet", {"snippet": body})