aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBibiko <bibiko@eva.mpg.de>2010-01-21 00:00:36 +0000
committerBibiko <bibiko@eva.mpg.de>2010-01-21 00:00:36 +0000
commitd6097cbbb95c78fa16b7bd0305a494186c5dd583 (patch)
tree051104bad253357df2036975e992786275e0a211
parenta485d370c24cb6378a52c3452dc0cdbadfefd50f (diff)
downloadsequelpro-d6097cbbb95c78fa16b7bd0305a494186c5dd583.tar.gz
sequelpro-d6097cbbb95c78fa16b7bd0305a494186c5dd583.tar.bz2
sequelpro-d6097cbbb95c78fa16b7bd0305a494186c5dd583.zip
• completion enhancements
- TAB and mouse double-click inserts suggestion - field type info for 'set' and 'enum' is fixed; in addition show an arrow to show the definition - preparations for fuzzy search completion (not yet active) - reduced the font size by 1pt to avoid truncating
-rw-r--r--Source/CMTextView.h2
-rw-r--r--Source/CMTextView.m53
-rw-r--r--Source/SPNarrowDownCompletion.h8
-rw-r--r--Source/SPNarrowDownCompletion.m122
4 files changed, 147 insertions, 38 deletions
diff --git a/Source/CMTextView.h b/Source/CMTextView.h
index 80515928..868e7093 100644
--- a/Source/CMTextView.h
+++ b/Source/CMTextView.h
@@ -87,7 +87,7 @@ static inline void NSMutableAttributedStringAddAttributeValueRange (NSMutableAtt
- (void) autoHelp;
- (void) doSyntaxHighlighting;
- (void) setConnection:(MCPConnection *)theConnection withVersion:(NSInteger)majorVersion;
-- (void) doCompletionByUsingSpellChecker:(BOOL)isDictMode;
+- (void) doCompletionByUsingSpellChecker:(BOOL)isDictMode fuzzyMode:(BOOL)fuzzySearch;
- (NSArray *)suggestionsForSQLCompletionWith:(NSString *)currentWord dictMode:(BOOL)isDictMode browseMode:(BOOL)dbBrowseMode withTableName:(NSString*)aTableName withDbName:(NSString*)aDbName;
- (void) selectCurrentQuery;
diff --git a/Source/CMTextView.m b/Source/CMTextView.m
index 6df89d03..1cceac97 100644
--- a/Source/CMTextView.m
+++ b/Source/CMTextView.m
@@ -270,7 +270,7 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
if(aTableNameExists) {
[sortedTables addObject:aTableName];
} else {
- [possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:db, @"display", @"database-small", @"image", @"", @"isRef", nil]];
+ [possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:db, @"display", @"database-small", @"image", db, @"isRef", nil]];
[sortedTables addObjectsFromArray:[allTables sortedArrayUsingDescriptors:[NSArray arrayWithObject:desc]]];
if([sortedTables count] > 1 && [sortedTables containsObject:currentTable]) {
[sortedTables removeObject:currentTable];
@@ -285,17 +285,17 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
if(!aTableNameExists)
switch(structtype) {
case 0:
- [possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:table, @"display", @"table-small-square", @"image", db, @"path", @"", @"isRef", nil]];
+ [possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:table, @"display", @"table-small-square", @"image", db, @"path", [NSString stringWithFormat:@"%@.%@",db,table], @"isRef", nil]];
break;
case 1:
- [possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:table, @"display", @"table-view-small-square", @"image", db, @"path", @"", @"isRef", nil]];
+ [possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:table, @"display", @"table-view-small-square", @"image", db, @"path", [NSString stringWithFormat:@"%@.%@",db,table], @"isRef", nil]];
break;
case 2:
- [possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:table, @"display", @"proc-small", @"image", db, @"path", nil]];
+ [possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:table, @"display", @"proc-small", @"image", db, @"path", [NSString stringWithFormat:@"%@.%@",db,table], @"isRef", nil]];
breakFlag = YES;
break;
case 3:
- [possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:table, @"display", @"func-small", @"image", db, @"path", nil]];
+ [possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:table, @"display", @"func-small", @"image", db, @"path", [NSString stringWithFormat:@"%@.%@",db,table], @"isRef", nil]];
breakFlag = YES;
break;
}
@@ -303,7 +303,27 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
NSArray *sortedFields = [allFields sortedArrayUsingDescriptors:[NSArray arrayWithObject:desc]];
for(id field in sortedFields) {
if(![field hasPrefix:@" "]) {
- [possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:field, @"display", @"field-small-square", @"image", [NSString stringWithFormat:@"%@⇠%@",table,db], @"path", [theTable objectForKey:field], @"type", @"", @"isRef", nil]];
+ NSString *typ = [theTable objectForKey:field];
+ if(typ && [typ hasPrefix:@"set("] || [typ hasPrefix:@"enum("]) {
+ NSString *t = [typ stringByReplacingOccurrencesOfRegex:@"\\(.*?\\)" withString:@"(…)"];
+ NSString *lst = [typ stringByMatching:@"\\(([^\\)]*?)\\)" capture:1L];
+ [possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:
+ field, @"display",
+ @"field-small-square", @"image",
+ [NSString stringWithFormat:@"%@⇠%@",table,db], @"path",
+ t, @"type",
+ lst, @"list",
+ [NSString stringWithFormat:@"%@.%@.%@",db,table,field], @"isRef",
+ nil]];
+ } else {
+ [possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:
+ field, @"display",
+ @"field-small-square", @"image",
+ [NSString stringWithFormat:@"%@⇠%@",table,db], @"path",
+ typ, @"type",
+ [NSString stringWithFormat:@"%@.%@.%@",db,table,field], @"isRef",
+ nil]];
+ }
}
}
}
@@ -361,13 +381,14 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
}
-- (void) doCompletionByUsingSpellChecker:(BOOL)isDictMode
+- (void) doCompletionByUsingSpellChecker:(BOOL)isDictMode fuzzyMode:(BOOL)fuzzySearch
{
// No completion for a selection (yet?) and if caret positiopn == 0
if([self selectedRange].length > 0 || ![self selectedRange].location) return;
NSInteger caretPos = [self selectedRange].location;
+ BOOL caretMovedLeft = NO;
// Check if caret is located after a ` - if so move caret inside
if([[self string] characterAtIndex:caretPos-1] == '`') {
@@ -375,6 +396,7 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
;
} else {
caretPos--;
+ caretMovedLeft = YES;
[self setSelectedRange:NSMakeRange(caretPos, 0)];
}
}
@@ -517,6 +539,12 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
tableName = [tableName substringFromIndex:2];
}
+ if(fuzzySearch) {
+ filter = [[NSString stringWithString:[[self string] substringWithRange:parseRange]] stringByReplacingOccurrencesOfString:@"`" withString:@""];
+ if([filter length]>15) return;
+ completionRange = parseRange;
+ }
+
} else {
filter = [NSString stringWithString:currentWord];
}
@@ -534,10 +562,12 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
inView:self
dictMode:isDictMode
dbMode:dbBrowseMode
+ fuzzySearch:fuzzySearch
backtickMode:backtickMode
withDbName:dbName
withTableName:tableName
- selectedDb:currentDb];
+ selectedDb:currentDb
+ caretMovedLeft:caretMovedLeft];
//Get the NSPoint of the first character of the current word
NSRange glyphRange = [[self layoutManager] glyphRangeForCharacterRange:NSMakeRange(completionRange.location,1) actualCharacterRange:NULL];
@@ -784,14 +814,17 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse)
long curFlags = ([theEvent modifierFlags] & allFlags);
if ([theEvent keyCode] == 53){ // ESC key for internal completion
- [self doCompletionByUsingSpellChecker:NO];
+ // if(curFlags==(NSControlKeyMask))
+ // [self doCompletionByUsingSpellChecker:NO fuzzyMode:YES];
+ // else
+ [self doCompletionByUsingSpellChecker:NO fuzzyMode:NO];
// Remove that attribute to suppress auto-uppercasing of certain keyword combinations
if(![self selectedRange].length && [self selectedRange].location)
[[self textStorage] removeAttribute:kSQLkeyword range:[self getRangeForCurrentWord]];
return;
}
if (insertedCharacter == NSF5FunctionKey){ // F5 for completion based on spell checker
- [self doCompletionByUsingSpellChecker:YES];
+ [self doCompletionByUsingSpellChecker:YES fuzzyMode:NO];
// Remove that attribute to suppress auto-uppercasing of certain keyword combinations
if(![self selectedRange].length && [self selectedRange].location)
[[self textStorage] removeAttribute:kSQLkeyword range:[self getRangeForCurrentWord]];
diff --git a/Source/SPNarrowDownCompletion.h b/Source/SPNarrowDownCompletion.h
index 06f9264a..f8f12a83 100644
--- a/Source/SPNarrowDownCompletion.h
+++ b/Source/SPNarrowDownCompletion.h
@@ -44,12 +44,15 @@
BOOL caseSensitive;
BOOL dictMode;
BOOL dbStructureMode;
+ BOOL fuzzyMode;
BOOL noFilterString;
+ BOOL cursorMovedLeft;
NSInteger backtickMode;
NSFont *tableFont;
NSRange theCharRange;
NSRange theParseRange;
NSString *theDbName;
+
id theView;
NSInteger maxWindowWidth;
@@ -60,8 +63,9 @@
- (id)initWithItems:(NSArray*)someSuggestions alreadyTyped:(NSString*)aUserString staticPrefix:(NSString*)aStaticPrefix
additionalWordCharacters:(NSString*)someAdditionalWordCharacters caseSensitive:(BOOL)isCaseSensitive
charRange:(NSRange)initRange parseRange:(NSRange)parseRange inView:(id)aView
- dictMode:(BOOL)mode dbMode:(BOOL)theDbMode
- backtickMode:(NSInteger)theBackTickMode withDbName:(NSString*)dbName withTableName:(NSString*)tableName selectedDb:(NSString*)selectedDb;
+ dictMode:(BOOL)mode dbMode:(BOOL)theDbMode fuzzySearch:(BOOL)fuzzySearch
+ backtickMode:(NSInteger)theBackTickMode withDbName:(NSString*)dbName withTableName:(NSString*)tableName
+ selectedDb:(NSString*)selectedDb caretMovedLeft:(BOOL)caretMovedLeft;
- (void)setCaretPos:(NSPoint)aPos;
- (void)insert_text:(NSString* )aString;
- (void)insertCommonPrefix;
diff --git a/Source/SPNarrowDownCompletion.m b/Source/SPNarrowDownCompletion.m
index 12d3532f..80d8c20c 100644
--- a/Source/SPNarrowDownCompletion.m
+++ b/Source/SPNarrowDownCompletion.m
@@ -131,8 +131,9 @@
- (id)initWithItems:(NSArray*)someSuggestions alreadyTyped:(NSString*)aUserString staticPrefix:(NSString*)aStaticPrefix
additionalWordCharacters:(NSString*)someAdditionalWordCharacters caseSensitive:(BOOL)isCaseSensitive
charRange:(NSRange)initRange parseRange:(NSRange)parseRange inView:(id)aView
- dictMode:(BOOL)mode dbMode:(BOOL)theDbMode
- backtickMode:(NSInteger)theBackTickMode withDbName:(NSString*)dbName withTableName:(NSString*)tableName selectedDb:(NSString*)selectedDb
+ dictMode:(BOOL)mode dbMode:(BOOL)theDbMode fuzzySearch:(BOOL)fuzzySearch
+ backtickMode:(NSInteger)theBackTickMode withDbName:(NSString*)dbName withTableName:(NSString*)tableName
+ selectedDb:(NSString*)selectedDb caretMovedLeft:(BOOL)caretMovedLeft
{
if(self = [self init])
{
@@ -141,8 +142,14 @@
if(aUserString)
[mutablePrefix appendString:aUserString];
+ fuzzyMode = fuzzySearch;
+ if(fuzzyMode)
+ [theTableView setBackgroundColor:[NSColor colorWithCalibratedRed:0.9f green:0.9f blue:0.9f alpha:1.0f]];
+ else
+ [theTableView setBackgroundColor:[NSColor whiteColor]];
+
dbStructureMode = theDbMode;
-
+ cursorMovedLeft = caretMovedLeft;
backtickMode = theBackTickMode;
if(aStaticPrefix)
@@ -202,7 +209,7 @@
- (void)setupInterface
{
[self setReleasedWhenClosed:YES];
- [self setLevel:NSStatusWindowLevel];
+ [self setLevel:NSNormalWindowLevel];
[self setHidesOnDeactivate:YES];
[self setHasShadow:YES];
[self setAlphaValue:0.9];
@@ -233,17 +240,21 @@
[theTableView addTableColumn:column1];
[column1 setWidth:170];
- NSTableColumn *column2 = [[[NSTableColumn alloc] initWithIdentifier:@"type"] autorelease];
+ NSTableColumn *column3 = [[[NSTableColumn alloc] initWithIdentifier:@"type"] autorelease];
+ [column3 setEditable:NO];
+ [theTableView addTableColumn:column3];
+ [column3 setWidth:139];
+
+ NSTableColumn *column2 = [[[NSTableColumn alloc] initWithIdentifier:@"list"] autorelease];
[column2 setEditable:NO];
- [[column2 dataCell] setTextColor:[NSColor darkGrayColor]];
[theTableView addTableColumn:column2];
- [column2 setWidth:145];
+ [column0 setMinWidth:0];
+ [column2 setWidth:6];
- NSTableColumn *column3 = [[[NSTableColumn alloc] initWithIdentifier:@"path"] autorelease];
- [column3 setEditable:NO];
- [[column3 dataCell] setTextColor:[NSColor darkGrayColor]];
- [theTableView addTableColumn:column3];
- [column3 setWidth:95];
+ NSTableColumn *column4 = [[[NSTableColumn alloc] initWithIdentifier:@"path"] autorelease];
+ [column4 setEditable:NO];
+ [theTableView addTableColumn:column4];
+ [column4 setWidth:95];
[theTableView setDataSource:self];
[scrollView setDocumentView:theTableView];
@@ -274,8 +285,34 @@
return @"";
} else if([[aTableColumn identifier] isEqualToString:@"name"]) {
+ // NSTextFieldCell *b = [[[NSTextFieldCell new] initTextCell:[[filtered objectAtIndex:rowIndex] objectForKey:@"display"]] autorelease];
+ [[aTableColumn dataCell] setFont:[NSFont systemFontOfSize:12]];
return [[filtered objectAtIndex:rowIndex] objectForKey:@"display"];
+ } else if ([[aTableColumn identifier] isEqualToString:@"list"]) {
+ if(dictMode) {
+ return @"";
+ } else {
+ if([[filtered objectAtIndex:rowIndex] objectForKey:@"list"]) {
+ NSPopUpButtonCell *b = [[NSPopUpButtonCell new] autorelease];
+ [b setPullsDown:NO];
+ [b setAltersStateOfSelectedItem:NO];
+ [b setControlSize:NSMiniControlSize];
+ NSMenu *m = [[NSMenu alloc] init];
+ [m addItemWithTitle:[[filtered objectAtIndex:rowIndex] objectForKey:@"list"] action:NULL keyEquivalent:@""];
+ [b setMenu:m];
+ [m release];
+ [b setPreferredEdge:NSMinXEdge];
+ [b setArrowPosition:NSPopUpArrowAtCenter];
+ [b setFont:[NSFont systemFontOfSize:11]];
+ [b setBordered:NO];
+ [aTableColumn setDataCell:b];
+ } else {
+ [aTableColumn setDataCell:[[NSTextFieldCell new] autorelease]];
+ }
+ return @"";
+ }
+
} else if([[aTableColumn identifier] isEqualToString:@"type"]) {
if(dictMode) {
return @"";
@@ -284,6 +321,7 @@
// return ([[filtered objectAtIndex:rowIndex] objectForKey:@"type"]) ? [[filtered objectAtIndex:rowIndex] objectForKey:@"type"] : @"";
NSTokenFieldCell *b = [[[NSTokenFieldCell alloc] initTextCell:([[filtered objectAtIndex:rowIndex] objectForKey:@"type"]) ? [[filtered objectAtIndex:rowIndex] objectForKey:@"type"] : @""] autorelease];
[b setEditable:NO];
+ [b setAlignment:NSRightTextAlignment];
[b setFont:[NSFont systemFontOfSize:11]];
[b setDelegate:self];
return b;
@@ -342,17 +380,45 @@
NSMutableArray* newFiltered = [[NSMutableArray alloc] initWithCapacity:5];
if([mutablePrefix length] > 0)
{
- NSPredicate* predicate;
- if(caseSensitive)
- predicate = [NSPredicate predicateWithFormat:@"match BEGINSWITH %@ OR (match == NULL AND display BEGINSWITH %@)", [self filterString], [self filterString]];
- else
- predicate = [NSPredicate predicateWithFormat:@"match BEGINSWITH[c] %@ OR (match == NULL AND display BEGINSWITH[c] %@)", [self filterString], [self filterString]];
- [newFiltered addObjectsFromArray:[suggestions filteredArrayUsingPredicate:predicate]];
if(dictMode) {
for(id w in [[NSSpellChecker sharedSpellChecker] completionsForPartialWordRange:NSMakeRange(0,[[self filterString] length]) inString:[self filterString] language:nil inSpellDocumentWithTag:0])
[newFiltered addObject:[NSDictionary dictionaryWithObjectsAndKeys:w, @"display", nil]];
} else {
- [self checkSpaceForAllowedCharacter];
+ @try{
+ NSPredicate* predicate;
+ if(fuzzyMode) {
+ NSMutableString *fuzzyRegexp = [[NSMutableString alloc] initWithCapacity:3];
+ [fuzzyRegexp setString:@".*"];
+ NSInteger i;
+ unichar c;
+ for(i=0; i<[[self filterString] length]; i++) {
+ if(i>20) break;
+ c = [[self filterString] characterAtIndex:i];
+ if(c != '`') {
+ if(c == '.' || c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}')
+ [fuzzyRegexp appendString:[NSString stringWithFormat:@"\\%c.*",c]];
+ else
+ [fuzzyRegexp appendString:[NSString stringWithFormat:@"%c.*",c]];
+ }
+ }
+ // NSLog(@"re %@", fuzzyRegexp);
+ if(caseSensitive)
+ predicate = [NSPredicate predicateWithFormat:@"display MATCHES %@ OR isRef MATCHES %@", fuzzyRegexp, fuzzyRegexp];
+ else
+ predicate = [NSPredicate predicateWithFormat:@"display MATCHES[c] %@ OR isRef MATCHES[c] %@", fuzzyRegexp, fuzzyRegexp];
+ [fuzzyRegexp release];
+ } else {
+ if(caseSensitive)
+ predicate = [NSPredicate predicateWithFormat:@"match BEGINSWITH %@ OR (match == NULL AND display BEGINSWITH %@)", [self filterString], [self filterString]];
+ else
+ predicate = [NSPredicate predicateWithFormat:@"match BEGINSWITH[c] %@ OR (match == NULL AND display BEGINSWITH[c] %@)", [self filterString], [self filterString]];
+ }
+ [newFiltered addObjectsFromArray:[suggestions filteredArrayUsingPredicate:predicate]];
+ }
+ @catch(id ae) {
+ NSLog(@"%@", @"Couldn't filter suggestion due to internal regexp error");
+ }
+
}
}
else
@@ -384,6 +450,8 @@
if (filtered) [filtered release];
filtered = [newFiltered retain];
[newFiltered release];
+ if(!dictMode)
+ [self checkSpaceForAllowedCharacter];
[theTableView reloadData];
}
@@ -459,7 +527,7 @@
{
break;
}
- else if(key == NSCarriageReturnCharacter)
+ else if(key == NSCarriageReturnCharacter || key == NSTabCharacter)
{
[self completeAndInsertSnippet];
}
@@ -491,15 +559,20 @@
}
else if(t == NSRightMouseDown || t == NSLeftMouseDown)
{
- [NSApp sendEvent:event];
- if(!NSPointInRect([NSEvent mouseLocation], [self frame]))
- break;
+ if(([event clickCount] == 2)) {
+ [self completeAndInsertSnippet];
+ } else {
+ [NSApp sendEvent:event];
+ if(!NSPointInRect([NSEvent mouseLocation], [self frame]))
+ break;
+ }
}
else
{
[NSApp sendEvent:event];
}
}
+ if(cursorMovedLeft) [theView performSelector:@selector(moveRight:)];
[self close];
usleep(70); // tiny delay to suppress while continously pressing of ESC overlapping
}
@@ -510,7 +583,7 @@
- (void)insertCommonPrefix
{
- if([theTableView selectedRow] == -1)
+ if([theTableView selectedRow] == -1 || fuzzyMode)
return;
id cur = [filtered objectAtIndex:0];
@@ -521,7 +594,6 @@
if(![curMatch length]) return;
- NSMutableArray* candidates = [NSMutableArray array];
NSMutableString *commonPrefix = [NSMutableString string];
[commonPrefix setString:curMatch];
for(id candidate in filtered) {