One day, I installed some software with Homebrew — it was a month ago, so I can’t remember what. There were no immediate problems, except that two days later, when I rebooted my computer, Emacs, also installed by Homebrew, involuntarily failed to boot. I’m a heavy org-mode user, and occasionally need to write Common Lisp code in SLIME, which runs in Emacs.
My gut tells me that maybe a re-installation of Emacs will restore everything to normal. After reinstalling Emacs, I ran into another problem — the buttons added to the Touch Bar with BetterTouchTools couldn’t switch to Emacs Windows when it was already started.
To be sure, it’s not a big problem. After all, most of the time, the MacBook Pro is used as the host with the lid closed, and the Touch Bar is not used frequently when working. Also, you don’t need Emacs to paste code in languages like node.js — VSCode is more appropriate.
But it was annoying, so I decided to fix it — with Hammerspoon.
What is Hammerspoon?
Hammerspoon’s website has a good description of how the tool is positioned and how it works
This is a tool for powerful automation of OS X. At its core, Hammerspoon is just a bridge between the operating system and a Lua scripting engine. What gives Hammerspoon its power is a set of extensions that expose specific pieces of system functionality, to the user.
- It runs on OS X — macOS now;
- It’s designed to automate operations — just like it’s built into the system
Automator
Or third partyAlfred Workflow
Like that; - Its principle is to encapsulate the functions of the operating system into usable
Lua
The module that the code calls;
For example, the following code
hs.hotkey.bind({"cmd"."alt"."ctrl"}, "E".function(a)
hs.alert.show("Hello World!")
end)
Copy the code
Allows the user to invoke Hello World to the center of the screen while pressing the ⌘⌥⌃e key. This text is
Why Hammerspoon?
Hammerspoon solves my problem with its hs.window module, which allows users to either traverse all open Windows (using the hs.window.allWindows function) or focus on a specific window (using the focus method). With them, it’s a natural progression to move Emacs to front-most:
- Call a function
hs.window.allWindows
Function to get a list of all Windows; - Check window objects in the list one by one if they belong to
Emacs
Call the window methodfocus
“And out of the loop.
The remaining two questions are:
Emacs
thebundle ID
What is;- How do I know a window object
bundle ID
.
Emacs的bundle ID
The Bundle ID uniquely identifies an application in macOS. Want to know what is the bundle ID of Emacs, only need to open the file/Applications/Emacs. The app/Contents/Info. The plist, look at the key CFBundleIdentifier value.
➜ Contents grep -A 1 'CFBundleIdentifier' Info.plist
<key>CFBundleIdentifier</key>
<string>org.gnu.Emacs</string>
➜ Contents
Copy the code
As you can see, the bundle ID of Emacs is org.gnu.
A little Lua code
Armed with the Bundle ID of Emacs, you can now define shortcuts in Hammerspoon. Since this set of shortcuts will eventually be triggered by buttons on the Touch Bar, it doesn’t matter if they are more complex, so I just use the ⌘⌥⌃ W in Hammerspoon’s starter guide as an example
hs.hotkey.bind({"cmd"."alt"."ctrl"}, "W".function(a)
end)
Copy the code
To iterate through window objects one by one in a loop, save the return value of hs.window.allWindows to a local variable
hs.hotkey.bind({"cmd"."alt"."ctrl"}, "W".function(a)
local windows = hs.window.allWindows()
end)
Copy the code
Follow the example of this article in Jane’s book to iterate through the variable Windows using for and Pairs
hs.hotkey.bind({"cmd"."alt"."ctrl"}, "W".function(a)
local windows = hs.window.allWindows()
- in Lua traverses the table method: https://www.jianshu.com/p/de5a4b132918
for _, win in pairs(windows) do
end
end)
Copy the code
The window itself does not have a bundle ID, so you need to obtain the application to which the window belongs. As you can see from the documentation, there is an Application method that is used to get the application object
hs.hotkey.bind({"cmd"."alt"."ctrl"}, "W".function(a)
local windows = hs.window.allWindows()
- in Lua traverses the table method: https://www.jianshu.com/p/de5a4b132918
for _, win in pairs(windows) do
local app = win:application()
end
end)
Copy the code
AllWindows is called with an English period (.) Application is called with a colon (:), which is the syntactic difference between calling functions and methods in Lua.
Use the application’s bundleID method to get its Bundle ID
hs.hotkey.bind({"cmd"."alt"."ctrl"}, "W".function(a)
local windows = hs.window.allWindows()
- in Lua traverses the table method: https://www.jianshu.com/p/de5a4b132918
for _, win in pairs(windows) do
local app = win:application()
local bundleID = app:bundleID()
end
end)
Copy the code
Now, as long as the variable bundleID equals the Bundle ID of Emacs, you can focus on the window being traversed
hs.hotkey.bind({"cmd"."alt"."ctrl"}, "W".function(a)
local windows = hs.window.allWindows()
- in Lua traverses the table method: https://www.jianshu.com/p/de5a4b132918
for _, win in pairs(windows) do
local app = win:application()
local bundleID = app:bundleID()
if bundleID == "org.gnu.Emacs" then
win:focus()
end
end
end)
Copy the code
Let the Touch Bar button trigger it all
Just configure it in BetterTouchTools
This method is better than the previous method of invoking /Applications/ emacs.app because it relies only on the logical impermanence of Emacs — the bundle ID — and not on its physical installation location.
Read the original