347 lines
7.4 KiB
Lua
347 lines
7.4 KiB
Lua
-- vim: :foldmethod=marker
|
|
|
|
hs.application.enableSpotlightForNameSearches(true)
|
|
|
|
local utils = hs.fnutils
|
|
|
|
local DEFAULTS = {
|
|
["EDITOR"] = {"BBEdit"},
|
|
["CHAT"] = {"Telegram"},
|
|
["MESSENGER"] = {"Messages"},
|
|
["MUSIC"] = {"Doppler"},
|
|
}
|
|
|
|
local APPS = {
|
|
browser = {{"Zen"}, {"Safari"}},
|
|
editors = {DEFAULTS["EDITOR"], {"Xcode"}, {"Code", "Visual Studio Code"}, {"IntelliJ IDEA"}},
|
|
chats = {{"Microsoft Teams"}, {"Telegram"}},
|
|
messengers = {{"Messages"}, {"Telegram"}, {"Signal"}},
|
|
music = {DEFAULTS["MUSIC"], {"Music"}},
|
|
calendar = {"Calendar"},
|
|
terminal = {"iTerm", "iTerm2"},
|
|
videocalls = {}
|
|
}
|
|
|
|
-- Watchers {{{1
|
|
|
|
-- Cfg Watcher {{{2
|
|
function reload(files)
|
|
doReload = false
|
|
for _,file in pairs(files) do
|
|
if file:sub(-4) == ".lua" then
|
|
doReload = true
|
|
end
|
|
end
|
|
if doReload then
|
|
hs.reload()
|
|
end
|
|
end
|
|
|
|
cfgWatcher = hs.pathwatcher.new(os.getenv("HOME") .. "/.hammerspoon/", reload):start()
|
|
|
|
hs.alert.show("Config loaded")
|
|
|
|
-- Apps {{{1
|
|
|
|
-- Listeners {{{2
|
|
local listeners = {}
|
|
appWatcher = hs.application.watcher.new(function(name, event, app)
|
|
for i, v in ipairs(listeners) do
|
|
v(name, event, app)
|
|
end
|
|
end):start()
|
|
|
|
function app_listen(func)
|
|
listeners[#listeners+1] = func
|
|
end
|
|
|
|
-- {{{3 Terminal(s)
|
|
app_listen(function(name, event, app)
|
|
if app_matches(app, APPS["terminal"]) and event == hs.application.watcher.deactivated then
|
|
-- Don't hide terminal windows that have "claude" in the title
|
|
local shouldHide = true
|
|
for _, window in ipairs(app:allWindows()) do
|
|
if window:title() and string.find(string.lower(window:title()), "claude") then
|
|
shouldHide = false
|
|
break
|
|
end
|
|
end
|
|
if shouldHide then
|
|
app:hide()
|
|
end
|
|
elseif app_matches(app, {"Terminal"}) and event == hs.application.watcher.deactivated then
|
|
app:hide()
|
|
end
|
|
end)
|
|
|
|
|
|
-- Picker {{{2
|
|
|
|
function app_matches(app, names) --{{{3
|
|
--print("MATCHING: " .. app:name() .. " vs " .. hs.json.encode(names))
|
|
for i,v in ipairs(names) do
|
|
if app:name() == v then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function app_tofront(names) --{{{3
|
|
for i, v in ipairs(names) do
|
|
if hs.application.launchOrFocus(v) then
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
function app_exists(names) --{{{3
|
|
for i, v in pairs(names) do
|
|
local app = hs.application.get(v)
|
|
if app then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function app_is_running(apps, names) --it accepts list of apps to choose from for performance sake {{{3
|
|
for i, app in ipairs(apps) do
|
|
print(app)
|
|
for i, name in ipairs(names) do
|
|
if app:name() == name and #(app:allWindows()) > 0 then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
function app_toggle(names) --{{{3
|
|
local front = hs.application.frontmostApplication()
|
|
|
|
-- print(front)
|
|
|
|
if app_matches(front, names) then
|
|
--print("matches " .. front:name())
|
|
|
|
front:hide()
|
|
else
|
|
--print("not matches " .. front:name())
|
|
app_tofront(names)
|
|
end
|
|
|
|
--print("END TOGGLE")
|
|
end
|
|
|
|
|
|
function app_one_of(app, others) --{{{3
|
|
for i,v in ipairs(others) do
|
|
if app_matches(app, v) then
|
|
return v
|
|
end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
function app_pick_next_running(running, front, apps) --{{{3
|
|
local pick = false
|
|
for i,v in ipairs(apps) do
|
|
if app_matches(front, v) then
|
|
pick = true
|
|
goto continue
|
|
end
|
|
|
|
if pick and app_is_running(running, v) then
|
|
return v
|
|
end
|
|
|
|
::continue::
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
function app_pick_first_running(running, front, apps) --{{{3
|
|
for i,v in ipairs(apps) do
|
|
if app_is_running(running, v) then
|
|
return v
|
|
end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
function app_pick(prev, apps, limit_running) --{{{3
|
|
local default = apps[1]
|
|
local running = hs.application.runningApplications()
|
|
local front = hs.application.frontmostApplication()
|
|
local picked = app_pick_next_running(running, front, apps)
|
|
|
|
if picked then
|
|
app_toggle(picked)
|
|
return picked
|
|
end
|
|
|
|
if prev and app_is_running(running, prev) and not app_matches(front, prev) then
|
|
app_toggle(prev)
|
|
return prev
|
|
end
|
|
|
|
if app_is_running(running, default) then -- optimisation, don't check for if installed if it's running
|
|
app_toggle(default)
|
|
used = default
|
|
if prev and app_matches(front, prev) and not app_matches(front, default) then
|
|
front:hide()
|
|
end
|
|
|
|
return default
|
|
end
|
|
|
|
if app_exists(default) and not limit_running then
|
|
app_toggle(default)
|
|
if prev and app_matches(front, prev) and not app_matches(front, default) then
|
|
front:hide()
|
|
end
|
|
return default
|
|
end
|
|
|
|
local first = app_pick_first_running(running, front, apps)
|
|
if first then
|
|
app_toggle(first)
|
|
return first
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
|
|
-- Key Bindings {{{1
|
|
|
|
-- Apps {{{2
|
|
|
|
-- Editor {{{3
|
|
hs.hotkey.bind({"cmd", "alt" }, "I", (function()
|
|
local last_editor = nil
|
|
|
|
app_listen(function(name, event, app)
|
|
if app and event == hs.application.watcher.activated then
|
|
local match = app_one_of(app, APPS["editors"])
|
|
if match then
|
|
last_editor = match
|
|
end
|
|
end
|
|
end)
|
|
|
|
return function()
|
|
last_editor = app_pick(last_editor and utils.copy(last_editor) or nil, APPS["editors"], true)
|
|
end
|
|
end)())
|
|
|
|
-- Finder {{{3
|
|
hs.hotkey.bind({"ctrl", "alt"}, "F", function()
|
|
app_toggle({"Finder"})
|
|
end)
|
|
|
|
-- Fork {{{3
|
|
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "G", function()
|
|
app_toggle({"Fork"})
|
|
end)
|
|
|
|
-- Mail {{{3
|
|
hs.hotkey.bind({"cmd", "alt"}, "M", function()
|
|
app_toggle({"Mail"})
|
|
end)
|
|
|
|
-- Calendar {{{3
|
|
hs.hotkey.bind({"cmd", "alt"}, "C", function()
|
|
app_toggle(APPS["calendar"])
|
|
end)
|
|
|
|
-- Notes {{{3
|
|
hs.hotkey.bind({"cmd", "alt"}, "N", function()
|
|
app_toggle({"Notes"})
|
|
end)
|
|
|
|
-- Reminders {{{3
|
|
hs.hotkey.bind({"cmd", "alt"}, "R", function()
|
|
app_toggle({"Reminders"})
|
|
end)
|
|
|
|
-- Reminders Alt {{{3
|
|
hs.hotkey.bind({"ctrl", "alt"}, "R", function()
|
|
app_toggle({"Reminders"})
|
|
end)
|
|
|
|
-- Browser {{{3
|
|
hs.hotkey.bind({"cmd", "alt"}, "B", (function()
|
|
local last_browser = nil
|
|
|
|
return function()
|
|
last_browser = app_pick(last_browser and utils.copy(last_browser) or nil, APPS["browser"])
|
|
end
|
|
end)())
|
|
|
|
-- Git
|
|
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "G", function()
|
|
app_toggle({"Fork"})
|
|
end)
|
|
|
|
-- Music {{{3
|
|
hs.hotkey.bind({"cmd", "alt"}, "U", (function()
|
|
local last_music = nil
|
|
app_listen(function(name, event, app)
|
|
if app and event == hs.application.watcher.activated then
|
|
local match = app_one_of(app, APPS["music"])
|
|
if match then
|
|
last_music = match
|
|
end
|
|
end
|
|
end)
|
|
|
|
return function()
|
|
last_music = app_pick(last_music and utils.copy(last_music) or ni, APPS["music"], true)
|
|
end
|
|
end)())
|
|
|
|
-- Chat {{{3
|
|
hs.hotkey.bind({"cmd", "alt"}, "S", (function()
|
|
local last_chat = nil
|
|
|
|
return function()
|
|
last_chat = app_pick(last_chat and utils.copy(last_chat) or nil, APPS["chats"])
|
|
end
|
|
end)())
|
|
|
|
-- Terminal {{{3
|
|
hs.hotkey.bind({"cmd"}, "\\", function()
|
|
app_toggle(APPS["terminal"])
|
|
end)
|
|
|
|
-- Video Calls {{{3
|
|
hs.hotkey.bind({"cmd", "alt"}, "Z", function()
|
|
app_toggle(APPS["videocalls"])
|
|
end)
|
|
|
|
-- Messenger {{{3
|
|
hs.hotkey.bind({"cmd", "alt"}, "T", (function()
|
|
local last_messenger = nil
|
|
|
|
app_listen(function(name, event, app)
|
|
if app and event == hs.application.watcher.activated then
|
|
local match = app_one_of(app, APPS["messengers"])
|
|
if match then
|
|
last_messenger = match
|
|
end
|
|
end
|
|
end)
|
|
|
|
return function()
|
|
last_messenger = app_pick(last_messenger and utils.copy(last_messenger) or nil, APPS["messengers"], true)
|
|
end
|
|
end)())
|
|
|