diff --git a/README.md b/README.md index 5cff44a..5a03ae0 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,17 @@ brew install terminal-notifier # Configure Hammerspoon (~/.hammerspoon/init.lua) require("hs.ipc") require("hs.window") -require("hs.window.filter") -require("hs.timer") +require("hs.urlevent") + +-- cc-notifier: click-to-focus URL scheme handler +hs.urlevent.bind("focus", function(_, params) + local id = params and tonumber(params.id) + if not id then return end + local w = hs.window.get(id) + if w then + w:focus() + end +end) # Reload: hs -c "hs.timer.doAfter(0, hs.reload)" diff --git a/cc_notifier.py b/cc_notifier.py index a4dd5fe..623c4ce 100644 --- a/cc_notifier.py +++ b/cc_notifier.py @@ -9,7 +9,6 @@ import json import os import re -import shlex import socket import subprocess import sys @@ -495,37 +494,17 @@ def get_focused_window_id() -> tuple[str, str]: ) from e -def create_focus_command(window_id: str) -> list[str]: - """ - Create the Hammerspoon focus command for cross-space window focusing. - - This uses a dual-filter approach to avoid infinite hangs that occur - with setCurrentSpace(nil). The approach combines windows from current - and other spaces, then searches for the target window ID. +def create_focus_url(window_id: str) -> str: + """Create a Hammerspoon URL scheme for cross-space window focusing. - If the window cannot be found or focused, shows an error notification. + Uses hammerspoon:// URL scheme instead of hs CLI to avoid shell escaping + issues with terminal-notifier's -execute flag and eliminate hs CLI startup + overhead (~1.8s). - Args: - window_id: The window ID to focus - - Returns: - List of command arguments for subprocess execution + Requires the 'focus' URL event handler in Hammerspoon's init.lua. + See README for setup instructions. """ - # Template for complex dual-filter cross-space window focusing - # This solves the macOS Spaces issue without using setCurrentSpace(nil) which causes hangs - # Shows error notification if window can't be found - focus_script = f"""local current = require('hs.window.filter').new():setCurrentSpace(true):getWindows() -local other = require('hs.window.filter').new():setCurrentSpace(false):getWindows() -for _,w in pairs(other) do table.insert(current, w) end -for _,w in pairs(current) do - if w:id()=={window_id} then - w:focus() - require('hs.timer').usleep(300000) - return - end -end -require('hs.notify').new({{title="cc-notifier", informativeText="Could not restore window focus. Try reopening your terminal or IDE.", soundName="Basso"}}):send()""" - return [HAMMERSPOON_CLI, "-c", focus_script] + return f"hammerspoon://focus?id={window_id}" # ============================================================================ @@ -643,11 +622,9 @@ def send_notification( "-ignoreDnD", ] - # Add click-to-focus functionality if window ID provided + # Add click-to-focus via Hammerspoon URL scheme (avoids shell escaping issues) if focus_window_id: - focus_cmd = create_focus_command(focus_window_id) - execute_cmd = " ".join(shlex.quote(arg) for arg in focus_cmd) - cmd.extend(["-execute", execute_cmd]) + cmd.extend(["-open", create_focus_url(focus_window_id)]) # Send notification in background try: