diff --git a/PBGitDefaults.h b/PBGitDefaults.h
index c7c494a..46b28b5 100644
--- a/PBGitDefaults.h
+++ b/PBGitDefaults.h
@@ -34,5 +34,7 @@
+ (void) removePreviousDocumentPaths;
+ (NSInteger) branchFilter;
+ (void) setBranchFilter:(NSInteger)state;
++ (NSInteger)historySearchMode;
++ (void)setHistorySearchMode:(NSInteger)mode;
@end
diff --git a/PBGitDefaults.m b/PBGitDefaults.m
index 0e042a5..ccc2162 100644
--- a/PBGitDefaults.m
+++ b/PBGitDefaults.m
@@ -7,6 +7,7 @@
//
#import "PBGitDefaults.h"
+#import "PBHistorySearchController.h"
#define kDefaultVerticalLineLength 50
#define kCommitMessageViewVerticalLineLength @"PBCommitMessageViewVerticalLineLength"
@@ -25,6 +26,7 @@
#define kOpenPreviousDocumentsOnLaunch @"PBOpenPreviousDocumentsOnLaunch"
#define kPreviousDocumentPaths @"PBPreviousDocumentPaths"
#define kBranchFilterState @"PBBranchFilter"
+#define kHistorySearchMode @"PBHistorySearchMode"
@implementation PBGitDefaults
@@ -53,6 +55,8 @@
forKey:kShouldCheckoutBranch];
[defaultValues setObject:[NSNumber numberWithBool:NO]
forKey:kOpenPreviousDocumentsOnLaunch];
+ [defaultValues setObject:[NSNumber numberWithInteger:kGitXBasicSeachMode]
+ forKey:kHistorySearchMode];
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultValues];
}
@@ -170,4 +174,15 @@
[[NSUserDefaults standardUserDefaults] setInteger:state forKey:kBranchFilterState];
}
++ (NSInteger)historySearchMode
+{
+ return [[NSUserDefaults standardUserDefaults] integerForKey:kHistorySearchMode];
+}
+
++ (void)setHistorySearchMode:(NSInteger)mode
+{
+ [[NSUserDefaults standardUserDefaults] setInteger:mode forKey:kHistorySearchMode];
+}
+
+
@end
diff --git a/PBGitHistoryView.xib b/PBGitHistoryView.xib
index b6bf807..f9e2774 100644
--- a/PBGitHistoryView.xib
+++ b/PBGitHistoryView.xib
@@ -702,6 +702,15 @@
266
+
+
+ progressIndicator
+
+
+
+ 448
+
@@ -2439,6 +2456,7 @@
+
Commits Scope Bar
@@ -2695,6 +2713,11 @@
+
+ 447
+
+
+
@@ -2803,6 +2826,7 @@
428.IBSegmentedControlInspectorSelectedSegmentMetadataKey
430.IBPluginDependency
431.IBPluginDependency
+ 447.IBPluginDependency
46.IBEditorWindowLastContentRect
46.IBPluginDependency
48.IBPluginDependency
@@ -2987,6 +3011,7 @@
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
{{9, 486}, {852, 432}}
com.apple.InterfaceBuilder.CocoaPlugin
com.apple.InterfaceBuilder.CocoaPlugin
@@ -3023,7 +3048,7 @@
- 437
+ 448
@@ -3480,6 +3505,9 @@
YES
YES
+ selectBasicSearch:
+ selectPickaxeSearch:
+ selectRegexSearch:
stepperPressed:
updateSearch:
@@ -3487,17 +3515,35 @@
YES
id
id
+ id
+ id
+ id
YES
YES
+ selectBasicSearch:
+ selectPickaxeSearch:
+ selectRegexSearch:
stepperPressed:
updateSearch:
YES
+
+ selectBasicSearch:
+ id
+
+
+ selectPickaxeSearch:
+ id
+
+
+ selectRegexSearch:
+ id
+
stepperPressed:
id
@@ -3515,6 +3561,7 @@
commitController
historyController
numberOfMatchesField
+ progressIndicator
searchField
stepper
@@ -3523,6 +3570,7 @@
NSArrayController
PBGitHistoryController
NSTextField
+ NSProgressIndicator
NSSearchField
NSSegmentedControl
@@ -3534,6 +3582,7 @@
commitController
historyController
numberOfMatchesField
+ progressIndicator
searchField
stepper
@@ -3551,6 +3600,10 @@
numberOfMatchesField
NSTextField
+
+ progressIndicator
+ NSProgressIndicator
+
searchField
NSSearchField
@@ -4360,13 +4413,6 @@
QuartzCore.framework/Headers/CIImageProvider.h
-
- NSObject
-
- IBFrameworkSource
- ScriptingBridge.framework/Headers/SBApplication.h
-
-
NSObject
@@ -4472,6 +4518,14 @@
AppKit.framework/Headers/NSPopUpButton.h
+
+ NSProgressIndicator
+ NSView
+
+ IBFrameworkSource
+ AppKit.framework/Headers/NSProgressIndicator.h
+
+
NSResponder
diff --git a/PBHistorySearchController.h b/PBHistorySearchController.h
index 75bd250..e51ba47 100644
--- a/PBHistorySearchController.h
+++ b/PBHistorySearchController.h
@@ -9,6 +9,13 @@
#import
+typedef enum historySearchModes {
+ kGitXBasicSeachMode = 1,
+ kGitXPickaxeSearchMode,
+ kGitXRegexSearchMode,
+ kGitXMaxSearchMode // always keep this item last
+} PBHistorySearchMode;
+
@class PBGitHistoryController;
@@ -16,11 +23,16 @@
PBGitHistoryController *historyController;
NSArrayController *commitController;
+ PBHistorySearchMode searchMode;
NSIndexSet *results;
NSSearchField *searchField;
NSSegmentedControl *stepper;
NSTextField *numberOfMatchesField;
+ NSProgressIndicator *progressIndicator;
+ NSTimer *searchTimer;
+
+ NSTask *backgroundSearchTask;
NSPanel *rewindPanel;
}
@@ -31,11 +43,16 @@
@property (assign) IBOutlet NSSearchField *searchField;
@property (assign) IBOutlet NSSegmentedControl *stepper;
@property (assign) IBOutlet NSTextField *numberOfMatchesField;
+@property (assign) IBOutlet NSProgressIndicator *progressIndicator;
+
+@property (assign) PBHistorySearchMode searchMode;
- (BOOL)isRowInSearchResults:(NSInteger)rowIndex;
- (BOOL)hasSearchResults;
+- (void)selectSearchMode:(id)sender;
+
- (void)selectNextResult;
- (void)selectPreviousResult;
- (IBAction)stepperPressed:(id)sender;
diff --git a/PBHistorySearchController.m b/PBHistorySearchController.m
index 1aa3313..8a48320 100644
--- a/PBHistorySearchController.m
+++ b/PBHistorySearchController.m
@@ -9,6 +9,7 @@
#import "PBHistorySearchController.h"
#import "PBGitHistoryController.h"
#import "PBGitRepository.h"
+#import "PBGitDefaults.h"
#import
@@ -20,6 +21,8 @@
- (void)setupSearchMenuTemplate;
- (void)startBasicSearch;
+- (void)startBackgroundSearch;
+- (void)clearProgressIndicator;
- (void)showSearchRewindPanelReverse:(BOOL)isReversed;
@@ -30,6 +33,8 @@
#define kGitXSearchDirectionPrevious -1
#define kGitXBasicSearchLabel @"Subject, Author, SHA"
+#define kGitXPickaxeSearchLabel @"Commit (pickaxe)"
+#define kGitXRegexSearchLabel @"Commit (pickaxe regex)"
#define kGitXSearchArrangedObjectsContext @"GitXSearchArrangedObjectsContext"
@@ -42,6 +47,9 @@
@synthesize searchField;
@synthesize stepper;
@synthesize numberOfMatchesField;
+@synthesize progressIndicator;
+
+@synthesize searchMode;
@@ -58,6 +66,12 @@
return ([results count] > 0);
}
+- (void)selectSearchMode:(id)sender
+{
+ self.searchMode = [sender tag];
+ [self updateSearch:self];
+}
+
- (void)selectNextResult
{
[self selectNextResultInDirection:kGitXSearchDirectionNext];
@@ -90,13 +104,16 @@
- (IBAction)updateSearch:(id)sender
{
- [self startBasicSearch];
+ if (self.searchMode == kGitXBasicSeachMode)
+ [self startBasicSearch];
+ else
+ [self startBackgroundSearch];
}
- (void)awakeFromNib
{
[self setupSearchMenuTemplate];
- [[searchField cell] setPlaceholderString:@"Subject, Author, SHA"];
+ self.searchMode = [PBGitDefaults historySearchMode];
[self updateUI];
@@ -181,6 +198,7 @@
[stepper setHidden:NO];
[historyController.commitList reloadData];
}
+ [self clearProgressIndicator];
}
// changes the selection to the next match after the current selected row unless the current row is already a match
@@ -203,6 +221,24 @@
NSMenu *searchMenu = [[NSMenu alloc] initWithTitle:@"Search Menu"];
NSMenuItem *item;
+ item = [[NSMenuItem alloc] initWithTitle:kGitXBasicSearchLabel action:@selector(selectSearchMode:) keyEquivalent:@""];
+ [item setTarget:self];
+ [item setTag:kGitXBasicSeachMode];
+ [searchMenu addItem:item];
+
+ item = [[NSMenuItem alloc] initWithTitle:kGitXPickaxeSearchLabel action:@selector(selectSearchMode:) keyEquivalent:@""];
+ [item setTarget:self];
+ [item setTag:kGitXPickaxeSearchMode];
+ [searchMenu addItem:item];
+
+ item = [[NSMenuItem alloc] initWithTitle:kGitXRegexSearchLabel action:@selector(selectSearchMode:) keyEquivalent:@""];
+ [item setTarget:self];
+ [item setTag:kGitXRegexSearchMode];
+ [searchMenu addItem:item];
+
+ item = [NSMenuItem separatorItem];
+ [searchMenu addItem:item];
+
item = [[NSMenuItem alloc] initWithTitle:@"Recent Searches" action:NULL keyEquivalent:@""];
[item setTag:NSSearchFieldRecentsTitleMenuItemTag];
[searchMenu addItem:item];
@@ -226,6 +262,77 @@
[[searchField cell] setSearchMenuTemplate:searchMenu];
}
+- (void)updateSearchMenuState
+{
+ NSMenu *searchMenu = [[searchField cell] searchMenuTemplate];
+ if (!searchMenu)
+ return;
+
+ NSMenuItem *item;
+
+ item = [searchMenu itemWithTag:kGitXBasicSeachMode];
+ [item setState:(searchMode == kGitXBasicSeachMode) ? NSOnState : NSOffState];
+
+ item = [searchMenu itemWithTag:kGitXPickaxeSearchMode];
+ [item setState:(searchMode == kGitXPickaxeSearchMode) ? NSOnState : NSOffState];
+
+ item = [searchMenu itemWithTag:kGitXRegexSearchMode];
+ [item setState:(searchMode == kGitXRegexSearchMode) ? NSOnState : NSOffState];
+
+ [[searchField cell] setSearchMenuTemplate:searchMenu];
+
+ [PBGitDefaults setHistorySearchMode:searchMode];
+}
+
+- (void)updateSearchPlaceholderString
+{
+ switch (self.searchMode) {
+ case kGitXPickaxeSearchMode:
+ [[searchField cell] setPlaceholderString:kGitXPickaxeSearchLabel];
+ break;
+ case kGitXRegexSearchMode:
+ [[searchField cell] setPlaceholderString:kGitXRegexSearchLabel];
+ break;
+ default:
+ [[searchField cell] setPlaceholderString:kGitXBasicSearchLabel];
+ break;
+ }
+}
+
+- (void)setSearchMode:(PBHistorySearchMode)mode
+{
+ if ((mode < kGitXBasicSeachMode) || (mode >= kGitXMaxSearchMode))
+ mode = kGitXBasicSeachMode;
+
+ searchMode = mode;
+ [PBGitDefaults setHistorySearchMode:searchMode];
+
+ [self updateSearchMenuState];
+ [self updateSearchPlaceholderString];
+}
+
+- (void)searchTimerFired:(NSTimer*)theTimer
+{
+ [self.progressIndicator setHidden:NO];
+ [self.progressIndicator startAnimation:self];
+}
+
+- (void)clearProgressIndicator
+{
+ [searchTimer invalidate];
+ searchTimer = nil;
+ [self.progressIndicator setHidden:YES];
+ [self.progressIndicator stopAnimation:self];
+}
+
+- (void)startProgressIndicator
+{
+ [self clearProgressIndicator];
+ [numberOfMatchesField setHidden:YES];
+ [stepper setHidden:YES];
+ searchTimer = [NSTimer scheduledTimerWithTimeInterval:0.25 target:self selector:@selector(searchTimerFired:) userInfo:nil repeats:NO];
+}
+
#pragma mark Basic Search
@@ -255,6 +362,67 @@
+#pragma mark Pickaxe/Regex Search
+
+- (void)startBackgroundSearch
+{
+ if (backgroundSearchTask) {
+ NSFileHandle *handle = [[backgroundSearchTask standardOutput] fileHandleForReading];
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:NSFileHandleReadToEndOfFileCompletionNotification object:handle];
+ [backgroundSearchTask terminate];
+ }
+
+ NSString *searchString = [[searchField stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+ if ([searchString isEqualToString:@""]) {
+ [self clearSearch];
+ return;
+ }
+
+ results = nil;
+
+ NSMutableArray *searchArguments = [NSMutableArray arrayWithObjects:@"log", @"--pretty=format:%H", [NSString stringWithFormat:@"-S%@", searchString], nil];
+ if (self.searchMode == kGitXRegexSearchMode)
+ [searchArguments insertObject:@"--pickaxe-regex" atIndex:1];
+
+ backgroundSearchTask = [PBEasyPipe taskForCommand:[PBGitBinary path] withArgs:searchArguments inDir:[[historyController.repository fileURL] path]];
+ [backgroundSearchTask launch];
+
+ NSFileHandle *handle = [[backgroundSearchTask standardOutput] fileHandleForReading];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(parseBackgroundSearchResults:) name:NSFileHandleReadToEndOfFileCompletionNotification object:handle];
+ [handle readToEndOfFileInBackgroundAndNotify];
+
+ [self startProgressIndicator];
+}
+
+- (void)parseBackgroundSearchResults:(NSNotification *)notification
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:NSFileHandleReadToEndOfFileCompletionNotification object:[notification object]];
+ backgroundSearchTask = nil;
+
+ NSMutableIndexSet *indexes = [NSMutableIndexSet indexSet];
+ NSData *data = [[notification userInfo] valueForKey:NSFileHandleNotificationDataItem];
+
+ NSString *resultsString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+ NSArray *resultsArray = [resultsString componentsSeparatedByString:@"\n"];
+
+ for (NSString *resultSHA in resultsArray) {
+ NSUInteger index = 0;
+ for (PBGitCommit *commit in [commitController arrangedObjects]) {
+ if ([resultSHA isEqualToString:commit.sha.string]) {
+ [indexes addIndex:index];
+ break;
+ }
+ index++;
+ }
+ }
+
+ results = indexes;
+ [self clearProgressIndicator];
+ [self updateSelectedResult];
+}
+
+
+
#pragma mark -
#pragma mark Rewind Panel