
15 Most Recent [RSS]
More...
|
Helpful Xcode User Scripts
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?
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?
Julián Romero writes: I use this one a lot. It adds a log of the selected variable:
#! /bin/sh
echo -n 'NSLog(@"%%%{PBXSelectedText}%%% => %@", %%%{PBXSelectedText}%%%%%%{PBXSelection}%%%);'
|
Ross Carter writes: I'm not a good typist, so I use user scripts to type things for me, like a divider:
#! /usr/bin/perl -w
# -- PB User Script Info --
# %%%{PBXName=NSLog}%%%
# %%%{PBXOutput=ReplaceSelection}%%%
use strict;
my $object = <<'SELECTION';
%%%{PBXSelectedText}%%%
SELECTION
chomp $object;
print "//-------------------------------------------------------
// xxxxxxxxxxxx
//-------------------------------------------------------
";
exit 0;
or logging the method selector:
(same as above but with:) print "NSLog(@\"%s\", _cmd);";
or localized strings:
print "NSLocalizedStringFromTable(@\"%%%{PBXSelectedText}%%%\", @\"TABLEGOESHERE\", @\"%%%{PBXSelectedText}%%%\")";
NSStringFrom (type re or ra to get autocompletion for Rect, Range, etc):
print "NSStringFrom";
and various pragmas, to promote consistency in how I organize code within a file:
print "#pragma mark -\n";
print "#pragma mark IBActions\n";
|
Uli Kusterer replies: ★ Dirk, that's a neat script, though it's unfortunate that it needs to mark up the ivars in a way that requires changes to the actual code. I wouldn't be able to use this on many open source projects unless I can convince everyone to use it.
|
Uli Kusterer replies: ★ Andy, that sounds like a neat idea, and Peter's command line tool looks like a good start. Would love to see what becomes of this. Along similar lines, I'd love a script that auto-adds method declarations to the @interface for a method I just declared in @interface. I.e. I write the implementation, leave the cursor somewhere nearby, start the script, and it finds the method signature, opens the header, finds the @implementation in there and inserts the prototype there.
It'd be even cooler to be able to do that from a call: Double-click opening bracket and it'll analyze the types of the parameters and generate the right signature, then create an empty implementation and interface declaration. But I guess for that one might need Clang to actually parse the code.
|
Uli Kusterer replies: ★ Julian, that one is neat. Short, sweet, and will log any object type. Would be interesting to see if one could do a localized search and try to determine the type of that variable, then also make it work for ints etc. |
|  |