MainTemplateFile is the main file to create. CounterpartTemplateFileis an optional second file. Description is the description that will appear in the new file window. So if you change description to ‘my test template’ and open the new file dialog you will see a User Templates section with a grouping named
YourGroupingName. Selecting this will show your file template.
Again, the name of the template directory (before the .pbfiletemplate part) will become the name of your file template.
If you read some of the existing file templates you can find some constants that will be replaced when the file is created. These will allow you to insert the new file name into the generated text (
<<FILEBASENAMEASIDENTIFIER>>), for instance.
Custom TextMate – Like Macros
One of the things I missed most about TextMate was the easy tab based macro completion with placeholders. It turns out that Xcode actually has something similar, but it is relatively painful to learn how to add your own macros. I’ll be covering how to do this in this section.
The first thing you’ll want to do is take note of the code completion keys that you have set up in the Xcode preferences. These can be found under Xcode preferences -> Key Bindings -> Edit -> Next Completion, Completion List, and Select Next Placeholder. I remapped these to be on my home row because I use them so much.
To follow the pattern of the rest of this post, I will be taking some existing Xcode macros and bending them to my evil will. First create a Specifications directory in your user override directory:
~/Library/Application Support/Developer/Shared/Xcode/Specifications. Then you’ll need to find the xcode macro specifications. These are in
/Developer/Applications/Xcode.app/Contents/PlugIns/TextMacros.xctxtmacro/Contents/Resources/. Copy the ObjectiveC.xctxtmacro file into your new Specifications directory. Any changes in this file will override the previous macro definitions; you are free to change existing macros or add more to your hearts content.
If you open your copy of ObjectiveC.xctxtmacro you will see a long list of declarations similar to this:
Identifier = objc.try;
BasedOn = objc;
IsMenuItem = YES;
Name = "Try / Catch Block";
TextString = "gibberish";
CompletionPrefix = "@try";
IncludeContexts = ( "xcode.lang.objc.block" );
Identifier - unique id for the macro. Doesn’t matter what this is, as long as it is unique.
BasedOn - This is a simple inheritance scheme. You can base one macro on another and any keys that are not declared will be pulled from the parent. Usually you will leave this as objc.
IsMenuItem - Determines whether or not this macro will show up in the Edit -> Insert Text Macro menu. Most of the time I set this to NO.
Name - This is the name the macro will appear under in the Edit -> Insert Text Macro menu if IsMenuItem is yet. Usually I put something descriptive in here regardless of whether it is a menu item, to make it easier to determine the purpose of the entry.
TextString - This is the string that your macro will expand to. You can ignore the funky syntax for now, I will explain it shortly. I’ve replaced it with ‘gibberish’ here, for clarity.
CompletionPrefix - this is the basic macro. If you type @try and then hit Next Completion, Xcode will replace this text with the TextString.
IncludeContexts/ExcludeContexts – these allow you to determine whereyour completion is valid. These are not necessary; if excluded your completion will work anywhere in an objective c file. In the above case, @try will only expand inside of a block.
Ok, lets create a very simple macro. Scroll to the bottom of this file and insert the following (make sure there is a comma after the previous entry):
Identifier = objc.asimplemacro;
BasedOn = objc;
IsMenuItem = NO;
Name = "My first Simple Macro";
TextString = "NSString *something = @/"Simple/"";
CompletionPrefix = simple;
Notice that the double quotes must be escaped. As simple as this is, it is what I get tripped up on the most. If Xcode encounters a parsing error like an unescaped double quote it will either 1) not load your file, using the original macros or 2) not load the macros after the error, resulting in some working and others not. It can be a bit frustrating to track down.
Now restart Xcode (every macro edit requires a restart), open an objective c file, and type ’simple’. Then use your ‘Next Completion’ key. It should replace the text with your NSString. In some cases you may have to go through a few completions to see your macro; this list includes function and variable name completions as well. If you keep your macros fairly unique, you won’t have this problem.
Now we will insert a custom placeholder. Replace the TextString line above with:
TextString = "NSString *<#varname#>= @/"<#text#>/"";
Restart Xcode and try your macro again. This time it should have two placeholders, varname and text. You should be able to jump between them using the Next Placeholder key.
And that’s it! Not quite as nice as TextMate, but a lot better than not having this functionality at all.
More Advanced Macro Techniques
Two other things I wanted to mention briefly.
First, if you use the same CompletionPrefix for two macros then Next Completion will cycle through them. This can be useful for defining two similar expansions with the same keyset. For Example, I use the obscure ‘df’ to first declare a CGFloat, then a float.
Second, IncludeContext and ExcludeContext. These allow you to define the same macro key and have it do different things in different places, for example the body of a function vs the function name, or the header vs the implementation. Some contexts I find useful:
"xcode.lang.objc.initializer" ‘initializer’ is after an equals expression. The others are fairly self explanatory. Or seem so to me, after looking at them for so long.
That concludes our Xcode fun for the day. Let me know if you have any questions or need clarification on some points. Hopefully this helps some of you have a more enjoyable Xcode experience.