- Notifications
You must be signed in to change notification settings - Fork 51
Working with Hammerspoon
There's an undocumented function to preproccess console input: hs._consoleInputPreparser
You can set this to always wrap your input in hs.inspect with a custom depth:
hs._consoleInputPreparser = function(s) return 'hs.inspect('..s..', { depth = 2 } )' end hs._consoleInputPreparser = function(s) return 'u.toJson('..s..')' endIf this is your first time experimenting with Hammerspoon, I can recommend zzamboni's fantastic ebook, Getting Started with Hammerspoon.
When you first startup Hammerspoon, you'll see a macOS notification informing you that Hammerspoon couldn’t find a configuration file. To fix this, run the commands below in a terminal window:
❯ touch $HOME/.hammerspoon/init.lua ❯ vim $HOME/.hammerspoon/init.lua Let's add something to your Hammerspoon config just to confirm that everything is working properly:
hs.hotkey.bindSpec({ { "cmd", "alt", "ctrl" }, "s" }, function() hs.notify.show("Hello from Hammerspoon!", "Everything looks good here, cap'n.", "Next, let's set up stackline.") end )Add the snippet above to your Hammerspoon config file and save the file. Then, click the 'Hammer' icon in your menu bar and select "Reload Config". Now, when you enter cmd + alt + ctrl, a macOS notification should appear with the message you entered above.
Congrats! Now you know enough about Hammerspoon to setup Stackline. If you'd like to continue learning more Hammerspoon's powers, see this blog post will be your guide.
lua is a unique language. It can be beautiful once you understand it, and perplexing if you don't (as I didn't when first working on Stackline). If, like me, you're not yet comfortable with lua check out the 'Working with lua' page for some quality-of-life tips before reading on.
The sections below represent areas of Hammerpsoon that required research on my part. It's not an exhuastive list of tips for beginners, but it might save you some time.
hs.task is async. There are 2 ways to deal with this:
hs.timer.waitUntil(pollingCallback, func)hs.task.new(…):start():waitUntilUNex()
The 1st polls a callback to check if the expected result of the async task has materialized.
The 2nd makes hs.task behave synchronously.
The docs strongly discourage use of the 2nd approach, but as long as there isn't background work that could be done while waiting (there isn't in the use case I'm thinking of), then it should be slightly faster than polling since the callback will fire immediately when the task completes. It also saves the cycles needed to poll in the first place.
-- Wait until the win.stackIdx is set from async shell script hs.task.new("/usr/local/bin/dash", function(_code, stdout, stderr) callback(stdout) end, {cmd, args}):start():waitUntilExit() -- NOTE: timer.waitUntil is like 'await' in javascript hs.timer.waitUntil(winIdxIsSet, function() return data end) -- Checker func to confirm that win.stackIdx is set -- For hs.timer.waitUntil -- NOTE: Temporarily using hs.task:waitUntilExit() to accomplish the -- same thing function winIdxIsSet() if win.stackIdx ~= nil then return true end end Yet another project has a similar take:
if canvas then canvas:delete() endClear any pre-existing status display canvases
for state, display in pairs(self.displays) do if display ~= nil then display:delete() self.displays[state] = nil end end