One of the more annoying tasks when writing Cocoa code is defining symbolic constants for all those keys when doing key-value coding. I've already posted  my trick for getting auto-validated key-value-observing constants, but there are constants that aren't accessors. Does lazy Uli have a trick for these as well?

xcode_user_scripts.jpg

Yes! Xcode has a really neat feature called "User scripts". It takes the form of a little black scripture roll in the menu bar. If you open it, there is an "Edit User Scripts..." menu item. Choose it, and it shows a list of the scripts that come with Xcode, plus an edit field on the right where you can edit the current script.

The neat thing here is: These are just unix shell scripts. Notice the shebang at the top? That means you can specify every script interpreter, and you aren't stuck with those terrible search-and-replace-with-side-effects-languages like bash or zsh. You could use Perl, or Ruby, or ... heck, why not use PHP? Let's do that, let's solve our problem with constants in PHP. Click the "+" button and add a new script, change its name and give it a nice keyboard shortcut (I chose Cmd-Ctrl-K, K as in Konstant - C was already taken). Then paste in the folowing script:

#!/usr/bin/php
<?php
$fd = fopen( "php://stdin", "r" ) ;
$the_ident = fgets($fd) ;
echo "NSString*\t$the_ident = @\"$the_ident\"; \n";
?>

Make sure the "Input" popup is set to "Selection", and the "Output" is set to "Place on Clipboard". Now, whenever you need a new string constant as a dictionary key in Cocoa, you can just write the constant's symbolic name

MyAppShouldOpenUntitledWindowPrefsKey

select it by double-clicking, hit Cmd-Ctrl-K, and then paste a finished declaration for it at the top of your source file:

NSString*    MyShouldOpenUntitledDocPrefsKey = @"MyShouldOpenUntitledDocPrefsKey";

Of course that's just one of the neat macro things you can do. Since most scripting languages these days support regular expressions, you can do things like turn detect string literals on a line and generate a .strings file entry from it (or vice versa), put brackets and angle brackets around the selected expression (set the output to also be "Selection"), and do a multitude of other handy things.

Okay, you don't really have to write code for putting brackets around certain expressions. Just look in the Edit -> Insert Text Macro -> C and Edit -> Insert Text Macro -> Objective-C submenus. You can use the Preferences window's Key Bindings page to specify keyboard shortcuts (I chose Cmd-Ctrl-9, the key where my UK keyboard has the opening bracket, for Parenthesize Expression and Cmd-Ctrl-[ for Bracket Expression).

Of course, you can also put scripts in this menu that talk to the command line tool for your version control system of choice. For example, if you're as addicted to GUI clients as I am, you'll want the following script:

#!/bin/bash
# Find current document's repository root and cd to it:
MYPATH=`osascript -e "tell application \"Xcode\" to (path of document 1)"`
while [[ -n "$MYPATH" && "$MYPATH" != "/" && ! -e "$MYPATH/.git" ]]
do
	MYPATH=`dirname "$MYPATH"`
done
cd "$MYPATH"
if [[ -n "$MYPATH" && "$MYPATH" != "/" ]]
then
	# Now do our magic!
	open -a GitX.app "$MYPATH"
fi

This opens the current Xcode file's Git repository in GitX so you can get yourself some hot merging and staging goodness. You can write a lot of code following this principle. For example, here is a script that does a git push on the project folder in a Terminal window, so you can actually type something into the password prompt:

#!/bin/bash
# Find current document's repository root and cd to it:
MYPATH=`osascript -e 'tell application "Xcode" to (path of document 1)'`
while [[ -n "$MYPATH" && "$MYPATH" != "/" && ! -e "$MYPATH/.git" ]]
do
 MYPATH=`dirname "$MYPATH"`
done

cd "$MYPATH" if [[ -n "$MYPATH" && "$MYPATH" != "/" ]] then # Now do our magic! IGNORE=`osascript -e "tell application \"Terminal\" to do script \"cd \" & quote & \"${MYPATH}\" & quote & \"; git push\""` fi

Any other suggestions for other useful scripts for coding that one may want to put in this menu?