I may believe that most computers contain unique customizations, which may be why most people hate reinstalling the operating systems or setting up a new computer.
Such as my laptop, there are a bunch of tools that improve my experience using a computer. Here is a non-exhaustive list:
App | Usage |
---|---|
SizeUp | Can easily attach the windows to the sides or corners of the screen. If the screen is big enough, you may put the documentation on the left and IDE on the right. |
Pap.er | It can periodically and automatically set a beautiful sightseeing image as your wallpaper. |
Stretchly | Timely covers your screen to make you have a rest. |
Lexico.com | The official site of the Oxford dictionary. |
Cheatsheet | It can show you the list of the selected application’s hotkeys. |
New Terminal Here | Open a terminal with the current folder path. |
Besides improving my experience in using a computer, these tools also cause a few inconveniences, especially when I need to reinstall the OS and set up a new laptop. I have to look for an alternative because sometimes one is no longer free of charge, or sometimes one no longer supports the latest OS. This didn’t bother me much until I changed my Macbook Pro thrice in half a year. So I tried to find a way to minimize the number of tools I relied on, and I found Hammerspoon. I can say this is really a Swiss Army Knife on macOS.
Actually, there are some similar tools, but Hammerspoon finds the best balance between usage simplicity and functionality complexity. The users only need a little knowledge of Lua before customizing with Hammerspoon. Under the situation of no experience in Lua, I quickly finished the customizing based on the official documentation.
We can customize with the official spoons, such as windows manipulation.
-- We can quickly implement this with the WinWin spoon
hs.loadSpoon("WinWin")
-- Check whether WinWin is loaded and bind hotkeys to different directions.
if spoon.WinWin then
-- Supporting symbol characters in the message of Hammerspoon is quite helpful. We will talk about this later. I will talk about this later.
-- Side
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "left", "Window ⬅", function() spoon.WinWin:moveAndResize("halfleft") end)
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "right", "Window ➡", function() spoon.WinWin:moveAndResize("halfright") end)
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "up", "Window ⬆", function() spoon.WinWin:moveAndResize("halfup") end)
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "down", "Window ⬇", function() spoon.WinWin:moveAndResize("halfdown") end)
-- Corner
hs.hotkey.bind({"shift", "alt", "ctrl"}, "left", "Window ↖", function() spoon.WinWin:moveAndResize("cornerNW") end)
hs.hotkey.bind({"shift", "alt", "ctrl"}, "right", "Window ↘", function() spoon.WinWin:moveAndResize("cornerSE") end)
hs.hotkey.bind({"shift", "alt", "ctrl"}, "up", "Window ↗", function() spoon.WinWin:moveAndResize("cornerNE") end)
hs.hotkey.bind({"shift", "alt", "ctrl"}, "down", "Window ↙", function() spoon.WinWin:moveAndResize("cornerSW") end)
-- Stretch
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "C", "Window Center", function() spoon.WinWin:moveAndResize("center") end)
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "M", "Window ↕↔", function() spoon.WinWin:moveAndResize("maximize") end)
-- Screen
hs.hotkey.bind({"alt", "ctrl"}, "right", "Window ➡ 🖥", function() spoon.WinWin:moveToScreen("next") end)
-- Other
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "/", "Window Undo", function() spoon.WinWin:undo() end)
end
Code language: PHP (php)
It is pretty easy, right? Only several hotkey bindings to functionality are enough.
We can also create spoons with the API, such as BreakTime.
To implement this, we need to periodically use a page or image to cover the whole screen to make the guys in front of the PC take a rest.
Firstly, we can quickly start a timer with hs.timer:
obj.Timer = hs.timer.new(60, refresh)
obj.Timer:start()
Code language: PHP (php)
Then, we can create a page covering the whole screen with hs.webview. Using a transparent image to make the page translucent is also not bad.
function makeBrowserOfBreakTime ()
local screen = require"hs.screen"
local webview = require"hs.webview"
local mainScreenFrame = screen:primaryScreen():frame()
browserFrame = {
x = mainScreenFrame.x,
y = mainScreenFrame.y,
h = mainScreenFrame.h,
w = mainScreenFrame.w
}
local options = {
developerExtrasEnabled = true,
}
-- local browser = webview.new(browserFrame, options):windowStyle(1+2+4+8)
local browser = webview.new(browserFrame, options):windowStyle(1+2+128)
:closeOnEscape(true)
:deleteOnClose(true)
:bringToFront(true)
:allowTextEntry(true)
:transparent(true)
return browser
end
Code language: PHP (php)
Next, we can show and remove the cover with browser:show()
and browser:delete()
periodically with the timer.
function refresh()
obj.curTime = obj.curTime + 1
if obj.curTime > obj.microbreakInterval then
obj.curMicrobreakCount = obj.curMicrobreakCount + 1
if obj.curMicrobreakCount > obj.microbreakCount then
hs.alert.show(obj.breakTime .. " minute break starts")
local browser = makeBrowserOfBreakTime();
browser:url("file://" .. hs.spoons.scriptPath() .. "BreakTime.html?time=" .. (obj.breakTime * 60 - 1)):show()
hs.timer.doAfter(obj.breakTime * 60, function()
if browser ~= nil then
browser:delete();
end
end)
obj.curMicrobreakCount = 0
else
hs.alert.show(obj.microbreakTime .. " second microbreak starts")
local browser = makeBrowserOfBreakTime();
browser:url("file://" .. hs.spoons.scriptPath() .. "BreakTime.html?time=" .. (obj.microbreakTime - 1)):show()
hs.timer.doAfter(obj.microbreakTime, function()
if browser ~= nil then
browser:delete();
end
end)
end
obj.curTime = obj.curTime - obj.microbreakInterval
end
end
Code language: JavaScript (javascript)
Load the BreakTime spoon in the same way to load the WinWin spoon, and start it. Done!
We can also customize the taskbar menu to improve the user experience.
Take BreakTime as an example. We can show the timeline of the next break.
Besides this, we can also show all the hotkeys defined with Hammerspoon.
Hammerspoon supports symbol characters quite well, so users can make the menu items more attractive. Isn’t this amazing? 😄
obj.menubar:setTitle("⌨️")
obj.menubar:setTooltip("Hot Key Info")
local hotkeys = hs.hotkey.getHotkeys()
local menuItem = {}
for key, value in pairs(hotkeys) do
local item = { title = value["msg"] }
table.insert(menuItem, item)
end
obj.menubar:setMenu(menuItem)
Code language: JavaScript (javascript)
Besides all the above, Hammerspoon still has much that needs going through. I am also keeping going through to make my customization more additional. Here’s mine.
BTW, not only reinstalling these tools, but I also need to reinstall all of the common applications such as VS Code, Plex, Sublime Text, VIM, etc. This is also terrible. Now I am maintaining a tap list containing the applications with homebrew. 😂