Tip: cdpath - Am I the last to know?

This one is just so simple, I can't believe I didn't know about it earlier.

First, setup the cdpath or CDPATH variable:

cdpath=(~ ~/Projects/apps ~/Projects/tools ~/Projects/plugins ~/Projects/sites)

Now, changing directory in the shell becomes a whole world easier:

tomw@fellini:~$ cd super-secret-app
~/Projects/apps/super-secret-app
tomw@fellini:~/Projects/apps/super-secret-app$ cd Documents
~/Documents
tomw@fellini:~/Documents$ cd tomafro.net
~/Projects/sites/tomafro.net
tomw@fellini:~/Projects/sites/tomafro.net $

I've already added this to my dotfiles.

Tip: Open new tab in OS X Terminal

Another simple shell function, this time just for OS X.

Usage is simple: tab <command> opens a new tab in Terminal, and runs the given command in the current working directory. For example tab script/server would open a new tab and run script/server.

tab () {
  osascript 2>/dev/null <<EOF
    tell application "System Events"
      tell process "Terminal" to keystroke "t" using command down
    end
    tell application "Terminal"
      activate
      do script with command "cd $PWD; $*" in window 1
    end tell
  EOF
}

ZSH Completion for gem and gem open

I've been trying to get my head around the ZSH completion system. It's not easy, but I'm slowly making progress.

Here's my first semi-successful attempt. It provides command completion for gem (including installed commands) and gem name completion for specific gem commands (update, and open from Adam Sanderson).

So typing gem <tab> gives a list of possible commands, whilst gem open <tab> will complete with the names of the currently installed gems.

#compdef gem

_gem_commands () {
  if [[ -z $gem_commands ]] ; then
    gem_commands=$(gem help commands | grep '^    [a-z]' | cut -d " " -f 5)
  fi
  
  # This seems unnecessary, but if I try to set gem_commands to an array, it falls over.
 
  typeset -a gem_command_array
  gem_command_array=($(echo $gem_commands))
  compadd $gem_command_array
}
 
_installed_gems () {
  if [[ -z $installed_gems ]] ; then
    installed_gems=($(gem list | grep '^[A-Za-z]' | cut -d " " -f 1))
  fi
  
  typeset -a installed_gem_array
  installed_gem_array=($(echo $installed_gems))
  compadd $installed_gem_array
}
 
if (( CURRENT == 2 )); then
  _gem_commands
else
  if [[ $words[2] == open || $words[2] == update ]] ; then
    _installed_gems
  fi
fi

As it's a first attempt, it's a long way from perfect. I've put it on gist, for other people to play with, and I'd appreciate any advice or improvements. Specifically I'd like to know how to avoid the use of both gem_command_array and gem_commands. I'd also like to know a better way to check if the given command is in the list [open, update].

Please fork the gist, or tweet me with your suggestions.

Kernel specific ZSH dotfiles

I work on a number of different machines, OS X based for development and Linux based for hosting. I've added various aliases and other commands to my shell, and use a github repository to share this configuration between these machines.

This works well, but while most commands work commonly across Linux and OS X, there are some nasty differences. One example is ls which takes different arguments on both systems; the default ls alias I use on OS X doesn't work on Linux. So how can we accommodate these differences, without removing all the shared configuration?

The answer is really simple. Create kernel specific configuration files, and use a case statement to load the correct one. The main obstacle was finding a way to distinguish between each kernel. In the end I found the $system_name environment variable, which is set on both OS X and the servers I use.

Here's the code:

case $system_name in
  Darwin*)
    source ~/.houseshare/zsh/kernel/darwin.zsh
    ;;
  *)
    source ~/.houseshare/zsh/kernel/linux.zsh
    ;;;
esac

As I said, simple.