New: xCodeCapp 3.2, command objj on each processing files or on the entire project

This pull requests adds a nice feature to xCodeCapp, now each time a fill is processing, xCodeCapp will launch the command objj to check the compilation issues. If it finds something, it will show them up on the classic error panel. This basically show import warnings, warnings you don't catch with your browser but only during the build of the application.
Objj is only launched if no errors was found after the first parsing (the parser which translate a file to objective-c).

This feature can be disabled on the preferences panel.

The menu has a new menu item "Check Compilation Issues". This action will launch objj on each files of the project and shows warnings and errors found.

The command objj will take automatically the OBJJ_INCLUDE_PATH in the index.html or index-debug.html. This options can be disabled in the preferences panel as well.

This PR only works with the PR #2248
This commit is contained in:
Alexandre Wilhelm
2014-11-05 12:57:03 -08:00
parent 4b058a8c56
commit b827b7ffce
8 changed files with 977 additions and 146 deletions
+17 -15
View File
@@ -138,21 +138,23 @@ AppController *SharedAppControllerInstance = nil;
- (void)registerDefaultPreferences
{
NSDictionary *appDefaults = @{
kDefaultLastEventId: [NSNumber numberWithUnsignedLongLong:kFSEventStreamEventIdSinceNow],
kDefaultFirstLaunch: @YES,
kDefaultFirstLaunchVersion: @2.0,
kDefaultXCCAPIMode: [NSNumber numberWithInt:kXCCAPIModeAuto],
kDefaultXCCReactToInodeMod: @YES,
kDefaultXCCReopenLastProject: @YES,
kDefaultXCCAutoOpenErrorsPanelOnErrors: @YES,
kDefaultXCCAutoOpenErrorsPanelOnCappLint: @YES,
kDefaultXCCAutoShowNotificationOnErrors: @YES,
kDefaultXCCAutoShowNotificationOnCappLint: @YES,
kDefaultXCCProjectHistory: [NSArray new],
kDefaultMaxRecentProjects: @20,
kDefaultLogLevel: [NSNumber numberWithInt:LOG_LEVEL_WARN],
kDefaultAutoOpenXcodeProject: @YES,
kDefaultUseSymlinkWhenCreatingProject: @YES
kDefaultLastEventId: [NSNumber numberWithUnsignedLongLong:kFSEventStreamEventIdSinceNow],
kDefaultFirstLaunch: @YES,
kDefaultFirstLaunchVersion: @2.0,
kDefaultXCCAPIMode: [NSNumber numberWithInt:kXCCAPIModeAuto],
kDefaultXCCReactToInodeMod: @YES,
kDefaultXCCReopenLastProject: @YES,
kDefaultXCCAutoOpenErrorsPanelOnErrors: @YES,
kDefaultXCCAutoOpenErrorsPanelOnCappLint: @YES,
kDefaultXCCAutoShowNotificationOnErrors: @YES,
kDefaultXCCAutoShowNotificationOnCappLint: @YES,
kDefaultXCCProjectHistory: [NSArray new],
kDefaultMaxRecentProjects: @20,
kDefaultLogLevel: [NSNumber numberWithInt:LOG_LEVEL_WARN],
kDefaultAutoOpenXcodeProject: @YES,
kDefaultUseSymlinkWhenCreatingProject: @YES,
kDefaultXCCUseDebugFrameworkWithObjj: @YES,
kDefaultXCCShouldProcessObjj: @YES
};
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+2 -2
View File
@@ -21,11 +21,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>3.1</string>
<string>3.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>3.1</string>
<string>3.2</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string>
<key>LSUIElement</key>
@@ -45,7 +45,7 @@
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
NSDictionary *info = @{ @"projectId":self.projectId, @"path":self.sourcePath };
NSDictionary *info = @{ @"projectId":self.projectId, @"path":self.sourcePath};
[center postNotificationName:XCCConversionDidStartNotification object:self userInfo:info];
DDLogVerbose(@"Conversion started: %@", self.sourcePath);
@@ -74,7 +74,7 @@
self.xcc.parserPath,
self.projectPath,
self.sourcePath
];
];
notificationTitle = @"Objective-J source processed";
}
@@ -141,7 +141,7 @@
@try
{
NSArray *errors = [response propertyList];
for (NSDictionary *error in errors)
{
[self postErrorNotificationForPath:error[@"path"] line:[error[@"line"] intValue] message:error[@"message"] status:status];
@@ -158,14 +158,23 @@
}
else if (!self.xcc.isLoadingProject)
{
BOOL showFinalNotification = YES;
BOOL showFinalNotification = NO;
// At this point, we should only detect warnings
if ([self.xcc shouldProcessWithObjjWarnings])
{
showFinalNotification = [self.xcc checkObjjWarningsForPath:[NSArray arrayWithObject:self.sourcePath]];
[self.xcc showObjjWarnings];
}
else
{
showFinalNotification = YES;
}
if ([self.xcc shouldProcessWithCappLint])
{
showFinalNotification = [self.xcc checkCappLintForPath:[NSArray arrayWithObject:self.sourcePath]];
if (!showFinalNotification)
[self.xcc showCappLintErrors];
showFinalNotification = [self.xcc checkCappLintForPath:[NSArray arrayWithObject:self.sourcePath]] && showFinalNotification;
[self.xcc showCappLintWarnings];
}
if (showFinalNotification)
+3
View File
@@ -19,8 +19,11 @@ extern NSString * const kDefaultXCCReactToInodeMod;
extern NSString * const kDefaultXCCReopenLastProject;
extern NSString * const kDefaultXCCAutoOpenErrorsPanelOnErrors;
extern NSString * const kDefaultXCCAutoOpenErrorsPanelOnCappLint;
extern NSString * const kDefaultXCCAutoOpenErrorsPanelOnObjjWarnings;
extern NSString * const kDefaultXCCAutoShowNotificationOnErrors;
extern NSString * const kDefaultXCCAutoShowNotificationOnCappLint;
extern NSString * const kDefaultXCCUseDebugFrameworkWithObjj;
extern NSString * const kDefaultXCCShouldProcessObjj;
extern NSString * const kDefaultXCCProjectHistory;
extern NSString * const kDefaultLastOpenedPath;
extern NSString * const kDefaultPathModificationDates;
+3 -1
View File
@@ -19,6 +19,8 @@ NSString * const kDefaultXCCAutoOpenErrorsPanelOnErrors = @"XCCAutoOpenErrorsPan
NSString * const kDefaultXCCAutoOpenErrorsPanelOnCappLint = @"XCCAutoOpenErrorsPanelOnCappLint";
NSString * const kDefaultXCCAutoShowNotificationOnErrors = @"XCCAutoOpenShowNotificationErrors";
NSString * const kDefaultXCCAutoShowNotificationOnCappLint = @"XCCAutoShowNotificationOnCappLint";
NSString * const kDefaultXCCUseDebugFrameworkWithObjj = @"XCCUseDebugFrameworkWithObjj";
NSString * const kDefaultXCCShouldProcessObjj = @"XCCShouldProcessObjj";
NSString * const kDefaultXCCProjectHistory = @"XCCProjectHistory";
NSString * const kDefaultLastOpenedPath = @"LastOpenedPath";
NSString * const kDefaultPathModificationDates = @"pathModificationDates";
@@ -26,4 +28,4 @@ NSString * const kDefaultMaxRecentProjects = @"maxRecentProjects";
NSString * const kDefaultLogLevel = @"logLevel";
NSString * const kDefaultAutoOpenXcodeProject = @"autoOpenXcodeProject";
NSString * const kDefaultUseSymlinkWhenCreatingProject = @"useSymlinkWhenCreatingProject";
NSString * const kDefaultUpdateCappuccinoWithLastVersionOfMasterBranch = @"updateCappuccinoWithLastVersionOfMasterBranch";
NSString * const kDefaultUpdateCappuccinoWithLastVersionOfMasterBranch = @"updateCappuccinoWithLastVersionOfMasterBranch";
+6 -1
View File
@@ -156,9 +156,14 @@ extern NSString * const XCCCappLintDidEndNotification;
- (NSDictionary*)createProject:(NSString*)aPath;
- (void)showCappLintWarnings;
- (void)showObjjWarnings;
- (BOOL)shouldProcessWithCappLint;
- (BOOL)checkCappLintForPath:(NSArray*)paths;
- (void)showCappLintErrors;
- (BOOL)shouldProcessWithObjjWarnings;
- (BOOL)checkObjjWarningsForPath:(NSArray*)paths;
- (void)updateCappuccino;
+249 -20
View File
@@ -76,6 +76,8 @@ static NSArray *XCCDefaultIgnoredPathPredicates = nil;
NSString * const XCCCappLintDidStartNotification = @"XCCCappLintDidStartNotification";
NSString * const XCCCappLintDidEndNotification = @"XCCCappLintDidEndNotification";
NSString * const XCCObjjDidStartNotification = @"XCCObjjDidStartNotification";
NSString * const XCCObjjDidEndNotification = @"XCCObjjDidEndNotification";
@interface XcodeCapp ()
@@ -1694,6 +1696,13 @@ void fsevents_callback(ConstFSEventStreamRef streamRef,
|| [defaults boolForKey:kDefaultXCCAutoShowNotificationOnCappLint];
}
- (BOOL)shouldProcessWithObjjWarnings
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
return ([defaults boolForKey:kDefaultXCCAutoOpenErrorsPanelOnErrors] || [defaults boolForKey:kDefaultXCCAutoShowNotificationOnErrors]) && [defaults boolForKey:kDefaultXCCShouldProcessObjj];
}
- (void)showErrors
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
@@ -1704,41 +1713,96 @@ void fsevents_callback(ConstFSEventStreamRef streamRef,
}
}
- (void)showCappLintErrors
- (void)showCappLintWarnings
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults boolForKey:kDefaultXCCAutoOpenErrorsPanelOnCappLint] && self.errorList.count)
NSUInteger numberError = [self.errorList count];
NSDictionary *firstError;
NSUInteger i = 0;
for (i = 0; i < numberError; i++)
{
NSDictionary *dict = [self.errorList objectAtIndex:i];
if ([[dict valueForKey:@"type"] isEqualToString: @"capp_lint"])
{
firstError = dict;
break;
}
}
if ([defaults boolForKey:kDefaultXCCAutoOpenErrorsPanelOnCappLint] && firstError)
[self openErrorsPanel:self];
if ([defaults boolForKey:kDefaultXCCAutoShowNotificationOnCappLint])
if ([defaults boolForKey:kDefaultXCCAutoShowNotificationOnCappLint] && firstError)
{
NSUInteger numberError = [self.errorList count];
NSDictionary *error = [self.errorList objectAtIndex:0];
NSString *filename = [error objectForKey:@"path"];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInteger:self.projectId] , @"projectId",
@"Code Style Issues", @"title",
filename.lastPathComponent , @"message",
nil];
[self wantUserNotificationWithInfo:dict];
}
}
- (void)showObjjWarnings
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSUInteger numberError = [self.errorList count];
NSDictionary *firstError;
NSUInteger i = 0;
for (i = 0; i < numberError; i++)
{
NSDictionary *dict = [self.errorList objectAtIndex:i];
if (numberError)
if ([[dict valueForKey:@"type"] isEqualToString: @"objj"])
{
NSDictionary *error = [self.errorList objectAtIndex:0];
NSString *filename = [error objectForKey:@"path"];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInteger:self.projectId] , @"projectId",
@"Code Style Issues", @"title",
filename.lastPathComponent , @"message",
nil];
[self wantUserNotificationWithInfo:dict];
firstError = dict;
break;
}
}
if ([defaults boolForKey:kDefaultXCCAutoOpenErrorsPanelOnErrors] && firstError)
[self openErrorsPanel:self];
if ([defaults boolForKey:kDefaultXCCAutoShowNotificationOnErrors] && firstError)
{
NSDictionary *error = [self.errorList objectAtIndex:0];
NSString *filename = [error objectForKey:@"path"];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInteger:self.projectId] , @"projectId",
@"Compiling Issues", @"title",
filename.lastPathComponent , @"message",
nil];
[self wantUserNotificationWithInfo:dict];
}
}
- (void)pruneProcessingErrorsForProjectPath:(NSString *)path
{
[self pruneProcessingErrorsForProjectPath:path type:nil];
}
- (void)pruneProcessingErrorsForProjectPath:(NSString *)path type:(NSString*)type
{
// Remove all errors for the path being processed
NSIndexSet *matchingErrors = [self.errorList indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop)
{
return [[obj valueForKey:@"path"] isEqualToString:path];
if (type)
return ([[obj valueForKey:@"path"] isEqualToString:path] || [[obj valueForKey:@"realPath"] isEqualToString:path]) && [[obj valueForKey:@"type"] isEqualToString:type];
else
return [[obj valueForKey:@"path"] isEqualToString:path] || [[obj valueForKey:@"realPath"] isEqualToString:path];
}];
[self.errorListController removeObjectsAtArrangedObjectIndexes:matchingErrors];
}
@@ -1758,6 +1822,170 @@ void fsevents_callback(ConstFSEventStreamRef streamRef,
return index != NSNotFound;
}
#pragma mark - objjj check
- (NSString*)_getObjjIncludePaths
{
NSRegularExpression *regulareExpressionFramework = [NSRegularExpression regularExpressionWithPattern:@"OBJJ_INCLUDE_PATHS ?= ?\\[\"(.*)\"\\," options:0 error:nil];
NSString *indexPath;
if ([[NSUserDefaults standardUserDefaults] boolForKey:kDefaultXCCUseDebugFrameworkWithObjj])
indexPath = [NSString stringWithFormat:@"%@/index-debug.html", self.projectPath];
else
indexPath = [NSString stringWithFormat:@"%@/index.html", self.projectPath];
NSDictionary *taskResult = [self runTaskWithLaunchPath:@"/bin/cat" arguments:[NSMutableArray arrayWithObject:indexPath] returnType:kTaskReturnTypeAny];
NSString *response = taskResult[@"response"];
NSArray *matches = [regulareExpressionFramework matchesInString:response options:0 range:NSMakeRange(0, [response length])];
for (NSTextCheckingResult *match in matches)
return [response substringWithRange:[match rangeAtIndex:1]];
return @"Frameworks/";
}
- (BOOL)checkObjjWarningsForPath:(NSArray*)paths
{
DDLogVerbose(@"Checking path %@ with objj", paths);
NSUInteger numberOfFiles = [paths count];
if (!numberOfFiles)
return YES;
[[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidStartNotification object:self];
[[NSNotificationCenter defaultCenter] postNotificationName:XCCObjjDidStartNotification object:self];
NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"-I", [self _getObjjIncludePaths], @"-m", nil];
[arguments addObjectsFromArray:paths];
NSDictionary *taskResult = [self runTaskWithLaunchPath:self.executablePaths[@"objj"]
arguments:arguments
returnType:kTaskReturnTypeStdOut];
NSInteger status = [taskResult[@"status"] intValue];
NSString *response = taskResult[@"response"];
if (status == 0 && [response length] == 0)
{
[[NSNotificationCenter defaultCenter] postNotificationName:XCCObjjDidEndNotification object:self];
[[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidEndNotification object:self];
return YES;
}
NSMutableArray *errors = [NSMutableArray arrayWithArray:[response componentsSeparatedByString:@"\n\n"]];
NSInteger numberOfErrors = [errors count];
NSInteger i = 0;
NSMutableArray *dicts = [NSMutableArray array];
// When checking of the entire project, we have to be ready to find errors
NSRegularExpression *regulareExpressionFramework = [NSRegularExpression regularExpressionWithPattern:@"([\\S\\s]*)(WARNING|ERROR) line ([0-9]*) in file\\:(.*)\\: ([\\S\\s]*)" options:0 error:nil];
NSString *filePath;
if ([paths count] == 1)
filePath = [paths firstObject];
for (i = 0; i < numberOfErrors; i++)
{
NSMutableString *error = (NSMutableString*)[errors objectAtIndex:i];
NSString *line;
NSString *path;
NSString *messageError;
// We have an extra new line for the first error
if (i == 0)
error = (NSMutableString*)[error substringFromIndex:1];
NSArray *matches = [regulareExpressionFramework matchesInString:error options:0 range:NSMakeRange(0, [error length])];
NSInteger j = 0;
if (![matches count])
{
DDLogVerbose(@"Error %@ has been ignored by xCodeCapp, the error doesn't respect any pattern", error);
continue;
}
for (NSTextCheckingResult *match in matches)
{
for (j = 0; j < [match numberOfRanges]; j++)
{
switch (j) {
case 1:
messageError = [error substringWithRange:[match rangeAtIndex:j]];
break;
case 3:
line = [error substringWithRange:[match rangeAtIndex:j]];
break;
case 4:
path = [error substringWithRange:[match rangeAtIndex:j]];
break;
case 5:
messageError = [NSString stringWithFormat:@"Compiling issue at line %@ of file %@:\n%@ \n%@", line, path.lastPathComponent, [error substringWithRange:[match rangeAtIndex:j]], messageError];
break;
default:
break;
}
}
}
// Make sure to delete all the compilations issue form the tableView
[self pruneProcessingErrorsForProjectPath:path type:@"objj"];
// Path and realPath are needed, we can get error on ViewController2.j while checking ViewController.j.
// When recompiling ViewController.j, realPath is used to know which errors have to be erased form the table
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:[line intValue]], @"line",
messageError , @"message",
(filePath ? filePath:path), @"path",
@"objj", @"type",
path , @"realPath",
nil];
// Compiler can show several times the same errors
if (![dicts containsObject:dict] && ![self.errorList containsObject:dict])
[dicts addObject:dict];
}
[self performSelectorOnMainThread:@selector(objjCompilerDidGenerateError:) withObject:dicts waitUntilDone:YES];
self.isProcessing = NO;
[[NSNotificationCenter defaultCenter] postNotificationName:XCCObjjDidEndNotification object:self];
[[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidEndNotification object:self];
return NO;
}
- (IBAction)checkProjectWithObjj:(id)sender
{
[self clearErrors:self];
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(objjDidEndNotification:) name:XCCObjjDidEndNotification object:nil];
[self performSelectorInBackground:@selector(checkObjjWarningsForPath:) withObject:self.xCodeCappTargetedFiles];
}
- (void)objjDidEndNotification:(NSNotification*)aNotification
{
[self showObjjWarnings];
[[NSNotificationCenter defaultCenter] removeObserver:self name:XCCObjjDidEndNotification object:nil];
}
- (void)objjCompilerDidGenerateError:(NSArray*)errors
{
[self.errorListController addObjects:errors];
}
#pragma mark - capp_lint
@@ -1773,7 +2001,7 @@ void fsevents_callback(ConstFSEventStreamRef streamRef,
- (void)cappLintDidEndNotification:(NSNotification*)aNotification
{
[self showCappLintErrors];
[self showCappLintWarnings];
[[NSNotificationCenter defaultCenter] removeObserver:self name:XCCCappLintDidEndNotification object:nil];
}
@@ -1840,18 +2068,19 @@ void fsevents_callback(ConstFSEventStreamRef streamRef,
NSInteger positionOfSecondColon = [errorWithoutPath rangeOfString:@":"].location;
line = [errorWithoutPath substringToIndex:positionOfSecondColon];
NSString *messageError = [NSString stringWithFormat:@"Code style issue: %@ \n%@", path.lastPathComponent, errorWithoutPath];
NSString *messageError = [NSString stringWithFormat:@"Code style issue at line %@ of file %@:\n%@", line, path.lastPathComponent, errorWithoutPath];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:[line intValue]], @"line",
messageError , @"message",
path, @"path",
@"capp_lint", @"type",
nil];
[dicts addObject:dict];
}
[self performSelectorOnMainThread:@selector(cappLintConversionDidGenerateError:) withObject:dicts waitUntilDone:NO];
[self performSelectorOnMainThread:@selector(cappLintConversionDidGenerateError:) withObject:dicts waitUntilDone:YES];
self.isProcessing = NO;
[[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidEndNotification object:self];
File diff suppressed because it is too large Load Diff