Merge pull request #2108 from Dogild/xCodeCappOptionsNotification

New: Added option in xCodeCapp for displaying error in notification
This commit is contained in:
Antoine Mercadal
2014-04-22 18:29:46 -07:00
7 changed files with 616 additions and 570 deletions
+5 -5
View File
@@ -111,7 +111,7 @@ AppController *SharedAppControllerInstance = nil;
[[NSApplication sharedApplication] terminate:self];
return;
}
// If we were opened from the command line, self.pathToOpenAtLaunch will be set.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
@@ -144,15 +144,15 @@ AppController *SharedAppControllerInstance = nil;
kDefaultXCCAPIMode: [NSNumber numberWithInt:kXCCAPIModeAuto],
kDefaultXCCReactToInodeMod: @YES,
kDefaultXCCReopenLastProject: @YES,
kDefaultXCCAutoOpenErrorsPanelOnWarnings: @YES,
kDefaultXCCAutoOpenErrorsPanelOnErrors: @YES,
kDefaultXCCAutoOpenErrorsPanelOnCappLint: @YES,
kDefaultXCCAutoShowNotificationOnErrors: @YES,
kDefaultXCCAutoShowNotificationOnCappLint: @NO,
kDefaultXCCProjectHistory: [NSArray new],
kDefaultMaxRecentProjects: @20,
kDefaultLogLevel: [NSNumber numberWithInt:LOG_LEVEL_WARN],
kDefaultAutoOpenXcodeProject: @YES,
kDefaultShowProcessingNotices: @YES,
kDefaultUseSymlinkWhenCreatingProject: @YES,
KDefaultUsesCappLintForEveryNotifications: @NO
kDefaultUseSymlinkWhenCreatingProject: @YES
};
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
@@ -152,12 +152,24 @@
[self postErrorNotificationForPath:self.sourcePath line:0 message:response status:status];
}
}
[self notifyUserWithTitle:notificationTitle message:notificationMessage];
if ([self.xcc shouldShowErrorNotification])
[self notifyUserWithTitle:notificationTitle message:notificationMessage];
}
else if (!self.xcc.isLoadingProject)
{
[self notifyUserWithTitle:notificationTitle message:notificationMessage];
BOOL showFinalNotification = YES;
if ([self.xcc shouldProcessWithCappLint])
{
showFinalNotification = [self.xcc checkCappLintForPath:[NSArray arrayWithObject:self.sourcePath]];
if (!showFinalNotification)
[self.xcc showCappLintErrors];
}
if (showFinalNotification)
[self notifyUserWithTitle:notificationTitle message:notificationMessage];
}
}
@@ -178,7 +190,7 @@
nil];
info[@"projectId"] = self.projectId;
info[@"message"] = [NSString stringWithFormat:@"%@, line %d\n%@", [self.sourcePath lastPathComponent], 0, message];
info[@"message"] = [NSString stringWithFormat:@"Compilation issue: %@, line %d\n%@", [self.sourcePath lastPathComponent], 0, message];
if (self.isCancelled)
return;
+3 -3
View File
@@ -17,16 +17,16 @@ extern NSString * const kDefaultFirstLaunchVersion;
extern NSString * const kDefaultXCCAPIMode;
extern NSString * const kDefaultXCCReactToInodeMod;
extern NSString * const kDefaultXCCReopenLastProject;
extern NSString * const kDefaultXCCAutoOpenErrorsPanelOnWarnings;
extern NSString * const kDefaultXCCAutoOpenErrorsPanelOnErrors;
extern NSString * const kDefaultXCCAutoOpenErrorsPanelOnCappLint;
extern NSString * const kDefaultXCCAutoShowNotificationOnErrors;
extern NSString * const kDefaultXCCAutoShowNotificationOnCappLint;
extern NSString * const kDefaultXCCProjectHistory;
extern NSString * const kDefaultLastOpenedPath;
extern NSString * const kDefaultPathModificationDates;
extern NSString * const kDefaultMaxRecentProjects;
extern NSString * const kDefaultLogLevel;
extern NSString * const kDefaultAutoOpenXcodeProject;
extern NSString * const kDefaultShowProcessingNotices;
extern NSString * const kDefaultUseSymlinkWhenCreatingProject;
extern NSString * const KDefaultUsesCappLintForEveryNotifications;
#endif
+3 -3
View File
@@ -15,14 +15,14 @@ NSString * const kDefaultFirstLaunchVersion = @"firstLaunchVersion";
NSString * const kDefaultXCCAPIMode = @"XCCAPIMode";
NSString * const kDefaultXCCReactToInodeMod = @"XCCReactMode";
NSString * const kDefaultXCCReopenLastProject = @"XCCReopenLastProject";
NSString * const kDefaultXCCAutoOpenErrorsPanelOnWarnings = @"XCCAutoOpenErrorsPanelOnWarnings";
NSString * const kDefaultXCCAutoOpenErrorsPanelOnErrors = @"XCCAutoOpenErrorsPanelOnErrors";
NSString * const kDefaultXCCAutoOpenErrorsPanelOnCappLint = @"XCCAutoOpenErrorsPanelOnCappLint";
NSString * const kDefaultXCCAutoShowNotificationOnErrors = @"XCCAutoOpenShowNotificationErrors";
NSString * const kDefaultXCCAutoShowNotificationOnCappLint = @"XCCAutoShowNotificationOnCappLint";
NSString * const kDefaultXCCProjectHistory = @"XCCProjectHistory";
NSString * const kDefaultLastOpenedPath = @"LastOpenedPath";
NSString * const kDefaultPathModificationDates = @"pathModificationDates";
NSString * const kDefaultMaxRecentProjects = @"maxRecentProjects";
NSString * const kDefaultLogLevel = @"logLevel";
NSString * const kDefaultAutoOpenXcodeProject = @"autoOpenXcodeProject";
NSString * const kDefaultShowProcessingNotices = @"showProcessingNotices";
NSString * const kDefaultUseSymlinkWhenCreatingProject = @"useSymlinkWhenCreatingProject";
NSString * const KDefaultUsesCappLintForEveryNotifications = @"usesCappLintForEveryNotifications";
+11 -1
View File
@@ -45,7 +45,8 @@ enum {
extern NSString * const XCCConversionDidStartNotification;
extern NSString * const XCCConversionDidEndNotification;
extern NSString * const XCCProjectDidFinishLoadingNotification;
extern NSString * const XCCCappLintDidStartNotification;
extern NSString * const XCCCappLintDidEndNotification;
@interface XcodeCapp : NSObject <NSTableViewDelegate, NSUserNotificationCenterDelegate, GrowlApplicationBridgeDelegate>
@@ -109,6 +110,9 @@ extern NSString * const XCCProjectDidFinishLoadingNotification;
// A list of errors generated from the current batch of source processing
@property NSMutableArray *errorList;
// A list of files name who can be processed, based on xcapp-ignore and path pf the project
@property NSMutableArray *xCodeCappTargetedFiles;
// Panel, table and controller used to display errors
@property (strong) IBOutlet NSPanel *errorsPanel;
@property (unsafe_unretained) IBOutlet NSTableView *errorTable;
@@ -132,6 +136,8 @@ extern NSString * const XCCProjectDidFinishLoadingNotification;
- (BOOL)isXibFile:(NSString *)path;
- (BOOL)isXCCIgnoreFile:(NSString *)path;
- (BOOL)shouldShowErrorNotification;
- (NSString *)shadowBasePathForProjectSourcePath:(NSString *)path;
- (BOOL)hasErrors;
@@ -143,6 +149,10 @@ extern NSString * const XCCProjectDidFinishLoadingNotification;
- (NSDictionary*)createProject:(NSString*)aPath;
- (BOOL)shouldProcessWithCappLint;
- (BOOL)checkCappLintForPath:(NSArray*)paths;
- (void)showCappLintErrors;
@end
@interface XcodeCapp (SnowLeopard)
+177 -73
View File
@@ -74,6 +74,8 @@ static NSPredicate * XCCDirectoriesToIgnorePredicate = nil;
// An array of the default predicates used to ignore paths.
static NSArray *XCCDefaultIgnoredPathPredicates = nil;
NSString * const XCCCappLintDidStartNotification = @"XCCCappLintDidStartNotification";
NSString * const XCCCappLintDidEndNotification = @"XCCCappLintDidEndNotification";
@interface XcodeCapp ()
@@ -317,9 +319,10 @@ void fsevents_callback(ConstFSEventStreamRef streamRef,
[self clearErrors:self];
[self computeIgnoredPaths];
[self prepareXcodeSupport];
[self populateXcodeProject];
[self populatexCodeCappTargetedFiles];
[self waitForOperationQueueToFinishWithSelector:@selector(projectDidFinishLoading)];
}
@@ -372,6 +375,25 @@ void fsevents_callback(ConstFSEventStreamRef streamRef,
return projectCompatibilityVersion.doubleValue >= appCompatibilityVersion;
}
- (void)populatexCodeCappTargetedFiles
{
NSFileManager *fm = [NSFileManager defaultManager];
NSDirectoryEnumerator *filesOfProject = [fm enumeratorAtPath:self.projectPath];
NSString *filename;
self.xCodeCappTargetedFiles = [NSMutableArray array];
while ((filename = [filesOfProject nextObject] )) {
NSString *fullPath = [self.projectPath stringByAppendingPathComponent:filename];
if (![self isSourceFile:fullPath])
continue;
[self.xCodeCappTargetedFiles addObject:fullPath];
}
}
- (void)createXcodeProject
{
if ([self.fm fileExistsAtPath:self.xcodeProjectPath])
@@ -730,11 +752,6 @@ void fsevents_callback(ConstFSEventStreamRef streamRef,
}
}
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults boolForKey:KDefaultUsesCappLintForEveryNotifications])
[self checkCappLintForPath:path];
DDLogVerbose(@"%@ %@", NSStringFromSelector(_cmd), path);
}
@@ -1364,6 +1381,7 @@ void fsevents_callback(ConstFSEventStreamRef streamRef,
return [path substringFromIndex:self.projectPath.length + 1];
}
#pragma mark - Shadow Files Management
- (NSString *)shadowBasePathForProjectSourcePath:(NSString *)path
@@ -1641,17 +1659,56 @@ void fsevents_callback(ConstFSEventStreamRef streamRef,
[self runTaskWithLaunchPath:executablePath arguments:args returnType:kTaskReturnTypeNone];
}
- (BOOL)shouldShowErrorNotification
{
return [[NSUserDefaults standardUserDefaults] boolForKey:kDefaultXCCAutoShowNotificationOnErrors];
}
- (BOOL)shouldProcessWithCappLint
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
return [defaults boolForKey:kDefaultXCCAutoOpenErrorsPanelOnCappLint]
|| [defaults boolForKey:kDefaultXCCAutoShowNotificationOnCappLint];
}
- (void)showErrors
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (([defaults boolForKey:kDefaultXCCAutoOpenErrorsPanelOnErrors] && self.hasErrors) ||
([defaults boolForKey:kDefaultXCCAutoOpenErrorsPanelOnWarnings] && self.errorList.count))
if ([defaults boolForKey:kDefaultXCCAutoOpenErrorsPanelOnErrors] && self.errorList.count)
{
[self openErrorsPanel:self];
}
}
- (void)showCappLintErrors
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults boolForKey:kDefaultXCCAutoOpenErrorsPanelOnCappLint] && self.errorList.count)
[self openErrorsPanel:self];
if ([defaults boolForKey:kDefaultXCCAutoShowNotificationOnCappLint])
{
NSUInteger numberError = [self.errorList count];
if (numberError)
{
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)pruneProcessingErrorsForProjectPath:(NSString *)path
{
// Remove all errors for the path being processed
@@ -1679,6 +1736,113 @@ void fsevents_callback(ConstFSEventStreamRef streamRef,
return index != NSNotFound;
}
#pragma mark - capp_lint
- (IBAction)checkProjectWithCappLint:(id)aSender
{
[self clearErrors:self];
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(cappLintDidEndNotification:) name:XCCCappLintDidEndNotification object:nil];
[self performSelectorInBackground:@selector(checkCappLintForPath:) withObject:self.xCodeCappTargetedFiles];
}
- (void)cappLintDidEndNotification:(NSNotification*)aNotification
{
[self showCappLintErrors];
[[NSNotificationCenter defaultCenter] removeObserver:self name:XCCCappLintDidEndNotification object:nil];
}
- (BOOL)checkCappLintForPath:(NSArray*)paths
{
DDLogVerbose(@"Checking path %@ with capp_lint", paths);
NSUInteger numberOfFiles = [paths count];
if (!numberOfFiles)
return YES;
self.isProcessing = YES;
[[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidStartNotification object:self];
[[NSNotificationCenter defaultCenter] postNotificationName:XCCCappLintDidStartNotification object:self];
NSString *baseDirectory = [NSString stringWithFormat:@"--basedir='%@'", self.projectPath];
NSMutableArray *arguments = [NSMutableArray arrayWithObjects:baseDirectory, nil];
[arguments addObjectsFromArray:paths];
NSDictionary *taskResult = [self runTaskWithLaunchPath:self.executablePaths[@"capp_lint"]
arguments:arguments
returnType:kTaskReturnTypeStdOut];
NSInteger status = [taskResult[@"status"] intValue];
if (status == 0)
{
[[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidEndNotification object:self];
[[NSNotificationCenter defaultCenter] postNotificationName:XCCCappLintDidEndNotification object:self];
return YES;
}
NSString *response = taskResult[@"response"];
NSMutableArray *errors = [NSMutableArray arrayWithArray:[response componentsSeparatedByString:@"\n\n"]];
// We need to remove the first object who is the number of errors and the last object who is an empty line
[errors removeLastObject];
[errors removeObjectAtIndex:0];
NSInteger numberOfErrors = [errors count];
NSInteger i = 0;
NSString *path;
NSMutableArray *dicts = [NSMutableArray array];
if (numberOfFiles == 1)
path = [paths objectAtIndex:0];
for (i = 0; i < numberOfErrors; i++)
{
NSMutableString *error = (NSMutableString*)[errors objectAtIndex:i];
NSString *line;
NSString *firstCaract = [NSString stringWithFormat:@"%c" ,[error characterAtIndex:0]];
if ([[NSScanner scannerWithString:firstCaract] scanInt:nil])
error = (NSMutableString*)[NSString stringWithFormat:@"%@:%@", path, error];
NSInteger positionOfFirstColon = [error rangeOfString:@":"].location;
if (numberOfFiles > 1)
path = [error substringToIndex:positionOfFirstColon];
NSString *errorWithoutPath = [error substringFromIndex:(positionOfFirstColon + 1)];
NSInteger positionOfSecondColon = [errorWithoutPath rangeOfString:@":"].location;
line = [errorWithoutPath substringToIndex:positionOfSecondColon];
NSString *messageError = [NSString stringWithFormat:@"Code style issue: %@ \n%@", path.lastPathComponent, errorWithoutPath];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:[line intValue]], @"line",
messageError , @"message",
path, @"path",
nil];
[dicts addObject:dict];
}
[self performSelectorOnMainThread:@selector(cappLintConversionDidGenerateError:) withObject:dicts waitUntilDone:NO];
self.isProcessing = NO;
[[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidEndNotification object:self];
[[NSNotificationCenter defaultCenter] postNotificationName:XCCCappLintDidEndNotification object:self];
return NO;
}
- (void)cappLintConversionDidGenerateError:(NSArray*)errors
{
[self.errorListController addObjects:errors];
}
#pragma mark - User notifications
- (NSString *)applicationNameForGrowl
@@ -1718,8 +1882,7 @@ void fsevents_callback(ConstFSEventStreamRef streamRef,
if ([info[@"projectId"] intValue] != self.projectId)
return;
if ([[NSUserDefaults standardUserDefaults] boolForKey:kDefaultShowProcessingNotices])
[self notifyUserWithTitle:info[@"title"] message:info[@"message"]];
[self notifyUserWithTitle:info[@"title"] message:info[@"message"]];
}
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification
@@ -1728,71 +1891,12 @@ void fsevents_callback(ConstFSEventStreamRef streamRef,
return YES;
}
- (IBAction)checkProjectWithCappLint:(id)aSender
- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
{
[self clearErrors:self];
[self performSelectorInBackground:@selector(checkCappLintForPath:) withObject:self.projectPath];
}
- (void)checkCappLintForPath:(NSString*)aPath
{
DDLogVerbose(@"Checking path %@ with capp_lint", aPath);
if ([self.errorList count])
[self openErrorsPanel:self];
self.isProcessing = YES;
[[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidStartNotification object:self];
NSString *baseDirectory = [NSString stringWithFormat:@"--basedir='%@'", self.projectPath];
NSArray *arguments = [NSArray arrayWithObjects:baseDirectory, aPath, nil];
NSDictionary *taskResult = [self runTaskWithLaunchPath:self.executablePaths[@"capp_lint"]
arguments:arguments
returnType:kTaskReturnTypeStdOut];
NSInteger status = [taskResult[@"status"] intValue];
NSString *response = taskResult[@"response"];
if (status == 0)
return;
NSMutableArray *errors = [NSMutableArray arrayWithArray:[response componentsSeparatedByString:@"\n\n"]];
// We need to remove the first object who is the number of errors and the last object who is an empty line
[errors removeLastObject];
[errors removeObjectAtIndex:0];
NSInteger i = 0;
NSInteger numberOfErrors = [errors count];
for (i = 0; i < numberOfErrors; i++)
{
NSMutableString *error = (NSMutableString*)[errors objectAtIndex:i];
NSString *firstCaract = [NSString stringWithFormat:@"%c" ,[error characterAtIndex:0]];
NSString *path;
NSString *line;
if ([[NSScanner scannerWithString:firstCaract] scanInt:nil])
error = (NSMutableString*)[NSString stringWithFormat:@"%@:%@",aPath,error];
NSInteger positionOfFirstColon = [error rangeOfString:@":"].location;
path = [error substringToIndex:positionOfFirstColon];
NSString *errorWithoutPath = [error substringFromIndex:(positionOfFirstColon + 1)];
NSInteger positionOfSecondColon = [errorWithoutPath rangeOfString:@":"].location;
line = [errorWithoutPath substringToIndex:positionOfSecondColon];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:[line intValue]], @"line",
[NSString stringWithFormat:@"capp_lint error in %@ \n%@", path, errorWithoutPath], @"message",
path, @"path",
nil];
[self.errorListController addObject:dict];
}
[self showErrors];
self.isProcessing = NO;
[[NSNotificationCenter defaultCenter] postNotificationName:XCCBatchDidEndNotification object:self];
[center removeDeliveredNotification:notification];
}
@end
File diff suppressed because it is too large Load Diff