Hotkeys for searching the Cocoa docs

Here's how to create global hotkeys for instantly searching the Cocoa docs using Dash, AppKiDo, or Xcode.

This whole exercise started when I saw this tweet by Matt Gemmell:

There’s a kind of zen calmness to the docs page for NSNull.

Since I have Dash installed, and since I've assigned a hotkey to its "Look up in Dash" system service, it took me all of two seconds, maybe less, to confirm this. I selected the word "NSNull", hit the hotkey, and there it was. Matt's right.

Here's where I assign the Dash hotkey, in System Preferences > Keyboard > Keyboard Shortcuts > Services:

Look up in dash

"Look up in AppKiDo"

UPDATE: You can ignore the rest of this post. I added a real system service to AppKiDo in version 0.991. You can configure a hotkey for the service just as you would for any other system service.

This got me thinking about adding a similar system service to AppKiDo. I wondered whether I should try to squeeze that into the upcoming release (which will have a few small changes, most importantly to point to appkido.com instead of MobileMe). But then I realized I could just use a keyboard macro utility (in my case, Keyboard Maestro) to accomplish the same thing. I created a keyboard shortcut that does the following: * Type Command-E, which is Mac standard for "Use Selection for Find". This puts whatever text is selected in your current app into the Find pasteboard. * Activate AppKiDo, which now displays the selected string in the Search field. * Type Shift-Command-F (which selects the Search field) and Return (which initiates a search). Look up in appkido Now I can look up NSNull in AppKiDo the same way as I did in Dash, by selecting text and hitting a key. This assumes AppKiDo has a browser window open and frontmost, but for me that's always the case. To search AppKiDo-for-iPhone, you'd need a separate hotkey. If you want to get technical, AppKiDo doesn't show the whole docs page, only one part of it at a time. To see the whole HTML page, and thus appreciate its zen-ness, you'd have to right-click and select "Open Page in Browser". And then you'd have to dismiss a dialog in Safari because that file is quarantined. So now we're talking maybe five seconds. Dash wins handily at displaying the whole page. ## The YoruFukurou problem While testing my "Look up in AppKiDo" shortcut, I discovered that YoruFukurou doesn't support the "Use Selection for Find" operation. It bugged me to have this edge case, so I created a variant of the shortcut just for YoruFukurou:
  • Type Command-C (copy to the clipboard).
  • Run the following AppleScript to activate AppKiDo and do the search.
    tell application "AppKiDo"
        activate
        search (the clipboard)
    end
Just for yorufukurou This uses the fact that AppKiDo can be scripted to do a search. I also use Keyboard Maestro's ability to have a keyboard shortcut do different things depending on which application is active, so I don't have to remember a separate shortcut for the YoruFukurou case. The reason I don't use this approach in all cases is that Command-C blows away the contents of the copy-paste pasteboard, whereas Command-E uses a different pasteboard. ## "Look up in Xcode" Finally, just for grins, I thought I'd do a similar shortcut for doing the search in Xcode. Xcode is very slow at searching the documentation, but it's useful for doing full-text searches of the complete documentation, as opposed to searching only the API reference docs based on the name of the API symbol. This shortcut uses the fact that in Xcode, hitting Shift-Option-Command-/ (aka Option-Command-?) always causes the doc window to be open with the Search field selected. * Type Command-C to copy the desired search string into the clipboard. * Activate Xcode. * Type Shift-Option-Command-/ to bring up the doc window, and Command-V to paste the search string into the search field. Look up in xcode Note that *within* Xcode there's already a shortcut for searching the docs for the selected text: Control-Option-Command-/ (last item in the Help menu).

[UPDATE: I'm getting better about editing my posts after publishing them, but I couldn't resist making a few changes. Nothing major.]

Dumb comments on purpose

(Note: This is about comments in code, not the topic of blog comments which was debated recently by various bloggers.)

One of the first things they teach programmers about comments is, "Don't merely repeat in the comment what the line of code literally does." A laughable example such as the following is usually given.

x = y * y;  // Set x to the square of y.

In general I abide by this rule, but there is one exception: when I need a comment to turn a line of code into a section of code.

I use inline comments to break a block into logical sections. Taken by themselves, the comments tell a story. For example, here's a method that creates a cake, the way some people would write it:

- (xxx *)cake
{
    // Bake in oven.
    xxxxx;
    xxxxx;
    xxxxx;
 
    // Add icing.
    xxxxx;
    xxxxx;
 
    return xxxxx;
}

The above code doesn't look right to me, because it looks like the "return xxxxx;" is part of the "Add icing" step when it's not. To rectify this I add a dumb comment that puts "return xxxxx;" into its own section:

- (xxx *)cake
{
    // Bake in oven.
    xxxxx;
    xxxxx;
    xxxxx;
 
    // Add icing.
    xxxxx;
    xxxxx;
 
    // Return the result.
    return xxxxx;
}

I do something similar with methods that run through a gauntlet of reasons for possibly returning early. If they survive the gauntlet, I add a dumb "If we got this far…" comment.

- (BOOL)shouldEatIceCream
{
    // Is the ice cream poisoned?
    if (xxxxx)
    {
        return NO;
    }
 
    // Is it my birthday?
    if (xxxxx)
    {
        return YES;
    }
 
    // If we got this far, we shouldn't eat the ice cream.
    return NO;
}

I try to think of something more intelligent to say in these comments, but often I don't.

Use parens as a hint to Xcode's autoindent

Sometimes I wish Xcode's autoindent would do things a little differently. For example, I like to use C's ternary operator:

NSString *label = [self someBooleanTest]
                  ? [self methodWithASortOfLongishName]
                  : [self anotherMethodWithALongishName];

Unfortunately Xcode (at least Xcode 3) autoindents this code like this:

NSString *label = [self someBooleanTest]
? [self methodWithASortOfLongishName]
: [self anotherMethodWithALongishName];

As a workaround, I use the fact that Xcode likes to align things under parentheses and other opening delimiters:

NSString *label = ([self someBooleanTest]
                   ? [self methodWithASortOfLongishName]
                   : [self anotherMethodWithALongishName]);

This can help with other compound expressions as well:

BOOL rectContainsPoint = ((point.x > NSMinX(rect))
                          && (point.x < NSMaxX(rect))
                          && (point.y > NSMinY(rect))
                          && (point.y < NSMaxY(rect)));

Side note: The reason I parenthesized the subexpressions of the boolean expression above is so I can easily select a subexpression by double-clicking on a parenthesis. This makes it easier to eyeball for correctness. I don't always do this — I probably wouldn't have done it with this particular code — but when I do it's more for this reason than for protecting myself from an operator-precedence mistake.

I have other indentation quibbles that I don't have workarounds for. I'll submit Radars for them when I get around to checking that they're still present in Xcode 4.

UPDATE: Parentheses can also help with autoindenting of blocks:

volumeCalculator = (^(float width, float height, float depth)
                    {
                        return width * height * depth;
                    });

Without the parentheses, the above would look like this, which makes less sense to me:

volumeCalculator = ^(float width, float height, float depth)
{
    return width * height * depth;
};

Double braces for start/end blocks

My friend Demitri showed me a coding technique he uses when he has a bunch of lines that need to be preceded by a "start" statement of some sort and followed by an "end" statement of some sort.

A recent example in my own code looks roughly like this:

[self startOutput];  // top-level "start"
 
[self startImageAssets];
[self addImageAssets];
[self endImageAssets];
 
[self startThumbnailAssets];
[self addThumbnailAssets];
[self endThumbnailAssets];
 
[self startAudioAssets];
[self addAudioAssets];
[self endAudioAssets];
 
[self endOutput];  // top-level "end"

The problem is that the "start" and the "end" may be far enough apart that it's not visually apparent that the lines in between are logically nested. In some cases, though not so much in this example, it can be easy to forget to add the "end" statement.

One approach would be to wrap all the interior stuff into a method, so it collapses into one line:

[self startOutput];
[self outputAllAssets];
[self endOutput];

This follows the excellent principle of Keeping Methods Short, and now the beginning/middle/end sequence is clear. But this isn't always convenient, and I don't always prefer it over inlining the intermediate statements.

I've seen code that indents the internal statements like this:

[self startOutput];
 
    [self startImageAssets];
    [self addImageAssets];
    [self endImageAssets];
 
    [self startThumbnailAssets];
    [self addThumbnailAssets];
    [self endThumbnailAssets];
 
    [self startAudioAssets];
    [self addAudioAssets];
    [self endAudioAssets];
 
[self endOutput];

I didn't indent the "add" statements because each of those groups of three lines is short enough that it's obvious what's going on, and I think indenting the middle lines would make the code harder to read, at least to my eye.

The problem with this approach is that when you tell Xcode to Re-Indent, you will lose all your custom indentation. (Side note: I'm not sure, but it seems to me "Re-Indent" in the Xcode menu should be "Re-indent".)

Demitri's solution is to put the internal statements into a C block, like this:

[self startOutput];
{
    [self startImageAssets];
    [self addImageAssets];
    [self endImageAssets];
 
    [self startThumbnailAssets];
    [self addThumbnailAssets];
    [self endThumbnailAssets];
 
    [self startAudioAssets];
    [self addAudioAssets];
    [self endAudioAssets];
}
[self endOutput];

This works nicely, but one teeny-weeny thing about it bothers me. When I see that opening brace it feels like I'm missing a line, like maybe I accidentally deleted an "if" or a "while". I could probably get used to this, especially since the "start" in the line above is a strong clue. But just to help myself see my intentions, I've taken to using double curly-braces:

[self startOutput];
{{
    [self startImageAssets];
    [self addImageAssets];
    [self endImageAssets];
 
    [self startThumbnailAssets];
    [self addThumbnailAssets];
    [self endThumbnailAssets];
 
    [self startAudioAssets];
    [self addAudioAssets];
    [self endAudioAssets];
}}
[self endOutput];

Now when I scan the code I can clearly see that the reason for the block was to indicate logical nesting.

This technique can also be useful for Create/Release pairs in CF code, or alloc/release pairs in Cocoa or iOS code. Or for those times when you create your own autorelease pool:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
{{
    // Autoreleased objects here go into the local pool.
}}
[pool drain];  // Less likely you'll forget to drain the pool.

I believe the example Demitri showed me was a begin/commit animation block in his iOS code. With the double braces it would look like this:

[UIView beginAnimations:animationID context:context];
{{
    // Add an animation to the animation block.
    // Add an animation to the animation block.
    // ...
}}
[UIView commitAnimations];

One concern is that someone else reading my code might be confused if they're not familiar with the convention I adopted. Ideally it would turn out I wasn't the first to think of the double-braces approach, and actually lots of people do it this way. But I haven't come across it. Maybe most people take the first approach I mentioned and create a separate method or function.

I think of the double braces sort of like the double parens in "old-style" init methods (which are not how Apple does them any more, but perfectly fine technically):

if ((self = [super init]))
{
    // ...
}

The double parens avoid a warning from the compiler that you might have meant == instead of =. My double braces avoid a "mental compiler warning" that I might be missing an "if" or a "while".