Browse files

Merge branch 'pu/pb/index_refactor'

* pu/pb/index_refactor: (24 commits)
  PBGitIndex: post notifications when index stuff fails
  GitIndexController: reorder methods a bit, remove unnecessary stuff
  PBGitIndex: Migrate discardChanges to the GitIndex
  CommitController: Make commit message editable after commit failed
  GitIndex: Fix a few comments
  GitIndex: explicitly tell when stuff is updated
  Remove cruft
  Show previous commit message when amending
  CommitController: Empty commit title when commit is successful
  CommitView: Remove cruft
  Add failed commit notifications
  GitIndex: add commit notifications
  CommitController: Add status messages for index operations
  GitIndex: Add a few notifications
  CommitView: Migrate patch apply stuff to GitIndex
  GitIndex: Add support for applying patches
  CommitController: Replace commit method with the one from GitIndex
  GitIndex: add basic commit method
  GitIndexController: Migrate stageFiles functions to GitIndex
  GitIndex: Add methods to stage and unstage files
  ...

Conflicts:
	PBGitCommitController.m
	PBGitIndexController.h
	PBGitIndexController.m
  • Loading branch information...
2 parents 1a5a211 + a2b3bf3 commit 1854fc0bd0ed3c335359af743965f41340ab167a @pieter committed Sep 17, 2009
View
18 GitX.xcodeproj/project.pbxproj
@@ -97,6 +97,7 @@
F59116E90E843BCB0072CCB1 /* PBGitCommitController.m in Sources */ = {isa = PBXBuildFile; fileRef = F59116E80E843BCB0072CCB1 /* PBGitCommitController.m */; };
F593DF780E9E636C003A8559 /* PBFileChangesTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = F593DF770E9E636C003A8559 /* PBFileChangesTableView.m */; };
F5945E170E02B0C200706420 /* PBGitRepository.m in Sources */ = {isa = PBXBuildFile; fileRef = F5945E160E02B0C200706420 /* PBGitRepository.m */; };
+ F59F1DD5105C4FF300115F88 /* PBGitIndex.m in Sources */ = {isa = PBXBuildFile; fileRef = F59F1DD4105C4FF300115F88 /* PBGitIndex.m */; };
F5AD56790E79B78100EDAAFE /* PBCommitList.m in Sources */ = {isa = PBXBuildFile; fileRef = F5AD56780E79B78100EDAAFE /* PBCommitList.m */; };
F5B721C40E05CF7E00AF29DC /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F5B721C20E05CF7E00AF29DC /* MainMenu.xib */; };
F5C007750E731B48007B84B2 /* PBGitRef.m in Sources */ = {isa = PBXBuildFile; fileRef = F5C007740E731B48007B84B2 /* PBGitRef.m */; };
@@ -250,6 +251,8 @@
F593DF770E9E636C003A8559 /* PBFileChangesTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBFileChangesTableView.m; sourceTree = "<group>"; };
F5945E150E02B0C200706420 /* PBGitRepository.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBGitRepository.h; sourceTree = "<group>"; };
F5945E160E02B0C200706420 /* PBGitRepository.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBGitRepository.m; sourceTree = "<group>"; };
+ F59F1DD3105C4FF300115F88 /* PBGitIndex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBGitIndex.h; sourceTree = "<group>"; };
+ F59F1DD4105C4FF300115F88 /* PBGitIndex.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBGitIndex.m; sourceTree = "<group>"; };
F5AD56770E79B78100EDAAFE /* PBCommitList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBCommitList.h; sourceTree = "<group>"; };
F5AD56780E79B78100EDAAFE /* PBCommitList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBCommitList.m; sourceTree = "<group>"; };
F5B721C30E05CF7E00AF29DC /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = "<group>"; };
@@ -467,6 +470,7 @@
F56174540E05887E001DCD79 /* Git */ = {
isa = PBXGroup;
children = (
+ F59F1DD2105C4FDE00115F88 /* Index */,
F5E927E30E883D6800056E75 /* Commit */,
F5E927E10E883D2E00056E75 /* History */,
F5945E150E02B0C200706420 /* PBGitRepository.h */,
@@ -549,6 +553,17 @@
name = SpeedTest;
sourceTree = "<group>";
};
+ F59F1DD2105C4FDE00115F88 /* Index */ = {
+ isa = PBXGroup;
+ children = (
+ F5E927F60E883E7200056E75 /* PBChangedFile.h */,
+ F5E927F70E883E7200056E75 /* PBChangedFile.m */,
+ F59F1DD3105C4FF300115F88 /* PBGitIndex.h */,
+ F59F1DD4105C4FF300115F88 /* PBGitIndex.m */,
+ );
+ name = Index;
+ sourceTree = "<group>";
+ };
F5B161BB0EAB6E0C005A1DE1 /* Diff */ = {
isa = PBXGroup;
children = (
@@ -604,8 +619,6 @@
children = (
93F7857D0EA3ABF100C1F443 /* PBCommitMessageView.h */,
93F7857E0EA3ABF100C1F443 /* PBCommitMessageView.m */,
- F5E927F60E883E7200056E75 /* PBChangedFile.h */,
- F5E927F70E883E7200056E75 /* PBChangedFile.m */,
F593DF760E9E636C003A8559 /* PBFileChangesTableView.h */,
F593DF770E9E636C003A8559 /* PBFileChangesTableView.m */,
);
@@ -854,6 +867,7 @@
47DBDBCA0E95016F00671A1E /* PBNSURLPathUserDefaultsTransfomer.m in Sources */,
F562C8870FE1766C000EC528 /* NSString_RegEx.m in Sources */,
EB2A734A0FEE3F09006601CF /* PBCollapsibleSplitView.m in Sources */,
+ F59F1DD5105C4FF300115F88 /* PBGitIndex.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
32 PBGitCommitController.h
@@ -9,12 +9,12 @@
#import <Cocoa/Cocoa.h>
#import "PBViewController.h"
-@class PBGitIndexController;
-@class PBIconAndTextCell;
-@class PBWebChangesController;
+@class PBGitIndexController, PBIconAndTextCell, PBWebChangesController, PBGitIndex;
@interface PBGitCommitController : PBViewController {
- NSMutableArray *files;
+ // This might have to transfer over to the PBGitRepository
+ // object sometime
+ PBGitIndex *index;
IBOutlet NSTextView *commitMessageView;
IBOutlet NSArrayController *unstagedFilesController;
@@ -24,28 +24,12 @@
IBOutlet PBWebChangesController *webController;
NSString *status;
-
- // We use busy as a count of active processes.
- // You can increase it when your process start
- // And decrease it after you have finished.
- int busy;
- BOOL amend;
- NSDictionary *amendEnvironment;
-
+ BOOL busy;
}
-@property (retain) NSMutableArray *files;
-@property (copy) NSString *status;
-@property (assign) int busy;
-@property (assign) BOOL amend;
-
-- (void) readCachedFiles:(NSNotification *)notification;
-- (void) readOtherFiles:(NSNotification *)notification;
-- (void) readUnstagedFiles:(NSNotification *)notification;
-- (void) stageHunk: (NSString *)hunk reverse:(BOOL)reverse;
-- (void)discardHunk:(NSString *)hunk;
-
-- (NSString *)parentTree;
+@property(copy) NSString *status;
+@property(readonly) PBGitIndex *index;
+@property(assign) BOOL busy;
- (IBAction) refresh:(id) sender;
- (IBAction) commit:(id) sender;
View
411 PBGitCommitController.m
@@ -10,26 +10,44 @@
#import "NSFileHandleExt.h"
#import "PBChangedFile.h"
#import "PBWebChangesController.h"
-#import "NSString_RegEx.h"
-#import "PBGitIndexController.h"
-
-@interface PBGitCommitController (PrivateMethods)
-- (NSArray *) linesFromNotification:(NSNotification *)notification;
-- (void) doneProcessingIndex;
-- (NSMutableDictionary *)dictionaryForLines:(NSArray *)lines;
-- (void) addFilesFromDictionary:(NSMutableDictionary *)dictionary staged:(BOOL)staged tracked:(BOOL)tracked;
-- (void)processHunk:(NSString *)hunk stage:(BOOL)stage reverse:(BOOL)reverse;
+#import "PBGitIndex.h"
+
+@interface PBGitCommitController ()
+- (void)refreshFinished:(NSNotification *)notification;
+- (void)commitStatusUpdated:(NSNotification *)notification;
+- (void)commitFinished:(NSNotification *)notification;
+- (void)commitFailed:(NSNotification *)notification;
+- (void)amendCommit:(NSNotification *)notification;
+- (void)indexChanged:(NSNotification *)notification;
+- (void)indexOperationFailed:(NSNotification *)notification;
@end
@implementation PBGitCommitController
-@synthesize files, status, busy, amend;
+@synthesize status, index, busy;
+
+- (id)initWithRepository:(PBGitRepository *)theRepository superController:(PBGitWindowController *)controller
+{
+ if (!(self = [super initWithRepository:theRepository superController:controller]))
+ return nil;
+
+ index = [[PBGitIndex alloc] initWithRepository:theRepository workingDirectory:[NSURL fileURLWithPath:[theRepository workingDirectory]]];
+ [index refresh];
+
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshFinished:) name:PBGitIndexFinishedIndexRefresh object:index];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitStatusUpdated:) name:PBGitIndexCommitStatus object:index];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitFinished:) name:PBGitIndexFinishedCommit object:index];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitFailed:) name:PBGitIndexCommitFailed object:index];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(amendCommit:) name:PBGitIndexAmendMessageAvailable object:index];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(indexChanged:) name:PBGitIndexIndexUpdated object:index];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(indexOperationFailed:) name:PBGitIndexOperationFailed object:index];
+
+ return self;
+}
- (void)awakeFromNib
{
- self.files = [NSMutableArray array];
[super awakeFromNib];
- [self refresh:self];
[commitMessageView setTypingAttributes:[NSDictionary dictionaryWithObject:[NSFont fontWithName:@"Monaco" size:12.0] forKey:NSFontAttributeName]];
@@ -41,12 +59,17 @@ - (void)awakeFromNib
[[NSSortDescriptor alloc] initWithKey:@"path" ascending:true], nil]];
[cachedFilesController setSortDescriptors:[NSArray arrayWithObject:
[[NSSortDescriptor alloc] initWithKey:@"path" ascending:true]]];
+
+ [cachedFilesController setAutomaticallyRearrangesObjects:NO];
+ [unstagedFilesController setAutomaticallyRearrangesObjects:NO];
}
+
- (void) removeView
{
[webController closeView];
[super finalize];
}
+
- (NSResponder *)firstResponder;
{
return commitMessageView;
@@ -68,106 +91,11 @@ - (IBAction)signOff:(id)sender
}
}
-- (void) setAmend:(BOOL)newAmend
-{
- if (newAmend == amend)
- return;
-
- amend = newAmend;
- amendEnvironment = nil;
-
- // If we amend, we want to keep the author information for the previous commit
- // We do this by reading in the previous commit, and storing the information
- // in a dictionary. This dictionary will then later be read by [self commit:]
- if (amend) {
- NSString *message = [repository outputForCommand:@"cat-file commit HEAD"];
- NSArray *match = [message substringsMatchingRegularExpression:@"\nauthor ([^\n]*) <([^\n>]*)> ([0-9]+[^\n]*)\n" count:3 options:0 ranges:nil error:nil];
- if (match)
- amendEnvironment = [NSDictionary dictionaryWithObjectsAndKeys:[match objectAtIndex:1], @"GIT_AUTHOR_NAME",
- [match objectAtIndex:2], @"GIT_AUTHOR_EMAIL",
- [match objectAtIndex:3], @"GIT_AUTHOR_DATE",
- nil];
-
- // Replace commit message with the old one if it's less than 3 characters long.
- // This is just a random number.
- if ([[commitMessageView string] length] <= 3) {
- // Find the commit message
- NSRange r = [message rangeOfString:@"\n\n"];
- if (r.location != NSNotFound)
- message = [message substringFromIndex:r.location + 2];
-
- commitMessageView.string = message;
- }
- }
-
- [self refresh:self];
-}
-
-- (NSArray *) linesFromNotification:(NSNotification *)notification
-{
- NSDictionary *userInfo = [notification userInfo];
- NSData *data = [userInfo valueForKey:NSFileHandleNotificationDataItem];
- if (!data)
- return NULL;
-
- NSString* string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
- if (!string)
- return NULL;
-
- // Strip trailing newline
- if ([string hasSuffix:@"\n"])
- string = [string substringToIndex:[string length]-1];
-
- NSArray *lines = [string componentsSeparatedByString:@"\0"];
- return lines;
-}
-
-- (NSString *) parentTree
-{
- NSString *parent = amend ? @"HEAD^" : @"HEAD";
-
- if (![repository parseReference:parent])
- // We don't have a head ref. Return the empty tree.
- return @"4b825dc642cb6eb9a060e54bf8d69288fbee4904";
-
- return parent;
-}
-
- (void) refresh:(id) sender
{
- if (![repository workingDirectory])
- return;
-
+ self.busy = YES;
self.status = @"Refreshing index…";
-
- // If self.busy reaches 0, all tasks have finished
- self.busy = 0;
-
- // Refresh the index, necessary for the next methods (that's why it's blocking)
- // FIXME: Make this non-blocking. This call can be expensive in large repositories
- [repository outputInWorkdirForArguments:[NSArray arrayWithObjects:@"update-index", @"-q", @"--unmerged", @"--ignore-missing", @"--refresh", nil]];
-
- NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
- [nc removeObserver:self];
-
- // Other files (not tracked, not ignored)
- NSArray *arguments = [NSArray arrayWithObjects:@"ls-files", @"--others", @"--exclude-standard", @"-z", nil];
- NSFileHandle *handle = [repository handleInWorkDirForArguments:arguments];
- [nc addObserver:self selector:@selector(readOtherFiles:) name:NSFileHandleReadToEndOfFileCompletionNotification object:handle];
- self.busy++;
- [handle readToEndOfFileInBackgroundAndNotify];
-
- // Unstaged files
- handle = [repository handleInWorkDirForArguments:[NSArray arrayWithObjects:@"diff-files", @"-z", nil]];
- [nc addObserver:self selector:@selector(readUnstagedFiles:) name:NSFileHandleReadToEndOfFileCompletionNotification object:handle];
- self.busy++;
- [handle readToEndOfFileInBackgroundAndNotify];
-
- // Staged files
- handle = [repository handleInWorkDirForArguments:[NSArray arrayWithObjects:@"diff-index", @"--cached", @"-z", [self parentTree], nil]];
- [nc addObserver:self selector:@selector(readCachedFiles:) name:NSFileHandleReadToEndOfFileCompletionNotification object:handle];
- self.busy++;
- [handle readToEndOfFileInBackgroundAndNotify];
+ [index refresh];
// Reload refs (in case HEAD changed)
[repository reloadRefs];
@@ -178,154 +106,6 @@ - (void) updateView
[self refresh:nil];
}
-// This method is called for each of the three processes from above.
-// If all three are finished (self.busy == 0), then we can delete
-// all files previously marked as deletable
-- (void) doneProcessingIndex
-{
- // if we're still busy, do nothing :)
- if (--self.busy)
- return;
-
- NSMutableArray *deleteFiles = [NSMutableArray array];
- for (PBChangedFile *file in files) {
- if (!file.hasStagedChanges && !file.hasUnstagedChanges)
- [deleteFiles addObject:file];
- }
-
- if ([deleteFiles count]) {
- [self willChangeValueForKey:@"files"];
- for (PBChangedFile *file in deleteFiles)
- [files removeObject:file];
- [self didChangeValueForKey:@"files"];
- }
- self.status = @"Ready";
-}
-
-- (void) readOtherFiles:(NSNotification *)notification;
-{
- NSArray *lines = [self linesFromNotification:notification];
- NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithCapacity:[lines count]];
- // We fake this files status as good as possible.
- NSArray *fileStatus = [NSArray arrayWithObjects:@":000000", @"100644", @"0000000000000000000000000000000000000000", @"0000000000000000000000000000000000000000", @"A", nil];
- for (NSString *path in lines) {
- if ([path length] == 0)
- continue;
- [dictionary setObject:fileStatus forKey:path];
- }
- [self addFilesFromDictionary:dictionary staged:NO tracked:NO];
- [self doneProcessingIndex];
-}
-
-- (NSMutableDictionary *)dictionaryForLines:(NSArray *)lines
-{
- NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:[lines count]/2];
-
- // Fill the dictionary with the new information
- NSArray *fileStatus;
- BOOL even = FALSE;
- for (NSString *line in lines) {
- if (!even) {
- even = TRUE;
- fileStatus = [line componentsSeparatedByString:@" "];
- continue;
- }
-
- even = FALSE;
- [dictionary setObject:fileStatus forKey:line];
- }
- return dictionary;
-}
-
-- (void) addFilesFromDictionary:(NSMutableDictionary *)dictionary staged:(BOOL)staged tracked:(BOOL)tracked
-{
- // Iterate over all existing files
- [indexController stopTrackingIndex];
- for (PBChangedFile *file in files) {
- NSArray *fileStatus = [dictionary objectForKey:file.path];
- // Object found, this is still a cached / uncached thing
- if (fileStatus) {
- if (tracked) {
- NSString *mode = [[fileStatus objectAtIndex:0] substringFromIndex:1];
- NSString *sha = [fileStatus objectAtIndex:2];
- file.commitBlobSHA = sha;
- file.commitBlobMode = mode;
-
- if (staged)
- file.hasStagedChanges = YES;
- else
- file.hasUnstagedChanges = YES;
- } else {
- // Untracked file, set status to NEW, only unstaged changes
- file.hasStagedChanges = NO;
- file.hasUnstagedChanges = YES;
- file.status = NEW;
- }
- [dictionary removeObjectForKey:file.path];
- } else { // Object not found, let's remove it from the changes
- if (staged)
- file.hasStagedChanges = NO;
- else if (tracked && file.status != NEW) // Only remove it if it's not an untracked file. We handle that with the other thing
- file.hasUnstagedChanges = NO;
- else if (!tracked && file.status == NEW)
- file.hasUnstagedChanges = NO;
- }
- }
- [indexController resumeTrackingIndex];
-
- // Do new files
- if (![[dictionary allKeys] count])
- return;
-
- [self willChangeValueForKey:@"files"];
- for (NSString *path in [dictionary allKeys]) {
- NSArray *fileStatus = [dictionary objectForKey:path];
-
- PBChangedFile *file = [[PBChangedFile alloc] initWithPath:path];
- if ([[fileStatus objectAtIndex:4] isEqualToString:@"D"])
- file.status = DELETED;
- else if([[fileStatus objectAtIndex:0] isEqualToString:@":000000"])
- file.status = NEW;
- else
- file.status = MODIFIED;
-
- if (tracked) {
- file.commitBlobMode = [[fileStatus objectAtIndex:0] substringFromIndex:1];
- file.commitBlobSHA = [fileStatus objectAtIndex:2];
- }
-
- file.hasStagedChanges = staged;
- file.hasUnstagedChanges = !staged;
-
- [files addObject: file];
- }
- [self didChangeValueForKey:@"files"];
-}
-
-- (void) readUnstagedFiles:(NSNotification *)notification
-{
- NSArray *lines = [self linesFromNotification:notification];
- NSMutableDictionary *dic = [self dictionaryForLines:lines];
- [self addFilesFromDictionary:dic staged:NO tracked:YES];
- [self doneProcessingIndex];
-}
-
-- (void) readCachedFiles:(NSNotification *)notification
-{
- NSArray *lines = [self linesFromNotification:notification];
- NSMutableDictionary *dic = [self dictionaryForLines:lines];
- [self addFilesFromDictionary:dic staged:YES tracked:YES];
- [self doneProcessingIndex];
-}
-
-- (void) commitFailedBecause:(NSString *)reason
-{
- self.busy--;
- self.status = [@"Commit failed: " stringByAppendingString:reason];
- [[repository windowController] showMessageSheet:@"Commit failed" infoText:reason];
- return;
-}
-
- (IBAction) commit:(id) sender
{
if ([[NSFileManager defaultManager] fileExistsAtPath:[repository.fileURL.path stringByAppendingPathComponent:@"MERGE_HEAD"]]) {
@@ -347,98 +127,61 @@ - (IBAction) commit:(id) sender
[cachedFilesController setSelectionIndexes:[NSIndexSet indexSet]];
[unstagedFilesController setSelectionIndexes:[NSIndexSet indexSet]];
- NSString *commitSubject;
- NSRange newLine = [commitMessage rangeOfString:@"\n"];
- if (newLine.location == NSNotFound)
- commitSubject = commitMessage;
- else
- commitSubject = [commitMessage substringToIndex:newLine.location];
-
- commitSubject = [@"commit: " stringByAppendingString:commitSubject];
-
- NSString *commitMessageFile;
- commitMessageFile = [repository.fileURL.path
- stringByAppendingPathComponent:@"COMMIT_EDITMSG"];
-
- [commitMessage writeToFile:commitMessageFile atomically:YES encoding:NSUTF8StringEncoding error:nil];
-
- self.busy++;
- self.status = @"Creating tree..";
- NSString *tree = [repository outputForCommand:@"write-tree"];
- if ([tree length] != 40)
- return [self commitFailedBecause:@"Could not create a tree"];
+ self.busy = YES;
+ [commitMessageView setEditable:NO];
- int ret;
-
- NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"commit-tree", tree, nil];
- NSString *parent = amend ? @"HEAD^" : @"HEAD";
- if ([repository parseReference:parent]) {
- [arguments addObject:@"-p"];
- [arguments addObject:parent];
- }
-
- NSString *commit = [repository outputForArguments:arguments
- inputString:commitMessage
- byExtendingEnvironment:amendEnvironment
- retValue: &ret];
-
- if (ret || [commit length] != 40)
- return [self commitFailedBecause:@"Could not create a commit object"];
-
- if (![repository executeHook:@"pre-commit" output:nil])
- return [self commitFailedBecause:@"Pre-commit hook failed"];
+ [index commitWithMessage:commitMessage];
+}
- if (![repository executeHook:@"commit-msg" withArgs:[NSArray arrayWithObject:commitMessageFile] output:nil])
- return [self commitFailedBecause:@"Commit-msg hook failed"];
- [repository outputForArguments:[NSArray arrayWithObjects:@"update-ref", @"-m", commitSubject, @"HEAD", commit, nil]
- retValue: &ret];
- if (ret)
- return [self commitFailedBecause:@"Could not update HEAD"];
+# pragma mark PBGitIndex Notification handling
+- (void)refreshFinished:(NSNotification *)notification
+{
+ self.busy = NO;
+ self.status = @"Index refresh finished";
+}
- if (![repository executeHook:@"post-commit" output:nil])
- [webController setStateMessage:[NSString stringWithFormat:@"Post-commit hook failed, however, successfully created commit %@", commit]];
- else
- [webController setStateMessage:[NSString stringWithFormat:@"Successfully created commit %@", commit]];
+- (void)commitStatusUpdated:(NSNotification *)notification
+{
+ self.status = [[notification userInfo] objectForKey:@"description"];
+}
- repository.hasChanged = YES;
- self.busy--;
+- (void)commitFinished:(NSNotification *)notification
+{
+ [commitMessageView setEditable:YES];
[commitMessageView setString:@""];
- amend = NO;
- amendEnvironment = nil;
- [self refresh:self];
- self.amend = NO;
+ [webController setStateMessage:[NSString stringWithFormat:[[notification userInfo] objectForKey:@"description"]]];
+}
+
+- (void)commitFailed:(NSNotification *)notification
+{
+ self.busy = NO;
+ NSString *reason = [[notification userInfo] objectForKey:@"description"];
+ self.status = [@"Commit failed: " stringByAppendingString:reason];
+ [commitMessageView setEditable:YES];
+ [[repository windowController] showMessageSheet:@"Commit failed" infoText:reason];
}
-- (void) stageHunk:(NSString *)hunk reverse:(BOOL)reverse
+- (void)amendCommit:(NSNotification *)notification
{
- [self processHunk:hunk stage:TRUE reverse:reverse];
+ // Replace commit message with the old one if it's less than 3 characters long.
+ // This is just a random number.
+ if ([[commitMessageView string] length] > 3)
+ return;
+
+ NSString *message = [[notification userInfo] objectForKey:@"message"];
+ commitMessageView.string = message;
}
-- (void)discardHunk:(NSString *)hunk
+- (void)indexChanged:(NSNotification *)notification
{
- [self processHunk:hunk stage:FALSE reverse:TRUE];
+ [cachedFilesController rearrangeObjects];
+ [unstagedFilesController rearrangeObjects];
}
-- (void)processHunk:(NSString *)hunk stage:(BOOL)stage reverse:(BOOL)reverse
+- (void)indexOperationFailed:(NSNotification *)notification
{
- NSMutableArray *array = [NSMutableArray arrayWithObjects:@"apply", nil];
- if (stage)
- [array addObject:@"--cached"];
- if (reverse)
- [array addObject:@"--reverse"];
-
- int ret = 1;
- NSString *error = [repository outputForArguments:array
- inputString:hunk
- retValue:&ret];
-
- // FIXME: show this error, rather than just logging it
- if (ret)
- NSLog(@"Error: %@", error);
-
- // TODO: We should do this smarter by checking if the file diff is empty, which is faster.
- [self refresh:self];
+ [[repository windowController] showMessageSheet:@"Index operation failed" infoText:[[notification userInfo] objectForKey:@"description"]];
}
@end
View
129 PBGitCommitView.xib
@@ -2,15 +2,14 @@
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.03">
<data>
<int key="IBDocument.SystemTarget">1050</int>
- <string key="IBDocument.SystemVersion">9J61</string>
+ <string key="IBDocument.SystemVersion">9L31a</string>
<string key="IBDocument.InterfaceBuilderVersion">677</string>
- <string key="IBDocument.AppKitVersion">949.46</string>
+ <string key="IBDocument.AppKitVersion">949.54</string>
<string key="IBDocument.HIToolboxVersion">353.00</string>
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
<bool key="EncodedWithXMLCoder">YES</bool>
+ <integer value="207"/>
<integer value="225"/>
- <integer value="113"/>
- <integer value="1" id="9"/>
</object>
<object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -127,7 +126,7 @@
<bool key="EncodedWithXMLCoder">YES</bool>
<integer value="12" id="777559147"/>
<reference ref="777559147"/>
- <reference ref="9"/>
+ <integer value="1" id="9"/>
</object>
</object>
</object>
@@ -964,38 +963,6 @@
<int key="connectionID">139</int>
</object>
<object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">contentArray: files</string>
- <reference key="source" ref="667905213"/>
- <reference key="destination" ref="1001"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="667905213"/>
- <reference key="NSDestination" ref="1001"/>
- <string key="NSLabel">contentArray: files</string>
- <string key="NSBinding">contentArray</string>
- <string key="NSKeyPath">files</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">149</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">contentArray: files</string>
- <reference key="source" ref="128809524"/>
- <reference key="destination" ref="1001"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="128809524"/>
- <reference key="NSDestination" ref="1001"/>
- <string key="NSLabel">contentArray: files</string>
- <string key="NSBinding">contentArray</string>
- <string key="NSKeyPath">files</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">150</int>
- </object>
- <object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">cachedFilesController</string>
<reference key="source" ref="1001"/>
@@ -1068,22 +1035,6 @@
<int key="connectionID">241</int>
</object>
<object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">value: amend</string>
- <reference key="source" ref="18874447"/>
- <reference key="destination" ref="1001"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="18874447"/>
- <reference key="NSDestination" ref="1001"/>
- <string key="NSLabel">value: amend</string>
- <string key="NSBinding">value</string>
- <string key="NSKeyPath">amend</string>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">252</int>
- </object>
- <object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">webController</string>
<reference key="source" ref="1001"/>
@@ -1164,22 +1115,6 @@
<int key="connectionID">264</int>
</object>
<object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">stagedButtonCell</string>
- <reference key="source" ref="446885874"/>
- <reference key="destination" ref="39450212"/>
- </object>
- <int key="connectionID">265</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">unstagedButtonCell</string>
- <reference key="source" ref="446885874"/>
- <reference key="destination" ref="45690317"/>
- </object>
- <int key="connectionID">266</int>
- </object>
- <object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">rowClicked:</string>
<reference key="source" ref="446885874"/>
@@ -1219,6 +1154,54 @@
</object>
<int key="connectionID">280</int>
</object>
+ <object class="IBConnectionRecord">
+ <object class="IBBindingConnection" key="connection">
+ <string key="label">contentArray: index.indexChanges</string>
+ <reference key="source" ref="128809524"/>
+ <reference key="destination" ref="1001"/>
+ <object class="NSNibBindingConnector" key="connector">
+ <reference key="NSSource" ref="128809524"/>
+ <reference key="NSDestination" ref="1001"/>
+ <string key="NSLabel">contentArray: index.indexChanges</string>
+ <string key="NSBinding">contentArray</string>
+ <string key="NSKeyPath">index.indexChanges</string>
+ <int key="NSNibBindingConnectorVersion">2</int>
+ </object>
+ </object>
+ <int key="connectionID">281</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBBindingConnection" key="connection">
+ <string key="label">contentArray: index.indexChanges</string>
+ <reference key="source" ref="667905213"/>
+ <reference key="destination" ref="1001"/>
+ <object class="NSNibBindingConnector" key="connector">
+ <reference key="NSSource" ref="667905213"/>
+ <reference key="NSDestination" ref="1001"/>
+ <string key="NSLabel">contentArray: index.indexChanges</string>
+ <string key="NSBinding">contentArray</string>
+ <string key="NSKeyPath">index.indexChanges</string>
+ <int key="NSNibBindingConnectorVersion">2</int>
+ </object>
+ </object>
+ <int key="connectionID">282</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBBindingConnection" key="connection">
+ <string key="label">value: index.amend</string>
+ <reference key="source" ref="18874447"/>
+ <reference key="destination" ref="1001"/>
+ <object class="NSNibBindingConnector" key="connector">
+ <reference key="NSSource" ref="18874447"/>
+ <reference key="NSDestination" ref="1001"/>
+ <string key="NSLabel">value: index.amend</string>
+ <string key="NSBinding">value</string>
+ <string key="NSKeyPath">index.amend</string>
+ <int key="NSNibBindingConnectorVersion">2</int>
+ </object>
+ </object>
+ <int key="connectionID">283</int>
+ </object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
@@ -1616,7 +1599,7 @@
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilderKit</string>
<string>com.apple.InterfaceBuilderKit</string>
- <string>{{59, 63}, {852, 432}}</string>
+ <string>{{428, 510}, {852, 432}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<integer value="0" id="8"/>
<reference ref="8"/>
@@ -1680,7 +1663,7 @@
</object>
</object>
<nil key="sourceID"/>
- <int key="maxID">280</int>
+ <int key="maxID">283</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
@@ -1764,20 +1747,16 @@
<object class="NSMutableArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>commitController</string>
- <string>stagedButtonCell</string>
<string>stagedFilesController</string>
<string>stagedTable</string>
- <string>unstagedButtonCell</string>
<string>unstagedFilesController</string>
<string>unstagedTable</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>PBGitCommitController</string>
- <string>PBIconAndTextCell</string>
<string>NSArrayController</string>
<string>NSTableView</string>
- <string>PBIconAndTextCell</string>
<string>NSArrayController</string>
<string>NSTableView</string>
</object>
View
80 PBGitIndex.h
@@ -0,0 +1,80 @@
+//
+// PBGitIndex.h
+// GitX
+//
+// Created by Pieter de Bie on 9/12/09.
+// Copyright 2009 Pieter de Bie. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+
+@class PBGitRepository;
+@class PBChangedFile;
+
+/*
+ * Notifications this class will send
+ */
+
+// Refreshing index
+extern NSString *PBGitIndexIndexRefreshStatus;
+extern NSString *PBGitIndexIndexRefreshFailed;
+extern NSString *PBGitIndexFinishedIndexRefresh;
+
+// The "indexChanges" array has changed
+extern NSString *PBGitIndexIndexUpdated;
+
+// Committing files
+extern NSString *PBGitIndexCommitStatus;
+extern NSString *PBGitIndexCommitFailed;
+extern NSString *PBGitIndexFinishedCommit;
+
+// Changing to amend
+extern NSString *PBGitIndexAmendMessageAvailable;
+
+// This is for general operations, like applying a patch
+extern NSString *PBGitIndexOperationFailed;
+
+
+
+// Represents a git index for a given work tree.
+// As a single git repository can have multiple trees,
+// the tree has to be given explicitly, even though
+// multiple trees is not yet supported in GitX
+@interface PBGitIndex : NSObject {
+
+@private
+ PBGitRepository *repository;
+ NSURL *workingDirectory;
+ NSMutableArray *files;
+
+ NSUInteger refreshStatus;
+ NSDictionary *amendEnvironment;
+ BOOL amend;
+}
+
+// Whether we want the changes for amending,
+// or for
+@property BOOL amend;
+
+- (id)initWithRepository:(PBGitRepository *)repository workingDirectory:(NSURL *)workingDirectory;
+
+// A list of PBChangedFile's with differences between the work tree and the index
+// This method is KVO-aware, so changes when any of the index-modifying methods are called
+// (including -refresh)
+- (NSArray *)indexChanges;
+
+// Refresh the index
+- (void)refresh;
+
+- (void)commitWithMessage:(NSString *)commitMessage;
+
+// Inter-file changes:
+- (BOOL)stageFiles:(NSArray *)stageFiles;
+- (BOOL)unstageFiles:(NSArray *)unstageFiles;
+- (void)discardChangesForFiles:(NSArray *)discardFiles;
+
+// Intra-file changes
+- (BOOL)applyPatch:(NSString *)hunk stage:(BOOL)stage reverse:(BOOL)reverse;
+- (NSString *)diffForFile:(PBChangedFile *)file staged:(BOOL)staged contextLines:(NSUInteger)context;
+
+@end
View
630 PBGitIndex.m
@@ -0,0 +1,630 @@
+//
+// PBGitIndex.m
+// GitX
+//
+// Created by Pieter de Bie on 9/12/09.
+// Copyright 2009 Pieter de Bie. All rights reserved.
+//
+
+#import "PBGitIndex.h"
+#import "PBGitRepository.h"
+#import "PBGitBinary.h"
+#import "PBEasyPipe.h"
+#import "NSString_RegEx.h"
+#import "PBChangedFile.h"
+
+NSString *PBGitIndexIndexRefreshStatus = @"PBGitIndexIndexRefreshStatus";
+NSString *PBGitIndexIndexRefreshFailed = @"PBGitIndexIndexRefreshFailed";
+NSString *PBGitIndexFinishedIndexRefresh = @"PBGitIndexFinishedIndexRefresh";
+
+NSString *PBGitIndexIndexUpdated = @"GBGitIndexIndexUpdated";
+
+NSString *PBGitIndexCommitStatus = @"PBGitIndexCommitStatus";
+NSString *PBGitIndexCommitFailed = @"PBGitIndexCommitFailed";
+NSString *PBGitIndexFinishedCommit = @"PBGitIndexFinishedCommit";
+
+NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable";
+NSString *PBGitIndexOperationFailed = @"PBGitIndexOperationFailed";
+
+@interface PBGitIndex (IndexRefreshMethods)
+
+- (NSArray *)linesFromNotification:(NSNotification *)notification;
+- (NSMutableDictionary *)dictionaryForLines:(NSArray *)lines;
+- (void)addFilesFromDictionary:(NSMutableDictionary *)dictionary staged:(BOOL)staged tracked:(BOOL)tracked;
+
+- (void)indexStepComplete;
+
+- (void)indexRefreshFinished:(NSNotification *)notification;
+- (void)readOtherFiles:(NSNotification *)notification;
+- (void)readUnstagedFiles:(NSNotification *)notification;
+- (void)readStagedFiles:(NSNotification *)notification;
+
+@end
+
+@interface PBGitIndex ()
+
+// Returns the tree to compare the index to, based
+// on whether amend is set or not.
+- (NSString *) parentTree;
+- (void)postCommitUpdate:(NSString *)update;
+- (void)postCommitFailure:(NSString *)reason;
+- (void)postIndexChange;
+- (void)postOperationFailed:(NSString *)description;
+@end
+
+@implementation PBGitIndex
+
+@synthesize amend;
+
+- (id)initWithRepository:(PBGitRepository *)theRepository workingDirectory:(NSURL *)theWorkingDirectory
+{
+ if (!(self = [super init]))
+ return nil;
+
+ NSAssert(theWorkingDirectory, @"PBGitIndex requires a working directory");
+ NSAssert(theRepository, @"PBGitIndex requires a repository");
+
+ repository = theRepository;
+ workingDirectory = theWorkingDirectory;
+ files = [NSMutableArray array];
+
+ return self;
+}
+
+- (NSArray *)indexChanges
+{
+ return files;
+}
+
+- (void)setAmend:(BOOL)newAmend
+{
+ if (newAmend == amend)
+ return;
+
+ amend = newAmend;
+ amendEnvironment = nil;
+
+ [self refresh];
+
+ if (!newAmend)
+ return;
+
+ // If we amend, we want to keep the author information for the previous commit
+ // We do this by reading in the previous commit, and storing the information
+ // in a dictionary. This dictionary will then later be read by [self commit:]
+ NSString *message = [repository outputForCommand:@"cat-file commit HEAD"];
+ NSArray *match = [message substringsMatchingRegularExpression:@"\nauthor ([^\n]*) <([^\n>]*)> ([0-9]+[^\n]*)\n" count:3 options:0 ranges:nil error:nil];
+ if (match)
+ amendEnvironment = [NSDictionary dictionaryWithObjectsAndKeys:[match objectAtIndex:1], @"GIT_AUTHOR_NAME",
+ [match objectAtIndex:2], @"GIT_AUTHOR_EMAIL",
+ [match objectAtIndex:3], @"GIT_AUTHOR_DATE",
+ nil];
+
+ // Find the commit message
+ NSRange r = [message rangeOfString:@"\n\n"];
+ if (r.location != NSNotFound) {
+ NSString *commitMessage = [message substringFromIndex:r.location + 2];
+ [[NSNotificationCenter defaultCenter] postNotificationName:PBGitIndexAmendMessageAvailable
+ object: self
+ userInfo:[NSDictionary dictionaryWithObject:commitMessage forKey:@"message"]];
+ }
+
+}
+
+- (void)refresh
+{
+ // If we were already refreshing the index, we don't want
+ // double notifications. As we can't stop the tasks anymore,
+ // just cancel the notifications
+ refreshStatus = 0;
+ NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+ [nc removeObserver:self];
+
+ // Ask Git to refresh the index
+ NSFileHandle *updateHandle = [PBEasyPipe handleForCommand:[PBGitBinary path]
+ withArgs:[NSArray arrayWithObjects:@"update-index", @"-q", @"--unmerged", @"--ignore-missing", @"--refresh", nil]
+ inDir:[workingDirectory path]];
+
+ [nc addObserver:self
+ selector:@selector(indexRefreshFinished:)
+ name:NSFileHandleReadToEndOfFileCompletionNotification
+ object:updateHandle];
+ [updateHandle readToEndOfFileInBackgroundAndNotify];
+
+}
+
+- (NSString *) parentTree
+{
+ NSString *parent = amend ? @"HEAD^" : @"HEAD";
+
+ if (![repository parseReference:parent])
+ // We don't have a head ref. Return the empty tree.
+ return @"4b825dc642cb6eb9a060e54bf8d69288fbee4904";
+
+ return parent;
+}
+
+// TODO: make Asynchronous
+- (void)commitWithMessage:(NSString *)commitMessage
+{
+ NSMutableString *commitSubject = [@"commit: " mutableCopy];
+ NSRange newLine = [commitMessage rangeOfString:@"\n"];
+ if (newLine.location == NSNotFound)
+ [commitSubject appendString:commitMessage];
+ else
+ [commitSubject appendString:[commitMessage substringToIndex:newLine.location]];
+
+ NSString *commitMessageFile;
+ commitMessageFile = [repository.fileURL.path stringByAppendingPathComponent:@"COMMIT_EDITMSG"];
+
+ [commitMessage writeToFile:commitMessageFile atomically:YES encoding:NSUTF8StringEncoding error:nil];
+
+
+ [self postCommitUpdate:@"Creating tree"];
+ NSString *tree = [repository outputForCommand:@"write-tree"];
+ if ([tree length] != 40)
+ return [self postCommitFailure:@"Creating tree failed"];
+
+
+ NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"commit-tree", tree, nil];
+ NSString *parent = amend ? @"HEAD^" : @"HEAD";
+ if ([repository parseReference:parent]) {
+ [arguments addObject:@"-p"];
+ [arguments addObject:parent];
+ }
+
+ [self postCommitUpdate:@"Creating commit"];
+ int ret = 1;
+ NSString *commit = [repository outputForArguments:arguments
+ inputString:commitMessage
+ byExtendingEnvironment:amendEnvironment
+ retValue: &ret];
+
+ if (ret || [commit length] != 40)
+ return [self postCommitFailure:@"Could not create a commit object"];
+
+ [self postCommitUpdate:@"Running hooks"];
+ if (![repository executeHook:@"pre-commit" output:nil])
+ return [self postCommitFailure:@"Pre-commit hook failed"];
+
+ if (![repository executeHook:@"commit-msg" withArgs:[NSArray arrayWithObject:commitMessageFile] output:nil])
+ return [self postCommitFailure:@"Commit-msg hook failed"];
+
+ [self postCommitUpdate:@"Updating HEAD"];
+ [repository outputForArguments:[NSArray arrayWithObjects:@"update-ref", @"-m", commitSubject, @"HEAD", commit, nil]
+ retValue: &ret];
+ if (ret)
+ return [self postCommitFailure:@"Could not update HEAD"];
+
+ [self postCommitUpdate:@"Running post-commit hook"];
+
+ BOOL success = [repository executeHook:@"post-commit" output:nil];
+ NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObject:[NSNumber numberWithBool:success] forKey:@"success"];
+ NSString *description;
+ if (success)
+ description = [NSString stringWithFormat:@"Successfull created commit %@", commit];
+ else
+ description = [NSString stringWithFormat:@"Post-commit hook failed, but successfully created commit %@", commit];
+
+ [userInfo setObject:description forKey:@"description"];
+ [userInfo setObject:commit forKey:@"sha"];
+
+ [[NSNotificationCenter defaultCenter] postNotificationName:PBGitIndexFinishedCommit
+ object:self
+ userInfo:userInfo];
+ if (!success)
+ return;
+
+ repository.hasChanged = YES;
+
+ amendEnvironment = nil;
+ if (amend)
+ self.amend = NO;
+ else
+ [self refresh];
+
+}
+
+- (void)postCommitUpdate:(NSString *)update
+{
+ [[NSNotificationCenter defaultCenter] postNotificationName:PBGitIndexCommitStatus
+ object:self
+ userInfo:[NSDictionary dictionaryWithObject:update forKey:@"description"]];
+}
+
+- (void)postCommitFailure:(NSString *)reason
+{
+ [[NSNotificationCenter defaultCenter] postNotificationName:PBGitIndexCommitFailed
+ object:self
+ userInfo:[NSDictionary dictionaryWithObject:reason forKey:@"description"]];
+}
+
+- (void)postOperationFailed:(NSString *)description
+{
+ [[NSNotificationCenter defaultCenter] postNotificationName:PBGitIndexOperationFailed
+ object:self
+ userInfo:[NSDictionary dictionaryWithObject:description forKey:@"description"]];
+}
+
+- (BOOL)stageFiles:(NSArray *)stageFiles
+{
+ // Input string for update-index
+ // This will be a list of filenames that
+ // should be updated. It's similar to
+ // "git add -- <files>
+ NSMutableString *input = [NSMutableString string];
+
+ for (PBChangedFile *file in stageFiles) {
+ [input appendFormat:@"%@\0", file.path];
+ }
+
+ int ret = 1;
+ [repository outputForArguments:[NSArray arrayWithObjects:@"update-index", @"--add", @"--remove", @"-z", @"--stdin", nil]
+ inputString:input
+ retValue:&ret];
+
+ if (ret) {
+ [self postOperationFailed:[NSString stringWithFormat:@"Error in staging files. Return value: %i", ret]];
+ return NO;
+ }
+
+ for (PBChangedFile *file in stageFiles)
+ {
+ file.hasUnstagedChanges = NO;
+ file.hasStagedChanges = YES;
+ }
+
+ [self postIndexChange];
+ return YES;
+}
+
+// TODO: Refactor with above. What's a better name for this?
+- (BOOL)unstageFiles:(NSArray *)unstageFiles
+{
+ NSMutableString *input = [NSMutableString string];
+
+ for (PBChangedFile *file in unstageFiles) {
+ [input appendString:[file indexInfo]];
+ }
+
+ int ret = 1;
+ [repository outputForArguments:[NSArray arrayWithObjects:@"update-index", @"-z", @"--index-info", nil]
+ inputString:input
+ retValue:&ret];
+
+ if (ret)
+ {
+ [self postOperationFailed:[NSString stringWithFormat:@"Error in unstaging files. Return value: %i", ret]];
+ return NO;
+ }
+
+ for (PBChangedFile *file in unstageFiles)
+ {
+ file.hasUnstagedChanges = YES;
+ file.hasStagedChanges = NO;
+ }
+
+ [self postIndexChange];
+ return YES;
+}
+
+- (void)discardChangesForFiles:(NSArray *)discardFiles
+{
+ NSArray *paths = [discardFiles valueForKey:@"path"];
+ NSString *input = [paths componentsJoinedByString:@"\0"];
+
+ NSArray *arguments = [NSArray arrayWithObjects:@"checkout-index", @"--index", @"--quiet", @"--force", @"-z", @"--stdin", nil];
+
+ int ret = 1;
+ [PBEasyPipe outputForCommand:[PBGitBinary path] withArgs:arguments inDir:[workingDirectory path] inputString:input retValue:&ret];
+
+ if (ret) {
+ [self postOperationFailed:[NSString stringWithFormat:@"Discarding changes failed with return value %i", ret]];
+ return;
+ }
+
+ for (PBChangedFile *file in discardFiles)
+ file.hasUnstagedChanges = NO;
+
+ [self postIndexChange];
+}
+
+- (BOOL)applyPatch:(NSString *)hunk stage:(BOOL)stage reverse:(BOOL)reverse;
+{
+ NSMutableArray *array = [NSMutableArray arrayWithObjects:@"apply", nil];
+ if (stage)
+ [array addObject:@"--cached"];
+ if (reverse)
+ [array addObject:@"--reverse"];
+
+ int ret = 1;
+ NSString *error = [repository outputForArguments:array
+ inputString:hunk
+ retValue:&ret];
+
+ if (ret) {
+ [self postOperationFailed:[NSString stringWithFormat:@"Applying patch failed with return value %i. Error: %@", ret, error]];
+ return NO;
+ }
+
+ // TODO: Try to be smarter about what to refresh
+ [self refresh];
+ return YES;
+}
+
+
+- (NSString *)diffForFile:(PBChangedFile *)file staged:(BOOL)staged contextLines:(NSUInteger)context
+{
+ NSString *parameter = [NSString stringWithFormat:@"-U%u", context];
+ if (staged) {
+ NSString *indexPath = [@":0:" stringByAppendingString:file.path];
+
+ if (file.status == NEW)
+ return [repository outputForArguments:[NSArray arrayWithObjects:@"show", indexPath, nil]];
+
+ return [repository outputInWorkdirForArguments:[NSArray arrayWithObjects:@"diff-index", parameter, @"--cached", [self parentTree], @"--", file.path, nil]];
+ }
+
+ // unstaged
+ if (file.status == NEW) {
+ NSStringEncoding encoding;
+ NSError *error = nil;
+ NSString *path = [[repository workingDirectory] stringByAppendingPathComponent:file.path];
+ NSString *contents = [NSString stringWithContentsOfFile:path
+ usedEncoding:&encoding
+ error:&error];
+ if (error)
+ return nil;
+
+ return contents;
+ }
+
+ return [repository outputInWorkdirForArguments:[NSArray arrayWithObjects:@"diff-files", parameter, @"--", file.path, nil]];
+}
+
+- (void)postIndexChange
+{
+ [[NSNotificationCenter defaultCenter] postNotificationName:PBGitIndexIndexUpdated
+ object:self];
+}
+
+# pragma mark WebKit Accessibility
+
++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector
+{
+ return NO;
+}
+
+@end
+
+@implementation PBGitIndex (IndexRefreshMethods)
+
+- (void)indexRefreshFinished:(NSNotification *)notification
+{
+ if ([(NSNumber *)[(NSDictionary *)[notification userInfo] objectForKey:@"NSFileHandleError"] intValue])
+ {
+ [[NSNotificationCenter defaultCenter] postNotificationName:PBGitIndexIndexRefreshFailed
+ object:self
+ userInfo:[NSDictionary dictionaryWithObject:@"update-index failed" forKey:@"description"]];
+ return;
+ }
+
+ [[NSNotificationCenter defaultCenter] postNotificationName:PBGitIndexIndexRefreshStatus
+ object:self
+ userInfo:[NSDictionary dictionaryWithObject:@"update-index success" forKey:@"description"]];
+
+ // Now that the index is refreshed, we need to read the information from the index
+ NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+
+ // Other files (not tracked, not ignored)
+ NSFileHandle *handle = [PBEasyPipe handleForCommand:[PBGitBinary path]
+ withArgs:[NSArray arrayWithObjects:@"ls-files", @"--others", @"--exclude-standard", @"-z", nil]
+ inDir:[workingDirectory path]];
+ [nc addObserver:self selector:@selector(readOtherFiles:) name:NSFileHandleReadToEndOfFileCompletionNotification object:handle];
+ [handle readToEndOfFileInBackgroundAndNotify];
+ refreshStatus++;
+
+ // Unstaged files
+ handle = [PBEasyPipe handleForCommand:[PBGitBinary path]
+ withArgs:[NSArray arrayWithObjects:@"diff-files", @"-z", nil]
+ inDir:[workingDirectory path]];
+ [nc addObserver:self selector:@selector(readUnstagedFiles:) name:NSFileHandleReadToEndOfFileCompletionNotification object:handle];
+ [handle readToEndOfFileInBackgroundAndNotify];
+ refreshStatus++;
+
+ // Staged files
+ handle = [PBEasyPipe handleForCommand:[PBGitBinary path]
+ withArgs:[NSArray arrayWithObjects:@"diff-index", @"--cached", @"-z", [self parentTree], nil]
+ inDir:[workingDirectory path]];
+ [nc addObserver:self selector:@selector(readStagedFiles:) name:NSFileHandleReadToEndOfFileCompletionNotification object:handle];
+ [handle readToEndOfFileInBackgroundAndNotify];
+ refreshStatus++;
+}
+
+- (void)readOtherFiles:(NSNotification *)notification
+{
+ NSArray *lines = [self linesFromNotification:notification];
+ NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithCapacity:[lines count]];
+ // Other files are untracked, so we don't have any real index information. Instead, we can just fake it.
+ // The line below is not used at all, as for these files the commitBlob isn't set
+ NSArray *fileStatus = [NSArray arrayWithObjects:@":000000", @"100644", @"0000000000000000000000000000000000000000", @"0000000000000000000000000000000000000000", @"A", nil];
+ for (NSString *path in lines) {
+ if ([path length] == 0)
+ continue;
+ [dictionary setObject:fileStatus forKey:path];
+ }
+
+ [self addFilesFromDictionary:dictionary staged:NO tracked:NO];
+ [self indexStepComplete];
+}
+
+- (void) readStagedFiles:(NSNotification *)notification
+{
+ NSArray *lines = [self linesFromNotification:notification];
+ NSMutableDictionary *dic = [self dictionaryForLines:lines];
+ [self addFilesFromDictionary:dic staged:YES tracked:YES];
+ [self indexStepComplete];
+}
+
+- (void) readUnstagedFiles:(NSNotification *)notification
+{
+ NSArray *lines = [self linesFromNotification:notification];
+ NSMutableDictionary *dic = [self dictionaryForLines:lines];
+ [self addFilesFromDictionary:dic staged:NO tracked:YES];
+ [self indexStepComplete];
+}
+
+- (void) addFilesFromDictionary:(NSMutableDictionary *)dictionary staged:(BOOL)staged tracked:(BOOL)tracked
+{
+ // Iterate over all existing files
+ for (PBChangedFile *file in files) {
+ NSArray *fileStatus = [dictionary objectForKey:file.path];
+ // Object found, this is still a cached / uncached thing
+ if (fileStatus) {
+ if (tracked) {
+ NSString *mode = [[fileStatus objectAtIndex:0] substringFromIndex:1];
+ NSString *sha = [fileStatus objectAtIndex:2];
+ file.commitBlobSHA = sha;
+ file.commitBlobMode = mode;
+
+ if (staged)
+ file.hasStagedChanges = YES;
+ else
+ file.hasUnstagedChanges = YES;
+ } else {
+ // Untracked file, set status to NEW, only unstaged changes
+ file.hasStagedChanges = NO;
+ file.hasUnstagedChanges = YES;
+ file.status = NEW;
+ }
+
+ // We handled this file, remove it from the dictionary
+ [dictionary removeObjectForKey:file.path];
+ } else {
+ // Object not found in the dictionary, so let's reset its appropriate
+ // change (stage or untracked) if necessary.
+
+ // Staged dictionary, so file does not have staged changes
+ if (staged)
+ file.hasStagedChanges = NO;
+ // Tracked file does not have unstaged changes, file is not new,
+ // so we can set it to No. (If it would be new, it would not
+ // be in this dictionary, but in the "other dictionary").
+ else if (tracked && file.status != NEW)
+ file.hasUnstagedChanges = NO;
+ // Unstaged, untracked dictionary ("Other" files), and file
+ // is indicated as new (which would be untracked), so let's
+ // remove it
+ else if (!tracked && file.status == NEW)
+ file.hasUnstagedChanges = NO;
+ }
+ }
+
+ // Do new files only if necessary
+ if (![[dictionary allKeys] count])
+ return;
+
+ // All entries left in the dictionary haven't been accounted for
+ // above, so we need to add them to the "files" array
+ [self willChangeValueForKey:@"indexChanges"];
+ for (NSString *path in [dictionary allKeys]) {
+ NSArray *fileStatus = [dictionary objectForKey:path];
+
+ PBChangedFile *file = [[PBChangedFile alloc] initWithPath:path];
+ if ([[fileStatus objectAtIndex:4] isEqualToString:@"D"])
+ file.status = DELETED;
+ else if([[fileStatus objectAtIndex:0] isEqualToString:@":000000"])
+ file.status = NEW;
+ else
+ file.status = MODIFIED;
+
+ if (tracked) {
+ file.commitBlobMode = [[fileStatus objectAtIndex:0] substringFromIndex:1];
+ file.commitBlobSHA = [fileStatus objectAtIndex:2];
+ }
+
+ file.hasStagedChanges = staged;
+ file.hasUnstagedChanges = !staged;
+
+ [files addObject:file];
+ }
+ [self didChangeValueForKey:@"indexChanges"];
+}
+
+# pragma mark Utility methods
+- (NSArray *)linesFromNotification:(NSNotification *)notification
+{
+ NSData *data = [[notification userInfo] valueForKey:NSFileHandleNotificationDataItem];
+ if (!data)
+ return [NSArray array];
+
+ NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+ // FIXME: throw an error?
+ if (!string)
+ return [NSArray array];
+
+ // Strip trailing null
+ if ([string hasSuffix:@"\0"])
+ string = [string substringToIndex:[string length]-1];
+
+ if ([string length] == 0)
+ return [NSArray array];
+
+ return [string componentsSeparatedByString:@"\0"];
+}
+
+- (NSMutableDictionary *)dictionaryForLines:(NSArray *)lines
+{
+ NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:[lines count]/2];
+
+ // Fill the dictionary with the new information. These lines are in the form of:
+ // :00000 :0644 OTHER INDEX INFORMATION
+ // Filename
+
+ NSAssert1([lines count] % 2 == 0, @"Lines must have an even number of lines: %@", lines);
+
+ NSEnumerator *enumerator = [lines objectEnumerator];
+ NSString *fileStatus;
+ while (fileStatus = [enumerator nextObject]) {
+ NSString *fileName = [enumerator nextObject];
+ [dictionary setObject:[fileStatus componentsSeparatedByString:@" "] forKey:fileName];
+ }
+
+ return dictionary;
+}
+
+// This method is called for each of the three processes from above.
+// If all three are finished (self.busy == 0), then we can delete
+// all files previously marked as deletable
+- (void)indexStepComplete
+{
+ // if we're still busy, do nothing :)
+ if (--refreshStatus) {
+ [self postIndexChange];
+ return;
+ }
+
+ // At this point, all index operations have finished.
+ // We need to find all files that don't have either
+ // staged or unstaged files, and delete them
+
+ NSMutableArray *deleteFiles = [NSMutableArray array];
+ for (PBChangedFile *file in files) {
+ if (!file.hasStagedChanges && !file.hasUnstagedChanges)
+ [deleteFiles addObject:file];
+ }
+
+ if ([deleteFiles count]) {
+ [self willChangeValueForKey:@"indexChanges"];
+ for (PBChangedFile *file in deleteFiles)
+ [files removeObject:file];
+ [self didChangeValueForKey:@"indexChanges"];
+ }
+
+ [[NSNotificationCenter defaultCenter] postNotificationName:PBGitIndexFinishedIndexRefresh
+ object:self];
+ [self postIndexChange];
+
+}
+
+@end
View
18 PBGitIndexController.h
@@ -11,33 +11,15 @@
#import "PBChangedFile.h"
@interface PBGitIndexController : NSObject {
- int contextSize;
-
IBOutlet NSArrayController *stagedFilesController, *unstagedFilesController;
IBOutlet PBGitCommitController *commitController;
- IBOutlet PBIconAndTextCell* unstagedButtonCell;
- IBOutlet PBIconAndTextCell* stagedButtonCell;
-
IBOutlet NSTableView *unstagedTable;
IBOutlet NSTableView *stagedTable;
}
-@property (assign) int contextSize;
-
-- (NSString *) contextParameter;
-
-- (void) stageFiles:(NSArray *)files;
-- (void) unstageFiles:(NSArray *)files;
-
- (IBAction) rowClicked:(NSCell *) sender;
- (IBAction) tableClicked:(NSTableView *)tableView;
-- (NSString *) stagedChangesForFile:(PBChangedFile *)file;
-- (NSString *) unstagedChangesForFile:(PBChangedFile *)file;
-
-- (void)stopTrackingIndex;
-- (void)resumeTrackingIndex;
-
- (NSMenu *) menuForTable:(NSTableView *)table;
@end
View
184 PBGitIndexController.m
@@ -9,17 +9,18 @@
#import "PBGitIndexController.h"
#import "PBChangedFile.h"
#import "PBGitRepository.h"
+#import "PBGitIndex.h"
#define FileChangesTableViewType @"GitFileChangedType"
-@implementation PBGitIndexController
+@interface PBGitIndexController ()
+- (void)discardChangesForFiles:(NSArray *)files force:(BOOL)force;
+@end
-@synthesize contextSize;
+@implementation PBGitIndexController
- (void)awakeFromNib
{
- contextSize = 3;
-
[unstagedTable setDoubleAction:@selector(tableClicked:)];
[stagedTable setDoubleAction:@selector(tableClicked:)];
@@ -28,64 +29,10 @@ - (void)awakeFromNib
[unstagedTable registerForDraggedTypes: [NSArray arrayWithObject:FileChangesTableViewType]];
[stagedTable registerForDraggedTypes: [NSArray arrayWithObject:FileChangesTableViewType]];
-
-}
-
-- (void) stageFiles:(NSArray *)files
-{
- NSMutableString *input = [NSMutableString string];
-
- for (PBChangedFile *file in files) {
- [input appendFormat:@"%@\0", file.path];
- }
-
- int ret = 1;
- [commitController.repository outputForArguments:[NSArray arrayWithObjects:@"update-index", @"--add", @"--remove", @"-z", @"--stdin", nil]
- inputString:input retValue:&ret];
-
- if (ret)
- {
- NSLog(@"Error when updating index. Retvalue: %i", ret);
- return;
- }
-
- [self stopTrackingIndex];
- for (PBChangedFile *file in files)
- {
- file.hasUnstagedChanges = NO;
- file.hasStagedChanges = YES;
- }
- [self resumeTrackingIndex];
-}
-
-- (void) unstageFiles:(NSArray *)files
-{
- NSMutableString *input = [NSMutableString string];
-
- for (PBChangedFile *file in files) {
- [input appendString:[file indexInfo]];
- }
-
- int ret = 1;
- [commitController.repository outputForArguments:[NSArray arrayWithObjects:@"update-index", @"-z", @"--index-info", nil]
- inputString:input retValue:&ret];
-
- if (ret)
- {
- NSLog(@"Error when updating index. Retvalue: %i", ret);
- return;
- }
-
- [self stopTrackingIndex];
- for (PBChangedFile *file in files)
- {
- file.hasUnstagedChanges = YES;
- file.hasStagedChanges = NO;
- }
- [self resumeTrackingIndex];
}
-- (void) ignoreFiles:(NSArray *)files
+// FIXME: Find a proper place for this method -- this is not it.
+- (void)ignoreFiles:(NSArray *)files
{
// Build output string
NSMutableArray *fileList = [NSMutableArray array];
@@ -122,63 +69,6 @@ - (void) ignoreFiles:(NSArray *)files
[[commitController.repository windowController] showErrorSheet:error];
}
-# pragma mark Displaying diffs
-
-- (NSString *) stagedChangesForFile:(PBChangedFile *)file
-{
- NSString *indexPath = [@":0:" stringByAppendingString:file.path];
-
- if (file.status == NEW)
- return [commitController.repository outputForArguments:[NSArray arrayWithObjects:@"show", indexPath, nil]];
-
- return [commitController.repository outputInWorkdirForArguments:[NSArray arrayWithObjects:@"diff-index", [self contextParameter], @"--cached", [commitController parentTree], @"--", file.path, nil]];
-}
-
-- (NSString *)unstagedChangesForFile:(PBChangedFile *)file
-{
- if (file.status == NEW) {
- NSStringEncoding encoding;
- NSError *error = nil;
- NSString *path = [[commitController.repository workingDirectory] stringByAppendingPathComponent:file.path];
- NSString *contents = [NSString stringWithContentsOfFile:path
- usedEncoding:&encoding
- error:&error];
- if (error)
- return nil;
-
- return contents;
- }
-
- return [commitController.repository outputInWorkdirForArguments:[NSArray arrayWithObjects:@"diff-files", [self contextParameter], @"--", file.path, nil]];
-}
-
-- (void)discardChangesForFiles:(NSArray *)files force:(BOOL)force
-{
- if(!force) {
- int ret = [[NSAlert alertWithMessageText:@"Discard changes"
- defaultButton:nil
- alternateButton:@"Cancel"
- otherButton:nil
- informativeTextWithFormat:@"Are you sure you wish to discard the changes to this file?\n\nYou cannot undo this operation."] runModal];
- if (ret != NSAlertDefaultReturn)
- return;
- }
-
- NSArray *paths = [files valueForKey:@"path"];
- NSString *input = [paths componentsJoinedByString:@"\0"];
-
- NSArray *arguments = [NSArray arrayWithObjects:@"checkout-index", @"--index", @"--quiet", @"--force", @"-z", @"--stdin", nil];
- int ret = 1;
- [commitController.repository outputForArguments:arguments inputString:input retValue:&ret];
- if (ret) {
- [[commitController.repository windowController] showMessageSheet:@"Discarding changes failed" infoText:[NSString stringWithFormat:@"Discarding changes failed with error code %i", ret]];
- return;
- }
-
- for (PBChangedFile *file in files)
- file.hasUnstagedChanges = NO;
-}
-
# pragma mark Context Menu methods
- (BOOL) allSelectedCanBeIgnored:(NSArray *)selectedFiles
{
@@ -255,12 +145,12 @@ - (NSMenu *) menuForTable:(NSTableView *)table
- (void) stageFilesAction:(id) sender
{
- [self stageFiles:[sender representedObject]];
+ [commitController.index stageFiles:[sender representedObject]];
}
- (void) unstageFilesAction:(id) sender
{
- [self unstageFiles:[sender representedObject]];
+ [commitController.index unstageFiles:[sender representedObject]];
}
- (void) openFilesAction:(id) sender
@@ -274,10 +164,11 @@ - (void) openFilesAction:(id) sender
- (void) ignoreFilesAction:(id) sender
{
NSArray *selectedFiles = [sender representedObject];
- if ([selectedFiles count] > 0) {
- [self ignoreFiles:selectedFiles];
- }
- [commitController refresh:NULL];
+ if ([selectedFiles count] == 0)
+ return;
+
+ [self ignoreFiles:selectedFiles];
+ [commitController.index refresh];
}
- (void)discardFilesAction:(id) sender
@@ -305,6 +196,20 @@ - (void) showInFinderAction:(id) sender
[ws selectFile: path inFileViewerRootedAtPath:nil];
}
+- (void)discardChangesForFiles:(NSArray *)files force:(BOOL)force
+{
+ if (!force) {
+ int ret = [[NSAlert alertWithMessageText:@"Discard changes"
+ defaultButton:nil
+ alternateButton:@"Cancel"
+ otherButton:nil
+ informativeTextWithFormat:@"Are you sure you wish to discard the changes to this file?\n\nYou cannot undo this operation."] runModal];
+ if (ret != NSAlertDefaultReturn)
+ return;
+ }
+
+ [commitController.index discardChangesForFiles:files];
+}
# pragma mark TableView icon delegate
- (void)tableView:(NSTableView*)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)rowIndex
@@ -320,9 +225,9 @@ - (void) tableClicked:(NSTableView *) tableView
NSIndexSet *selectionIndexes = [tableView selectedRowIndexes];
NSArray *files = [[controller arrangedObjects] objectsAtIndexes:selectionIndexes];
if ([tableView tag] == 0)
- [self stageFiles:files];
+ [commitController.index stageFiles:files];
else
- [self unstageFiles:files];
+ [commitController.index unstageFiles:files];
}
- (void) rowClicked:(NSCell *)sender
@@ -382,36 +287,11 @@ - (BOOL)tableView:(NSTableView *)aTableView
NSArray *files = [[controller arrangedObjects] objectsAtIndexes:rowIndexes];
if ([aTableView tag] == 0)
- [self unstageFiles:files];
+ [commitController.index unstageFiles:files];
else
- [self stageFiles:files];
+ [commitController.index stageFiles:files];
return YES;
}
-- (NSString *) contextParameter
-{
- return [[NSString alloc] initWithFormat:@"-U%i", contextSize];
-}
-
-# pragma mark WebKit Accessibility
-
-+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector
-{
- return NO;
-}
-
-#pragma mark Private Methods
-- (void)stopTrackingIndex
-{
- [stagedFilesController setAutomaticallyRearrangesObjects:NO];
- [unstagedFilesController setAutomaticallyRearrangesObjects:NO];
-}
-- (void)resumeTrackingIndex
-{
- [stagedFilesController setAutomaticallyRearrangesObjects:YES];
- [unstagedFilesController setAutomaticallyRearrangesObjects:YES];
- [stagedFilesController rearrangeObjects];
- [unstagedFilesController rearrangeObjects];
-}
@end
View
1 PBWebChangesController.h
@@ -27,5 +27,4 @@
- (void) setStateMessage:(NSString *)state;
- (void) showMultiple:(NSArray *)files;
-- (void) setContextSize:(int)size;
@end
View
24 PBWebChangesController.m
@@ -8,6 +8,7 @@
#import "PBWebChangesController.h"
#import "PBGitIndexController.h"
+#import "PBGitIndex.h"
@implementation PBWebChangesController
@@ -25,15 +26,10 @@ - (void) awakeFromNib
- (void) didLoad
{
- [[self script] setValue:indexController forKey:@"IndexController"];
+ [[self script] setValue:controller.index forKey:@"Index"];
[self refresh];
}
-- (BOOL) amend
-{
- return controller.amend;
-}
-
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
@@ -81,9 +77,11 @@ - (void) refresh
[NSNumber numberWithBool:selectedFileIsCached], nil]];
}
-- (void) stageHunk:(NSString *)hunk reverse:(BOOL)reverse
+- (void)stageHunk:(NSString *)hunk reverse:(BOOL)reverse
{
- [controller stageHunk: hunk reverse:reverse];
+ [controller.index applyPatch:hunk stage:YES reverse:reverse];
+ // FIXME: Don't need a hard refresh
+
[self refresh];
}
@@ -99,7 +97,7 @@ - (void)discardHunk:(NSString *)hunk altKey:(BOOL)altKey
}
if (ret == NSAlertDefaultReturn) {
- [controller discardHunk:hunk];
+ [controller.index applyPatch:hunk stage:NO reverse:YES];
[self refresh];
}
}
@@ -110,12 +108,4 @@ - (void) setStateMessage:(NSString *)state
[script callWebScriptMethod:@"setState" withArguments: [NSArray arrayWithObject:state]];
}
-- (void) setContextSize:(int)size
-{
- if (size == indexController.contextSize)
- return;
-
- indexController.contextSize = size;
- [self refresh];
-}
@end
View
21 html/views/commit/commit.js
@@ -1,11 +1,13 @@
/* Commit: Interface for selecting, staging, discarding, and unstaging
hunks, individual lines, or ranges of lines. */
+var contextLines = 5;
+
var showNewFile = function(file)
{
setTitle("New file: " + file.path);
- var contents = IndexController.unstagedChangesForFile_(file);
+ var contents = Index.diffForFile_staged_contextLines_(file, false, contextLines);
if (!contents) {
notify("Can not display changes (Binary file?)", -1);
diff.innerHTML = "";
@@ -49,23 +51,16 @@ var showFileChanges = function(file, cached) {
hideState();
$("contextSize").oninput = function(element) {
- Controller.setContextSize_($("contextSize").value);
+ contextSize = $("contextSize").value;
}
if (file.status == 0) // New file?
return showNewFile(file);
- var changes;
- if (cached) {
- setTitle("Staged changes for " + file.path);
- displayContext();
- changes = IndexController.stagedChangesForFile_(file);
- }
- else {
- setTitle("Unstaged changes for " + file.path);
- displayContext();
- changes = IndexController.unstagedChangesForFile_(file);
- }
+ setTitle((cached ? "Staged": "Unstaged") + " changes for" + file.path);
+ displayContext();
+ var changes = Index.diffForFile_staged_contextLines_(file, cached, contextLines);
+
if (changes == "") {
notify("This file has no more changes", 1);

0 comments on commit 1854fc0

Please sign in to comment.