Navigating the Command Line

When learning to love the command line, nothing made a bigger difference to me than when I discovered I could edit commands with out pressing and holding the arrow keys. That was just slow and awkward. There is a better way. Really you only need two or three little tricks and you will be in a whole new world of productivity.

If you can only learn one thing, learn these two keyboard shortcuts:

Jump to the beginning

Pressing control-a will jump the cursor to the beginning of the line.
Mnemonic: Control-Awesome I can move back to the beginning with out holding the arrow key.
Also I find I remember this because the A key is the furthest left key on the home row.

Jump to the end

Pressing control-e will jump the cursor to the end of the line.
Mnemonic: Control-End

Now, take a few minutes to go give those a try. I’ll wait.

Want some more? Rad. But a little caution if you are just learning these things: just pick a couple and find ways to use them until they are second nature. Practice. If you think you are ready for more, here you go. I think these are the next most useful:

Delete Back a Word

Pressing control-w will delete the word before the cursor.
Mnemonic: Control-Why did I type that Word

Delete to the End

Pressing control-k will delete from the cursor to the end of the line
Mnemonic: Control-Kill to the end of the line

Delete to the Beginning

Pressing control-u will delete from the cursor to the beginning of the line
Mnemonic: Control-Uhh that wasn't right

I think these are the most critical shortcuts to learn, and have made life on the command line damn nice.

A Bit About Input Modes

Really I should end this post here, but am somehow compelled to mention this thing called input modes.

There are two input modes that a command line will use: vi or emacs.

The examples above assume you are using emacs mode for your shell. This is the default for bash and most other shells. If you are having problems with them you may need to set the input mode. In bash you can simply run set -o emacs

I can hear you asking “But wait, you are a vim guy, why do you use emacs mode for your shell?”

Well, it wasn’t an easy choice. I thought I would like vi mode on the command line. And I tried to use it. I wanted to want to. But in the end it was just never felt right.

My reasons:

  1. It is the default on most systems. Nice to open a new term on a strange server and have things Just Work™.
  2. Anywhere libreadline is used these things will work. Basically this is the line editing library that most terminal based apps will use. This includes your shell, bash, irb, ipython, irc clients and the like.
  3. I use a Mac, and there is a decent overlap between the default keyboard shortcuts in Cocoa and emacs mode.
  4. On the command line I can quickly edit the command in vim by mashing Control-X Control-E or running fc.
  5. And probably the most critical reason is I have the exact same keybindings in Vim’s insert and command modes.

Ignore Advice from Blog Articles

The only thing you should do is pick some tools and learn them. Don’t worry about what some random blog article says. Don’t worry about those kids on irc demanding you use zsh. Don’t worry about editors – learn something. It will all translate in some way, won’t be wasted effort. Most important thing you can do as a developer is train how to use your tools.

What do you use?

What command line tricks do you use to make your day happier?



Making ARC and non-ARC files play nice together

If you want to exclude a file from being compiled with ARC you can do so by setting a flag on the .m file:

Click the Project -> Build Phases Tab -> Compile Sources Section -> Double Click on the file name

Then add -fno-objc-arc to the popup window.

Likewise, if you want to include a file in ARC, you can use the -fobjc-arc flag.

Xcode Screen Shot

See the clang docs for more details.

A helpful trick is to use the __has_feature language extension to throw errors when this is not set properly.

Enforce a file is ARC:

#if ! __has_feature(objc_arc)
#error This file must be compiled with ARC. Either turn on ARC for the project or use -fobjc-arc flag
#endif

The inverse:

#if __has_feature(objc_arc)
#error This file cannot be compiled with ARC. Either turn off ARC for the project or use -fno-objc-arc flag
#endif

This was adapted from a post by Greg Parker on the on the Objective-C mailing list. He goes on to point out the following:

You should be careful with the interface to your shared code such that ARC and non-ARC clients can use it freely.

  • Conform to Cocoa’s memory management conventions even though an all-ARC or no-ARC project would not require it
  • Don’t use object pointers inside C structs
  • Avoid CF types


Prevent Xcode from opening extra projects

Insistent I don’t want persistence.

I’ve been a little annoyed with Xcode on Lion. Every time I open a project it also opens the last project I was working on. This might be fine if I was only working on one project – but recently I have been working on Captured in the evenings, and Zippy’s iPhone app during the day. I don’t want to open the project for Captured when I get to work in the morning. Plus it is particularly frustrating when one of those projects is a workspace, if you create a new project Xcode insists on adding it to the current workspace.

The solution: fix my xcode script, by passing in a user defaults flag.

I have been using a helper function to load xcode from the command line for a while now, and really it is the primary way that I open a project. Maybe I am in minority for Cocoa developers, but I live on the command line – so this is better for me.

#!/usr/bin/env ruby
f = []
f.concat Dir["*.xcworkspace"]
f.concat Dir["*.xcodeproj"]

if f.length > 0
  puts "opening #{f.first}"
  `open -a /Developer/Applications/Xcode.app #{f.first} --args -ApplePersistenceIgnoreState YES`
  exit 0
end

puts "No Xcode projects found"
exit 1

The trick is the ApplePersistenceIgnoreState option passed in to Xcode, this overrides the NSUserDefault for the app persistence.

If you want to use this, just create a file xcode somewhere in your path and then set it to be executable chmod +x xcode. Then opening project is as simple as:

cd path/to/proj
xcode

Refreshing.



Project specific git author, without the gas pains

I heard about a git-related project called GAS, the Git Author Switcher, on that Ruby5 podcast–and initially I was intrigued. But once I thought about it, I think there is a better way to handle this. With just plain ole git.

Why don’t I like having GAS? Well, it changes the author globally – and you have to remember to switch it up when changing projects. I would prefer to set it on a per project basis, then forget about it.

So my setup is to put my personal user and email (i.e. the one I use on github) in the global config, which most anyone using git should have setup already:

git config --global user.name "Chris"
git config --global user.email "chris@personal.dev"

Then in my work projects, I use a different email address, so I change it in that repo by running:

git config user.email "chris@work.dev"

Luckily, I don’t use a different name at work, so there is no need to override that setting. Although I could if I really wanted to.

If you have to to this frequently, I think a simple git alias is pretty nice for streamlining this:

git config --global alias.workprofile 'config user.email "chris@work.dev"'

Then when you clone a new work project, just run git workprofile and it will be configured to use that email.

Admittedly, if you are using a shared machine or are pairing (or pairing on a shared machine), then GAS might be exactly what you need. Just use the right tool for the job.



Multiple Dropboxen on Mac the right way

I really didn’t like the way other people explained setting up multiple dropboxen on a mac, which involved creating multiple directories and files, incliuding, of all things, faux app bundles. This bugged me, so I made a new launchd.plist and drive it all from that one config file.

First, create a file in ~/Library/LaunchAgents/com.dropbox.alt.plist with the following contents, updating the USERNAME for your username.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>com.dropbox.alt</string>
    <key>LowPriorityIO</key>
    <true/>
    <key>EnvironmentVariables</key>
    <dict>
      <key>HOME</key>
      <string>/Users/USERNAME/.dropbox-alt</string>
    </dict>
    <key>ProgramArguments</key>
    <array>
      <string>/Applications/Dropbox.app/Contents/MacOS/Dropbox</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
  </dict>
</plist>

Second, run the following commands:

launchctl load ~/Library/LaunchAgents/com.dropbox.alt.plist
launchctl start com.dropbox.alt

The Dropbox dialog will appear. On the “Setup Type” screen of their installer make sure you change the folder to a custom location that makes sense for you (otherwise it will put it in ~/.dropbox-alt/Dropbox).

Dropbox Installer

Done. No faux app bundles. Everything is controled by launchd, just the way it should be.