Terminal Nirvana on Snow Leopard with SIMBL + Visor
Note 1: The method described here should also work in Mac OS X Leopard or Tiger, just get the appropriate versions of SIMBL / Visor.
Note 2: If you don’t want everything on my bullet list, just follow the steps appropriate for what you want to accomplish.
Note 3: I have provided .patch files, etc. at the bottom of the post for those who, like me, are a bit lazy.
What is Terminal Nirvana?
As a developer, Terminal is one of my best friends. Maybe you can relate. I have constantly been in search of the ultimate Terminal configuration, and it has ever eluded me… until now.
But what is Terminal Nirvana? Here are my criteria:
- I want the Home / End keys to move the cursor to the front / end of the line. I grew up on Windows, and I like the keys to function this way. To me, it just makes sense. Unfortunately, KeyFixer doesn’t work in Terminal (but I highly recommend it for changing the behavior in most other apps!).
- I don’t want Home / End to behave differently when I am in a screen session. I use screen all the time, and Home / End need to behave consistently.
- I don’t want Home / End to do unexpected things in VIM – ever. Pressing Home / End in VIM should, at the very least, not do weird things like delete lines, whether I am in a screen session or not.
- I want my terminal window available at all times. With as much as I use the terminal, opening Terminal.app all the time feels wasteful. There should be a better way. This is where SIMBL and Visor come in.
- I don’t want it to show up in the Dock, or in my Command + Tab list. As useful as Terminal is, there are a lot of other useful applications around, and I use a lot of them. Since I always want Terminal open anyway, it is annoying to constantly avoid / ignore / tab over it when I am using Command + Tab to switch to another running application. Oh, and it should stay away from my Dock, too.
- I want good, configurable colors in my shell. Fortunately, Visor takes care of this one by including TerminalColours as part of the package, so you get this one “for free.”
Sound like a tall order? It took me a few hours crawling around the web and experimenting to come up with a good solution, but I managed it in the end. Hopefully my experience can help save a few people some time in the future.
This is how I did it.
First things first
Home / End keys
To change the Home / End keys in Terminal.app, you are going to need to go to Terminal -> Preferences -> [Settings] -> [Keyboard]. Remember, settings are profile-specific, so you will need to make the changes to any profiles you care about. (Note: Visor uses the “Visor” profile, regardless of what you set as your default profile. What I do is rename the automatically-created “Visor” profile, configure my default profile, and then duplicate it with the name “Visor”.)
The first thing I tried was changing the keybindings to “\001” and “\005” per the instructions I found on Ricky Campbell’s blog. This seemed to make sense; CTRL+A and CTRL+E move the cursor to the front / end of the line in Terminal. And I thought it was working perfectly, for a few glorious moments…
Unfortunately, CTRL+A is also the key combination to start a command in screen. So when I launched screen, suddenly my home key didn’t work anymore, and I randomly started sending screen commands when I used it.
I also tried using a ~/.inputrc file and the keybindings “\033[1~” and “\033[4~” as discussed on two blogs I stumbled across while looking for an alternate solution. Now, I really thought I had the problem licked. Except, Home / End did weird things in VIM running within a screen session, and the necessity of using an additional .inputrc file was just a bit of a bummer.
Turns out Shift + Home and Shift + End already did what I wanted, so the simplest solution of all is to just copy those keybindings already present in the Terminal settings. For good measure, I copied the “shift page up” and “shift page down” bindings to “page up” and “page down.” (Note: you can either copy-paste the existing values, or hit ESC to get the \033 value and then type the other characters manually.)
Terminal key bindings:
- Value: \033[H
- Value: \033[F
- page up
- Value: \033[5~
- page down
- Value: \033[6~
Fixing VIM in screen
Okay, almost there with the keybindings. If you run VIM inside a screen session, you will notice that Home deletes the current line, and using the arrow keys while in insert mode inserts A / B / C / D rather than moving the cursor. Not good.
A little tweak to your existing ~/.vimrc file will fix it right up (or, if you don’t have an existing ~/.vimrc, create it). (Note: the easiest way to get the proper escape characters is to enter insert mode, and hit CTRL+V followed by the Home or End key. This will add the ^[ escape character, as well as the [F or [H characters. Do the same thing for CTRL + O to get the ^O escape character.) By using CTRL+O on the imap lines, we make the Home / End keys work the same way in insert mode or command mode.
As an added bonus, this fixes the arrow keys while in insert mode. Though, to be honest, I have no idea why…
""" ~/.vimrc """ Fix home and end keybindings for screen map ^[[F $ imap ^[[F ^O$ map ^[[H g0 imap ^[[H ^Og0
Making Terminal always available
This one was actually pretty simple. Using SIMBL and Visor (both compatible with 64-bit Terminal at the time of this writing) you can get Terminal to dock to the top / side / bottom of your screen, and configure it to open with a keystroke you can define.
My keystroke is Command + Esc (turn off Front Row first, if you hate it as much as I do). Once Terminal has been launched for the first time (thus creating the Visor window), this keystroke gets you in from anywhere, or hides it when you are done.
Hiding the Dock icon, and removing Terminal from the Command + Tab list
This is the most involved step, but it also provides one of the biggest benefits in my mind. Most of the information here comes from a MetaSkills blog article.
In order to accomplish this, the LSUIElement key in Terminal’s Info.plist must be set to “1”. This disables the Dock icon and removes the application from the Command + Tab list. Don’t want to completely prevent Terminal from ever functioning like a normal application? The quick solution is to create new application “VisorTerminal.app” which is used for Visor, while leaving Terminal.app alone to function as normal. (This is actually a good thing, because another side-effect of setting LSUIElement : 1 is you no longer have anything change in the menubar when you are in your application… ie, you can’t click on VisorTerminal next to the Apple icon, and go into Preferences.)
Create a new VisorTerminal.app
Duplicate the existing Terminal.app.
cp -r /Applications/Utilities/Terminal.app /Applications/Utilities/VisorTerminal.app
Once you have duplicated Terminal.app, you need to change a few bundle identifiers in your new application so the two appear as distinct entities to Mac OS X. In other words, change “Terminal” to “VisorTerminal” in a few places. This is also when you add LSUIElements : 1.
<!-- /Applications/Utilities/VisorTerminal.app/Contents/Info.plist --> ... <key>CFBundleDisplayName</key> <string>VisorTerminal</string> ... <key>CFBundleIdentifier</key> <string>com.apple.VisorTerminal</string> ... <key>CFBundleName</key> <string>VisorTerminal</string> ... <!-- Note: Put this right before the closing </dict></plist> at the end of the file --> <key>LSUIElement</key> <string>1</string> ...
At this point, rather than entering my preferences all over again, I elected to copy my Terminal.app preferences. Repeat this step any time you make preference changes that you want to copy over. (Note: using a symlink does not seem to work. If you make changes while in VisorTerminal, such as changing the Visor hotkey, the modified file is saved over your symlink.)
cp ~/Library/Preferences/com.apple.Terminal.plist ~/Library/Preferences/com.apple.VisorTerminal.plist
Modify Visor to use VisorTerminal.app
Once your new application is created and ready to go, you need to tell Visor to activate for that application rather than Terminal.app. Apply the following very familiar tweaks to Visor’s Info.plist:
<!-- ~/Library/Application\ Support/SIMBL/Plugins/Visor.bundle/Contents/Info.plist --> ... <key>BundleIdentifier</key> <string>com.apple.VisorTerminal</string> ... <key>ExecPattern</key> <string>*/VisorTerminal.app/Contents/MacOS/Terminal</string> ... <key>BundleIdentifier</key> <string>com.apple.VisorTerminal</string> ...
Once this last step is done, you are almost there. Make sure Terminal.app and VisorTerminal.app are both closed. Now, launch VisorTerminal.app and behold its wonder!
What? It didn’t work?
Let me guess. A Terminal window opened, but Visor didn’t take effect. What gives? (You may have also noticed that you don’t have an entry in your menubar… see above.)
Turns out newer versions of SIMBL don’t activate in applications with LSUIElement : 1. Apparently this is expected behavior due to the Cocoa event mechanism. But all is not lost!
You can manually inject SIMBL into an application using Apple Script.
tell application "VisorTerminal" inject SIMBL into Snow Leopard end tell
Great, but I don’t want to do something manually every time I want a Visor window. I just want it to always be there, remember?
Use the AppleScript Editor to save this snippet as an application, and then include that application in your user startup items. Voila! When you log in, the AppleScript helper executes, which launches VisorTerminal with SIMBL injected. Visor activates, your terminal automatically hides itself, yet is always there when you want it with the push of a button. It doesn’t clutter up your Dock, your application switching, and you can still use Terminal.app as usual whenever it makes sense to do so.
First off, note that this tutorial was written using SIMBL 0.9.7a, Visor 2.2, and Terminal 2.1.1 (273) on Mac OS X Snow Leopard 10.6.4. YMMV.
Secondly, my thanks to all the people who are smarter than me and figured all this out. All I did was put things together.
Third, see below for patch files and my AppleScript application.
Finally, does anyone have the following issue, and know a way around it? After setting my key bindings, when I launch Terminal for the first time, they don’t take effect. Home does nothing special. If I open a new Terminal window, the home key starts working as expected, both in the new window as well as the original window. This happens to me whether I use \001 for the control character (and this without a ~/.inputrc file) or if I use the solution described above. Slightly bothersome, but since I almost always use my Visor terminal (which doesn’t exhibit the same problem… nor did it using Visor sans any modifications discussed here) I don’t notice it too often.