Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into main_january25
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisnicollo committed Jan 31, 2025
2 parents 1ce1309 + b57dac8 commit 63e9a38
Show file tree
Hide file tree
Showing 163 changed files with 3,345 additions and 1,901 deletions.
5 changes: 5 additions & 0 deletions BREAKING_CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and when the change was applied given the delay between changes being
submitted and the time they were reviewed and merged.

---
* 2025-01-19 Deprecated a bunch of programming language operator commands in favor of using Talon lists
* 2024-12-3 Introduced an intermediate layer for naming snap window positions instead of using the raw spoken forms. Instead of calling snap_window_to_position("top right") you should now call snap_window_to_position("TOP_RIGHT")
* 2024-12-26 Deprecated action `user.zoom_close` in favor of `tracking.zoom_cancel`.
* 2024-11-24 Deprecated a bunch of symbol commands to insert delimited pairs
("", '', []) in favor of the new `delimiter_pair` Talon list file.
* 2024-09-07 Removed `get_list_from_csv` from `user_settings.py`. Please
use the new `track_csv_list` decorator, which leverages Talon's
`talon.watch` API for robustness on Talon launch.
Expand Down
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ Prose formatters (marked with \* in the help window) preserve hyphens and apostr

Reformat existing text with one or more formatters by selecting it, then saying the formatter name(s) followed by `that`. Say `help reformat` to display how each formatter reformats `one_two_three`.

Formatter names (snake, dubstring) are defined [here](core/text/formatters.py#L245). Formatter-related commands are defined in [text.talon](core/text/text.talon#L8).
Formatter names (snake, dubstring) are defined [here](core/formatters/formatters.py#L245). Formatter-related commands are defined in [text.talon](core/text/text.talon#L8).

### Mouse commands

Expand All @@ -144,7 +144,7 @@ Say `go up fifth` or `go up five times` to go up five lines. `select up third` w

### Window management

Global window managment commands are defined in [window_management.talon](core/windows_and_tabs/window_management.talon).
Global window management commands are defined in [window_management.talon](core/windows_and_tabs/window_management.talon).

- `running list` toggles a window displaying words you can say to switch to running applications. To customize the spoken forms for an app (or hide an app entirely from the list), edit the `app_name_overrides_<platform>.csv` files in the [core/app_switcher](core/app_switcher) directory.
- `focus chrome` will focus the Chrome application.
Expand Down Expand Up @@ -180,7 +180,6 @@ Python, C#, Talon and JavaScript language support is broken up into multiple tag
- `lang/tags/functions_common.{talon,py}` - common functions (also includes a GUI for picking functions)
- `lang/tags/imperative.{talon,py}` - statements (e.g., `if`, `while`, `switch`)
- `lang/tags/libraries.{talon,py}` - libraries and imports
- `lang/tags/libraries_gui.{talon,py}` - graphical helper for common libraries
- `lang/tags/object_oriented.{talon,py}` - objects and classes (e.g., `this`)
- `lang/tags/operators_array.{talon,py}` - array operators (e.g., Ruby's `x[0]`)
- `lang/tags/operators_assignment.{talon,py}` - assignment operators (e.g., C++'s `x += 5`)
Expand Down
6 changes: 6 additions & 0 deletions apps/adobe/adobe_acrobat_reader_dc_win.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,9 @@ def page_jump(number: int):

def page_final():
actions.key("end")

def page_rotate_right():
actions.key("shift-ctrl-0")

def page_rotate_left():
actions.key("shift-ctrl-1")
50 changes: 50 additions & 0 deletions apps/dock/dock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from pathlib import Path
from typing import Optional

from talon import Context, Module, actions, clip, ui

ctx = Context()
mod = Module()

ctx.matches = """
os: mac
"""


@mod.action_class
class Actions:
def dock_send_notification(notification: str):
"""Send a CoreDock notification to the macOS Dock using SPI"""

def dock_app_expose(app: Optional[ui.App] = None):
"""Activate macOS app Exposé via its Dock item (for the frontmost app if not specified)"""


@ctx.action_class("user")
class UserActions:
def dock_app_expose(app=None):
if app is None:
app = ui.active_app()

app_name = Path(app.path).stem
dock_items = ui.apps(bundle="com.apple.dock")[0].children.find(
AXSubrole="AXApplicationDockItem", AXTitle=app_name, max_depth=1
)
match len(dock_items):
case 1:
dock_items[0].perform("AXShowExpose")
case 0:
actions.app.notify(
body=f"No dock icon for “{app_name}”",
title="Unable to activate App Exposé",
)
case _:
actions.app.notify(
body=f"Multiple dock icons for “{app_name}”",
title="Unable to activate App Exposé",
)

def dock_send_notification(notification: str):
from talon.mac.dock import dock_notify

dock_notify(notification)
5 changes: 5 additions & 0 deletions apps/dock/dock.talon
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
os: mac
-
^desktop$: user.dock_send_notification("com.apple.showdesktop.awake")
^window$: user.dock_app_expose()
^launch pad$: user.dock_send_notification("com.apple.launchpad.toggle")
9 changes: 9 additions & 0 deletions apps/finder/finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,12 @@ def file_manager_select_file(path: str):
"""selects the file"""
actions.key("home")
actions.insert(path)

def address_focus():
actions.key("cmd-shift-g")

def address_copy_address():
actions.key("alt-cmd-c")

def address_navigate(address: str):
actions.user.file_manager_open_directory(address)
3 changes: 2 additions & 1 deletion apps/finder/finder.talon
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
os: mac
app: finder
-
tag(): user.address
tag(): user.file_manager
tag(): user.navigation
tag(): user.tabs
preferences: key(cmd-,)
options: key(cmd-j)
Expand All @@ -21,7 +23,6 @@ column view: key(cmd-3)
list view: key(cmd-2)
gallery view: key(cmd-4)

copy path: key(alt-cmd-c)
trash it: key(cmd-backspace)

hide [finder]: key(cmd-h)
Expand Down
6 changes: 6 additions & 0 deletions apps/foxit_reader/foxit_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,9 @@ def page_jump(number: int):
def page_final():
# actions.key("fn-right")
actions.key("end")

def page_rotate_right():
actions.key("shift-ctrl-keypad_plus")

def page_rotate_left():
actions.key("shift-ctrl-keypad_minus")
5 changes: 0 additions & 5 deletions apps/foxit_reader/foxit_reader.talon
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,3 @@ tag(): user.tabs
tag(): user.pages

tab close all: key(ctrl-shift-w)

[page] rotate right: key("shift-ctrl-keypad_equals")
[page] rotate left: key("shift-ctrl-keypad_minus")

go back: key(alt-left)
92 changes: 55 additions & 37 deletions apps/jetbrains/jetbrains.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import os
import os.path
import tempfile
import time
from pathlib import Path
from typing import Optional

import requests
from talon import Context, Module, actions, clip, ui
from talon import Context, Module, actions, app, clip, ui

# Courtesy of https://github.com/anonfunc/talon-user/blob/master/apps/jetbrains.py

extendCommands = []

# Each IDE gets its own port, as otherwise you wouldn't be able
# to run two at the same time and switch between them.
# Note that MPS and IntelliJ ultimate will conflict...
Expand All @@ -33,6 +31,7 @@
"google-android-studio": 8652,
"idea64.exe": 8653,
"IntelliJ IDEA": 8653,
"IntelliJ IDEA Community Edition": 8654,
"jetbrains-appcode": 8655,
"jetbrains-clion": 8657,
"jetbrains-datagrip": 8664,
Expand All @@ -56,58 +55,50 @@
"pycharm64.exe": 8658,
"WebStorm": 8663,
"webstorm64.exe": 8663,
"PhpStorm": 8662,
# Local plugin development:
"com.jetbrains.jbr.java": 8666,
}


def _get_nonce(port, file_prefix):
def _get_nonce(port: int, file_prefix: str) -> Optional[str]:
file_name = file_prefix + str(port)
try:
with open(os.path.join(tempfile.gettempdir(), file_name)) as fh:
return fh.read()
except FileNotFoundError as e:
except FileNotFoundError:
try:
home = str(Path.home())
with open(os.path.join(home, file_name)) as fh:
with open(Path.home() / file_name) as fh:
return fh.read()
except FileNotFoundError as eb:
except FileNotFoundError:
print(f"Could not find {file_name} in tmp or home")
return None
except OSError as e:
print(e)
return None


def send_idea_command(cmd):
print(f"Sending {cmd}")
def send_idea_command(cmd: str) -> str:
active_app = ui.active_app()
bundle = active_app.bundle or active_app.name
port = port_mapping.get(bundle, None)
if not port:
raise Exception(f"unknown application {bundle}")
nonce = _get_nonce(port, ".vcidea_") or _get_nonce(port, "vcidea_")
proxies = {"http": None, "https": None}
print(f"sending {bundle} {port} {nonce}")
if port and nonce:
response = requests.get(
f"http://localhost:{port}/{nonce}/{cmd}",
proxies=proxies,
timeout=(0.05, 3.05),
)
response.raise_for_status()
return response.text


def get_idea_location():
return send_idea_command("location").split()
if not nonce:
raise FileNotFoundError(f"Couldn't find IDEA nonce file for port {port}")

response = requests.get(
f"http://localhost:{port}/{nonce}/{cmd}",
proxies={"http": None, "https": None},
timeout=(0.05, 3.05),
)
response.raise_for_status()
return response.text

def idea_commands(commands):
command_list = commands.split(",")
print("executing jetbrains", commands)
global extendCommands
extendCommands = command_list
for cmd in command_list:
if cmd:
send_idea_command(cmd.strip())
time.sleep(0.1)

def get_idea_location() -> list[str]:
return send_idea_command("location").split()


ctx = Context()
Expand All @@ -133,22 +124,47 @@ def idea_commands(commands):
mod.apps.jetbrains = """
os: mac
and app.bundle: com.jetbrains.pycharm
"""
mod.apps.jetbrains = """
os: mac
and app.bundle: com.jetbrains.rider
"""
mod.apps.jetbrains = """
os: mac
and app.bundle: com.jetbrains.goland
"""
mod.apps.jetbrains = """
os: mac
and app.bundle: com.jetbrains.intellij.ce
"""
mod.apps.jetbrains = r"""
os: windows
and app.name: JetBrains Rider
os: windows
and app.exe: /^rider64\.exe$/i
"""

# Local plugin development:
mod.apps.jetbrains = """
os: mac
and app.bundle: com.jetbrains.jbr.java
"""


@mod.action_class
class Actions:

def idea(commands: str):
"""Send a command to Jetbrains product"""
idea_commands(commands)
command_list = commands.split(",")
try:
for cmd in command_list:
if cmd:
send_idea_command(cmd.strip())
actions.sleep(0.1)
except Exception as e:
app.notify(str(e))
raise

def idea_grab(times: int):
"""Copies specified number of words to the left"""
Expand All @@ -162,8 +178,6 @@ def idea_grab(times: int):
send_idea_command("action EditorPaste")
finally:
clip.set(old_clip)
global extendCommands
extendCommands = []


ctx.matches = r"""
Expand Down Expand Up @@ -286,6 +300,10 @@ def filename() -> str:

@ctx.action_class("user")
class UserActions:

def command_server_directory() -> str:
return "jetbrains-command-server"

def tab_jump(number: int):
# depends on plugin GoToTabs
if number < 10:
Expand Down
8 changes: 5 additions & 3 deletions apps/jetbrains/jetbrains.talon
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ tag(): user.multiple_cursors
tag(): user.splits
tag(): user.tabs
tag(): user.command_search
tag(): user.command_client

# multiple_cursors.py support end

# Auto complete
Expand Down Expand Up @@ -58,7 +60,7 @@ find (everywhere | all) <user.text> [over]:
recent: user.idea("action RecentFiles")

surround [this] with <user.text> [over]:
idea("action SurroundWith")
user.idea("action SurroundWith")
sleep(500ms)
insert(text)
# Making these longer to reduce collisions with real code dictation.
Expand All @@ -67,7 +69,7 @@ insert generated <user.text> [over]:
sleep(500ms)
insert(text)
insert template <user.text> [over]:
idea("action InsertLiveTemplate")
user.idea("action InsertLiveTemplate")
sleep(500ms)
insert(text)
create (template | snippet): user.idea("action SaveAsTemplate")
Expand All @@ -76,7 +78,7 @@ toggle recording: user.idea("action StartStopMacroRecording")
change (recording | recordings): user.idea("action EditMacros")
play recording: user.idea("action PlaybackLastMacro")
play recording <user.text> [over]:
idea("action PlaySavedMacrosAction")
user.idea("action PlaySavedMacrosAction")
insert(text)
sleep(500ms)
Key("enter")
Expand Down
2 changes: 1 addition & 1 deletion apps/kindle/kindle.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# --- App definition ---
mod = Module()
mod.apps.kindle = """
mod.apps.kindle = r"""
os: windows
and app.name: Kindle
os: windows
Expand Down
2 changes: 1 addition & 1 deletion apps/nitro_reader/nitro_reader_5.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# --- App definition ---
mod = Module()
mod.apps.nitro_reader_five = """
mod.apps.nitro_reader_five = r"""
os: windows
and app.name: Nitro Reader 5
os: windows
Expand Down
Loading

0 comments on commit 63e9a38

Please sign in to comment.