|
-- Hammerspoon: Focus Vivaldi browser, VSCode, Terminal, Finder, Chat, Spotify, and Terminal toggles with AppWindowSwitcher |
|
local hyper = {"ctrl", "alt", "cmd", "shift"} |
|
local lcag = {"ctrl", "alt", "cmd"} |
|
|
|
---@type table<string, string> |
|
local appLaunchMap = { |
|
["Vivaldi"] = "Vivaldi", |
|
["Code"] = "Visual Studio Code", |
|
["iTerm"] = "iTerm", |
|
["Terminal"] = "Terminal", |
|
["Finder"] = "Finder", |
|
["Spotify"] = "Spotify", |
|
["Discord"] = "Discord", |
|
["Slack"] = "Slack", |
|
["Signal"] = "Signal", |
|
["Notion"] = "Notion", |
|
["Todoist"] = "Todoist" |
|
} |
|
|
|
hs.loadSpoon("AppWindowSwitcher") -- :setLogLevel("debug") |
|
|
|
---@param appNames string[] |
|
---@return hs.window|nil |
|
local function findLastMatchingWindow(appNames) |
|
local switcher = spoon.AppWindowSwitcher |
|
local lastMatch = nil |
|
for _, w in pairs(hs.window.orderedWindows()) do |
|
if switcher.match(w, appNames) then |
|
lastMatch = w |
|
end |
|
end |
|
return lastMatch |
|
end |
|
|
|
---@param appNames string[] |
|
---@return hs.window|nil |
|
local function findFirstMatchingWindow(appNames) |
|
local switcher = spoon.AppWindowSwitcher |
|
for _, w in pairs(hs.window.orderedWindows()) do |
|
if switcher.match(w, appNames) then |
|
return w |
|
end |
|
end |
|
return nil |
|
end |
|
|
|
---@param appNames string[] |
|
local function launchApp(appNames) |
|
for _, appName in pairs(appNames) do |
|
if appLaunchMap[appName] then |
|
hs.application.launchOrFocus(appLaunchMap[appName]) |
|
return |
|
end |
|
end |
|
end |
|
|
|
---@param appNames string[] |
|
---@return function |
|
local function switchOrLaunch(appNames) |
|
return function() |
|
local focusedWindow = hs.window.focusedWindow() |
|
if not focusedWindow then |
|
return |
|
end |
|
|
|
local switcher = spoon.AppWindowSwitcher |
|
local targetWindow = nil |
|
|
|
if switcher.match(focusedWindow, appNames) then |
|
targetWindow = findLastMatchingWindow(appNames) |
|
else |
|
targetWindow = findFirstMatchingWindow(appNames) |
|
end |
|
|
|
if targetWindow then |
|
targetWindow:raise():focus() |
|
return |
|
end |
|
|
|
launchApp(appNames) |
|
end |
|
end |
|
|
|
hs.hotkey.bind({"alt"}, "b", switchOrLaunch({"Vivaldi"})) |
|
hs.hotkey.bind({"alt"}, "e", switchOrLaunch({"Code", "Zed"})) |
|
hs.hotkey.bind({"alt"}, "t", switchOrLaunch({"iTerm", "Terminal", "Warp"})) |
|
hs.hotkey.bind({"alt"}, "f", switchOrLaunch({"Finder"})) |
|
hs.hotkey.bind({"alt"}, "m", switchOrLaunch({"Spotify"})) |
|
hs.hotkey.bind({"alt"}, "c", switchOrLaunch({"Discord", "Slack", "Signal"})) |
|
hs.hotkey.bind({"alt"}, "n", switchOrLaunch({"Notion"})) |
|
hs.hotkey.bind({"alt"}, "s", switchOrLaunch({"Todoist"})) |
|
|
|
hs.loadSpoon("MiddleClickDragScroll"):start() |
|
|
|
hs.loadSpoon("HoldToMinimize"):start() |
|
|
|
clipboard_tool = hs.loadSpoon("ClipboardTool") |
|
clipboard_tool.show_copied_alert = false |
|
clipboard_tool:bindHotkeys({ |
|
toggle_clipboard = {{"ctrl"}, "v"} |
|
}) |
|
|
|
clipboard_tool:start() |
|
|
|
hs.loadSpoon("WindowHalfsAndThirds"):bindHotkeys({ |
|
max_toggle = {lcag, "up"}, |
|
left_half = {lcag, "left"}, |
|
right_half = {lcag, "right"}, |
|
third_left = {lcag, "1"}, |
|
third_right = {lcag, "3"}, |
|
larger = {lcag, "4"}, |
|
smaller = {lcag, "2"} |
|
}) |
|
|
|
-- GitHubPRMenu Spoon Configuration |
|
hs.loadSpoon("GitHubPRMenu") |
|
spoon.GitHubPRMenu:start() |
|
|
|
-- Optional: Customize refresh interval (default: 3600 seconds = 1 hour) |
|
-- spoon.GitHubPRMenu:setRefreshInterval(1800) -- 30 minutes |