Easy Xcode Template Customization
Sun. November 20, 2011Categories: iOS, Python, Xcode
Tags: ios, python, template, xcode
I got tired of changing the comments, curly braces, etc every time I had to create a new class or protocol in Xcode, so I whipped up this little python script. What it does is remove most of the comments, move the {
off of its own line and up to the end of the method definition line, and a few other nifty things. It’s not clean or pretty, but it does the job. Simply pass in a single parameter indicating the location of your base template file directory and any optional flags (-r, -v, -q, -i), and this will automatically create better templates.
Before:
//
// ___FILENAME___
// ___PROJECTNAME___
//
// Created by ___FULLUSERNAME___ on ___DATE___.
// Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved.
//
#import "___FILEBASENAME___.h"
@implementation ___FILEBASENAMEASIDENTIFIER___
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
#warning Potentially incomplete method implementation.
// Return the number of sections.
return 0;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
#warning Incomplete method implementation.
// Return the number of rows in the section.
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
return cell;
}
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/
/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
*/
}
@end
After:
/*
* ___FILENAME___
* ___PROJECTNAME___
*
* Author: ___FULLUSERNAME___
* Date: ___DATE___
*
* Copyright ___YEAR___ ___FULLUSERNAME___
* http://hozbox.com
*/
#import "___FILEBASENAME___.h"
@implementation ___FILEBASENAMEASIDENTIFIER___
- (id)initWithStyle:(UITableViewStyle)style {
if ((self = [super initWithStyle:style])) {
}
return self;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark - View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
#warning Potentially incomplete method implementation.
return 0;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
#warning Incomplete method implementation.
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
return cell;
}
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
*/
/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
*/
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@"<#Nib name#>" bundle:nil];
[self.navigationController pushViewController:detailViewController animated:YES];
*/
}
@end
Script:
#!/usr/bin/python
import fnmatch
import shutil
import glob
import time
import sys
import os
import re
RECURSIVE = False
VERBOSE = False
QUIET = False
INTERACTIVE = False
TEMPLATE_DEFAULT_DIR = os.path.join(r"/Developer", "Platforms", "iPhoneOS.platform", "Developer", "Library", "Xcode", "Templates", "File Templates")
IGNORED_LINES = [
"#import <UIKit/UIKit.h>",
"// Custom initialization",
"// Release any retained subviews of the main view.",
"// e.g. self.myOutlet = nil;",
"// Uncomment the following line to preserve selection between presentations.",
"// self.clearsSelectionOnViewWillAppear = NO;",
"// Releases the view if it doesn't have a superview.",
"// Release any cached data, images, etc that aren't in use.",
"// Release any retained subviews of the main view.",
"// e.g. self.myOutlet = nil;",
"// Return YES for supported orientations",
"// Return the number of sections.",
"// Return the number of rows in the section.",
"// Configure the cell...",
"// Return NO if you do not want the specified item to be editable.",
"// Return NO if you do not want the item to be re-orderable.",
"// Navigation logic may go here. Create and push another view controller.",
"// ...",
"// Pass the selected object to the new view controller.",
"// Implement loadView to create a view hierarchy programmatically, without using a nib.",
"// Implement viewDidLoad to do additional setup after loading the view, typically from a nib."
]
paths = []
args = sys.argv[1:]
if "-r" in args:
args.remove("-r")
RECURSIVE = True
if "-v" in args:
args.remove("-v")
VERBOSE = True
if "-q" in args:
args.remove("-q")
QUIET = True
if "-i" in args:
args.remove("-i")
INTERACTIVE = True
if not len(args):
while not (os.path.exists(TEMPLATE_DEFAULT_DIR) and os.path.isdir(TEMPLATE_DEFAULT_DIR) and os.access(TEMPLATE_DEFAULT_DIR, os.F_OK | os.R_OK | os.X_OK)):
try:
TEMPLATE_DEFAULT_DIR = raw_input("Please provide the path of the Xcode templates directory (Usually %s): " % TEMPLATE_DEFAULT_DIR).strip()
except KeyboardInterrupt:
print
sys.exit(1)
args = [os.path.join(TEMPLATE_DEFAULT_DIR, "*.[hm]")]
for arg in args:
if os.path.isfile(arg):
paths.append(os.path.abspath(arg))
else:
if RECURSIVE:
dirname = os.path.dirname(arg)
basename = os.path.basename(arg)
for root, dirs, files in os.walk(dirname):
paths.extend([os.path.join(root, fname) for fname in fnmatch.filter(files, basename)])
else:
print "Error: Path given is directory but no recursive (-r) flag given!"
sys.exit()
for f in paths:
if INTERACTIVE:
try:
if not raw_input("Fix %s? [y/n]: " % f).strip().lower().startswith("y"):
continue
except KeyboardInterrupt:
print "\n\n", sys.exit()
if not (QUIET or INTERACTIVE):
print "Starting on: %s" % f
source = open(f, "r").read()
if VERBOSE:
print "\tFixing comments..."
source = source.replace("""\
//
// ___FILENAME___
// ___PROJECTNAME___
//
// Created by ___FULLUSERNAME___ on ___DATE___.
// Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved.
//
""", """\
/*
* ___FILENAME___
* ___PROJECTNAME___
*
* Author: ___FULLUSERNAME___
* Date: ___DATE___
*
* Copyright ___YEAR___ ___FULLUSERNAME___
* http://hozbox.com
*/
""")
new_source = "%s\n" % "\n".join(source.splitlines()[:10])
source = "\n".join(source.splitlines()[10:])
remove_next_brace = False
in_interface = False
self_init = None
in_brace = False
for line in [l.expandtabs(4) for l in source.splitlines()]:
indent_count = len([ind for ind in line.split(" ") if not ind]) * 4
line = line.strip()
if line in IGNORED_LINES or (not line and in_brace):
print "\tRemoving line:".ljust(25), "%s%s" % ((" " * indent_count), line)
continue
elif line.startswith("- (") and not line.endswith("{"):
in_brace = True
remove_next_brace = True
line = line + " {"
if VERBOSE:
print "\tFixed line:".ljust(25),
elif line.startswith("{"):
in_brace = True
if remove_next_brace:
if VERBOSE:
print "\tRemoving line:".ljust(25), "%s%s" % ((" " * indent_count), line)
continue
else:
if VERBOSE:
print "\tNot Modified:".ljust(25),
elif line.startswith("}"):
if VERBOSE:
print "\tNot Modified:".ljust(25),
in_brace = False
elif line.startswith("@interface"):
in_interface = True
line = line + " {"
if VERBOSE:
print "\tFixed line:".ljust(25),
elif line.startswith("@end"):
if in_interface:
line = "}\n\n" + line
in_interface = False
line += "\n"
if VERBOSE:
print "\tFixed line:".ljust(25),
elif line.startswith("self = [super init"):
self_init = line.strip(";")
if VERBOSE:
print "\tRemoving line:".ljust(25), "%s%s" % ((" " * indent_count), line)
continue
elif line.startswith("if (self)") and self_init is not None:
line = line.replace("(self)", "((%s))" % self_init)
self_init = None
if VERBOSE:
print "\tFixed line:".ljust(25),
else:
if VERBOSE:
print "\tNot Modified:".ljust(25),
if VERBOSE:
print "%s%s" % ((" " * indent_count), line)
new_source += "%s%s\n" % ((" " * indent_count), line)
open(f, "w").write(new_source)
if not QUIET:
print "Done Fixing Template File: %s" % os.path.basename(f)
Comments