Warning: this entry is old. It may contain outdated information and may not reflect my opinion anymore.
I recently decided to give iTerm a try, so I needed a way to launch shells and other things requiring a terminal the same way I launched them inside rxvt-unicode: using Quicksilver.
I suppose I could use AppleScript to do this, but…
- I don’t really like its syntax;
- I’m currently addicted to python;
So I made qslaunch, a very small python package to help do the job, and this little post to tell how to use it :)
In this post, I’m assuming some knowledge of python, regular expressions and how to use a shell.
I won’t detail things too much either as I think the code speaks by itself.
First, let’s delve into two ways to execute things using Quicksilver.
Quicksilver’s “actions”
In Quicksilver, you can have “Actions”. They reside in the directory:
~/Library/Application Support/Quicksilver/Actions
An action can be an AppleScript script, or an executable shell file.
Lets say you have an executable script named “my_prog” in that directory.
You call up Quicksilver’s window, type “.” to enter the text mode, and then you type “ssh-hostname”. In the Action box below, you select “my_prog”, and press enter.
Here’s what happens next: Quicksilver runs the program as if you typed this in a terminal: my_prog ssh-hostname.
I won’t describe this technique in detail because it’s not the one I use… too much keyboard typing.
The other way
Lets say you have a directory ~/quicksilver and that you have added that directory to Quicksilver’s catalogue.
You then place an executable script named “ssh-hostname” in that directory.
You call up Quicksilver’s window, and begin to type “ssh-ho”… and QS completes to “ssh-hostname” by itself. You then press enter.
Here’s what happens next: Quicksilver runs the program as if you typed this in a terminal: ssh-hostname.
This is the technique I use. It involves as many files as I have things to launch, but it’s a small price to pay to have Quicksilver’s auto completion :)
The other way’s problem
It’s annoying to duplicate a script 30 times if you have 30 servers to connect to.
Most of the time, there’s also a pattern involved… for example, you may have 10 servers under the domain “example1.org”, and 16 under the domain “example2.org”. It would be fun to have a single script that handles all that!
So the trick is to make one python script, and give it 30 different names.
We can’t use symbolic links because whatever the name the link has, the program will always be called by its original name.
We don’t want to copy the file 30 times – making changes would become way too annoying.
What we need are hard links.
A hard link is similar to a copy, except that instead of copying the contents of a file, we simply give it a second name.
Changing one file’s contents implies changing the second file’s contents :)
Installing the required stuff
You should already have these installed:
- iTerm
- Quicksilver
- Growl (very optional)
Now, the python modules.
First, we need qslaunch. So fire-up a terminal (preferably iTerm since it’s the subject of this post!) and type:
1 | $ sudo easy_install qslaunch
|
You’ll obviously need to type in your password for sudo to gain administrative privileges.
Then, if you wish, you can install Growl’s python bindings.
The only reason to install these is to have some visual feedback if something goes wrong.
They are actually annoying to install because you first need to get Growl’s SDK disk image from Growl’s sources page.
Once the disk is downloaded and mounted, copy the directory Bindings/python from the disk image to your desktop. Then, in your terminal:
1 2 | $ cd ~/Desktop/python $ sudo python setup.py install |
You can now delete the copy of the directory you just made and unmount the disk.
Creating a launcher script
The next step is to create the actual script that’ll be aliased to many names using hard links.
If you want to install the sample script as ~/scripts/qs_launcher.py:
1 2 3 4 5 | $ cd ~ $ mkdir scripts $ cd scripts $ wget 'http://greyworld.net/media/dynamic/qslaunch_sample/qs_launcher.py' $ chmod a+x ~/scripts/qs_launcher.py |
Here’s highlighted version: qs_launcher.py. It’s identical to sample_name.py in the examples directory of the source, with less comments.
The script has the following parts:
- the usual import block;
- a commands variable;
- a main() function that extracts the “program name”, and then call execute() on the commands variable.
The interesting part is the commands variable. It’s a list of rules. Each rule is a tuple with two elements:
- a regular expression,
- a command to execute.
The command is actually a 4-elements tuple, but this example exclusively uses shortcuts, so it looks like a function call.
Rule 1 – Local shell
1 | (r'^local$', iterm.bookmark('A Local Shell', 'tab')) |
This line will match exactly the program name “local”.
A new tab is created (or a new window if there are none). Inside it, a session is launched according to iTerm’s bookmark named “A Local Shell”.
Rule 2 – Local shell, cd to Finder’s top window dir
1 2 | (r'^local-finder$', iterm.bookmark('A Local Shell', 'tab', \ cd=finder.front_most_path)), |
This is the same as the first rule, but with the additional parameter cd.
That parameter can be either a string or a callable (a “function”) that returns a string.
Once the session is opened, a cd string is sent to it.
finder.front_most_path() is an helper function that returns the path of the front most Finder window. If there are no windows, an error is displayed through Growl (if installed).
Rule 3 – (server).example.org
1 | (r'^s-(?P<server>[^\.]*)$', iterm.shell_exec('ssh %(server)s.example.org.', 'tab')) |
A new tab is created on the front most iTerm window. Insite it, the command ssh %(server)s.example.org. is executed.
In the regular expression, we capture a part of the string which we name “server”. That part is replaced in the string to execute.
So if the program name was “s-myhost”, then the actual command would be ssh myhost.example.org.
Why is there a dot at the end of that string?
Well, it’s a DNS thing. Your computer might be configured to “search” for domain names like “myprovider.net”. In this case, if you type “www” in your web browser for example, the first thing it’ll try is to connect to “www.myprovider.net”. Then, if this fails, it’ll try “www”.
If you type something like “ssh myhost.example.org” in a shell, ssh will attempt to find a server named “myhost.example.org.myprovidet.net”. It won’t exist, and so it will then try “myhost.example.org”.
The dot at the end tells the name resolution system to not automatically append any domain.
So if you type “ssh myhost.example.org.”, ssh will only try to resolve one name: “myhost.example.org”.
Rule 4 – full hostname
1 | (r'^s-(?P<server>.*)$', iterm.shell_exec('ssh %(server)s.', 'tab')), |
This is very similar to the previous rule, except that it also sucks in dots.
So the program name could be s-host.there.com, which would cause this to be executed:
1 | ssh host.there.com. |
This rule is a superset of the previous example. It works because the rules are executed in the order they are listed.
Rule 5 – gnuplot
1 | (r'^gnuplot$', iterm.shell_exec('/bin/bash -l -c gnuplot')) |
This rule exactly matches “gnuplot”.
If it’s installed on your system, a new iTerm window’ll be created and in it, /bin/bash -l -c gnuplot will be executed.
I start gnuplot through /bin/bash -l to give gnuplot a full environment, just like when we actually type “gnuplot” in the shell.
Setting up Quicksilver
Now you need a directory to place the files as seen by Quicksilver. I’ll assume the use of ~/quicksilver:
1 2 | $ mkdir ~/quicksilver $ cd ~/quicksilver |
Lets add a few links to match our script:
1 2 3 4 5 | $ ln ~/scripts/qs_launcher.py local $ ln ~/scripts/qs_launcher.py local-finder $ ln ~/scripts/qs_launcher.py s-abc $ ln ~/scripts/qs_launcher.py s-def.google.com.py $ ln ~/scripts/qs_launcher.py gnuplot |
You can test to see if it works:
1 | $ ./local
|
Should open an iTerm window.
Now, go into quicksilver’s “Catalog” configuration section, in the “Custom” tab, and add a new “File & folder scanner”. In the file requester, select the directory you just made.
When you make changes in that directory, you need to wait until QS rescans it, or you simply go back to that window and hit the circular arrow on the bottom-right of the window (similar to: ↻).
The reason I put a “.py” in “s-def.google.com.py” is that QS, at least on my system, won’t launch things ending with “.com”. Maybe it’s a Windows related thing with some other software I have installed.
I really don’t care about the true cause because using “.py” solves the problem anyway.
Launching stuff
Call up Quicksilver’s window, type one of the new commands, and press enter!
Comments
There are no comments for this entry.