Hammerspoon

up:: 05 Programming MOC

Overviews

Inspiration

Cheat sheets

Hyper Applications:

  • Obsidian - Hyper + O (research, notes, writing)
  • Firefox - Hyper + B (browser)
  • Brave - Hyper + K
  • Spotify - Hyper + S
  • Calendar - Hyper + C (review, planning, calendar)
  • Todoist - Hyper + T (review, planning)

Installing Spoons

spoon.SpoonInstall:andUse("WindowScreenLeftAndRight")

Loading Spoons

hs.loadSpoon("SpoonInstall")

Starting Application

hs.application.launchOrFocus("Safari")
local safari = hs.appfinder.appFromName("Safari")

Seeing the status of an application

function applicationWatcher(appName, eventType, appObject)
    if (eventType == hs.application.watcher.activated) then
        if (appName == "Finder") then
            -- Bring all Finder windows forward when one gets activated
            appObject:selectMenuItem({"Window", "Bring All to Front"})
        end
    end
end
appWatcher = hs.application.watcher.new(applicationWatcher)
appWatcher:start()

Opening an application

hs.application.open('com.brave.Browser')

Quitting an application

hs.application.find('com.todoist.mac.Todoist'):kill()

Names of Applications (run in console)

hs.fnutils.each(hs.application.runningApplications(), function(app) print(app:title()) end)

BundleID (run in console)

osascript -e 'id of app "Name of App"'

Start a chooser

hs.chooser.new(function(choice)
 
      local toggl = require('Spoons/Headspace/toggl')
      toggl.startTimer(hs.settings.get("secrets").toggl.projects.binge, choice.text)
 
      -- Open URL of choice
      hs.urlevent.openURL(choice.url)
    end)
    :choices({
      {
        text = 'Netflix',
        url = 'http://netflix.com/'
      },
      {
        text = 'Youtube',
        url = 'https://www.youtube.com/feed/subscriptions/'
      },
    })
    :placeholderText("What do you want to binge?")
      :show()

URL scheme

hammerspoon://move Parameters:

  • dir
    • r / l
    • 30 / 50 / 70
    • max
  • app

Example: hammerspoon://move?app=Obsidian&dir=l25

Usages

Application blocking

function stopApp(name)
  app = hs.application.get(name)
  if app and app:isRunning() then
    app:kill()
  end
end
 
function forceKillProcess(name)
  hs.execute("pkill " .. name)
end
 
function startApp(name)
  hs.application.open(name)
end

Config Reload

function reloadConfig(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
myWatcher = hs.pathwatcher.new(os.getenv("HOME") .. "/.hammerspoon/", reloadConfig):start()hs.alert.show("Config loaded")

Hotkey variables

ctrl_cmd = {"cmd", "ctrl"}
cmd_alt = {"cmd", "alt"}
shift_ctrl_cmd = {"shift", "cmd", "ctrl"}

Window management

hs.loadSpoon("SpoonInstall")
hs.loadSpoon("MiroWindowsManager")
 
hs.window.animationDuration = 0
spoon.MiroWindowsManager:bindHotkeys({
    up =         { cmd_alt, "up" },
    right =      { cmd_alt, "right" },
    down =       { cmd_alt, "down" },
    left =       { cmd_alt, "left" },
    fullscreen = { cmd_alt, "m" }
   }
)
 
spoon.SpoonInstall:andUse("WindowScreenLeftAndRight")
spoon.WindowScreenLeftAndRight.animationDuration = 0
spoon.WindowScreenLeftAndRight:bindHotkeys(
{
  screen_left = { ctrl_cmd, "Left" },
  screen_right= { ctrl_cmd, "Right" },
})

Headphone Switcher

-- BLUETOOTH HEADPHONE SWITCHER
function bluetooth_headphones_toggle(deviceName)
  local s = [[
    activate application "SystemUIServer"
    tell application "System Events"
      tell process "SystemUIServer"
        set btMenu to (menu bar item 1 of menu bar 1 whose description contains "bluetooth")
        tell btMenu
          click
 
          ]]
            ..
                    'tell (menu item "' .. deviceName .. '" of menu 1)'
            ..
            [[
 
 
          click
            if exists menu item "Connect" of menu 1 then
              click menu item "Connect" of menu 1
              return "Connecting..."
            else
              click menu item "Disconnect" of menu 1
              return "Disconecting..."
            end if
          end tell
        end tell
      end tell
    end tell
  ]]
 
  return hs.osascript.applescript(s)
  
end
 
hs.hotkey.bind(ctrl_cmd, "I", function()
  local ok, output = bluetooth_headphones_toggle('i9P')
  if ok then
    hs.alert.show(output)
  else
    hs.alert.show("Couldn't connect to AirPods!")
  end
end)
 
hs.hotkey.bind(ctrl_cmd, "N", function()
  local ok, output = bluetooth_headphones_toggle('Nightshade')
  if ok then
    hs.alert.show(output)
  else
    hs.alert.show("Couldn't connect to AirPods!")
  end
end)
 

Snip Highlight to Drafts

-- Snip current highlight in Brave
hyper:bind({}, 's', nil, function()
  hs.osascript.applescript([[
    -- stolen from: https://gist.github.com/gabeanzelini/1931128eb233b0da8f51a8d165b418fa
 
    if (count of theSelectionFromBrave()) is greater than 0 then
      set str to "tags: #link\n\n" & theTitleFromBrave() & "\n\n> " & theSelectionFromBrave() & "\n\n[" & theTitleFromBrave() & "](" & theCurrentUrlInBrave() & ")"
 
      tell application "Drafts"
        make new draft with properties {content:str, tags: {"link"}}
      end tell
    end if
 
 
    on theCurrentUrlInBrave()
      tell application "Brave Browser" to get the URL of the active tab in the first window
    end theCurrentUrlInBrave
 
    on theSelectionFromBrave()
      tell application "Brave Browser" to execute front window's active tab javascript "getSelection().toString();"
    end theSelectionFromBrave
 
    on theTitleFromBrave()
      tell application "Brave Browser" to get the title of the active tab in the first window
    end theTitleFromBrave
  ]])
  hs.notify.show("Snipped!", "The snippet has been sent to Drafts", "")
end)