Slow Motion Shaolin Warriors


Fascinating footage of Shaolin monks performing in slow motion.


My Setup


The Uses This series, and Shawn Blanc’s Sweet Mac Setups series have always intrigued me, so I decided to write one of my own.

##Who are you and what do you do? My name is Mark Nichols. I’m married to Sibylle Kuder, I play violoncello, I hack around with various computer technologies, and I’m an all-around good guy. Professionally I work for Kansas State University as an “Integration Services Coordinator” — dealing with the sometimes messy intersection of differing systems and their needs. Lately I’ve been diving into the world of Vagrant and Chef.

##What hardware do you use? My personal computer is a mid-2009 15" 2009 MacBook Pro with a 2.66 GHz Core 2 Duo processor and 8 GB of RAM. Within the next week the original 320 GB hard drive will be replaced with a new 1 TB drive.

I also have a 16GB iPad Mini that is easily one of the nicest computers I have ever owned. My phone is a 16GB iPhone 5 on AT&T.

My employer provides me with wonderful tools, so I have on my desk a mid-2010 27" iMac with a 256GB SSD and a 1 TB spinning drive. My work laptop is a 13" Retina MacBook Pro, with a 500 GB SSD and 8 GB of RAM. It is the sweetest computer I’ve ever had the pleasure of using.

Tunes in my car are provided via an 8 GB 6th-generation iPod Nano. The car, a 2010 Honda Insight, has the world’s clunkiest iPod interface, but it does let me listen to Zoë Keating on my way to and from work. I have an aging (no longer holds a charge but works fine plugged in) 30 GB iPod that holds most of my music and lives in the corner of the house where I practice my cello, so that I can listen to the pieces I am learning.

My cello is a Hans Stainer 100, made by Eastman, fitted with Jargar Strings and played with a CodaBow Diamond SX bow. I use Gustave Bernardel rosin.

For printing we have a newly purchased HP OfficeJet Pro 8600 All-in-One printer/copier/fax/scanner. It’s beautiful, it’s wireless, and it prints like a dream.

At work I use a pair of Apple EarPods to listen to music or videos. At home I use a variety of earbud style earphones, but only when the cat isn’t around. She considers them string with which to be toyed.

##And what software? Sublime Text 2, Vim, tmux, and iTerm2 for most coding. IntelliJ IDEA for Java, and XCode for Cocoa and iOS development.

Safari for 99% of my browsing and Google Chrome on rare occasion.

Adium for instant message chat and IRC. Twitterrific for Twitter.

Fetch handles my SFTP needs, although I am making more and more use of sshfs for accessing remote drives.

Growl for notifications and Alfred for Cmd-Space-ing things.

TakeFive helps me to control what’s playing, and Cobook gives me access to my contacts.

F.Lux dims my laptop screen at night, and brightens it during the daylight hours.

Dropbox for convenient movement of files between computers, and Git for version control of all my coding projects.

##What would be your dream setup? After spending a couple weeks with the 13" Retina MacBook Pro I would be hard pressed to consider any other machine. Well, maybe the 15" Retina MacBook Pro.

I’d like a dead simple storage system that hung off our router that would let Sibylle backup her Windows-based machines and me back up my OS X-based machines seamlessly. And perhaps a Mac Mini tied to a couple large drives to house all our music and DVD movies.

I’d also like an iPod Classic as it would be large enough to hold my complete collection of music and audio books. But first I’ll need a car with a decent iPod interface.

I’m intrigued by the Sonos Speaker systems, but other priorities have kept that on the someday list.

And someday I hope to be advanced enough on the cello to warrant a really good, old, instrument.


Vortex View of Planetary Motion



Seventeen


So this happened a week ago.

$ whois zanshin.net | grep "Creation Date"
   Creation Date: 20-feb-1996

Seventeen years, 2088 postings, 627,706 words.


50 Years of Bond



SurfacePad Review


After a year of use the Apple Bumper case for my iPhone 4S developed a tear in one corner. The case is still functional, but I found the tear unsightly and used it as an excuse to get a new case for my phone.

Case shopping can be frustrating. Local merchants are likely to only have the popular cases, many of which are garish, which limits your choices. Shopping on the Internet broadens the pool of cases to choose from, but you can’t “test drive” one. After a visits to BestBuy and the local Verizon store, I used a holiday to visit the nearest Apple store, two hours away in Kansas City. None of the cases really pulled my string, so I continued to use the torn bumper case.

I actually like the look and feel of the iPhone naked, but the glass by itself is slippery and I am always afraid I’ll drop it when it’s not in a case.

##Enter the SurfacePad

It’s the perfect cover for those who have an iPhone, and are not afraid to show it.

It’s not a case, per se, nor is it a sleeve. The best description is that it’s a jacket for your phone. A wonderfully supple Napa leather jacket. The leather is less than a 1/10th of an inch thick and weighs next to nothing at under an ounce. TwelveSouth says that

[r]ather than protecting your iPhone from falling off the side of a cliff, the luxury leather SurfacePad shields your iPhone from more common hazards, like the keys in your pocket.

I’ve had my SurfacePad for just over two weeks now and I could not be happier with it. Rather than hide the beautiful design of the iPhone in a plastic or rubber cover, the SurfacePad accentuates phones presence. The juxtaposition of leather with the metal and glass of the phone is perfect.

It slips into and out of my pocket with ease, but it doesn’t feel slippery at all. The leather protects the front glass, and wraps around the volume control side of the phone’s chassis. The back adheres to the phone with “modern adhesive” that has been used for years on TwelveSouth’s SurfacePad for MacBooks for years. The jacket can be removed a reattached.

The jacket is designed to act as a stand for the phone in landscape orientation. As luck would have it my favorite tuner/metronome app works in landscape orientation, so I use the stand on a daily basis.

For most activities I am unaware of the cover, but I do notice it a bit when making phone calls. I am left-handed when it comes to phone calls, so I fold the cover back completely, which slightly increases the phones thickness. It’s not enough to be objectionable, but I do notice it.

TwelveSouth has minimal branding on the jacket. The bottom of the front cover has a small embossed TwelveSouth logo. Inside the cover, oriented so that you can read it when the jacket is being used as a stand, is the product name, SurfacePad. And hidden away in the hinge of the case, is a repeat of the logo and the company name, TwelveSouth. The understated branding suits me very well as it allows the phone to be the center of attention.

The black leather on my jacket is smooth and unblemished. The interior side is a light grey with a very fine nap. It feels a bit like a high quality lens cloth. The double row of stitching on the back where the hinge is located is well done. There are no lose threads and the stitches are nearly flush with the leather. There is a cutout for the rear facing camera and flash. After two plus weeks of use my jacket is staring to feel broken in – like a favorite leather coat.

At $34.99 this isn’t the least expensive nor the most expensive cover for your iPhone. But in terms of quality, fit and finish, and enhancement to the phone, I don’t think you could find anything better.


Instant Sublime Text Starter


At the end of January I received an email asking me if I would be willing to read and review a short book on getting started with Sublime Text 2. The email seemed legitimate and after investigating a little bit I decided to take them up on their offer. Here’s the email:

Hi Mark My name is Dyson D’ Souza and I work for Packt Publishing, a UK-based publishing company specializing in focused IT books. We have recently published a book Sublime Text Starter, and I was wondering if you’d be interested in taking a look at the book and sharing your comments on your blog and on Amazon.com. A few details about the book: book composes of around 40 pages, learn something new in an Instant! A short, fast, focused guide delivering immediate results, utilize multiple cursors to edit your text in many locations at the same time, etc. For more information please visit : http://www.packtpub.com/sublime-text-starter/book I’m contacting you because I’m aware that you share good knowledge in the subject this book covers, and so believe that your comments would be important for both consumers and readers alike. For this, I’d be glad to offer you a digital copy of the book.

Would be great to hear from you. Thank you

Kind regards,

Dyson D’ Souza Marketing Research Executive | Packt Publishing | www.PacktPub.com Email: dysond@packtpub.com

About a week after I replied I received a second email that contained the details on an account which had been created for me so I could download a PDF copy of the book. I’ve read through it a couple of times now and my review of it follows.

##Instant Sublime Text Starter At 46 pages, Instant Sublime Text Starter is short and to the point. It covers Sublime Text 2 installation (on Windows, Linux, or Macintosh operating systems), walks you through very basic steps on quickly creating and editing a document, and rounds out with a very brief look at some Sublime Text features.

If you were brand new to text editors and wanted something to get you started quickly Instant Sublime Text Starter might be an acceptable resource. Unfortunately there’s no depth to any of the material covered. It really is just a starter.

For anyone with any experience at all setting up and configuring programming tools, the level of discussion in Instant Sublime Text Starter will be too basic. And the suggestion that you edit Preferences | Settings Default to enable Vintage mode rather than Preferences | Settings User is not a good idea. Changes made to Settings Default will be overlaid the next time you update Sublime. User configurations and settings should always be made in Preferences | Settings User.

There are many resources available to get you started in any new topic, and Sublime Text is no exception. For my money I’d recommend the tutsplus.com Perfect Workflow in Sublime Text 2 to any developer wanting to really explore Sublime Text. For non-technical users wanting just enough information to get started, you might consider Instant Sublime Text Starter.


Tracking Your iPhone's Location


After reading Jack Perkes’ article Tracking Your iPhone’s Location I decided I wanted to do this with my phone. ##Getting a Copy of the Project I started by forking the Github findi project. There is a sample Heroku project as well, complete with instructions on using Heroku to host your tracking efforts. While I’m not using Heroku I did make use of the bootstrap.py and record_location.py scripts and requirements.txt file from the findi-heroku-example project.

Once I had cloned the fork to my laptop, I copied the contents of the bootstrap.py, record_location.py, and requirements.txt files to my local copy of the project. This way my fork is based on the findi project itself, and not the example Heroku one, but I have the additional files from the example project.

I also added a Python .gitignore to my fork.

##Testing on the Command Line Next I tested findi against my iPhone. findi wrappers Apple’s Find My iPhone API and therefore is dependent upon your Apple ID. Once you instantiate a findi object using your Apple ID and Password, you can get a list of all the devices you are tracking. In my case that list contained 5 devices: my laptop, an original iPad, a brand-new iPad Mini, my iPhone, and my work iMac.

Plugging the index of my iPhone (3, in a zero-based list) into the API gave my my current latitude and longitude. Using copy and paste I was able to verify my location on Google Maps.

##Modifying the Script for My Device List The record_location.py script expects a device mapped to your Apple account.

"Fetches an iPhone location from the Apple API and creates a Location Object"
    iphone = FindMyIPhone(APPLE_EMAIL, APPLE_PASSWORD)
    iphone_location = iphone.locate()

Since I have 5 devices I changed the code slightly and hard-coded the index for my iPhone:

"Fetches an iPhone location from the Apple API and creates a Location Object"
    iDevices = FindMyIPhone(APPLE_EMAIL, APPLE_PASSWORD)
    # my phone is the 4th device (index 3) in the list
    iphone_location = iDevices.locate(device_num=3)

By default the script records the UTC time for each location.

date = Column(String, default=datetime.utcnow,
                  onupdate=datetime.utcnow)

I’d rather have the time for my timezone, so I changed the utcnow method to be today:

date = Column(String, default=datetime.today,
                  onupdate=datetime.today)

Finally, in order to execute record_location.py easily from cron, I added a hash-bang to the top of the file:

#!/usr/local/bin/python2.6

My server through WebFaction provides multiple Python versions, the python2.6 specifies the exact version I want.

##Setting Up PostgreSQL and Cron I used WebFaction’s control panel to create a new PostgreSQL database, along with a database userid and password. record_location.py expects the Apple Email, Apple Password, and database URL to be in environment variables called APPLE_EMAIL, APPLE_PASSWORD, and DATABASE_URL respectively. At the command prompt I exported these variables, filling in the appropriate values:

$ export APPLE_EMAIL="you@example.com"
$ export APPLE_PASSWORD="lettersAndNumbers"
$ export DATABASE_URL="postgresl://<user>:<password>:@localhost:5432:<databasename>"

Running bootstrap.py with the exports in place created the table needed inside the PostgreSQL database.

Running the record_location.py script now resulted in a new row being inserted into the database.

Cron runs in its own environment and knows nothing about my exports, so I created a .cronvars file to house the required variables, so that I could source them, thereby making them available to the cron environment when the the script was executed. Here’s the line I added to my crontab:

* 0 0 0 0 source $HOME/.cronvars; $HOME/pyapps/findi/record_location.py > /dev/null

Initially I set the cron job to run every few minutes so I could see some rows appear in the table and verify that everything was working. Once it was clear that it was working, I changed the time to be 0, or once an hour on the hour.

##Fun and Profit Now I have to wait a while to start collecting data from my phone’s location; which by and large is my location. Eventually I’ll use TileMill and MapBox to create a map. That will be the subject of a future posting.


Zsh Configuration From the Ground Up


In July of 2011 I attended the Überconf in Denver Colorado. One of the evening sessions was Developer Productivity Power Up on Mac OS X given by Matthew McCullough. In addition to Github, CloudApp, Dropbox, iTerm2, and EC2, he demonstrated zsh, or z-shell. I had heard of zsh prior to his talk, but had never investigated it.

zsh is a superset of the venerable Bash shell. It has first class functions, modular enhancements, comes pre-installed on Mac OS X, and offers fantastic tab completion. As a jump start to getting a working zsh environment in place, Matthew pointed us toward oh-my-zsh, a framework with tremendous community support. oh-my-zsh offers modular zsh plug-ins, Git repository information in your prompt, a customizable right-side prompt, themes, and more.

By cloning the oh-my-zsh project on Github, selecting one of the themes, and changing your default shell to zsh you can have a flexible and powerful new shell in a matter of minutes. With a little judicious Googling and some experimentation it’s easy to develop a shell environment that’s tuned to your style of working. Over time I built up my prompt (the most visible portion of the environment) to display interactive version control status information from Git, Mercurial (hg), or Subversion (svn) when the current directory was under version control. My right-prompt showed the current RVM managed Ruby and Python virtual environment. I could also see at a glance what user I was, on which machine, and the current directory path. Oh, and all in vibrant colors.

Over time the features of zsh that I’ve come to rely upon the most are the tab completion and some of the directory movement commands. However, recently I had become dissatisfied with the delay when opening a new shell in a tab or window. A several second delay wasn’t unusual. In my efforts to pack as much information as possible into the prompt I created a resource intensive monster that was increasingly annoying. I began to question the need for dynamic svn repository information in the prompt when I rarely worked with Subversion any more.

Additionally, I had switched away from the main oh-my-zsh project to a fork created by Steve Losh. He added a function that exposed more status states for Git repositories. And I was using a Python script of his that exposed Mercurial repository information for the prompt. My prompt was capable of informing me of many things based on the current context, but the underlying structure had grown large and burdensome. Two weeks ago I decided to pare down my zsh setup, and in doing so I hoped to achieve two goals. One, I wanted to have a much better understanding of what was actually driving my shell’s environment. Two, I wanted to have a simpler, and hopefully quicker loading, setup.

Lobotomizing My oh-my-zsh theme

My first thoughts were to remove some of the less used information from my zsh prompt theme. I had added svn information since we use svn at work. However my role there shifted and I have no real need (at the moment) for Subversion reporting in my prompt.

It was the matter of a couple minutes work to comment out the Subversion related code from my theme file and source .zshrc. The subjective measure of my prompt’s loading time wasn’t much improved.

Next up I commented out the Mercurial aspects of the prompt. I stared out using hg a few years ago but, following the herd, I’ve moved all my projects to Git and Github. Again, my prompt didn’t really seem to be any faster.

Taking a new tack, I hunted around and found a completely new zsh theme I liked the general looks of called Fino. It had basic Git repository status information, RVM or rbenv Ruby information, and Python virtualenv reporting. With it in place in my .zshrc file the prompt was changed but I started getting error messages. zsh: command not found: rvm_ruby with every command issued.

Googling the message took me to a number of stackOverflow threads and some pages about Mac OS X’s path_helper. Something about the new theme wasn’t getting along with the rest of my zsh environment.

A Brief Digression into path_helper

path_helper examines the contents of /etc/paths.d and adds entries to your $PATH. The consensus seems to be that while it’s a good idea, it may not be implemented in the best fashion.

While I was reading all the pages I could find about path_helper, I wasn’t seeing the forest for the trees. RVM, and rbenv, are dependent upon their libraries being first in the PATH. If the PATH is altered after those key libraries are setup, the order may no longer be correct.

Frustrated by my lack of success in either altering my theme or incorporating the Fino theme, and not getting the clue the path_finder Google results were giving me, I reverted to my original theme and changed my primary text editor from TextMate to Sublime Text 2. When in doubt, go shave a yak.

Shaving the Sublime Text 2 Yak

I tend to collect open tabs in my browser. I usually have 30 or 40 open tabs and sometimes as many as 100. Periodically I scrub through them all and “do something” with at least some of them. Mentally stuck on the zsh: command not found error, I wandered through my open tabs and stopped on the nettuts plus Perfect Workflow in Sublime Text free course. Next thing you know I’ve dusted off my previously installed, but never really used, Sublime Text 2 application and started adding plug-ins and a color theme or two. I wasn’t solving my zsh theme issues, but I was using new and different tools to look at the reluctant code. When you can’t see the solution, change glasses, right?

With a newly configured and tweaked editor ready for use I returned to the original project.

Struggles with RVM

There are two Ruby environment managers: RVM and rbenv. I’ve used both in the past, although RVM has been my primary one for longer. The framework I use for my Websites is Octopress, which is Ruby-based. I initially installed RVM to setup and configure the required Ruby and Gems to get my site infrastructure working.

Since the error message I was getting seemed to be pointing a finger at RVM I decided to switch to rbenv. Rather than solve the problem, I thought, I’ll just switch environment managers. Easy as pie.

Rather than jeopardize my working-if-slow-loading environment I decided to use a different machine for my rbenv experiment. I have access to an older, but still serviceable aluminum MacBook Pro. I had recently formatted its hard drive and installed Linux Mint on it just to explore that distribution. I wiped the drive and installed Mountain Lion and rebuilt the machine to match my personal machine as closely as possible with one key difference: I setup rbenv and not RVM.

At this point, with a test bed that I could afford to be risky with, I stepped back from trying to get oh-my-zsh working and considered switching to the other zsh framework I had read about.

Looking at zshuery

zshuery is a much lighter-weight framework than oh-my-zsh. Based on the commit activity it isn’t nearly as frequently updated either. My concerns with it ran deeper than a seeming lack of support. Without digging into both oh-my-zsh and zshuery and comparing them at a nuts and bolts level I wouldn’t know what one had that the other didn’t. What would I gain with zshuery? What would I lose and have to recreate?

While starting out with oh-my-zsh was fantastic, it came with a hidden cost. Since I knew nothing about zsh prior to using the framework I had no way of knowing what was raw zsh and what was framework-added. To me, oh-my-zsh was zsh.

We Interrupt this Program for a Brief Word About Writing Sorts

In my college internal data structures course we wrote a sort. After a lecture discussion the ins and outs of the algorithm I wrote my very own bubble sort. The following lecture the professor showed us the JCL sort utility. At first I was upset that I spent all the time and effort to reinvent the sort wheel, but later I came to realize that I had a better understand and appreciation for sorts as a result of the exercise.

My zsh experience was the opposite of my sort experience. I started zsh with the polished, design-decisions-already-made-for-you solution. If I really wanted to get to the bottom of my zsh shell slowness I would need to build my own environment, eschewing frameworks.

ze-best-zsh-config

Github is a wonderful place as people store all sorts of things there, open to the public. In my sifting of Google zsh search results I stumbled onto a repository cheekily named ze-best-zsh-config. At first glance it looked well laid out. The various aspects of the configuration, options, exports, the prompt, history, aliases, and functions, were all isolated in their own .zsh files, and the resulting components brought together in the .zshrc file.

Here was a starting point for my own, hand-rolled zsh environment. I cloned the repository and started working through the .zsh files it contained line-by-line to understand them.

Switching to rbenv

Installing and using rbenv isn’t any harder than installing and using RVM. Reflecting the current active Ruby in my shell’s right-prompt (RPROMPT) proved to be one of the hardest parts of this project.

I liked the code from the Fino theme for interrogating the host machine for either RVM or rbenv and then determining what Ruby was active. Copying that code to my new prompt.zsh file didn’t work however. The right-prompt either showed nothing at all, or the line of code that should have resolved to the Ruby name. After an evening of Googling and trial and error I finally posted a question on stackOverflow. The next morning I not only had a working answer, I had an explanation of how it worked. I love the Internet.

setopts, Exports, Aliases, Functions, Colors, Completions, and History

With my prompt sorted it was time to understand all the configuration options available to me, and setup my environment. Working from the setops included in ze-best-zsh-config, I looked everything up. Some I kept, others I changed, a few I dropped. Next I read through the options defined in zshuery.

I performed similar examinations of the colors, completions, history, exports, aliases, and functions .zsh files. I merged my existing functions and aliases into the starter files, and incorporated some more from zshuery.

From zshuery I liberated the idea of testing the host machine’s operating system (uname) and setting an attribute. This allows me to have options that are OS specific.

More path_helper Adventures

During the due diligence process I managed to break the right-prompt. Suddenly the zsh: command not found error was back. Somewhere along the line I had managed to break the path. After much searching and reading I finally created a .zshenv file and copied the code necessary to run path_helper there. I then altered this code to completely clear the path, ensuring that I had no unexpected cruft there. This article about path_helper was instrumental in my getting the problem solved.

I also placed the path and shim setup for rbenv into the .zshenv file. With this file in place the zsh: command not found error disappeared. Hopefully for good.

Putting it All Together

My new .zshrc file is just a list of .zsh files that get sourced.

source ~/.zsh/checks.zsh
source ~/.zsh/colors.zsh
source ~/.zsh/setopt.zsh
source ~/.zsh/exports.zsh
source ~/.zsh/prompt.zsh
source ~/.zsh/completion.zsh
source ~/.zsh/aliases.zsh
source ~/.zsh/bindkeys.zsh
source ~/.zsh/functions.zsh
source ~/.zsh/history.zsh
source ~/.zsh/zsh_hooks.zsh
source  ${HOME}/.dotfiles/z/z.sh

And those files each contain a portion of the overall configuration. I suppose they could all be combined into one large file, but I like breaking them up into logically related components.

.zshenv

Here is where we override path_helper by calling it again ourselves. The PATH is cleared first and then rebuilt. The result is far less duplication of directories. rbenv is also setup here.

# Mac OS X uses path_helper and /etc/paths.d to preload PATH, clear it out first
if [ -x /usr/libexec/path_helper ]; then
    PATH=''
    eval `/usr/libexec/path_helper -s`
fi

# if rbenv is present, configure it for use
if which rbenv &> /dev/null; then
    # Put the rbenv entry at the front of the line
    export PATH="$HOME/.rbenv/bin:$PATH"

    # enable shims and auto-completion
    eval "$(rbenv init -)"
fi

checks.zsh

These tests allow me to later isolate exports, or setopt statement based on the host machine’s operating system.

# checks (stolen from zshuery)
if [[ $(uname) = 'Linux' ]]; then
    IS_LINUX=1
fi

if [[ $(uname) = 'Darwin' ]]; then
    IS_MAC=1
fi

if [[ -x `which brew` ]]; then
    HAS_BREW=1
fi

if [[ -x `which apt-get` ]]; then
    HAS_APT=1
fi

if [[ -x `which yum` ]]; then
    HAS_YUM=1
fi

colors.zsh

A colorful shell is a happy shell. But the escaped codes are arcane and miserable to work with. Let’s give them some readable names.

autoload colors; colors

# The variables are wrapped in \%\{\%\}. This should be the case for every
# variable that does not contain space.
for COLOR in RED GREEN YELLOW BLUE MAGENTA CYAN BLACK WHITE; do
  eval PR_$COLOR='%{$fg_no_bold[${(L)COLOR}]%}'
  eval PR_BOLD_$COLOR='%{$fg_bold[${(L)COLOR}]%}'
done

eval RESET='$reset_color'
export PR_RED PR_GREEN PR_YELLOW PR_BLUE PR_WHITE PR_BLACK
export PR_BOLD_RED PR_BOLD_GREEN PR_BOLD_YELLOW PR_BOLD_BLUE
export PR_BOLD_WHITE PR_BOLD_BLACK

# Clear LSCOLORS
unset LSCOLORS

# Main change, you can see directories on a dark background
#expor tLSCOLORS=gxfxcxdxbxegedabagacad

export CLICOLOR=1
export LS_COLORS=exfxcxdxbxegedabagacad

setopt.zsh

There are a dizzying array of options available. These are a start.

# ===== Basics
setopt no_beep # don't beep on error
setopt interactive_comments # Allow comments even in interactive shells (especially for Muness)

# ===== Changing Directories
setopt auto_cd # If you type foo, and it isn't a command, and it is a directory in your cdpath, go there
setopt cdablevarS # if argument to cd is the name of a parameter whose value is a valid directory, it will become the current directory
setopt pushd_ignore_dups # don't push multiple copies of the same directory onto the directory stack

# ===== Expansion and Globbing
setopt extended_glob # treat #, ~, and ^ as part of patterns for filename generation

# ===== History
setopt append_history # Allow multiple terminal sessions to all append to one zsh command history
setopt extended_history # save timestamp of command and duration
setopt inc_append_history # Add comamnds as they are typed, don't wait until shell exit
setopt hist_expire_dups_first # when trimming history, lose oldest duplicates first
setopt hist_ignore_dups # Do not write events to history that are duplicates of previous events
setopt hist_ignore_space # remove command line from history list when first character on the line is a space
setopt hist_find_no_dups # When searching history don't display results already cycled through twice
setopt hist_reduce_blanks # Remove extra blanks from each command line being added to history
setopt hist_verify # don't execute, just expand history
setopt share_history # imports new commands and appends typed commands to history

# ===== Completion
setopt always_to_end # When completing from the middle of a word, move the cursor to the end of the word
setopt auto_menu # show completion menu on successive tab press. needs unsetop menu_complete to work
setopt auto_name_dirs # any parameter that is set to the absolute name of a directory immediately becomes a name for that directory
setopt complete_in_word # Allow completion from within a word/phrase

unsetopt menu_complete # do not autoselect the first completion entry

# ===== Correction
setopt correct # spelling correction for commands
setopt correctall # spelling correction for arguments

# ===== Prompt
setopt prompt_subst # Enable parameter expansion, command substitution, and arithmetic expansion in the prompt
setopt transient_rprompt # only show the rprompt on the current prompt

# ===== Scripts and Functions
setopt multios # perform implicit tees or cats when multiple redirections are attempted

exports.zsh

The PATH is altered here after having been cleared and started in .zshenv.

# Currently this path is appended to dynamically when picking a ruby version
# zshenv has already started PATH with rbenv so append only here
export PATH=$PATH~/bin:/usr/local/bin:/usr/local/sbin:~/bin

# Set default console Java to 1.6
export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home

# Setup terminal, and turn on colors
export TERM=xterm-256color
export CLICOLOR=1
export LSCOLORS=Gxfxcxdxbxegedabagacad

# Enable color in grep
export GREP_OPTIONS='--color=auto'
export GREP_COLOR='3;33'

# This resolves issues install the mysql, postgres, and other gems with native non universal binary extensions
export ARCHFLAGS='-arch x86_64'

export LESS='--ignore-case --raw-control-chars'
export PAGER='less'
export EDITOR='subl -w'

#export NODE_PATH=/opt/github/homebrew/lib/node_modules
#export PYTHONPATH=/usr/local/lib/python2.6/site-packages
# CTAGS Sorting in VIM/Emacs is better behaved with this in place
export LC_COLLATE=C

# Virtual Environment Stuff
export WORKON_HOME=$HOME/.virtualenvs
export PROJECT_HOME=$HOME/Projects/django
source /usr/local/bin/virtualenvwrapper.sh

prompt.zsh

The visible tip of the zsh environment iceberg. Lots going on here.

The Python virtual environment, if one is active, is captured for display in the right-prompt.

The prompt character displayed is normally a $ or maybe a >. I’m using the symbols Steve Losh had in his extravagant zsh prompt

box_name is a clever way to show your preferred name for the machine you are on. Just create a ~/.box-name file and put the name you want there. Or, on Mac OS X, use the sudo scutil --set HostName <your-name-here> command.

A variety of variables are set up for Git repository status reporting, and then there are some functions to interrogate Git. This information is shown in the main prompt.

The current Ruby active is determined by interrogating either RVM or rbenv, which ever is present on the machine. This function, _update_ruby_version(), has been added to the chpwd_functions array like so: chpwd_functions+=(_update_ruby_version). This means it is only executed when the directory changes.

Finally there is a function to get the name of the current working directory.

The primary prompt shows the username, box name, current working directory, and git branch and status (if present). The prompt is preceded by a blank line, and places the prompt character on a line of its own. This makes reading the console far easier.

zsh provides an error prompt, which I’m using to spell correct commands. The export SPROMPT line handles this.

Lastly the troublesome right-prompt or RPROMPT. Here the Python virtual environment information and active Ruby information is displayed. One of the setops defined above, setopt transient_rprompt causes the RPROMPT to only appear on the current, most recent, prompt. I’m not sure yet if I like this, but it does make the console seem less cluttered.

function virtualenv_info {
    [ $VIRTUAL_ENV ] && echo '('`basename $VIRTUAL_ENV`') '
}

function prompt_char {
    git branch >/dev/null 2>/dev/null && echo '±' && return
    hg root >/dev/null 2>/dev/null && echo '☿' && return
    echo '○'
}

function box_name {
    [ -f ~/.box-name ] && cat ~/.box-name || hostname -s
}

# http://blog.joshdick.net/2012/12/30/my_git_prompt_for_zsh.html
# copied from https://gist.github.com/4415470
# Adapted from code found at <https://gist.github.com/1712320>.

#setopt promptsubst
autoload -U colors && colors # Enable colors in prompt

# Modify the colors and symbols in these variables as desired.
GIT_PROMPT_SYMBOL="%{$fg[blue]%}±"
GIT_PROMPT_PREFIX="%{$fg[green]%} [%{$reset_color%}"
GIT_PROMPT_SUFFIX="%{$fg[green]%}]%{$reset_color%}"
GIT_PROMPT_AHEAD="%{$fg[red]%}ANUM%{$reset_color%}"
GIT_PROMPT_BEHIND="%{$fg[cyan]%}BNUM%{$reset_color%}"
GIT_PROMPT_MERGING="%{$fg_bold[magenta]%}⚡︎%{$reset_color%}"
GIT_PROMPT_UNTRACKED="%{$fg_bold[red]%}u%{$reset_color%}"
GIT_PROMPT_MODIFIED="%{$fg_bold[yellow]%}d%{$reset_color%}"
GIT_PROMPT_STAGED="%{$fg_bold[green]%}s%{$reset_color%}"

# Show Git branch/tag, or name-rev if on detached head
function parse_git_branch() {
  (git symbolic-ref -q HEAD || git name-rev --name-only --no-undefined --always HEAD) 2> /dev/null
}

# Show different symbols as appropriate for various Git repository states
function parse_git_state() {

  # Compose this value via multiple conditional appends.
  local GIT_STATE=""

  local NUM_AHEAD="$(git log --oneline @{u}.. 2> /dev/null | wc -l | tr -d ' ')"
  if [ "$NUM_AHEAD" -gt 0 ]; then
    GIT_STATE=$GIT_STATE${GIT_PROMPT_AHEAD//NUM/$NUM_AHEAD}
  fi

  local NUM_BEHIND="$(git log --oneline ..@{u} 2> /dev/null | wc -l | tr -d ' ')"
  if [ "$NUM_BEHIND" -gt 0 ]; then
    GIT_STATE=$GIT_STATE${GIT_PROMPT_BEHIND//NUM/$NUM_BEHIND}
  fi

  local GIT_DIR="$(git rev-parse --git-dir 2> /dev/null)"
  if [ -n $GIT_DIR ] && test -r $GIT_DIR/MERGE_HEAD; then
    GIT_STATE=$GIT_STATE$GIT_PROMPT_MERGING
  fi

  if [[ -n $(git ls-files --other --exclude-standard 2> /dev/null) ]]; then
    GIT_STATE=$GIT_STATE$GIT_PROMPT_UNTRACKED
  fi

  if ! git diff --quiet 2> /dev/null; then
    GIT_STATE=$GIT_STATE$GIT_PROMPT_MODIFIED
  fi

  if ! git diff --cached --quiet 2> /dev/null; then
    GIT_STATE=$GIT_STATE$GIT_PROMPT_STAGED
  fi

  if [[ -n $GIT_STATE ]]; then
    echo "$GIT_PROMPT_PREFIX$GIT_STATE$GIT_PROMPT_SUFFIX"
  fi

}


# If inside a Git repository, print its branch and state
function git_prompt_string() {
  local git_where="$(parse_git_branch)"
  [ -n "$git_where" ] && echo "on %{$fg[blue]%}${git_where#(refs/heads/|tags/)}$(parse_git_state)"
}

# determine Ruby version whether using RVM or rbenv
# the chpwd_functions line cause this to update only when the directory changes
function _update_ruby_version() {
    typeset -g ruby_version=''
    if which rvm-prompt &> /dev/null; then
      ruby_version="$(rvm-prompt i v g)"
    else
      if which rbenv &> /dev/null; then
        ruby_version="$(rbenv version | sed -e "s/ (set.*$//")"
      fi
    fi
}
chpwd_functions+=(_update_ruby_version)

function current_pwd {
  echo $(pwd | sed -e "s,^$HOME,~,")
}

PROMPT='
${PR_GREEN}%n%{$reset_color%} %{$FG[239]%}at%{$reset_color%} ${PR_BOLD_BLUE}$(box_name)%{$reset_color%} %{$FG[239]%}in%{$reset_color%} ${PR_BOLD_YELLOW}$(current_pwd)%{$reset_color%} $(git_prompt_string)
$(prompt_char) '

export SPROMPT="Correct $fg[red]%R$reset_color to $fg[green]%r$reset_color [(y)es (n)o (a)bort (e)dit]? "

RPROMPT='${PR_GREEN}$(virtualenv_info)%{$reset_color%} ${PR_RED}${ruby_version}%{$reset_color%}'

completion.zsh

Tab completion is like magic, and the incantations in the completions.zsh file are magic to me. I need to learn more about these.

autoload -U compinit && compinit
zmodload -i zsh/complist

# man zshcontrib
zstyle ':vcs_info:*' actionformats '%F{5}(%f%s%F{5})%F{3}-%F{5}[%F{2}%b%F{3}|%F{1}%a%F{5}]%f '
zstyle ':vcs_info:*' formats '%F{5}(%f%s%F{5})%F{3}-%F{5}[%F{2}%b%F{5}]%f '
zstyle ':vcs_info:*' enable git #svn cvs

# Enable completion caching, use rehash to clear
zstyle ':completion::complete:*' use-cache on
zstyle ':completion::complete:*' cache-path ~/.zsh/cache/$HOST

# Fallback to built in ls colors
zstyle ':completion:*' list-colors ''

# Make the list prompt friendly
zstyle ':completion:*' list-prompt '%SAt %p: Hit TAB for more, or the character to insert%s'

# Make the selection prompt friendly when there are a lot of choices
zstyle ':completion:*' select-prompt '%SScrolling active: current selection at %p%s'

# Add simple colors to kill
zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#) ([0-9a-z-]#)*=01;34=0=01'

# list of completers to use
zstyle ':completion:*::::' completer _expand _complete _ignored _approximate

zstyle ':completion:*' menu select=1 _complete _ignored _approximate

# insert all expansions for expand completer
# zstyle ':completion:*:expand:*' tag-order all-expansions

# match uppercase from lowercase
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'

# offer indexes before parameters in subscripts
zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters

# formatting and messages
zstyle ':completion:*' verbose yes
zstyle ':completion:*:descriptions' format '%B%d%b'
zstyle ':completion:*:messages' format '%d'
zstyle ':completion:*:warnings' format 'No matches for: %d'
zstyle ':completion:*:corrections' format '%B%d (errors: %e)%b'
zstyle ':completion:*' group-name ''

# ignore completion functions (until the _ignored completer)
zstyle ':completion:*:functions' ignored-patterns '_*'
zstyle ':completion:*:scp:*' tag-order files users 'hosts:-host hosts:-domain:domain hosts:-ipaddr"IP\ Address *'
zstyle ':completion:*:scp:*' group-order files all-files users hosts-domain hosts-host hosts-ipaddr
zstyle ':completion:*:ssh:*' tag-order users 'hosts:-host hosts:-domain:domain hosts:-ipaddr"IP\ Address *'
zstyle ':completion:*:ssh:*' group-order hosts-domain hosts-host users hosts-ipaddr
zstyle '*' single-ignored show

aliases.zsh

I’ve had some of these aliases for as long as I’ve been working on *nix-based machines. They are as much a part of my muscle memory as tying my shoe or combing my hair. Since zsh tries to spell correct commands, the nocorrect section is at the top. Here is where you put commands that you don’t want spell checked every time they are used.

# -------------------------------------------------------------------
# use nocorrect alias to prevent auto correct from "fixing" these
# -------------------------------------------------------------------
#alias foobar='nocorrect foobar'
alias g8='nocorrect g8'

# -------------------------------------------------------------------
# Ruby stuff
# -------------------------------------------------------------------
alias ri='ri -Tf ansi' # Search Ruby documentation
alias rake="noglob rake" # necessary to make rake work inside of zsh
#alias be='bundle exec'
#alias bx='bundle exec'
#alias gentags='ctags .'

# -------------------------------------------------------------------
# directory movement
# -------------------------------------------------------------------
alias ..='cd ..'
alias ...='cd ../..'
alias ....='cd ../../..'
alias 'bk=cd $OLDPWD'

# -------------------------------------------------------------------
# directory information
# -------------------------------------------------------------------
alias lh='ls -d .*' # show hidden files/directories only
alias lsd='ls -aFhlG'
alias l='ls -al'
alias ls='ls -GFh' # Colorize output, add file type indicator, and put sizes in human readable format
alias ll='ls -GFhl' # Same as above, but in long listing format
alias tree="ls -R | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/   /' -e 's/-/|/'"
alias 'dus=du -sckx * | sort -nr' #directories sorted by size

alias 'wordy=wc -w * | sort | tail -n10' # sort files in current directory by the number of words they contain
alias 'filecount=find . -type f | wc -l' # number of files (not directories)

# -------------------------------------------------------------------
# Mac only
# -------------------------------------------------------------------
if [[ $IS_MAC -eq 1 ]]; then
    alias ql='qlmanage -p 2>/dev/null' # OS X Quick Look
    alias oo='open .' # open current directory in OS X Finder
    alias 'today=calendar -A 0 -f /usr/share/calendar/calendar.mark | sort'
    alias 'mailsize=du -hs ~/Library/mail'
    alias 'smart=diskutil info disk0 | grep SMART' # display SMART status of hard drive
    # Hall of the Mountain King
    alias cello='say -v cellos "di di di di di di di di di di di di di di di di di di di di di di di di di di"'
    # alias to show all Mac App store apps
    alias apps='mdfind "kMDItemAppStoreHasReceipt=1"'
    # reset Address Book permissions in Mountain Lion (and later presumably)
    alias resetaddressbook='tccutil reset AddressBook'
    # refresh brew by upgrading all outdated casks
    alias refreshbrew='brew outdated | while read cask; do brew upgrade $cask; done'
    # rebuild Launch Services to remove duplicate entries on Open With menu
    alias rebuildopenwith='/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.fram ework/Support/lsregister -kill -r -domain local -domain system -domain user'
fi


# -------------------------------------------------------------------
# remote machines
# -------------------------------------------------------------------
alias 'palantir=ssh mhn@palantir.ome.ksu.edu -p 11122'
alias 'pvnc=open vnc://palantir.ome.ksu.edu'
alias 'ksunix=ssh mhn@unix.ksu.edu'
alias 'veld=ssh mhn@veld.ome.ksu.edu'
alias 'dev=ssh mhn@ome-dev-as1.ome.campus'
alias 'wf=ssh markn@markn.webfactional.com'

# -------------------------------------------------------------------
# database
# -------------------------------------------------------------------
alias 'psqlstart=/usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data -l logfile start'
alias 'psqlstop=/usr/local/pgsql/bin/pg_ctl stop'
#alias mysql='mysql -u root'
#alias mysqladmin='mysqladmin -u root'

# -------------------------------------------------------------------
# ome devvm start, stop, ssh, and mount
# -------------------------------------------------------------------
alias 'startvm=VBoxHeadless --startvm devvm'
alias 'stopvm=VBoxManage controlvm devvm poweroff'
alias 'devvm=ssh -p 10022 ome@localhost'

# -------------------------------------------------------------------
# Mercurial (hg)
# -------------------------------------------------------------------
alias 'h=hg status'
alias 'hc=hg commit'
alias 'push=hg push'
alias 'pull=hg pull'
alias 'clone=hg clone'

# -------------------------------------------------------------------
# Git
# -------------------------------------------------------------------
alias ga='git add'
alias gp='git push'
alias gl='git log'
alias gpl="git log --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
alias gs='git status'
alias gd='git diff'
alias gm='git commit -m'
alias gma='git commit -am'
alias gb='git branch'
alias gc='git checkout'
alias gcb='git checkout -b'
alias gra='git remote add'
alias grr='git remote rm'
alias gpu='git pull'
alias gcl='git clone'
alias gta='git tag -a -m'
alias gf='git reflog'
alias gv='git log --pretty=format:'%s' | cut -d " " -f 1 | sort | uniq -c | sort -nr'

# leverage aliases from ~/.gitconfig
alias gh='git hist'
alias gt='git today'

# curiosities
# gsh shows the number of commits for the current repos for all developers
alias gsh="git shortlog | grep -E '^[ ]+\w+' | wc -l"

# gu shows a list of all developers and the number of commits they've made
alias gu="git shortlog | grep -E '^[^ ]'"

# -------------------------------------------------------------------
# Python virtualenv
# -------------------------------------------------------------------
alias mkenv='mkvirtualenv'
alias on="workon"
alias off="deactivate"

# -------------------------------------------------------------------
# Oddball stuff
# -------------------------------------------------------------------
alias 'sloc=/usr/local/sloccount/bin/sloccount'
alias 'adventure=emacs -batch -l dunnet' # play adventure in the console
alias 'ttop=top -ocpu -R -F -s 2 -n30' # fancy top
alias 'rm=rm -i' # make rm command (potentially) less destructive

# Force tmux to use 256 colors
alias tmux='TERM=screen-256color-bce tmux'

# alias to cat this file to display
alias acat='< ~/.zsh/aliases.zsh'
alias fcat='< ~/.zsh/functions.zsh'
alias sz='source ~/.zshrc'


# -------------------------------------------------------------------
# some Octopress helpers
# -------------------------------------------------------------------
alias 'generate=date ; rake generate ; date ;'
alias 'gen=date ; rake generate ; date ;'
alias 'ingen=date ; rake integrate ; generate ; date ;'
alias 'deploy=rm deploy.log ; rake deploy > deploy.log ; tail -n 3 deploy.log ;'
alias 'np=newpost.rb'

# copy .htaccess files for zanshin.net and its image sub-directory
alias 'htaccess=scp /Users/mark/Projects/octopress/zanshin/source/htaccess/.htaccess markn@markn.webfactional.com:~/webapps/zanshin ; scp /Users/mark/Projects/octopress/zanshin/source/images/.htaccess markn@markn.webfactional.com:~/webapps/zanshin/images ;'

# deploy zanshin.net and move its .htaccess files
alias 'dz=deploy ; htaccess ;'

# -------------------------------------------------------------------
# Source: http://aur.archlinux.org/packages/lolbash/lolbash/lolbash.sh
# -------------------------------------------------------------------
alias wtf='dmesg'
alias onoz='cat /var/log/errors.log'
alias rtfm='man'
alias visible='echo'
alias invisible='cat'
alias moar='more'
alias icanhas='mkdir'
alias donotwant='rm'
alias dowant='cp'
alias gtfo='mv'
alias hai='cd'
alias plz='pwd'
alias inur='locate'
alias nomz='ps aux | less'
alias nomnom='killall'
alias cya='reboot'
alias kthxbai='halt'

bindkeys.zsh

Create your own keybindings for fun and profit. Still more material to learn better.

# To see the key combo you want to use just do:
# cat > /dev/null
# And press it

bindkey "^K"      kill-whole-line                      # ctrl-k
bindkey "^R"      history-incremental-search-backward  # ctrl-r
bindkey "^A"      beginning-of-line                    # ctrl-a
bindkey "^E"      end-of-line                          # ctrl-e
bindkey "[B"      history-search-forward               # down arrow
bindkey "[A"      history-search-backward              # up arrow
bindkey "^D"      delete-char                          # ctrl-d
bindkey "^F"      forward-char                         # ctrl-f
bindkey "^B"      backward-char                        # ctrl-b
bindkey -v   # Default to standard vi bindings, regardless of editor string

functions.zsh

Some of these are my own creation, others I’ve picked up along the way. The most recent addition, path() displays your current PATH beautifully. Immensely helpful when sorting out path issues.

# -------------------------------------------------------------------
# compressed file expander
# (from https://github.com/myfreeweb/zshuery/blob/master/zshuery.sh)
# -------------------------------------------------------------------
ex() {
    if [[ -f $1 ]]; then
        case $1 in
          *.tar.bz2) tar xvjf $1;;
          *.tar.gz) tar xvzf $1;;
          *.tar.xz) tar xvJf $1;;
          *.tar.lzma) tar --lzma xvf $1;;
          *.bz2) bunzip $1;;
          *.rar) unrar $1;;
          *.gz) gunzip $1;;
          *.tar) tar xvf $1;;
          *.tbz2) tar xvjf $1;;
          *.tgz) tar xvzf $1;;
          *.zip) unzip $1;;
          *.Z) uncompress $1;;
          *.7z) 7z x $1;;
          *.dmg) hdiutul mount $1;; # mount OS X disk images
          *) echo "'$1' cannot be extracted via >ex<";;
    esac
    else
        echo "'$1' is not a valid file"
    fi
}

# -------------------------------------------------------------------
# any function from http://onethingwell.org/post/14669173541/any
# search for running processes
# -------------------------------------------------------------------
any() {
    emulate -L zsh
    unsetopt KSH_ARRAYS
    if [[ -z "$1" ]] ; then
        echo "any - grep for process(es) by keyword" >&2
        echo "Usage: any " >&2 ; return 1
    else
        ps xauwww | grep -i --color=auto "[${1[1]}]${1[2,-1]}"
    fi
}

# -------------------------------------------------------------------
# display a neatly formatted path
# -------------------------------------------------------------------
path() {
  echo $PATH | tr ":" "\n" | \
    awk "{ sub(\"/usr\",   \"$fg_no_bold[green]/usr$reset_color\"); \
           sub(\"/bin\",   \"$fg_no_bold[blue]/bin$reset_color\"); \
           sub(\"/opt\",   \"$fg_no_bold[cyan]/opt$reset_color\"); \
           sub(\"/sbin\",  \"$fg_no_bold[magenta]/sbin$reset_color\"); \
           sub(\"/local\", \"$fg_no_bold[yellow]/local$reset_color\"); \
           print }"
}

# -------------------------------------------------------------------
# Mac specific functions
# -------------------------------------------------------------------
if [[ $IS_MAC -eq 1 ]]; then

    # view man pages in Preview
    pman() { ps=`mktemp -t manpageXXXX`.ps ; man -t $@ > "$ps" ; open "$ps" ; }

    # function to show interface IP assignments
    ips() { foo=`/Users/mark/bin/getip.py; /Users/mark/bin/getip.py en0; /Users/mark/bin/getip.py en1`; echo $foo; }

    # notify function - http://hints.macworld.com/article.php?story=20120831112030251
    notify() { automator -D title=$1 -D subtitle=$2 -D message=$3 ~/Library/Workflows/DisplayNotification.wflow }
fi

# -------------------------------------------------------------------
# nice mount (http://catonmat.net/blog/another-ten-one-liners-from-commandlingfu-explained)
# displays mounted drive information in a nicely formatted manner
# -------------------------------------------------------------------
function nicemount() { (echo "DEVICE PATH TYPE FLAGS" && mount | awk '$2="";1') | column -t ; }

# -------------------------------------------------------------------
# myIP address
# -------------------------------------------------------------------
function myip() {
  ifconfig lo0 | grep 'inet ' | sed -e 's/:/ /' | awk '{print "lo0       : " $2}'
  ifconfig en0 | grep 'inet ' | sed -e 's/:/ /' | awk '{print "en0 (IPv4): " $2 " " $3 " " $4 " " $5 " " $6}'
  ifconfig en0 | grep 'inet6 ' | sed -e 's/ / /' | awk '{print "en0 (IPv6): " $2 " " $3 " " $4 " " $5 " " $6}'
  ifconfig en1 | grep 'inet ' | sed -e 's/:/ /' | awk '{print "en1 (IPv4): " $2 " " $3 " " $4 " " $5 " " $6}'
  ifconfig en1 | grep 'inet6 ' | sed -e 's/ / /' | awk '{print "en1 (IPv6): " $2 " " $3 " " $4 " " $5 " " $6}'
}

# -------------------------------------------------------------------
# (s)ave or (i)nsert a directory.
# -------------------------------------------------------------------
s() { pwd > ~/.save_dir ; }
i() { cd "$(cat ~/.save_dir)" ; }

# -------------------------------------------------------------------
# console function
# -------------------------------------------------------------------
function console () {
  if [[ $# > 0 ]]; then
    query=$(echo "$*"|tr -s ' ' '|')
    tail -f /var/log/system.log|grep -i --color=auto -E "$query"
  else
    tail -f /var/log/system.log
  fi
}

# -------------------------------------------------------------------
# shell function to define words
# http://vikros.tumblr.com/post/23750050330/cute-little-function-time
# -------------------------------------------------------------------
givedef() {
  if [[ $# -ge 2 ]] then
    echo "givedef: too many arguments" >&2
    return 1
  else
    curl "dict://dict.org/d:$1"
  fi
}

history.zsh

The variables control how the command history is managed.

# HISTORY
HISTSIZE=10000
SAVEHIST=9000
HISTFILE=~/.zsh_history

zsh_hooks.zsh

This file controls the use of the precmd, preexec and postcmd features. I’m not entirely sure I understand all there is to know about this. It’s on the list to investigate more thoroughly.

function precmd {
  # vcs_info
  # Put the string "hostname::/full/directory/path" in the title bar:
  echo -ne "\e]2;$PWD\a"

  # Put the parentdir/currentdir in the tab
  echo -ne "\e]1;$PWD:h:t/$PWD:t\a"
}

function set_running_app {
  printf "\e]1; $PWD:t:$(history $HISTCMD | cut -b7- ) \a"
}

function preexec {
  set_running_app
}

function postexec {
  set_running_app
}

z.sh

z tracks your most used directories based on ‘frequency’. By typing z and part of a directory name I can quickly jump to that part of the file system. Obviously the longer you have it installed the better it performs. I highly recommend it.

Looking Forward

My original RVM + oh-my-zsh configuration had the path and setup for RVM contained in the .zlogin file. The new rbenv + zsh configuration has the rbenv setup in .zshenv. I need to read more on these two files and decide which ought to be used.

I need to explore the subject of bindkeys more to fully understand what they are and how I can benefit from them. I also need to learn about precmd, preexec, and postexec. There use in my setup was copied from ze-best-zsh-config. And zsh_hooks.

My testbed machine has 100 GB of free space on it’s hard drive that I am planning on using to install Linux Mint. Once that OS is setup and running I want to use my dotfiles repository, including the new zsh configuration, there. As I get things setup and working under Linux I’m sure there will be Linux-specific tweaks to add to the configuration.

In the end I’m not sure I’ve made my prompt load any faster. I certainly understand the processes and configuration behind it far better than before. I haven’t taken the step of removing all the entires from /etc/paths.d and placing them directly into my $PATH. This feels like something that would need constant minding and I’m not ready for that yet.

I’ll need to live with this setup for a while to discover things I’ve lost by leaving oh-my-zsh. Hopefully nothing to drastic or hard to configure myself. It’s been an interesting couple of weeks sorting this out. I have a greater appreciation for my shell now, and a greater understanding of what makes it tick.


The First Rule


{{ “B005X4AMBK” | amazon_mediumleft_image }} The First Rule is the second Joe Pike book the Robert Crais has written. While Elvis Cole plays a minor role in the story it really centers on Pike. The the Elvis Cole series, this book was quick-paced and easy to consume in a couple of sittings. After years of only seeing the still surface of Pike’s character, it is interesting to finally get to plumb his depths.