diff --git a/PBGitBinary.m b/PBGitBinary.m
index 49ef7b7..ccb0b0b 100644
--- a/PBGitBinary.m
+++ b/PBGitBinary.m
@@ -66,7 +66,7 @@ static NSString* gitPath = nil;
// Try to find the path of the Git binary
char* path = getenv("GIT_PATH");
- if (path && [self acceptBinary:[NSString stringWithCString:path]])
+ if (path && [self acceptBinary:[NSString stringWithUTF8String:path]])
return;
// No explicit path. Try it with "which"
diff --git a/PBGitCommitController.m b/PBGitCommitController.m
index cec4ffc..8342fce 100644
--- a/PBGitCommitController.m
+++ b/PBGitCommitController.m
@@ -201,7 +201,6 @@
- (void) readOtherFiles:(NSNotification *)notification;
{
- [unstagedFilesController setAutomaticallyRearrangesObjects:NO];
NSArray *lines = [self linesFromNotification:notification];
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithCapacity:[lines count]];
// We fake this files status as good as possible.
@@ -324,6 +323,11 @@
- (IBAction) commit:(id) sender
{
+ if ([[NSFileManager defaultManager] fileExistsAtPath:[repository.fileURL.path stringByAppendingPathComponent:@"MERGE_HEAD"]]) {
+ [[repository windowController] showMessageSheet:@"Cannot commit merges" infoText:@"GitX cannot commit merges yet. Please commit your changes from the command line."];
+ return;
+ }
+
if ([[cachedFilesController arrangedObjects] count] == 0) {
[[repository windowController] showMessageSheet:@"No changes to commit" infoText:@"You must first stage some changes before committing"];
return;
diff --git a/PBGitConfig.m b/PBGitConfig.m
index 3d4f156..9166cc4 100644
--- a/PBGitConfig.m
+++ b/PBGitConfig.m
@@ -79,7 +79,7 @@
// Check if it exists globally. In that case, write it as a global
- NSArray *arguments = [NSArray arrayWithObjects:@"config", @"--global", @"--get", path];
+ NSArray *arguments = [NSArray arrayWithObjects:@"config", @"--global", @"--get", path, nil];
int ret;
[PBEasyPipe outputForCommand:[PBGitBinary path] withArgs:arguments inDir:nil retValue:&ret];
if (!ret) // It exists globally
diff --git a/PBGitHistoryController.h b/PBGitHistoryController.h
index f87c462..6c99a20 100644
--- a/PBGitHistoryController.h
+++ b/PBGitHistoryController.h
@@ -42,6 +42,13 @@
- (IBAction) openSelectedFile: sender;
- (void) updateQuicklookForce: (BOOL) force;
+// Context menu methods
+- (NSMenu *)contextMenuForTreeView;
+- (NSArray *)menuItemsForPaths:(NSArray *)paths;
+- (void)showCommitsFromTree:(id)sender;
+- (void)showInFinderAction:(id)sender;
+- (void)openFilesAction:(id)sender;
+
- (void) copyCommitInfo;
- (BOOL) hasNonlinearPath;
diff --git a/PBGitHistoryController.m b/PBGitHistoryController.m
index 3b5e9e1..fb4d886 100644
--- a/PBGitHistoryController.m
+++ b/PBGitHistoryController.m
@@ -208,6 +208,7 @@
[super removeView];
}
+#pragma mark Table Column Methods
- (NSMenu *)tableColumnMenu
{
NSMenu *menu = [[NSMenu alloc] initWithTitle:@"Table columns menu"];
@@ -223,4 +224,76 @@
return menu;
}
+#pragma mark Tree Context Menu Methods
+
+- (void)showCommitsFromTree:(id)sender
+{
+ // TODO: Enable this from webview as well!
+
+ NSMutableArray *filePaths = [NSMutableArray arrayWithObjects:@"HEAD", @"--", NULL];
+ [filePaths addObjectsFromArray:[sender representedObject]];
+
+ PBGitRevSpecifier *revSpec = [[PBGitRevSpecifier alloc] initWithParameters:filePaths];
+
+ repository.currentBranch = [repository addBranch:revSpec];
+}
+
+- (void)showInFinderAction:(id)sender
+{
+ NSString *workingDirectory = [[repository workingDirectory] stringByAppendingString:@"/"];
+ NSString *path;
+ NSWorkspace *ws = [NSWorkspace sharedWorkspace];
+
+ for (NSString *filePath in [sender representedObject]) {
+ path = [workingDirectory stringByAppendingPathComponent:filePath];
+ [ws selectFile: path inFileViewerRootedAtPath:path];
+ }
+
+}
+
+- (void)openFilesAction:(id)sender
+{
+ NSString *workingDirectory = [[repository workingDirectory] stringByAppendingString:@"/"];
+ NSString *path;
+ NSWorkspace *ws = [NSWorkspace sharedWorkspace];
+
+ for (NSString *filePath in [sender representedObject]) {
+ path = [workingDirectory stringByAppendingPathComponent:filePath];
+ [ws openFile:path];
+ }
+}
+
+
+- (NSMenu *)contextMenuForTreeView
+{
+ NSArray *filePaths = [[treeController selectedObjects] valueForKey:@"fullPath"];
+
+ NSMenu *menu = [[NSMenu alloc] init];
+ for (NSMenuItem *item in [self menuItemsForPaths:filePaths])
+ [menu addItem:item];
+ return menu;
+}
+
+- (NSArray *)menuItemsForPaths:(NSArray *)paths
+{
+ BOOL multiple = [paths count] != 1;
+ NSMenuItem *historyItem = [[NSMenuItem alloc] initWithTitle:multiple? @"Show history of files" : @"Show history of file"
+ action:@selector(showCommitsFromTree:)
+ keyEquivalent:@""];
+ NSMenuItem *finderItem = [[NSMenuItem alloc] initWithTitle:@"Show in Finder"
+ action:@selector(showInFinderAction:)
+ keyEquivalent:@""];
+ NSMenuItem *openFilesItem = [[NSMenuItem alloc] initWithTitle:multiple? @"Open Files" : @"Open File"
+ action:@selector(openFilesAction:)
+ keyEquivalent:@""];
+
+ NSArray *menuItems = [NSArray arrayWithObjects:historyItem, finderItem, openFilesItem, nil];
+ for (NSMenuItem *item in menuItems) {
+ [item setTarget:self];
+ [item setRepresentedObject:paths];
+ }
+
+ return menuItems;
+}
+
@end
diff --git a/PBGitHistoryView.xib b/PBGitHistoryView.xib
index 9861c21..3b7152f 100644
--- a/PBGitHistoryView.xib
+++ b/PBGitHistoryView.xib
@@ -9,7 +9,7 @@
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
- {{178, 79}, {852, 432}}
+ {{358, 67}, {852, 432}}
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
@@ -2988,7 +2988,7 @@
- 274
+ 286
@@ -3048,6 +3052,7 @@
commitList
fileBrowser
searchField
+ treeContextMenu
treeController
webView
@@ -3057,6 +3062,7 @@
NSTableView
NSOutlineView
NSSearchField
+ NSMenu
NSTreeController
id
diff --git a/PBGitIndexController.m b/PBGitIndexController.m
index 382f48f..4d3cc78 100644
--- a/PBGitIndexController.m
+++ b/PBGitIndexController.m
@@ -157,8 +157,18 @@
return [commitController.repository outputInWorkdirForArguments:[NSArray arrayWithObjects:@"diff-files", [self contextParameter], @"--", file.path, nil]];
}
-- (void) forceRevertChangesForFiles:(NSArray *)files
+- (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"];
@@ -166,7 +176,7 @@
int ret = 1;
[commitController.repository outputForArguments:arguments inputString:input retValue:&ret];
if (ret) {
- [[commitController.repository windowController] showMessageSheet:@"Reverting changes failed" infoText:[NSString stringWithFormat:@"Reverting changes failed with error code %i", ret]];
+ [[commitController.repository windowController] showMessageSheet:@"Discarding changes failed" infoText:[NSString stringWithFormat:@"Discarding changes failed with error code %i", ret]];
return;
}
@@ -174,19 +184,6 @@
file.hasUnstagedChanges = NO;
}
-- (void) revertChangesForFiles:(NSArray *)files
-{
- int ret = [[NSAlert alertWithMessageText:@"Revert changes"
- defaultButton:nil
- alternateButton:@"Cancel"
- otherButton:nil
- informativeTextWithFormat:@"Are you sure you wish to revert changes?\n\nYou cannot undo this operation."] runModal];
-
- if (ret == NSAlertDefaultReturn)
- [self forceRevertChangesForFiles:files];
-}
-
-
# pragma mark Context Menu methods
- (BOOL) allSelectedCanBeIgnored:(NSArray *)selectedFiles
{
@@ -244,19 +241,19 @@
if (!file.hasUnstagedChanges)
return menu;
- NSMenuItem *revertItem = [[NSMenuItem alloc] initWithTitle:@"Revert Changes…" action:@selector(revertFilesAction:) keyEquivalent:@""];
- [revertItem setTarget:self];
- [revertItem setAlternate:NO];
- [revertItem setRepresentedObject:selectedFiles];
+ NSMenuItem *discardItem = [[NSMenuItem alloc] initWithTitle:@"Discard changes" action:@selector(discardFilesAction:) keyEquivalent:@""];
+ [discardItem setTarget:self];
+ [discardItem setAlternate:NO];
+ [discardItem setRepresentedObject:selectedFiles];
- [menu addItem:revertItem];
+ [menu addItem:discardItem];
- NSMenuItem *revertForceItem = [[NSMenuItem alloc] initWithTitle:@"Revert Changes" action:@selector(forceRevertFilesAction:) keyEquivalent:@""];
- [revertForceItem setTarget:self];
- [revertForceItem setAlternate:YES];
- [revertForceItem setRepresentedObject:selectedFiles];
- [revertForceItem setKeyEquivalentModifierMask:NSAlternateKeyMask];
- [menu addItem:revertForceItem];
+ NSMenuItem *discardForceItem = [[NSMenuItem alloc] initWithTitle:@"Discard changes" action:@selector(forceDiscardFilesAction:) keyEquivalent:@""];
+ [discardForceItem setTarget:self];
+ [discardForceItem setAlternate:YES];
+ [discardForceItem setRepresentedObject:selectedFiles];
+ [discardForceItem setKeyEquivalentModifierMask:NSAlternateKeyMask];
+ [menu addItem:discardForceItem];
return menu;
}
@@ -288,18 +285,18 @@
[commitController refresh:NULL];
}
-- (void) revertFilesAction:(id) sender
+- (void)discardFilesAction:(id) sender
{
NSArray *selectedFiles = [sender representedObject];
if ([selectedFiles count] > 0)
- [self revertChangesForFiles:selectedFiles];
+ [self discardChangesForFiles:selectedFiles force:FALSE];
}
-- (void) forceRevertFilesAction:(id) sender
+- (void)forceDiscardFilesAction:(id) sender
{
NSArray *selectedFiles = [sender representedObject];
if ([selectedFiles count] > 0)
- [self forceRevertChangesForFiles:selectedFiles];
+ [self discardChangesForFiles:selectedFiles force:TRUE];
}
- (void) showInFinderAction:(id) sender
diff --git a/PBGitRepository.m b/PBGitRepository.m
index 89691f9..821cd2a 100644
--- a/PBGitRepository.m
+++ b/PBGitRepository.m
@@ -72,10 +72,12 @@ NSString* PBGitRepositoryErrorDomain = @"GitXErrorDomain";
return repositoryURL;
}
-- (BOOL)readFromFileWrapper:(NSFileWrapper *)fileWrapper ofType:(NSString *)typeName error:(NSError **)outError
+// NSFileWrapper is broken and doesn't work when called on a directory containing a large number of directories and files.
+//because of this it is safer to implement readFromURL than readFromFileWrapper.
+//Because NSFileManager does not attempt to recursively open all directories and file when fileExistsAtPath is called
+//this works much better.
+- (BOOL)readFromURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError
{
- BOOL success = NO;
-
if (![PBGitBinary path])
{
if (outError) {
@@ -86,30 +88,32 @@ NSString* PBGitRepositoryErrorDomain = @"GitXErrorDomain";
return NO;
}
- if (![fileWrapper isDirectory]) {
+ BOOL isDirectory = FALSE;
+ [[NSFileManager defaultManager] fileExistsAtPath:[absoluteURL path] isDirectory:&isDirectory];
+ if (!isDirectory) {
if (outError) {
- NSDictionary* userInfo = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Reading files is not supported.", [fileWrapper filename]]
- forKey:NSLocalizedRecoverySuggestionErrorKey];
+ NSDictionary* userInfo = [NSDictionary dictionaryWithObject:@"Reading files is not supported."
+ forKey:NSLocalizedRecoverySuggestionErrorKey];
*outError = [NSError errorWithDomain:PBGitRepositoryErrorDomain code:0 userInfo:userInfo];
}
- } else {
- NSURL* gitDirURL = [PBGitRepository gitDirForURL:[self fileURL]];
- if (gitDirURL) {
- [self setFileURL:gitDirURL];
- success = YES;
- } else if (outError) {
- NSDictionary* userInfo = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"%@ does not appear to be a git repository.", [fileWrapper filename]]
- forKey:NSLocalizedRecoverySuggestionErrorKey];
- *outError = [NSError errorWithDomain:PBGitRepositoryErrorDomain code:0 userInfo:userInfo];
- }
-
- if (success) {
- [self setup];
- [self readCurrentBranch];
- }
+ return NO;
}
- return success;
+
+ NSURL* gitDirURL = [PBGitRepository gitDirForURL:[self fileURL]];
+ if (!gitDirURL) {
+ if (outError) {
+ NSDictionary* userInfo = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"%@ does not appear to be a git repository.", [self fileName]]
+ forKey:NSLocalizedRecoverySuggestionErrorKey];
+ *outError = [NSError errorWithDomain:PBGitRepositoryErrorDomain code:0 userInfo:userInfo];
+ }
+ return NO;
+ }
+
+ [self setFileURL:gitDirURL];
+ [self setup];
+ [self readCurrentBranch];
+ return YES;
}
- (void) setup
diff --git a/PBQLOutlineView.m b/PBQLOutlineView.m
index 4e620bd..459d908 100644
--- a/PBQLOutlineView.m
+++ b/PBQLOutlineView.m
@@ -58,6 +58,25 @@
return fileNames;
}
+- (NSMenu *)menuForEvent:(NSEvent *)theEvent
+{
+ if ([theEvent type] == NSRightMouseDown)
+ {
+ // get the current selections for the outline view.
+ NSIndexSet *selectedRowIndexes = [self selectedRowIndexes];
+
+ // select the row that was clicked before showing the menu for the event
+ NSPoint mousePoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
+ int row = [self rowAtPoint:mousePoint];
+
+ // figure out if the row that was just clicked on is currently selected
+ if ([selectedRowIndexes containsIndex:row] == NO)
+ [self selectRow:row byExtendingSelection:NO];
+ }
+
+ return [controller contextMenuForTreeView];
+}
+
/* Implemented to satisfy datasourcee protocol */
- (BOOL) outlineView: (NSOutlineView *)ov
isItemExpandable: (id)item { return NO; }
diff --git a/PBWebHistoryController.m b/PBWebHistoryController.m
index 0f553b3..35979a4 100644
--- a/PBWebHistoryController.m
+++ b/PBWebHistoryController.m
@@ -76,21 +76,23 @@ contextMenuItemsForElement:(NSDictionary *)element
{
DOMNode *node = [element valueForKey:@"WebElementDOMNode"];
- // If clicked on the text, select the containing div
- if ([[node className] isEqualToString:@"DOMText"])
+ while (node) {
+ // Every ref has a class name of 'refs' and some other class. We check on that to see if we pressed on a ref.
+ if ([[node className] hasPrefix:@"refs "]) {
+ NSString *selectedRefString = [[[node childNodes] item:0] textContent];
+ for (PBGitRef *ref in historyController.webCommit.refs)
+ {
+ if ([[ref shortName] isEqualToString:selectedRefString])
+ return [contextMenuDelegate menuItemsForRef:ref commit:historyController.webCommit];
+ }
+ NSLog(@"Could not find selected ref!");
+ return defaultMenuItems;
+ }
+ if ([node hasAttributes] && [[node attributes] getNamedItem:@"representedFile"])
+ return [historyController menuItemsForPaths:[NSArray arrayWithObject:[[[node attributes] getNamedItem:@"representedFile"] value]]];
+
node = [node parentNode];
-
- // Every ref has a class name of 'refs' and some other class. We check on that to see if we pressed on a ref.
- if (![[node className] hasPrefix:@"refs "])
- return defaultMenuItems;
-
- NSString *selectedRefString = [[[node childNodes] item:0] textContent];
- for (PBGitRef *ref in historyController.webCommit.refs)
- {
- if ([[ref shortName] isEqualToString:selectedRefString])
- return [contextMenuDelegate menuItemsForRef:ref commit:historyController.webCommit];
}
- NSLog(@"Could not find selected ref!");
return defaultMenuItems;
}
diff --git a/Site/templates/site.html b/Site/templates/site.html
index c1001b6..c308843 100644
--- a/Site/templates/site.html
+++ b/Site/templates/site.html
@@ -40,7 +40,7 @@ end
<%= @body %>