From 3d21ae4053aca10f4bad26c9cad6030b302ab7ed Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Wed, 17 Sep 2008 12:58:39 +0200 Subject: [PATCH 1/7] Add objective c diff header --- .gitattributes | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..b448c4f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.m diff=objc +*.mm diff=objc \ No newline at end of file From eeb3309f1e44b3ee04c42aa82f31d8218f55027e Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Wed, 17 Sep 2008 23:13:05 +0200 Subject: [PATCH 2/7] Multithread test --- GitX.xcodeproj/project.pbxproj | 4 +- PBGitGrapher.h | 5 +- PBGitGrapher.m | 223 ++++++++++++++++----------------- PBGitRevList.m | 60 ++++++--- 4 files changed, 153 insertions(+), 139 deletions(-) diff --git a/GitX.xcodeproj/project.pbxproj b/GitX.xcodeproj/project.pbxproj index 59d0476..609efee 100644 --- a/GitX.xcodeproj/project.pbxproj +++ b/GitX.xcodeproj/project.pbxproj @@ -274,8 +274,6 @@ isa = PBXGroup; children = ( F5C6F6750E65FE2B00478D97 /* Graphing */, - F5FF4E780E082E440006317A /* PBGitGrapher.h */, - F5FF4E790E082E440006317A /* PBGitGrapher.m */, F5945E150E02B0C200706420 /* PBGitRepository.h */, F5945E160E02B0C200706420 /* PBGitRepository.m */, F56524EE0E02D45200F03B52 /* PBGitCommit.h */, @@ -342,6 +340,8 @@ F5C6F6750E65FE2B00478D97 /* Graphing */ = { isa = PBXGroup; children = ( + F5FF4E780E082E440006317A /* PBGitGrapher.h */, + F5FF4E790E082E440006317A /* PBGitGrapher.m */, F5C007730E731B48007B84B2 /* PBGitRef.h */, F5C007740E731B48007B84B2 /* PBGitRef.m */, F50FE0E10E07BE9600854FCD /* PBGitRevisionCell.h */, diff --git a/PBGitGrapher.h b/PBGitGrapher.h index 2b46430..a4a0d07 100644 --- a/PBGitGrapher.h +++ b/PBGitGrapher.h @@ -20,11 +20,14 @@ struct PBGitGraphColumn { #define PBGitMaxColumns 100 @interface PBGitGrapher : NSObject { + PBGraphCellInfo* previous; + NSMutableArray* previousLanes; NSMutableArray* cellsInfo; + NSDictionary* refs; PBGitRepository* repository; } - (id) initWithRepository: (PBGitRepository*) repo; -- (void) parseCommits: (NSArray *) array; +- (void) decorateCommit: (PBGitCommit *) commit; - (PBGraphCellInfo*) cellInfoForRow: (int) row; @end diff --git a/PBGitGrapher.m b/PBGitGrapher.m index 5dbcd46..da4794e 100644 --- a/PBGitGrapher.m +++ b/PBGitGrapher.m @@ -14,139 +14,127 @@ - (id) initWithRepository: (PBGitRepository*) repo { - repository = repo; + refs = repo.refs; + // We don't know how many commits to parse. + cellsInfo = [NSMutableArray arrayWithCapacity:100]; + + previousLanes = [NSMutableArray array]; + return self; } -- (void) parseCommits: (NSArray *) commits +- (void) decorateCommit: (PBGitCommit *) commit { - cellsInfo = [NSMutableArray arrayWithCapacity: [commits count]]; - int row = 0; + int i = 0, newPos = -1; + NSMutableArray* currentLanes = [NSMutableArray array]; + NSMutableArray* lines = [NSMutableArray array]; + PBGitLane* currentLane = NULL; + BOOL didFirst = NO; - NSDictionary* refs = nil; - if (repository) - refs = repository.refs; + // First, iterate over earlier columns and pass through any that don't want this commit + if (previous != nil) { - PBGraphCellInfo* previous; - NSMutableArray* previousLanes = [NSMutableArray array]; - - for (PBGitCommit* commit in commits) { - int i = 0, newPos = -1; - NSMutableArray* currentLanes = [NSMutableArray array]; - NSMutableArray* lines = [NSMutableArray array]; - PBGitLane* currentLane = NULL; - BOOL didFirst = NO; - - // First, iterate over earlier columns and pass through any that don't want this commit - if (previous != nil) { - - // We can't count until numColumns here, as it's only used for the width of the cell. - for (PBGitLane* lane in previousLanes) { - i++; - // This is our commit! We should do a "merge": move the line from - // our upperMapping to their lowerMapping - if ([lane isCommit:commit.sha]) { - if (!didFirst) { - didFirst = YES; - currentLane = lane; - [currentLanes addObject: lane]; - newPos = [currentLanes count]; - } - [lines addObject: [PBGitGraphLine upperLineFrom: i to: newPos color: [lane index]]]; + // We can't count until numColumns here, as it's only used for the width of the cell. + for (PBGitLane* lane in previousLanes) { + i++; + // This is our commit! We should do a "merge": move the line from + // our upperMapping to their lowerMapping + if ([lane isCommit:commit.sha]) { + if (!didFirst) { + didFirst = YES; + currentLane = lane; + [currentLanes addObject: lane]; + newPos = [currentLanes count]; } - else { - // We are not this commit. - // Try to find an earlier column for this commit. - int j = 0; - BOOL found = NO; - for (PBGitLane* column in currentLanes) { - j++; - // ??? what is this? + [lines addObject: [PBGitGraphLine upperLineFrom: i to: newPos color: [lane index]]]; + } + else { + // We are not this commit. + // Try to find an earlier column for this commit. + int j = 0; + BOOL found = NO; + for (PBGitLane* column in currentLanes) { + j++; + // ??? what is this? // if (j == newPos) // continue; - if ([lane isCommit: commit.sha]) { - // We already have a column for this commit. use it instead - [lines addObject: [PBGitGraphLine upperLineFrom: i to: j color: [lane index]]]; - found = YES; - break; - } - } - - // We need a new column for this. - if (!found) { - - // This was used as a hack to stop large lanes from drawing - //if (previous->columns[i].color == 10) - // continue; - - [currentLanes addObject: lane]; - [lines addObject: [PBGitGraphLine upperLineFrom: i to: [currentLanes count] color: [lane index]]]; - [lines addObject: [PBGitGraphLine lowerLineFrom: [currentLanes count] to: [currentLanes count] color: [lane index]]]; + if ([lane isCommit: commit.sha]) { + // We already have a column for this commit. use it instead + [lines addObject: [PBGitGraphLine upperLineFrom: i to: j color: [lane index]]]; + found = YES; + break; } } - // For existing columns, we always just continue straight down - // ^^ I don't know what that means anymore :( - [lines addObject:[PBGitGraphLine lowerLineFrom:newPos to:newPos color: [currentLane index]]]; - } - } - - //Add your own parents - - // If we already did the first parent, don't do so again - if (!didFirst) { - PBGitLane* newLane = [[PBGitLane alloc] initWithCommit:[commit.parents objectAtIndex:0]]; - [currentLanes addObject: newLane]; - newPos = [currentLanes count]; - [lines addObject:[PBGitGraphLine lowerLineFrom: newPos to: newPos color: [newLane index]]]; - } - - // Add all other parents - - // If we add at least one parent, we can go back a single column. - // This boolean will tell us if that happened - BOOL addedParent = NO; - for (NSString* parent in [commit.parents subarrayWithRange:NSMakeRange(1, [commit.parents count] -1)]) { - int i = 0; - BOOL was_displayed = NO; - for (PBGitLane* column in currentLanes) { - i++; - if ([column isCommit: parent]) { - [lines addObject:[PBGitGraphLine lowerLineFrom: i to: newPos color: [column index]]]; - was_displayed = YES; - break; + // We need a new column for this. + if (!found) { + + [currentLanes addObject: lane]; + [lines addObject: [PBGitGraphLine upperLineFrom: i to: [currentLanes count] color: [lane index]]]; + [lines addObject: [PBGitGraphLine lowerLineFrom: [currentLanes count] to: [currentLanes count] color: [lane index]]]; } } - if (was_displayed) - continue; - - // Really add this parent - addedParent = YES; - PBGitLane* newLane = [[PBGitLane alloc] initWithCommit:parent]; - [currentLanes addObject: newLane]; - [lines addObject:[PBGitGraphLine lowerLineFrom: [currentLanes count] to: newPos color: [newLane index]]]; + // For existing columns, we always just continue straight down + // ^^ I don't know what that means anymore :( + [lines addObject:[PBGitGraphLine lowerLineFrom:newPos to:newPos color: [currentLane index]]]; } - - ++row; - previous = [[PBGraphCellInfo alloc] initWithPosition:newPos andLines:lines]; - previous.sign = commit.sign; - if (refs && [refs objectForKey:commit.sha]) - previous.refs = [refs objectForKey:commit.sha]; - - // If a parent was added, we have room to not indent. - if (addedParent) - previous.numColumns = [currentLanes count] - 1; - else - previous.numColumns = [currentLanes count]; - - if ([commit.parents count] > 0 && ![[commit.parents objectAtIndex:0] isEqualToString:@""]) - currentLane.sha = [commit.parents objectAtIndex:0]; - else - [currentLanes removeObject:currentLane]; - - previousLanes = currentLanes; - [cellsInfo addObject: previous]; } + + //Add your own parents + + // If we already did the first parent, don't do so again + if (!didFirst) { + PBGitLane* newLane = [[PBGitLane alloc] initWithCommit:[commit.parents objectAtIndex:0]]; + [currentLanes addObject: newLane]; + newPos = [currentLanes count]; + [lines addObject:[PBGitGraphLine lowerLineFrom: newPos to: newPos color: [newLane index]]]; + } + + // Add all other parents + + // If we add at least one parent, we can go back a single column. + // This boolean will tell us if that happened + BOOL addedParent = NO; + + for (NSString* parent in [commit.parents subarrayWithRange:NSMakeRange(1, [commit.parents count] -1)]) { + int i = 0; + BOOL was_displayed = NO; + for (PBGitLane* column in currentLanes) { + i++; + if ([column isCommit: parent]) { + [lines addObject:[PBGitGraphLine lowerLineFrom: i to: newPos color: [column index]]]; + was_displayed = YES; + break; + } + } + if (was_displayed) + continue; + + // Really add this parent + addedParent = YES; + PBGitLane* newLane = [[PBGitLane alloc] initWithCommit:parent]; + [currentLanes addObject: newLane]; + [lines addObject:[PBGitGraphLine lowerLineFrom: [currentLanes count] to: newPos color: [newLane index]]]; + } + + previous = [[PBGraphCellInfo alloc] initWithPosition:newPos andLines:lines]; + previous.sign = commit.sign; + if (refs && [refs objectForKey:commit.sha]) + previous.refs = [refs objectForKey:commit.sha]; + + // If a parent was added, we have room to not indent. + if (addedParent) + previous.numColumns = [currentLanes count] - 1; + else + previous.numColumns = [currentLanes count]; + + if ([commit.parents count] > 0 && ![[commit.parents objectAtIndex:0] isEqualToString:@""]) + currentLane.sha = [commit.parents objectAtIndex:0]; + else + [currentLanes removeObject:currentLane]; + + previousLanes = currentLanes; + [cellsInfo addObject: previous]; } - (PBGraphCellInfo*) cellInfoForRow: (int) row @@ -156,7 +144,6 @@ - (void) finalize { - free(cellsInfo); [super finalize]; } @end diff --git a/PBGitRevList.m b/PBGitRevList.m index 8bdc268..14a7b22 100644 --- a/PBGitRevList.m +++ b/PBGitRevList.m @@ -65,7 +65,6 @@ NSMutableArray* newArray = [NSMutableArray array]; NSMutableArray* arguments; - NSDate* start = [NSDate date]; BOOL showSign = [rev hasLeftRight]; if (showSign) @@ -80,6 +79,10 @@ NSFileHandle* handle = [repository handleForArguments: arguments]; + // We decorate the commits in a separate thread. + NSThread * decorationThread = [[NSThread alloc] initWithTarget: self selector: @selector(decorateRevisions:) object:newArray]; + [decorationThread start]; + int fd = [handle fileDescriptor]; FILE* f = fdopen(fd, "r"); int BUFFERSIZE = 2048; @@ -87,7 +90,7 @@ buffer[BUFFERSIZE - 2] = 0; char* l; - int num = 0; + NSMutableString* currentLine = [NSMutableString string]; while (l = fgets(buffer, BUFFERSIZE, f)) { NSString *s = [NSString stringWithCString:(const char *)l encoding:NSUTF8StringEncoding]; @@ -117,28 +120,49 @@ if (showSign) newCommit.sign = [[components objectAtIndex:5] characterAtIndex:0]; - [newArray addObject: newCommit]; - num++; - if (num % 10000 == 0) - [self performSelectorOnMainThread:@selector(setCommits:) withObject:newArray waitUntilDone:NO]; + @synchronized(newArray) { + [newArray addObject: newCommit]; + } currentLine = [NSMutableString string]; } - [self performSelectorOnMainThread:@selector(setCommits:) withObject:newArray waitUntilDone:YES]; + [decorationThread cancel]; - if (![rev hasPathLimiter]) { - PBGitGrapher* g = [[PBGitGrapher alloc] initWithRepository: repository]; - [g parseCommits: self.commits]; - [self performSelectorOnMainThread:@selector(setGrapher:) withObject:g waitUntilDone:YES]; - [self performSelectorOnMainThread:@selector(setCommits:) withObject:newArray waitUntilDone:YES]; - } - else - grapher = nil; - - NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:start]; - NSLog(@"Loaded %i commits in %f seconds", num, duration); [NSThread exit]; } +- (void) decorateRevisions: (NSMutableArray*) revisions +{ + NSDate* start = [NSDate date]; + + NSMutableArray* allRevisions = [NSMutableArray arrayWithCapacity:1000]; + int num = 0; + PBGitGrapher* g = [[PBGitGrapher alloc] initWithRepository: repository]; + [self performSelectorOnMainThread:@selector(setGrapher:) withObject:g waitUntilDone:YES]; + + while (!([[NSThread currentThread] isCancelled] && [revisions count] == 0)) { + if ([revisions count] == 0) + usleep(10000); + + NSArray* currentRevisions; + @synchronized(revisions) { + currentRevisions = [revisions copy]; + [revisions removeAllObjects]; + } + for (PBGitCommit* commit in currentRevisions) { + num++; + [g decorateCommit: commit]; + [allRevisions addObject: commit]; + if (num % 1000 == 0) + [self performSelectorOnMainThread:@selector(setCommits:) withObject:allRevisions waitUntilDone:NO]; + } + } + + [self performSelectorOnMainThread:@selector(setCommits:) withObject:allRevisions waitUntilDone:YES]; + NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:start]; + NSLog(@"Loaded %i commits in %f seconds", num, duration); + + [NSThread exit]; +} @end From 48fa14081376c499f6331ff01f8c3f1699084a9a Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Wed, 17 Sep 2008 23:40:42 +0200 Subject: [PATCH 3/7] Only decorate if we need to --- PBGitRevList.m | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/PBGitRevList.m b/PBGitRevList.m index 14a7b22..d01cef2 100644 --- a/PBGitRevList.m +++ b/PBGitRevList.m @@ -60,6 +60,11 @@ [self readCommits]; } +struct decorateParameters { + NSMutableArray* revisions; + PBGitRevSpecifier* rev; +}; + - (void) walkRevisionListWithSpecifier: (PBGitRevSpecifier*) rev { @@ -80,7 +85,8 @@ NSFileHandle* handle = [repository handleForArguments: arguments]; // We decorate the commits in a separate thread. - NSThread * decorationThread = [[NSThread alloc] initWithTarget: self selector: @selector(decorateRevisions:) object:newArray]; + struct decorateParameters params = { newArray, rev }; + NSThread * decorationThread = [[NSThread alloc] initWithTarget: self selector: @selector(decorateRevisions:) object:¶ms]; [decorationThread start]; int fd = [handle fileDescriptor]; @@ -131,18 +137,25 @@ [NSThread exit]; } -- (void) decorateRevisions: (NSMutableArray*) revisions +// We're not supposed to pass on structs, only objects, but this is much easier +- (void) decorateRevisions: (struct decorateParameters*) params { + NSMutableArray* revisions = params->revisions; + PBGitRevSpecifier* rev = params->rev; + + BOOL decorateCommits = ![rev hasPathLimiter]; NSDate* start = [NSDate date]; NSMutableArray* allRevisions = [NSMutableArray arrayWithCapacity:1000]; int num = 0; + PBGitGrapher* g = [[PBGitGrapher alloc] initWithRepository: repository]; - [self performSelectorOnMainThread:@selector(setGrapher:) withObject:g waitUntilDone:YES]; + if (decorateCommits) + [self performSelectorOnMainThread:@selector(setGrapher:) withObject:g waitUntilDone:YES]; while (!([[NSThread currentThread] isCancelled] && [revisions count] == 0)) { if ([revisions count] == 0) - usleep(10000); + usleep(5000); NSArray* currentRevisions; @synchronized(revisions) { @@ -151,9 +164,10 @@ } for (PBGitCommit* commit in currentRevisions) { num++; - [g decorateCommit: commit]; + if (decorateCommits) + [g decorateCommit: commit]; [allRevisions addObject: commit]; - if (num % 1000 == 0) + if (num % 1000 == 0 || num == 10) [self performSelectorOnMainThread:@selector(setCommits:) withObject:allRevisions waitUntilDone:NO]; } } From 6e978dcea47a0502126a58d5b01c456c0665b4bb Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Thu, 18 Sep 2008 01:27:05 +0200 Subject: [PATCH 4/7] Refactor cellInfo structure This makes the PBGitRevisionCell a bit nicer by retrieving all values from the PBGitCommit object itself, and using another NSTextFieldCell to draw the text. This mean that PBGitGrapher now stores its information in the PBGitCommit's, rather than in a custom grapher array. Also, because we don't need the grapher to display refs anymore, the ref labels are also displayed when using path limiting (for example, 'gitx -- Makefile'). --- English.lproj/RepositoryWindow.xib | 59 +++++++++++++++++---------- PBDetailController.m | 14 ------- PBGitCommit.h | 5 ++- PBGitCommit.m | 2 +- PBGitGrapher.h | 2 - PBGitGrapher.m | 13 +----- PBGitRevList.h | 2 - PBGitRevList.m | 9 +++-- PBGitRevisionCell.h | 10 +++-- PBGitRevisionCell.m | 64 ++++++++++++++++-------------- 10 files changed, 92 insertions(+), 88 deletions(-) diff --git a/English.lproj/RepositoryWindow.xib b/English.lproj/RepositoryWindow.xib index 3b8f28e..25626d8 100644 --- a/English.lproj/RepositoryWindow.xib +++ b/English.lproj/RepositoryWindow.xib @@ -2,13 +2,13 @@ 1050 - 9E17 + 9F33 670 - 949.33 + 949.34 352.00 YES - + YES @@ -1831,22 +1831,6 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ 84 - - - value: arrangedObjects.subject - - - - - - value: arrangedObjects.subject - value - arrangedObjects.subject - 2 - - - 85 - value: arrangedObjects.author @@ -2242,6 +2226,26 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ 233 + + + value: arrangedObjects + + + + + + value: arrangedObjects + value + arrangedObjects + + NSConditionallySetsEditable + + + 2 + + + 243 + @@ -3010,7 +3014,7 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ - 233 + 243 @@ -3094,7 +3098,20 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ PBGitRevisionCell - NSTextFieldCell + NSCell + + YES + + YES + objectValue + value + + + YES + id + id + + IBProjectSource PBGitRevisionCell.h diff --git a/PBDetailController.m b/PBDetailController.m index 3128105..1df8d29 100644 --- a/PBDetailController.m +++ b/PBDetailController.m @@ -160,18 +160,4 @@ int index = [[commitController selectionIndexes] firstIndex]; [commitList scrollRowToVisible: index]; } - -- (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex -{ - if (![[aTableColumn identifier] isEqualToString:@"subject"]) - return; - - PBGitRevisionCell* cell = aCell; - if (self.repository.revisionList.grapher && - ![commitController filterPredicate] && - [[commitController sortDescriptors] count] == 0) { - PBGitGrapher* g = self.repository.revisionList.grapher; - [cell setCellInfo: [g cellInfoForRow:rowIndex]]; - } -} @end diff --git a/PBGitCommit.h b/PBGitCommit.h index 2194608..e2c87c2 100644 --- a/PBGitCommit.h +++ b/PBGitCommit.h @@ -16,8 +16,10 @@ NSString* author; NSString* details; NSArray* parents; + NSArray* refs; NSDate* date; char sign; + id lineInfo; PBGitRepository* repository; } @@ -26,7 +28,7 @@ @property (copy) NSString* sha; @property (copy) NSString* subject; @property (copy) NSString* author; -@property (retain) NSArray* parents; +@property (retain) NSArray* parents, *refs; @property (copy) NSDate* date; @property (readonly) NSString* dateString; @property (assign) char sign; @@ -35,4 +37,5 @@ @property (readonly) PBGitTree* tree; @property (readonly) NSArray* treeContents; @property (retain) PBGitRepository* repository; +@property (retain) id lineInfo; @end diff --git a/PBGitCommit.m b/PBGitCommit.m index ff94454..0fef796 100644 --- a/PBGitCommit.m +++ b/PBGitCommit.m @@ -11,7 +11,7 @@ @implementation PBGitCommit -@synthesize sha, repository, subject, author, date, parents, sign; +@synthesize sha, repository, subject, author, date, parents, sign, lineInfo, refs; - (NSString *) dateString diff --git a/PBGitGrapher.h b/PBGitGrapher.h index a4a0d07..806b551 100644 --- a/PBGitGrapher.h +++ b/PBGitGrapher.h @@ -22,12 +22,10 @@ struct PBGitGraphColumn { @interface PBGitGrapher : NSObject { PBGraphCellInfo* previous; NSMutableArray* previousLanes; - NSMutableArray* cellsInfo; NSDictionary* refs; PBGitRepository* repository; } - (id) initWithRepository: (PBGitRepository*) repo; - (void) decorateCommit: (PBGitCommit *) commit; -- (PBGraphCellInfo*) cellInfoForRow: (int) row; @end diff --git a/PBGitGrapher.m b/PBGitGrapher.m index da4794e..2fad4dd 100644 --- a/PBGitGrapher.m +++ b/PBGitGrapher.m @@ -15,9 +15,7 @@ - (id) initWithRepository: (PBGitRepository*) repo { refs = repo.refs; - // We don't know how many commits to parse. - cellsInfo = [NSMutableArray arrayWithCapacity:100]; - + repository = repo; previousLanes = [NSMutableArray array]; return self; @@ -119,8 +117,6 @@ previous = [[PBGraphCellInfo alloc] initWithPosition:newPos andLines:lines]; previous.sign = commit.sign; - if (refs && [refs objectForKey:commit.sha]) - previous.refs = [refs objectForKey:commit.sha]; // If a parent was added, we have room to not indent. if (addedParent) @@ -134,12 +130,7 @@ [currentLanes removeObject:currentLane]; previousLanes = currentLanes; - [cellsInfo addObject: previous]; -} - -- (PBGraphCellInfo*) cellInfoForRow: (int) row -{ - return [cellsInfo objectAtIndex: row]; + commit.lineInfo = previous; } - (void) finalize diff --git a/PBGitRevList.h b/PBGitRevList.h index f587556..cde4418 100644 --- a/PBGitRevList.h +++ b/PBGitRevList.h @@ -11,7 +11,6 @@ @interface PBGitRevList : NSObject { NSArray* commits; - id grapher; id repository; NSString* lastSha; } @@ -20,6 +19,5 @@ - (void) readCommits; @property(retain) NSArray* commits; -@property(retain) id grapher; @end diff --git a/PBGitRevList.m b/PBGitRevList.m index d01cef2..f5db47a 100644 --- a/PBGitRevList.m +++ b/PBGitRevList.m @@ -14,7 +14,7 @@ @implementation PBGitRevList -@synthesize commits, grapher; +@synthesize commits; - initWithRepository: (id) repo { repository = repo; @@ -142,6 +142,7 @@ struct decorateParameters { { NSMutableArray* revisions = params->revisions; PBGitRevSpecifier* rev = params->rev; + NSDictionary* refs = [repository refs]; BOOL decorateCommits = ![rev hasPathLimiter]; NSDate* start = [NSDate date]; @@ -150,8 +151,6 @@ struct decorateParameters { int num = 0; PBGitGrapher* g = [[PBGitGrapher alloc] initWithRepository: repository]; - if (decorateCommits) - [self performSelectorOnMainThread:@selector(setGrapher:) withObject:g waitUntilDone:YES]; while (!([[NSThread currentThread] isCancelled] && [revisions count] == 0)) { if ([revisions count] == 0) @@ -166,6 +165,10 @@ struct decorateParameters { num++; if (decorateCommits) [g decorateCommit: commit]; + + if (refs && [refs objectForKey:commit.sha]) + commit.refs = [refs objectForKey:commit.sha]; + [allRevisions addObject: commit]; if (num % 1000 == 0 || num == 10) [self performSelectorOnMainThread:@selector(setCommits:) withObject:allRevisions waitUntilDone:NO]; diff --git a/PBGitRevisionCell.h b/PBGitRevisionCell.h index def74c8..8bb26ea 100644 --- a/PBGitRevisionCell.h +++ b/PBGitRevisionCell.h @@ -8,11 +8,13 @@ #import #import "PBGitGrapher.h" +#import "PBGraphCellInfo.h" -@interface PBGitRevisionCell : NSTextFieldCell { - PBGraphCellInfo* cellInfo; - BOOL isReady; +@interface PBGitRevisionCell : NSActionCell { + id objectValue; + PBGraphCellInfo* cellInfo; + NSTextFieldCell* textCell; } -@property(assign) PBGraphCellInfo* cellInfo; +@property(retain) PBGitCommit* objectValue; @end diff --git a/PBGitRevisionCell.m b/PBGitRevisionCell.m index 8a50c03..3d3c0de 100644 --- a/PBGitRevisionCell.m +++ b/PBGitRevisionCell.m @@ -58,19 +58,11 @@ @implementation PBGitRevisionCell -@synthesize cellInfo; --(void) setCellInfo: (PBGraphCellInfo*) info -{ - isReady = YES; - cellInfo = info; -} - (id) initWithCoder: (id) coder { self = [super initWithCoder:coder]; - if (self != nil) { - isReady = NO; - } + textCell = [[NSTextFieldCell alloc] initWithCoder:coder]; return self; } @@ -196,13 +188,14 @@ static const float ref_padding = 10.0f; static const float ref_spacing = 2.0f; + NSArray* refs = [self.objectValue refs]; NSRect refRect = (NSRect){rect->origin, rect->size}; [[NSColor blackColor] setStroke]; int index; - for (index = 0; index < [cellInfo.refs count]; ++index) { - PBGitRef* ref = [cellInfo.refs objectAtIndex:index]; + for (index = 0; index < [refs count]; ++index) { + PBGitRef* ref = [refs objectAtIndex:index]; NSMutableDictionary* attributes = [self attributesForRefLabelSelected:[self isHighlighted]]; NSSize refSize = [[ref shortName] sizeWithAttributes:attributes]; @@ -231,31 +224,44 @@ - (void) drawWithFrame: (NSRect) rect inView:(NSView *)view { - if (!isReady) - return [super drawWithFrame:rect inView:view]; + cellInfo = [self.objectValue lineInfo]; + + if (cellInfo) { + float pathWidth = 10 + 10 * cellInfo.numColumns; - float pathWidth = 10 + 10 * cellInfo.numColumns; + NSRect ownRect; + NSDivideRect(rect, &ownRect, &rect, pathWidth, NSMinXEdge); - NSRect ownRect; - NSDivideRect(rect, &ownRect, &rect, pathWidth, NSMinXEdge); + for (PBGitGraphLine* line in cellInfo.lines) { + if (line.upper == 0) + [self drawLineFromColumn: line.from toColumn: line.to inRect:ownRect offset: ownRect.size.height color: line.colorIndex]; + else + [self drawLineFromColumn: line.from toColumn: line.to inRect:ownRect offset: 0 color:line.colorIndex]; + } - for (PBGitGraphLine* line in cellInfo.lines) { - if (line.upper == 0) - [self drawLineFromColumn: line.from toColumn: line.to inRect:ownRect offset: ownRect.size.height color: line.colorIndex]; + if (cellInfo.sign == '<' || cellInfo.sign == '>') + [self drawTriangleInRect: ownRect sign: cellInfo.sign]; else - [self drawLineFromColumn: line.from toColumn: line.to inRect:ownRect offset: 0 color:line.colorIndex]; + [self drawCircleInRect: ownRect]; } - if (cellInfo.sign == '<' || cellInfo.sign == '>') - [self drawTriangleInRect: ownRect sign: cellInfo.sign]; - else - [self drawCircleInRect: ownRect]; - - if (cellInfo.refs) + if ([self.objectValue refs]) [self drawRefsInRect:&rect]; - - [super drawWithFrame:rect inView:view]; - isReady = NO; + + // Still use this superclass because of hilighting differences + //_contents = [self.objectValue subject]; + //[super drawWithFrame:rect inView:view]; + [textCell setObjectValue: [self.objectValue subject]]; + [textCell setHighlighted: [self isHighlighted]]; + [textCell drawWithFrame:rect inView: view]; +} + +- (void) setObjectValue: (PBGitCommit*)object { + [super setObjectValue:[NSValue valueWithNonretainedObject:object]]; +} + +- (PBGitCommit*) objectValue { + return [[super objectValue] nonretainedObjectValue]; } @end From f48d0022e209e98e47e523e2f410537f8e90adae Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Fri, 19 Sep 2008 13:55:33 +0200 Subject: [PATCH 5/7] Allow copy and pasting of web source by pressing 'c' --- PBCommitList.m | 2 +- PBWebGitController.m | 8 ++++++++ html/keyboardNavigation.js | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/PBCommitList.m b/PBCommitList.m index 67d446d..a7f03e2 100644 --- a/PBCommitList.m +++ b/PBCommitList.m @@ -22,7 +22,7 @@ else [webView scrollPageDown: self]; } - else if ([character rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"jkv"]].location == 0) + else if ([character rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"jkcv"]].location == 0) [webController sendKey: character]; else [super keyDown: event]; diff --git a/PBWebGitController.m b/PBWebGitController.m index 245c9af..2516ef2 100644 --- a/PBWebGitController.m +++ b/PBWebGitController.m @@ -73,6 +73,14 @@ [script callWebScriptMethod:@"handleKeyFromCocoa" withArguments: [NSArray arrayWithObject:key]]; } +- (void) copySource +{ + NSString *source = [[[[view mainFrame] DOMDocument] documentElement] outerHTML]; + NSPasteboard *a =[NSPasteboard generalPasteboard]; + [a declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:self]; + [a setString:source forType: NSStringPboardType]; +} + + (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector { return NO; diff --git a/html/keyboardNavigation.js b/html/keyboardNavigation.js index 671be3d..7ed1f44 100644 --- a/html/keyboardNavigation.js +++ b/html/keyboardNavigation.js @@ -24,6 +24,8 @@ var handleKeyFromCocoa = function(key) { changeHunk(false); else if (key == 'v') showDiffs(); + else if (key == 'c') + Controller.copySource(); } var changeHunk = function(next) { From 58f0a383b292980ea1c65c46863c05f881381a8c Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Fri, 19 Sep 2008 13:56:46 +0200 Subject: [PATCH 6/7] Show refs in HTML view --- PBGitRef.m | 9 +++++++++ html/commit.html | 4 ++++ html/commit.js | 10 ++++++++++ html/commits.css | 20 ++++++++++++++++++++ 4 files changed, 43 insertions(+) diff --git a/PBGitRef.m b/PBGitRef.m index 3dadf59..f345a0a 100644 --- a/PBGitRef.m +++ b/PBGitRef.m @@ -41,4 +41,13 @@ return self; } ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector +{ + return NO; +} + ++ (BOOL)isKeyExcludedFromWebScript:(const char *)name { + return NO; +} + @end diff --git a/html/commit.html b/html/commit.html index 9e3d472..70fe140 100644 --- a/html/commit.html +++ b/html/commit.html @@ -27,6 +27,10 @@ Subject: Pieter de Bie + + Refs: + +
diff --git a/html/commit.js b/html/commit.js index 87de52d..b2720c3 100644 --- a/html/commit.js +++ b/html/commit.js @@ -2,6 +2,7 @@ var commit; var Commit = Class.create({ initialize: function(obj) { this.raw = obj.details; + this.refs = obj.refs; var diffStart = this.raw.indexOf("\ndiff "); var messageStart = this.raw.indexOf("\n\n") + 2; @@ -67,6 +68,15 @@ var loadCommit = function() { new_row.innerHTML = "Parent:" + parent + ""; }); + if (commit.refs){ + $('refs').parentNode.style.display = ""; + $('refs').innerHTML = ""; + $A(commit.refs).each(function(ref) { + $('refs').innerHTML += '' + ref.shortName() + ''; + }); + } else + $('refs').parentNode.style.display = "none"; + $("message").innerHTML = commit.message.replace(/\n/g,"
"); if (commit.diff.length < 10000) { diff --git a/html/commits.css b/html/commits.css index 244d59f..ceaeeb8 100644 --- a/html/commits.css +++ b/html/commits.css @@ -36,4 +36,24 @@ a.showdiff { font-size: 1.3em; } +.refs { + font-size: 9px; + font-family: Helvetica; + border: 1px solid black; + margin-right: 5px; + padding: 1px 3px 1px 3px; + -webkit-border-radius: 2px; +} + +.refs.head { + background-color: #aaf254; +} + +.refs.remote { + background-color: #b2dfff; +} + +.refs.tag { + background-color: #fced4f; +} From f8270f38fba2e40b776dc1367b9a93a355b14a59 Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Fri, 19 Sep 2008 14:40:51 +0200 Subject: [PATCH 7/7] Add framework to support removing refs --- English.lproj/RepositoryWindow.xib | 29 ++++++++++++++--------------- PBWebGitController.m | 20 ++++++++++++++++++++ 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/English.lproj/RepositoryWindow.xib b/English.lproj/RepositoryWindow.xib index 25626d8..b11e7c8 100644 --- a/English.lproj/RepositoryWindow.xib +++ b/English.lproj/RepositoryWindow.xib @@ -8,7 +8,7 @@ 352.00 YES - + YES @@ -2239,13 +2239,21 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ arrangedObjects NSConditionallySetsEditable - + 2
243
+ + + UIDelegate + + + + 244 +
@@ -3014,7 +3022,7 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ - 243 + 244 @@ -3098,19 +3106,10 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ PBGitRevisionCell - NSCell + NSActionCell - YES - - YES - objectValue - value - - - YES - id - id - + objectValue + id IBProjectSource diff --git a/PBWebGitController.m b/PBWebGitController.m index 2516ef2..7549b42 100644 --- a/PBWebGitController.m +++ b/PBWebGitController.m @@ -90,4 +90,24 @@ return NO; } +- (void) removeRef: (id) sender +{ + NSLog(@"Removing refs is not yet supported"); +} + +- (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element defaultMenuItems:(NSArray *)defaultMenuItems { + DOMNode *node = [element valueForKey:@"WebElementDOMNode"]; + + if ([[node className] isEqualToString:@"DOMText"]) + node = [node parentNode]; + + // Every ref has a class name of 'refs' and some other class. We check on that to see if we pressed on a ref. + if ([[node className] hasPrefix:@"refs "]) { + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@"Remove" action:@selector(removeRef:) keyEquivalent: @""]; + [item setTarget: self]; + return [NSArray arrayWithObject: item]; + } + + return defaultMenuItems; +} @end