mirror of
https://github.com/kennethreitz-archive/gitx.git
synced 2026-06-05 23:40:18 +00:00
Merge branch 'master' of git://github.com/pieter/gitx
This commit is contained in:
@@ -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;
|
||||
};
|
||||
|
||||
+3
-1
@@ -57,7 +57,9 @@
|
||||
break;
|
||||
|
||||
NSRange range = NSMakeRange(pmatch[i].rm_so, pmatch[i].rm_eo - pmatch[i].rm_so);
|
||||
NSString * substring = [self substringWithRange:range];
|
||||
NSString * substring = [[[NSString alloc] initWithBytes:[self UTF8String] + range.location
|
||||
length:range.length
|
||||
encoding:NSUTF8StringEncoding] autorelease];
|
||||
[outMatches addObject:substring];
|
||||
|
||||
if (ranges)
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
[document.windowController showCommitView:self];
|
||||
else {
|
||||
PBGitRevSpecifier* rev = [[PBGitRevSpecifier alloc] initWithParameters:arguments];
|
||||
rev.workingDirectory = repositoryPath;
|
||||
document.currentBranch = [document addBranch: rev];
|
||||
[document.windowController showHistoryView:self];
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#define MIN_GIT_VERSION "1.6.0"
|
||||
|
||||
@interface PBGitBinary : NSObject {
|
||||
|
||||
|
||||
+4
-4
@@ -37,7 +37,7 @@ static NSString* gitPath = nil;
|
||||
if (!version)
|
||||
return NO;
|
||||
|
||||
int c = [version compare:@"1.5.4"];
|
||||
int c = [version compare:@"" MIN_GIT_VERSION];
|
||||
if (c == NSOrderedSame || c == NSOrderedDescending) {
|
||||
gitPath = path;
|
||||
return YES;
|
||||
@@ -60,7 +60,7 @@ static NSString* gitPath = nil;
|
||||
alternateButton:nil
|
||||
otherButton:nil
|
||||
informativeTextWithFormat:@"You entered a custom git path in the Preferences pane, "
|
||||
"but this path is not a valid git v1.5.4 or higher binary. We're going to use the default "
|
||||
"but this path is not a valid git v" MIN_GIT_VERSION " or higher binary. We're going to use the default "
|
||||
"search paths instead"] runModal];
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ static NSString* gitPath = nil;
|
||||
return;
|
||||
}
|
||||
|
||||
NSLog(@"Could not find a git binary higher than version 1.5.4.");
|
||||
NSLog(@"Could not find a git binary higher than version " MIN_GIT_VERSION);
|
||||
}
|
||||
|
||||
+ (NSString *) path;
|
||||
@@ -109,7 +109,7 @@ static NSMutableArray *locations = nil;
|
||||
+ (NSString *) notFoundError
|
||||
{
|
||||
NSMutableString *error = [NSMutableString stringWithString:
|
||||
@"Could not find a git binary version 1.5.4 or higher.\n"
|
||||
@"Could not find a git binary version " MIN_GIT_VERSION " or higher.\n"
|
||||
"Please make sure there is a git binary in one of the following locations:\n\n"];
|
||||
for (NSString *location in [PBGitBinary searchLocations]) {
|
||||
[error appendFormat:@"\t%@\n", location];
|
||||
|
||||
+2
-12
@@ -66,20 +66,10 @@
|
||||
return str;
|
||||
}
|
||||
|
||||
// NOTE: This method should remain threadsafe, as we load it in async
|
||||
// from the web view.
|
||||
// FIXME: Remove this method once it's unused.
|
||||
- (NSString*) details
|
||||
{
|
||||
if (details != nil)
|
||||
return details;
|
||||
|
||||
NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"show", @"--pretty=raw", @"-M", @"--no-color", [self realSha], nil];
|
||||
if (![PBGitDefaults showWhitespaceDifferences])
|
||||
[arguments insertObject:@"-w" atIndex:1];
|
||||
|
||||
details = [self.repository outputForArguments:arguments];
|
||||
|
||||
return details;
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSString *) patch
|
||||
|
||||
+8
-24
@@ -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;
|
||||
|
||||
+76
-331
@@ -10,26 +10,44 @@
|
||||
#import "NSFileHandleExt.h"
|
||||
#import "PBChangedFile.h"
|
||||
#import "PBWebChangesController.h"
|
||||
#import "NSString_RegEx.h"
|
||||
#import "PBGitIndex.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;
|
||||
@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 @@
|
||||
[[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 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (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,152 +106,6 @@
|
||||
[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
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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"]]) {
|
||||
@@ -345,98 +127,61 @@
|
||||
[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];
|
||||
self.busy = YES;
|
||||
[commitMessageView setEditable:NO];
|
||||
|
||||
NSString *commitMessageFile;
|
||||
commitMessageFile = [repository.fileURL.path
|
||||
stringByAppendingPathComponent:@"COMMIT_EDITMSG"];
|
||||
[index commitWithMessage:commitMessage];
|
||||
}
|
||||
|
||||
[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"];
|
||||
# pragma mark PBGitIndex Notification handling
|
||||
- (void)refreshFinished:(NSNotification *)notification
|
||||
{
|
||||
self.busy = NO;
|
||||
self.status = @"Index refresh finished";
|
||||
}
|
||||
|
||||
int ret;
|
||||
- (void)commitStatusUpdated:(NSNotification *)notification
|
||||
{
|
||||
self.status = [[notification userInfo] objectForKey:@"description"];
|
||||
}
|
||||
|
||||
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"];
|
||||
|
||||
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"];
|
||||
|
||||
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]];
|
||||
|
||||
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
|
||||
|
||||
+54
-75
@@ -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>
|
||||
@@ -963,38 +962,6 @@
|
||||
</object>
|
||||
<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>
|
||||
@@ -1067,22 +1034,6 @@
|
||||
</object>
|
||||
<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>
|
||||
@@ -1163,22 +1114,6 @@
|
||||
</object>
|
||||
<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>
|
||||
@@ -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>
|
||||
|
||||
@@ -66,8 +66,7 @@
|
||||
|
||||
switch (self.selectedTab) {
|
||||
case 0: self.webCommit = realCommit; break;
|
||||
case 1: self.rawCommit = realCommit; break;
|
||||
case 2: self.gitTree = realCommit.tree; break;
|
||||
case 1: self.gitTree = realCommit.tree; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+149
-359
@@ -2,14 +2,14 @@
|
||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.03">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1050</int>
|
||||
<string key="IBDocument.SystemVersion">9L30</string>
|
||||
<string key="IBDocument.SystemVersion">9L31a</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">677</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="46"/>
|
||||
<integer value="237"/>
|
||||
<integer value="46"/>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.PluginDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
@@ -98,7 +98,7 @@
|
||||
<object class="NSSegmentedControl" id="802449565">
|
||||
<reference key="NSNextResponder" ref="319362431"/>
|
||||
<int key="NSvFlags">293</int>
|
||||
<string key="NSFrame">{{376, 6}, {99, 25}}</string>
|
||||
<string key="NSFrame">{{376, 6}, {71, 25}}</string>
|
||||
<reference key="NSSuperview" ref="319362431"/>
|
||||
<bool key="NSEnabled">YES</bool>
|
||||
<object class="NSSegmentedCell" key="NSCell" id="534046869">
|
||||
@@ -124,23 +124,14 @@
|
||||
<int key="NSSegmentItemImageScaling">2</int>
|
||||
</object>
|
||||
<object class="NSSegmentItem">
|
||||
<object class="NSCustomResource" key="NSSegmentItemImage">
|
||||
<string key="NSClassName">NSImage</string>
|
||||
<string key="NSResourceName">NSListViewTemplate</string>
|
||||
</object>
|
||||
<string key="NSSegmentItemLabel"/>
|
||||
<string key="NSSegmentItemTooltip">Raw View</string>
|
||||
<int key="NSSegmentItemTag">1</int>
|
||||
<int key="NSSegmentItemImageScaling">2</int>
|
||||
</object>
|
||||
<object class="NSSegmentItem">
|
||||
<double key="NSSegmentItemWidth">3.200000e+01</double>
|
||||
<object class="NSCustomResource" key="NSSegmentItemImage">
|
||||
<string key="NSClassName">NSImage</string>
|
||||
<string key="NSResourceName">NSPathTemplate</string>
|
||||
</object>
|
||||
<string key="NSSegmentItemLabel"/>
|
||||
<string key="NSSegmentItemTooltip">Tree View</string>
|
||||
<int key="NSSegmentItemImageScaling">0</int>
|
||||
<int key="NSSegmentItemTag">9</int>
|
||||
<int key="NSSegmentItemImageScaling">2</int>
|
||||
</object>
|
||||
</object>
|
||||
<int key="NSSegmentStyle">2</int>
|
||||
@@ -153,7 +144,7 @@
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSScrollView" id="663765878">
|
||||
<reference key="NSNextResponder" ref="202620420"/>
|
||||
<int key="NSvFlags">274</int>
|
||||
<int key="NSvFlags">4370</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSClipView" id="546023969">
|
||||
@@ -320,7 +311,6 @@
|
||||
</object>
|
||||
<int key="NSResizingMask">3</int>
|
||||
<bool key="NSIsResizeable">YES</bool>
|
||||
<bool key="NSIsEditable">NO</bool>
|
||||
<reference key="NSTableView" ref="254268962"/>
|
||||
<bool key="NSHidden">YES</bool>
|
||||
</object>
|
||||
@@ -410,7 +400,7 @@
|
||||
<object class="NSTabViewItem" id="375889551">
|
||||
<string key="NSIdentifier">1</string>
|
||||
<object class="NSView" key="NSView" id="859052736">
|
||||
<nil key="NSNextResponder"/>
|
||||
<reference key="NSNextResponder" ref="135073984"/>
|
||||
<int key="NSvFlags">274</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
@@ -477,268 +467,10 @@
|
||||
</object>
|
||||
<reference key="NSTabView" ref="135073984"/>
|
||||
</object>
|
||||
<object class="NSTabViewItem" id="465071889">
|
||||
<string key="NSIdentifier">2</string>
|
||||
<object class="NSView" key="NSView" id="624894365">
|
||||
<nil key="NSNextResponder"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSScrollView" id="670264682">
|
||||
<reference key="NSNextResponder" ref="624894365"/>
|
||||
<int key="NSvFlags">274</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSClipView" id="948090592">
|
||||
<reference key="NSNextResponder" ref="670264682"/>
|
||||
<int key="NSvFlags">2304</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSTextView" id="239018083">
|
||||
<reference key="NSNextResponder" ref="948090592"/>
|
||||
<int key="NSvFlags">2322</int>
|
||||
<string key="NSFrameSize">{835, 70}</string>
|
||||
<reference key="NSSuperview" ref="948090592"/>
|
||||
<object class="NSTextContainer" key="NSTextContainer" id="53511606">
|
||||
<object class="NSLayoutManager" key="NSLayoutManager">
|
||||
<object class="NSTextStorage" key="NSTextStorage">
|
||||
<object class="NSMutableString" key="NSString">
|
||||
<characters key="NS.bytes">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum Et harumd und lookum like Greek to me, dereud facilis est er expedit distinct. Nam liber te conscient to factor tum poen legum odioque civiuda</characters>
|
||||
</object>
|
||||
<object class="NSDictionary" key="NSAttributes" id="631771906">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSMutableArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>NSFont</string>
|
||||
<string>NSParagraphStyle</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSFont">
|
||||
<string key="NSName">Monaco</string>
|
||||
<double key="NSSize">1.000000e+01</double>
|
||||
<int key="NSfFlags">16</int>
|
||||
</object>
|
||||
<object class="NSParagraphStyle">
|
||||
<int key="NSAlignment">3</int>
|
||||
<object class="NSArray" key="NSTabStops">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">0.000000e+00</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">5.600000e+01</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.120000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.680000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">2.240000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">2.800000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">3.360000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">3.920000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">4.480000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">5.040000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">5.600000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">6.160000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">6.720000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">7.280000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">7.840000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">8.400000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">8.960000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">9.520000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.008000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.064000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.120000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.176000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.232000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.288000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.344000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.400000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.456000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.512000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.568000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.624000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.680000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.736000e+03</double>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<nil key="NSDelegate"/>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="NSTextContainers">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="53511606"/>
|
||||
</object>
|
||||
<int key="NSLMFlags">6</int>
|
||||
<nil key="NSDelegate"/>
|
||||
</object>
|
||||
<reference key="NSTextView" ref="239018083"/>
|
||||
<double key="NSWidth">8.350000e+02</double>
|
||||
<int key="NSTCFlags">1</int>
|
||||
</object>
|
||||
<object class="NSTextViewSharedData" key="NSSharedData">
|
||||
<int key="NSFlags">2369</int>
|
||||
<reference key="NSBackgroundColor" ref="965176493"/>
|
||||
<reference key="NSInsertionColor" ref="381686569"/>
|
||||
<object class="NSDictionary" key="NSSelectedAttributes">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSMutableArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>NSBackgroundColor</string>
|
||||
<string>NSColor</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSColor" id="688833546">
|
||||
<int key="NSColorSpace">6</int>
|
||||
<string key="NSCatalogName">System</string>
|
||||
<string key="NSColorName">selectedTextBackgroundColor</string>
|
||||
<reference key="NSColor" ref="827382333"/>
|
||||
</object>
|
||||
<object class="NSColor" id="349701971">
|
||||
<int key="NSColorSpace">6</int>
|
||||
<string key="NSCatalogName">System</string>
|
||||
<string key="NSColorName">selectedTextColor</string>
|
||||
<reference key="NSColor" ref="381686569"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<nil key="NSMarkedAttributes"/>
|
||||
<object class="NSDictionary" key="NSLinkAttributes">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSMutableArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>NSColor</string>
|
||||
<string>NSUnderline</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSColor" id="882067667">
|
||||
<int key="NSColorSpace">1</int>
|
||||
<bytes key="NSRGB">MCAwIDEAA</bytes>
|
||||
</object>
|
||||
<reference ref="9"/>
|
||||
</object>
|
||||
</object>
|
||||
<nil key="NSDefaultParagraphStyle"/>
|
||||
</object>
|
||||
<int key="NSTVFlags">6</int>
|
||||
<string key="NSMaxSize">{1687, 1e+07}</string>
|
||||
<string key="NSMinize">{83, 0}</string>
|
||||
<nil key="NSDelegate"/>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrame">{{1, 1}, {835, 185}}</string>
|
||||
<reference key="NSSuperview" ref="670264682"/>
|
||||
<reference key="NSNextKeyView" ref="239018083"/>
|
||||
<reference key="NSDocView" ref="239018083"/>
|
||||
<reference key="NSBGColor" ref="965176493"/>
|
||||
<object class="NSCursor" key="NSCursor" id="841457992">
|
||||
<string key="NSHotSpot">{4, -5}</string>
|
||||
<int key="NSCursorType">1</int>
|
||||
</object>
|
||||
<int key="NScvFlags">4</int>
|
||||
</object>
|
||||
<object class="NSScroller" id="722857290">
|
||||
<reference key="NSNextResponder" ref="670264682"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrame">{{836, 1}, {15, 185}}</string>
|
||||
<reference key="NSSuperview" ref="670264682"/>
|
||||
<reference key="NSTarget" ref="670264682"/>
|
||||
<string key="NSAction">_doScroller:</string>
|
||||
<double key="NSPercent">2.240493e-01</double>
|
||||
</object>
|
||||
<object class="NSScroller" id="585622122">
|
||||
<reference key="NSNextResponder" ref="670264682"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<string key="NSFrame">{{-100, -100}, {87, 18}}</string>
|
||||
<reference key="NSSuperview" ref="670264682"/>
|
||||
<int key="NSsFlags">1</int>
|
||||
<reference key="NSTarget" ref="670264682"/>
|
||||
<string key="NSAction">_doScroller:</string>
|
||||
<double key="NSCurValue">1.000000e+00</double>
|
||||
<double key="NSPercent">9.456522e-01</double>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrameSize">{852, 187}</string>
|
||||
<reference key="NSSuperview" ref="624894365"/>
|
||||
<reference key="NSNextKeyView" ref="948090592"/>
|
||||
<int key="NSsFlags">18</int>
|
||||
<reference key="NSVScroller" ref="722857290"/>
|
||||
<reference key="NSHScroller" ref="585622122"/>
|
||||
<reference key="NSContentView" ref="948090592"/>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrameSize">{852, 186}</string>
|
||||
</object>
|
||||
<string key="NSLabel">Raw</string>
|
||||
<reference key="NSColor" ref="457244339"/>
|
||||
<reference key="NSTabView" ref="135073984"/>
|
||||
</object>
|
||||
<object class="NSTabViewItem" id="529992882">
|
||||
<string key="NSIdentifier">Item 2</string>
|
||||
<object class="NSView" key="NSView" id="657042048">
|
||||
<reference key="NSNextResponder" ref="135073984"/>
|
||||
<nil key="NSNextResponder"/>
|
||||
<int key="NSvFlags">256</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
@@ -869,7 +601,124 @@
|
||||
<object class="NSMutableString" key="NSString">
|
||||
<characters key="NS.bytes">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum Et harumd und lookum like Greek to me, dereud facilis est er expedit distinct. Nam liber te conscient to factor tum poen legum odioque civiuda</characters>
|
||||
</object>
|
||||
<reference key="NSAttributes" ref="631771906"/>
|
||||
<object class="NSDictionary" key="NSAttributes">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSMutableArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>NSFont</string>
|
||||
<string>NSParagraphStyle</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSFont">
|
||||
<string key="NSName">Monaco</string>
|
||||
<double key="NSSize">1.000000e+01</double>
|
||||
<int key="NSfFlags">16</int>
|
||||
</object>
|
||||
<object class="NSParagraphStyle">
|
||||
<int key="NSAlignment">3</int>
|
||||
<object class="NSArray" key="NSTabStops">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">0.000000e+00</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">5.600000e+01</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.120000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.680000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">2.240000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">2.800000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">3.360000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">3.920000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">4.480000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">5.040000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">5.600000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">6.160000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">6.720000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">7.280000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">7.840000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">8.400000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">8.960000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">9.520000e+02</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.008000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.064000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.120000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.176000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.232000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.288000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.344000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.400000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.456000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.512000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.568000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.624000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.680000e+03</double>
|
||||
</object>
|
||||
<object class="NSTextTab">
|
||||
<double key="NSLocation">1.736000e+03</double>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<nil key="NSDelegate"/>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="NSTextContainers">
|
||||
@@ -896,8 +745,18 @@
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="688833546"/>
|
||||
<reference ref="349701971"/>
|
||||
<object class="NSColor">
|
||||
<int key="NSColorSpace">6</int>
|
||||
<string key="NSCatalogName">System</string>
|
||||
<string key="NSColorName">selectedTextBackgroundColor</string>
|
||||
<reference key="NSColor" ref="827382333"/>
|
||||
</object>
|
||||
<object class="NSColor">
|
||||
<int key="NSColorSpace">6</int>
|
||||
<string key="NSCatalogName">System</string>
|
||||
<string key="NSColorName">selectedTextColor</string>
|
||||
<reference key="NSColor" ref="381686569"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<nil key="NSMarkedAttributes"/>
|
||||
@@ -910,7 +769,10 @@
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="882067667"/>
|
||||
<object class="NSColor">
|
||||
<int key="NSColorSpace">1</int>
|
||||
<bytes key="NSRGB">MCAwIDEAA</bytes>
|
||||
</object>
|
||||
<reference ref="9"/>
|
||||
</object>
|
||||
</object>
|
||||
@@ -927,7 +789,10 @@
|
||||
<reference key="NSNextKeyView" ref="75600241"/>
|
||||
<reference key="NSDocView" ref="75600241"/>
|
||||
<reference key="NSBGColor" ref="965176493"/>
|
||||
<reference key="NSCursor" ref="841457992"/>
|
||||
<object class="NSCursor" key="NSCursor">
|
||||
<string key="NSHotSpot">{4, -5}</string>
|
||||
<int key="NSCursorType">1</int>
|
||||
</object>
|
||||
<int key="NScvFlags">4</int>
|
||||
</object>
|
||||
<object class="NSScroller" id="802032705">
|
||||
@@ -967,21 +832,20 @@
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrameSize">{852, 186}</string>
|
||||
<reference key="NSSuperview" ref="135073984"/>
|
||||
</object>
|
||||
<string key="NSLabel">Tree</string>
|
||||
<reference key="NSColor" ref="457244339"/>
|
||||
<reference key="NSTabView" ref="135073984"/>
|
||||
</object>
|
||||
</object>
|
||||
<reference key="NSSelectedTabViewItem" ref="529992882"/>
|
||||
<reference key="NSSelectedTabViewItem" ref="375889551"/>
|
||||
<reference key="NSFont" ref="924107556"/>
|
||||
<int key="NSTvFlags">6</int>
|
||||
<bool key="NSAllowTruncatedLabels">YES</bool>
|
||||
<bool key="NSDrawsBackground">YES</bool>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="657042048"/>
|
||||
<reference ref="859052736"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
@@ -1936,22 +1800,6 @@
|
||||
</object>
|
||||
<int key="connectionID">217</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBBindingConnection" key="connection">
|
||||
<string key="label">value: rawCommit.details</string>
|
||||
<reference key="source" ref="239018083"/>
|
||||
<reference key="destination" ref="1001"/>
|
||||
<object class="NSNibBindingConnector" key="connector">
|
||||
<reference key="NSSource" ref="239018083"/>
|
||||
<reference key="NSDestination" ref="1001"/>
|
||||
<string key="NSLabel">value: rawCommit.details</string>
|
||||
<string key="NSBinding">value</string>
|
||||
<string key="NSKeyPath">rawCommit.details</string>
|
||||
<int key="NSNibBindingConnectorVersion">2</int>
|
||||
</object>
|
||||
</object>
|
||||
<int key="connectionID">230</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">commitController</string>
|
||||
@@ -2221,23 +2069,12 @@
|
||||
<reference key="object" ref="135073984"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="465071889"/>
|
||||
<reference ref="375889551"/>
|
||||
<reference ref="529992882"/>
|
||||
</object>
|
||||
<reference key="parent" ref="202620420"/>
|
||||
<string key="objectName">Bottom View</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">5</int>
|
||||
<reference key="object" ref="465071889"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="624894365"/>
|
||||
</object>
|
||||
<reference key="parent" ref="135073984"/>
|
||||
<string key="objectName">Raw View</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">6</int>
|
||||
<reference key="object" ref="375889551"/>
|
||||
@@ -2360,41 +2197,6 @@
|
||||
<reference key="object" ref="676796335"/>
|
||||
<reference key="parent" ref="859052736"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">22</int>
|
||||
<reference key="object" ref="624894365"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="670264682"/>
|
||||
</object>
|
||||
<reference key="parent" ref="465071889"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">23</int>
|
||||
<reference key="object" ref="670264682"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="722857290"/>
|
||||
<reference ref="585622122"/>
|
||||
<reference ref="239018083"/>
|
||||
</object>
|
||||
<reference key="parent" ref="624894365"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">24</int>
|
||||
<reference key="object" ref="722857290"/>
|
||||
<reference key="parent" ref="670264682"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">25</int>
|
||||
<reference key="object" ref="585622122"/>
|
||||
<reference key="parent" ref="670264682"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">26</int>
|
||||
<reference key="object" ref="239018083"/>
|
||||
<reference key="parent" ref="670264682"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">47</int>
|
||||
<reference key="object" ref="555671215"/>
|
||||
@@ -2819,11 +2621,9 @@
|
||||
<string>20.IBPluginDependency</string>
|
||||
<string>21.IBAttributePlaceholdersKey</string>
|
||||
<string>21.IBPluginDependency</string>
|
||||
<string>22.IBPluginDependency</string>
|
||||
<string>223.IBPluginDependency</string>
|
||||
<string>224.IBPluginDependency</string>
|
||||
<string>225.IBPluginDependency</string>
|
||||
<string>23.IBPluginDependency</string>
|
||||
<string>231.IBPluginDependency</string>
|
||||
<string>236.IBEditorWindowLastContentRect</string>
|
||||
<string>236.IBWindowTemplateEditedContentRect</string>
|
||||
@@ -2835,15 +2635,12 @@
|
||||
<string>237.IBPluginDependency</string>
|
||||
<string>238.IBPluginDependency</string>
|
||||
<string>239.IBPluginDependency</string>
|
||||
<string>24.IBPluginDependency</string>
|
||||
<string>240.IBPluginDependency</string>
|
||||
<string>242.IBPluginDependency</string>
|
||||
<string>243.IBPluginDependency</string>
|
||||
<string>245.IBPluginDependency</string>
|
||||
<string>246.IBPluginDependency</string>
|
||||
<string>247.IBPluginDependency</string>
|
||||
<string>25.IBPluginDependency</string>
|
||||
<string>26.IBPluginDependency</string>
|
||||
<string>261.IBAttributePlaceholdersKey</string>
|
||||
<string>261.IBPluginDependency</string>
|
||||
<string>262.IBPluginDependency</string>
|
||||
@@ -2890,7 +2687,6 @@
|
||||
<string>47.IBPluginDependency</string>
|
||||
<string>48.IBPluginDependency</string>
|
||||
<string>49.IBPluginDependency</string>
|
||||
<string>5.IBPluginDependency</string>
|
||||
<string>50.IBPluginDependency</string>
|
||||
<string>51.IBPluginDependency</string>
|
||||
<string>52.IBPluginDependency</string>
|
||||
@@ -2949,8 +2745,6 @@
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>{{504, 612}, {346, 102}}</string>
|
||||
<string>{{504, 612}, {346, 102}}</string>
|
||||
<integer value="0" id="8"/>
|
||||
@@ -2967,9 +2761,6 @@
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<object class="NSMutableDictionary">
|
||||
<string key="NS.key.0">ToolTip</string>
|
||||
<object class="IBToolTipAttribute" key="NS.object.0">
|
||||
@@ -3038,7 +2829,6 @@
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="unlocalizedProperties">
|
||||
|
||||
@@ -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
|
||||
+630
@@ -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
|
||||
@@ -11,30 +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;
|
||||
|
||||
- (NSMenu *) menuForTable:(NSTableView *)table;
|
||||
@end
|
||||
|
||||
+30
-155
@@ -9,22 +9,18 @@
|
||||
#import "PBGitIndexController.h"
|
||||
#import "PBChangedFile.h"
|
||||
#import "PBGitRepository.h"
|
||||
#import "PBGitIndex.h"
|
||||
|
||||
#define FileChangesTableViewType @"GitFileChangedType"
|
||||
|
||||
@interface PBGitIndexController (PrivateMethods)
|
||||
- (void)stopTrackingIndex;
|
||||
- (void)resumeTrackingIndex;
|
||||
@interface PBGitIndexController ()
|
||||
- (void)discardChangesForFiles:(NSArray *)files force:(BOOL)force;
|
||||
@end
|
||||
|
||||
@implementation PBGitIndexController
|
||||
|
||||
@synthesize contextSize;
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
contextSize = 3;
|
||||
|
||||
[unstagedTable setDoubleAction:@selector(tableClicked:)];
|
||||
[stagedTable setDoubleAction:@selector(tableClicked:)];
|
||||
|
||||
@@ -33,64 +29,10 @@
|
||||
|
||||
[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];
|
||||
@@ -127,63 +69,6 @@
|
||||
[[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
|
||||
{
|
||||
@@ -260,12 +145,12 @@
|
||||
|
||||
- (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
|
||||
@@ -279,10 +164,11 @@
|
||||
- (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
|
||||
@@ -310,6 +196,20 @@
|
||||
[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
|
||||
@@ -325,9 +225,9 @@
|
||||
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
|
||||
@@ -387,36 +287,11 @@ writeRowsWithIndexes:(NSIndexSet *)rowIndexes
|
||||
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
|
||||
|
||||
+3
-2
@@ -8,14 +8,15 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class PBGitRepository;
|
||||
|
||||
@interface PBGitRevList : NSObject {
|
||||
NSArray* commits;
|
||||
id repository;
|
||||
PBGitRepository *repository;
|
||||
NSString* lastSha;
|
||||
}
|
||||
|
||||
- initWithRepository:(id)repo;
|
||||
- initWithRepository:(PBGitRepository *)repo;
|
||||
- (void) readCommitsForce: (BOOL) force;
|
||||
- (void) reload;
|
||||
|
||||
|
||||
+7
-9
@@ -23,7 +23,7 @@ using namespace std;
|
||||
@implementation PBGitRevList
|
||||
|
||||
@synthesize commits;
|
||||
- initWithRepository: (id) repo
|
||||
- (id)initWithRepository:(PBGitRepository *)repo
|
||||
{
|
||||
repository = repo;
|
||||
[repository addObserver:self forKeyPath:@"currentBranch" options:0 context:nil];
|
||||
@@ -74,23 +74,21 @@ using namespace std;
|
||||
PBGitGrapher* g = [[PBGitGrapher alloc] initWithRepository: repository];
|
||||
std::map<string, NSStringEncoding> encodingMap;
|
||||
|
||||
NSMutableArray* arguments;
|
||||
NSString *formatString = @"--pretty=format:%H\01%e\01%an\01%s\01%P\01%at";
|
||||
BOOL showSign = [rev hasLeftRight];
|
||||
|
||||
if (showSign)
|
||||
arguments = [NSMutableArray arrayWithObjects:@"log", @"-z", @"--early-output", @"--topo-order", @"--pretty=format:%H\01%e\01%an\01%s\01%P\01%at\01%m", nil];
|
||||
else
|
||||
arguments = [NSMutableArray arrayWithObjects:@"log", @"-z", @"--early-output", @"--topo-order", @"--pretty=format:%H\01%e\01%an\01%s\01%P\01%at", nil];
|
||||
formatString = [formatString stringByAppendingString:@"\01%m"];
|
||||
|
||||
NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"log", @"-z", @"--early-output", @"--topo-order", @"--children", formatString, nil];
|
||||
|
||||
if (!rev)
|
||||
[arguments addObject:@"HEAD"];
|
||||
else
|
||||
[arguments addObjectsFromArray:[rev parameters]];
|
||||
|
||||
if ([rev hasPathLimiter])
|
||||
[arguments insertObject:@"--children" atIndex:1];
|
||||
|
||||
NSTask *task = [PBEasyPipe taskForCommand:[PBGitBinary path] withArgs:arguments inDir:[repository fileURL].path];
|
||||
NSString *directory = rev.workingDirectory ? rev.workingDirectory.path : repository.fileURL.path;
|
||||
NSTask *task = [PBEasyPipe taskForCommand:[PBGitBinary path] withArgs:arguments inDir:directory];
|
||||
[task launch];
|
||||
NSFileHandle* handle = [task.standardOutput fileHandleForReading];
|
||||
|
||||
|
||||
+7
-4
@@ -10,8 +10,9 @@
|
||||
#import <PBGitRef.h>
|
||||
|
||||
@interface PBGitRevSpecifier : NSObject {
|
||||
NSString* description;
|
||||
NSArray* parameters;
|
||||
NSString *description;
|
||||
NSArray *parameters;
|
||||
NSURL *workingDirectory;
|
||||
}
|
||||
|
||||
- (id) initWithParameters:(NSArray*) params;
|
||||
@@ -27,6 +28,8 @@
|
||||
+ (PBGitRevSpecifier *)allBranchesRevSpec;
|
||||
+ (PBGitRevSpecifier *)localBranchesRevSpec;
|
||||
|
||||
@property(copy) NSString* description;
|
||||
@property(readonly) NSArray* parameters;
|
||||
@property(retain) NSString *description;
|
||||
@property(readonly) NSArray *parameters;
|
||||
@property(retain) NSURL *workingDirectory;
|
||||
|
||||
@end
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
|
||||
@implementation PBGitRevSpecifier
|
||||
|
||||
@synthesize parameters, description;
|
||||
@synthesize parameters, description, workingDirectory;
|
||||
|
||||
- (id) initWithParameters:(NSArray*) params
|
||||
{
|
||||
|
||||
+8
-15
@@ -63,18 +63,12 @@
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)hasBinaryHeader:(NSString *)fileHeader
|
||||
- (BOOL)hasBinaryHeader:(NSString*)contents
|
||||
{
|
||||
if (!fileHeader)
|
||||
if(!contents)
|
||||
return NO;
|
||||
|
||||
NSString *filetype = [PBEasyPipe outputForCommand:@"/usr/bin/file"
|
||||
withArgs:[NSArray arrayWithObjects:@"-b", @"-N", @"-", nil]
|
||||
inDir:[repository workingDirectory]
|
||||
inputString:fileHeader
|
||||
retValue:nil];
|
||||
|
||||
return [filetype rangeOfString:@"text"].location == NSNotFound;
|
||||
return [contents rangeOfString:@"\0" options:0 range:NSMakeRange(0, ([contents length] >= 8000) ? 7999 : [contents length])].location != NSNotFound;
|
||||
}
|
||||
|
||||
- (BOOL)hasBinaryAttributes
|
||||
@@ -143,14 +137,13 @@
|
||||
if ([self hasBinaryAttributes])
|
||||
return [NSString stringWithFormat:@"%@ appears to be a binary file of %d bytes", [self fullPath], [self fileSize]];
|
||||
|
||||
long long fileSize = [self fileSize];
|
||||
if (fileSize > 52428800) // ~50MB
|
||||
return [NSString stringWithFormat:@"%@ is too big to be displayed (%d bytes)", [self fullPath], fileSize];
|
||||
if ([self fileSize] > 52428800) // ~50MB
|
||||
return [NSString stringWithFormat:@"%@ is too big to be displayed (%d bytes)", [self fullPath], [self fileSize]];
|
||||
|
||||
NSString *contents = [self contents];
|
||||
NSString* contents = [self contents];
|
||||
|
||||
if ([self hasBinaryHeader:([contents length] >= 100) ? [contents substringToIndex:99] : contents])
|
||||
return [NSString stringWithFormat:@"%@ appears to be a binary file of %d bytes", [self fullPath], fileSize];
|
||||
if ([self hasBinaryHeader:contents])
|
||||
return [NSString stringWithFormat:@"%@ appears to be a binary file of %d bytes", [self fullPath], [self fileSize]];
|
||||
|
||||
return contents;
|
||||
}
|
||||
|
||||
@@ -27,5 +27,4 @@
|
||||
- (void) setStateMessage:(NSString *)state;
|
||||
|
||||
- (void) showMultiple:(NSArray *)files;
|
||||
- (void) setContextSize:(int)size;
|
||||
@end
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import "PBWebChangesController.h"
|
||||
#import "PBGitIndexController.h"
|
||||
#import "PBGitIndex.h"
|
||||
|
||||
@implementation PBWebChangesController
|
||||
|
||||
@@ -25,15 +26,10 @@
|
||||
|
||||
- (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 @@
|
||||
[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 @@
|
||||
}
|
||||
|
||||
if (ret == NSAlertDefaultReturn) {
|
||||
[controller discardHunk:hunk];
|
||||
[controller.index applyPatch:hunk stage:NO reverse:YES];
|
||||
[self refresh];
|
||||
}
|
||||
}
|
||||
@@ -110,12 +108,4 @@
|
||||
[script callWebScriptMethod:@"setState" withArguments: [NSArray arrayWithObject:state]];
|
||||
}
|
||||
|
||||
- (void) setContextSize:(int)size
|
||||
{
|
||||
if (size == indexController.contextSize)
|
||||
return;
|
||||
|
||||
indexController.contextSize = size;
|
||||
[self refresh];
|
||||
}
|
||||
@end
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
#import "PBWebHistoryController.h"
|
||||
#import "PBGitDefaults.h"
|
||||
|
||||
@implementation PBWebHistoryController
|
||||
|
||||
@@ -49,6 +50,37 @@
|
||||
|
||||
NSArray *arguments = [NSArray arrayWithObjects:content, [[[historyController repository] headRef] simpleRef], nil];
|
||||
[[self script] callWebScriptMethod:@"loadCommit" withArguments: arguments];
|
||||
|
||||
// Now we load the extended details. We used to do this in a separate thread,
|
||||
// but this caused some funny behaviour because NSTask's and NSThread's don't really
|
||||
// like each other. Instead, just do it async.
|
||||
|
||||
NSMutableArray *taskArguments = [NSMutableArray arrayWithObjects:@"show", @"--pretty=raw", @"-M", @"--no-color", currentSha, nil];
|
||||
if (![PBGitDefaults showWhitespaceDifferences])
|
||||
[taskArguments insertObject:@"-w" atIndex:1];
|
||||
|
||||
NSFileHandle *handle = [repository handleForArguments:taskArguments];
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
// Remove notification, in case we have another one running
|
||||
[nc removeObserver:self];
|
||||
[nc addObserver:self selector:@selector(commitDetailsLoaded:) name:NSFileHandleReadToEndOfFileCompletionNotification object:handle];
|
||||
[handle readToEndOfFileInBackgroundAndNotify];
|
||||
}
|
||||
|
||||
- (void)commitDetailsLoaded:(NSNotification *)notification
|
||||
{
|
||||
NSData *data = [[notification userInfo] valueForKey:NSFileHandleNotificationDataItem];
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
NSString *details = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
if (!details)
|
||||
details = [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding];
|
||||
|
||||
if (!details)
|
||||
return;
|
||||
|
||||
[[view windowScriptObject] callWebScriptMethod:@"loadCommitDetails" withArguments:[NSArray arrayWithObject:details]];
|
||||
}
|
||||
|
||||
- (void) selectCommit: (NSString*) sha
|
||||
|
||||
@@ -31,9 +31,9 @@ changes will be staged. Clicking the 'Discard' button will irreversibly throw aw
|
||||
confirmation can be silenced using Alt-Click.
|
||||
|
||||
GitX 0.7 introduced a new way of staging lines: Simply drag-select a few of the lines you want to stage/unstage and a
|
||||
'Stage lines' button will appear next to it. This allows for much finer granularity than the hunks determined by diff.
|
||||
Double-clicking a line selects the sub-part of this hunk which isn't separated by blank lines. Selecting lines across
|
||||
hunks is currently not possible.
|
||||
'Stage lines' button will appear next to it. This allows for much finer granularity than the hunks determined by diff.
|
||||
Double-clicking a changed line selects the entire surrounding block of changes. Selecting lines across hunks is not
|
||||
possible.
|
||||
|
||||
#### Committing
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ then in silky smooth OS X style!
|
||||
|
||||
<h3>Requirements</h3>
|
||||
<p>
|
||||
GitX runs on Mac OS X 10.5 Leopard and Mac OS X 10.6 Snow Leopard. Because it uses features like Garbage Collection, you can't compile it on earlier systems. GitX also requires a fairly recent Git -- version 1.5.6 and higher are all supported.
|
||||
GitX runs on Mac OS X 10.5 Leopard and Mac OS X 10.6 Snow Leopard. Because it uses features like Garbage Collection, you can't compile it on earlier systems. GitX also requires a fairly recent Git -- version 1.6.0 and higher are all supported.
|
||||
</p>
|
||||
|
||||
<h3>Download</h3>
|
||||
|
||||
+2
-1
@@ -5,4 +5,5 @@ body {
|
||||
margin: 0;
|
||||
margin-top: 5px;
|
||||
width: 100%;
|
||||
}
|
||||
font-family: 'Lucida Grande', Arial;
|
||||
}
|
||||
|
||||
-3061
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
var commit;
|
||||
|
||||
// Create a new Commit object
|
||||
// obj: PBGitCommit object
|
||||
var Commit = function(obj) {
|
||||
this.object = obj;
|
||||
|
||||
@@ -7,12 +10,14 @@ var Commit = function(obj) {
|
||||
this.sha = obj.realSha();
|
||||
this.parents = obj.parents;
|
||||
this.subject = obj.subject;
|
||||
this.notificationID = null;
|
||||
|
||||
// TODO:
|
||||
// this.author_date instant
|
||||
|
||||
// This all needs to be async
|
||||
this.loadedRaw = function(details) {
|
||||
// This can be called later with the output of
|
||||
// 'git show' to fill in missing commit details (such as a diff)
|
||||
this.parseDetails = function(details) {
|
||||
this.raw = details;
|
||||
|
||||
var diffStart = this.raw.indexOf("\ndiff ");
|
||||
@@ -138,6 +143,7 @@ var selectCommit = function(a) {
|
||||
Controller.selectCommit_(a);
|
||||
}
|
||||
|
||||
// Relead only refs
|
||||
var reload = function() {
|
||||
$("notification").style.display = "none";
|
||||
commit.reloadRefs();
|
||||
@@ -159,13 +165,15 @@ var showRefs = function() {
|
||||
|
||||
var loadCommit = function(commitObject, currentRef) {
|
||||
// These are only the things we can do instantly.
|
||||
// Other information will be loaded later by loadExtendedCommit
|
||||
commit = new Commit(commitObject);
|
||||
Controller.callSelector_onObject_callBack_("details", commitObject,
|
||||
function(data) { commit.loadedRaw(data); loadExtendedCommit(commit); });
|
||||
commit.currentRef = currentRef;
|
||||
// Other information will be loaded later by loadCommitDetails,
|
||||
// Which will be called from the controller once
|
||||
// the commit details are in.
|
||||
|
||||
notify("Loading commit…", 0);
|
||||
if (commit && commit.notificationID)
|
||||
clearTimeout(commit.notificationID);
|
||||
|
||||
commit = new Commit(commitObject);
|
||||
commit.currentRef = currentRef;
|
||||
|
||||
$("commitID").innerHTML = commit.sha;
|
||||
$("authorID").innerHTML = commit.author_name;
|
||||
@@ -196,9 +204,18 @@ var loadCommit = function(commitObject, currentRef) {
|
||||
"<a href='' onclick='selectCommit(this.innerHTML); return false;'>" +
|
||||
commit.parents[i] + "</a></td>";
|
||||
}
|
||||
|
||||
commit.notificationID = setTimeout(function() {
|
||||
if (!commit.fullyLoaded)
|
||||
notify("Loading commit…", 0);
|
||||
commit.notificationID = null;
|
||||
}, 500);
|
||||
|
||||
}
|
||||
|
||||
var showDiff = function() {
|
||||
|
||||
// Callback for the diff highlighter. Used to generate a filelist
|
||||
var newfile = function(name1, name2, id, mode_change, old_mode, new_mode) {
|
||||
var button = document.createElement("div");
|
||||
var p = document.createElement("p");
|
||||
@@ -270,8 +287,15 @@ var enableFeatures = function()
|
||||
enableFeature("gravatar", $("gravatar"))
|
||||
}
|
||||
|
||||
var loadExtendedCommit = function(commit)
|
||||
var loadCommitDetails = function(data)
|
||||
{
|
||||
commit.parseDetails(data);
|
||||
|
||||
if (commit.notificationID)
|
||||
clearTimeout(commit.notificationID)
|
||||
else
|
||||
$("notification").style.display = "none";
|
||||
|
||||
var formatEmail = function(name, email) {
|
||||
return email ? name + " <<a href='mailto:" + email + "'>" + email + "</a>>" : name;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user