diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/CMTextView.h | 5 | ||||
-rw-r--r-- | Source/CMTextView.m | 1062 | ||||
-rw-r--r-- | Source/SPConstants.h | 1 | ||||
-rw-r--r-- | Source/SPConstants.m | 1 | ||||
-rw-r--r-- | Source/SPNarrowDownCompletion.h | 3 | ||||
-rw-r--r-- | Source/SPNarrowDownCompletion.m | 38 | ||||
-rw-r--r-- | Source/SPQueryController.h | 9 | ||||
-rw-r--r-- | Source/SPQueryController.m | 67 |
8 files changed, 161 insertions, 1025 deletions
diff --git a/Source/CMTextView.h b/Source/CMTextView.h index 558bc284..71799f26 100644 --- a/Source/CMTextView.h +++ b/Source/CMTextView.h @@ -74,6 +74,7 @@ static inline id NSMutableAttributedStringAttributeAtIndex (NSMutableAttributedS BOOL snippetWasJustInserted; BOOL completionIsOpen; + BOOL completionWasReinvokedAutomatically; NSColor *queryHiliteColor; NSColor *queryEditorBackgroundColor; @@ -101,6 +102,7 @@ static inline id NSMutableAttributedStringAttributeAtIndex (NSMutableAttributedS @property(assign) NSRange queryRange; @property(assign) BOOL shouldHiliteQuery; @property(assign) BOOL completionIsOpen; +@property(assign) BOOL completionWasReinvokedAutomatically; - (IBAction)showMySQLHelpForCurrentWord:(id)sender; @@ -110,9 +112,6 @@ static inline id NSMutableAttributedStringAttributeAtIndex (NSMutableAttributedS - (BOOL) wrapSelectionWithPrefix:(NSString *)prefix suffix:(NSString *)suffix; - (BOOL) shiftSelectionRight; - (BOOL) shiftSelectionLeft; -// - (NSArray *) completionsForPartialWordRange:(NSRange)charRange indexOfSelectedItem:(NSInteger *)index; -- (NSArray *) keywords; -- (NSArray *) functions; - (void) setAutoindent:(BOOL)enableAutoindent; - (BOOL) autoindent; - (void) setAutoindentIgnoresEnter:(BOOL)enableAutoindentIgnoresEnter; diff --git a/Source/CMTextView.m b/Source/CMTextView.m index 30c4d7a5..0c6d2187 100644 --- a/Source/CMTextView.m +++ b/Source/CMTextView.m @@ -99,6 +99,7 @@ static inline NSPoint SPPointOnLine(NSPoint a, NSPoint b, CGFloat t) { return NS @synthesize queryRange; @synthesize shouldHiliteQuery; @synthesize completionIsOpen; +@synthesize completionWasReinvokedAutomatically; /* * Sort function (mainly used to sort the words in the textView) @@ -141,6 +142,8 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) [self setAutopair:[prefs boolForKey:SPCustomQueryAutoPairCharacters]]; [self setAutohelp:[prefs boolForKey:SPCustomQueryUpdateAutoHelp]]; [self setAutouppercaseKeywords:[prefs boolForKey:SPCustomQueryAutoUppercaseKeywords]]; + [self setCompletionWasReinvokedAutomatically:NO]; + // Re-define tab stops for a better editing [self setTabStops]; @@ -278,12 +281,17 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) if(!isDictMode) { // Add predefined keywords - for(id s in [self keywords]) + NSArray *keywordList = [[NSArray arrayWithArray:[[SPQueryController sharedQueryController] keywordList]] retain]; + for(id s in keywordList) [possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:s, @"display", @"dummy-small", @"image", nil]]; // Add predefined functions - for(id s in [self functions]) + NSArray *functionList = [[NSArray arrayWithArray:[[SPQueryController sharedQueryController] functionList]] retain]; + for(id s in functionList) [possibleCompletions addObject:[NSDictionary dictionaryWithObjectsAndKeys:s, @"display", @"func-small", @"image", nil]]; + + [functionList release]; + [keywordList release]; } } @@ -482,7 +490,9 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) if([[[self textStorage] attribute:kQuote atIndex:r.location-1 effectiveRange:nil] isEqualToString:kQuoteValue]) return; if(![[NSCharacterSet whitespaceAndNewlineCharacterSet] characterIsMember:[[self string] characterAtIndex:r.location-1]]) - [self doCompletionByUsingSpellChecker:NO fuzzyMode:NO autoCompleteMode:YES]; + // Suppress auto-completion if window isn't active anymore + if([[NSApp keyWindow] firstResponder] == self) + [self doCompletionByUsingSpellChecker:NO fuzzyMode:NO autoCompleteMode:YES]; } } @@ -520,7 +530,7 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) // Break for long stuff if(completionRange.length>100000) return; - NSString* allow; // additional chars which not close the popup + NSString* allow; // additional chars which won't close the suggestion list window if(isDictMode) allow= @"_"; else @@ -848,18 +858,25 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) - (BOOL) wrapSelectionWithPrefix:(NSString *)prefix suffix:(NSString *)suffix { + NSRange currentRange = [self selectedRange]; + // Only proceed if a selection is active - if ([self selectedRange].length == 0 || ![self isEditable]) + if (currentRange.length == 0 || ![self isEditable]) return NO; + NSString *selString = [[self string] substringWithRange:currentRange]; + // Replace the current selection with the selected string wrapped in prefix and suffix - [self insertText: - [NSString stringWithFormat:@"%@%@%@", - prefix, - [[self string] substringWithRange:[self selectedRange]], - suffix - ] - ]; + [self insertText:[NSString stringWithFormat:@"%@%@%@", prefix, selString, suffix]]; + + // Re-select original selection + NSRange innerSelectionRange = NSMakeRange(currentRange.location+1, [selString length]); + [self setSelectedRange:innerSelectionRange]; + + // If autopair is enabled mark last autopair character as autopair-linked + if([prefs boolForKey:SPCustomQueryAutoPairCharacters]) + [[self textStorage] addAttribute:kAPlinked value:kAPval range:NSMakeRange(NSMaxRange(innerSelectionRange), 1)]; + return YES; } @@ -1271,6 +1288,10 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) [self breakUndoCoalescing]; [self insertText:snip]; + // If autopair is enabled check whether snip begins with ( and ends with ), if so mark ) as pair-linked + if([prefs boolForKey:SPCustomQueryAutoPairCharacters] && ([snip hasPrefix:@"("] && [snip hasSuffix:@")"] || ([snip hasPrefix:@"`"] && [snip hasSuffix:@"`"]) || ([snip hasPrefix:@"'"] && [snip hasSuffix:@"'"]) || ([snip hasPrefix:@"\""] && [snip hasSuffix:@"\""]))) + [[self textStorage] addAttribute:kAPlinked value:kAPval range:NSMakeRange([self selectedRange].location - 1, 1)]; + // Any snippets defined? if(snippetControlCounter > -1) { // Find and select first defined snippet @@ -1475,6 +1496,12 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) selector:@selector(autoHelp) object:nil]; + // Cancel auto-completion timer + if([prefs boolForKey:SPCustomQueryAutoComplete]) + [NSObject cancelPreviousPerformRequestsWithTarget:self + selector:@selector(doAutoCompletion) + object:nil]; + [super mouseDown:theEvent]; // Start autoHelp timer @@ -1497,6 +1524,13 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) afterDelay:[[prefs valueForKey:SPCustomQueryAutoHelpDelay] doubleValue]]; } + // Cancel auto-completion timer + if([prefs boolForKey:SPCustomQueryAutoComplete]) + [NSObject cancelPreviousPerformRequestsWithTarget:self + selector:@selector(doAutoCompletion) + object:nil]; + + long allFlags = (NSShiftKeyMask|NSControlKeyMask|NSAlternateKeyMask|NSCommandKeyMask); // Check if user pressed ⌥ to allow composing of accented characters. @@ -1516,6 +1550,8 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) if ([theEvent keyCode] == 53 && [self isEditable]){ // ESC key for internal completion + [self setCompletionWasReinvokedAutomatically:NO]; + // Cancel autocompletion trigger if([prefs boolForKey:SPCustomQueryAutoComplete]) [NSObject cancelPreviousPerformRequestsWithTarget:self @@ -1529,6 +1565,7 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) return; } if (insertedCharacter == NSF5FunctionKey && [self isEditable]){ // F5 for completion based on spell checker + [self setCompletionWasReinvokedAutomatically:NO]; [self doCompletionByUsingSpellChecker:YES fuzzyMode:NO autoCompleteMode:NO]; return; } @@ -1827,993 +1864,6 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) } /* - * List of keywords for autocompletion. If you add a keyword here, - * it should also be added to the flex file SPEditorTokens.l - */ --(NSArray *)keywords -{ - return [NSArray arrayWithObjects: - @"ACCESSIBLE", - @"ACTION", - @"ADD", - @"AFTER", - @"AGAINST", - @"AGGREGATE", - @"ALGORITHM", - @"ALL", - @"ALTER", - @"ALTER COLUMN", - @"ALTER DATABASE", - @"ALTER EVENT", - @"ALTER FUNCTION", - @"ALTER LOGFILE GROUP", - @"ALTER PROCEDURE", - @"ALTER SCHEMA", - @"ALTER SERVER", - @"ALTER TABLE", - @"ALTER TABLESPACE", - @"ALTER VIEW", - @"ANALYZE", - @"ANALYZE TABLE", - @"AND", - @"ANY", - @"AS", - @"ASC", - @"ASCII", - @"ASENSITIVE", - @"AT", - @"AUTHORS", - @"AUTOEXTEND_SIZE", - @"AUTO_INCREMENT", - @"AVG", - @"AVG_ROW_LENGTH", - @"BACKUP", - @"BACKUP TABLE", - @"BEFORE", - @"BEGIN", - @"BETWEEN", - @"BIGINT", - @"BINARY", - @"BINLOG", - @"BIT", - @"BLOB", - @"BOOL", - @"BOOLEAN", - @"BOTH", - @"BTREE", - @"BY", - @"BYTE", - @"CACHE", - @"CACHE INDEX", - @"CALL", - @"CASCADE", - @"CASCADED", - @"CASE", - @"CHAIN", - @"CHANGE", - @"CHANGED", - @"CHAR", - @"CHARACTER", - @"CHARACTER SET", - @"CHARSET", - @"CHECK", - @"CHECK TABLE", - @"CHECKSUM", - @"CHECKSUM TABLE", - @"CIPHER", - @"CLIENT", - @"CLOSE", - @"COALESCE", - @"CODE", - @"COLLATE", - @"COLLATION", - @"COLUMN", - @"COLUMNS", - @"COLUMN_FORMAT" - @"COMMENT", - @"COMMIT", - @"COMMITTED", - @"COMPACT", - @"COMPLETION", - @"COMPRESSED", - @"CONCURRENT", - @"CONDITION", - @"CONNECTION", - @"CONSISTENT", - @"CONSTRAINT", - @"CONTAINS", - @"CONTINUE", - @"CONTRIBUTORS", - @"CONVERT", - @"CREATE", - @"CREATE DATABASE", - @"CREATE EVENT", - @"CREATE FUNCTION", - @"CREATE INDEX", - @"CREATE LOGFILE GROUP", - @"CREATE PROCEDURE", - @"CREATE SCHEMA", - @"CREATE TABLE", - @"CREATE TABLESPACE", - @"CREATE TRIGGER", - @"CREATE USER", - @"CREATE VIEW", - @"CROSS", - @"CUBE", - @"CURRENT_DATE", - @"CURRENT_TIME", - @"CURRENT_TIMESTAMP", - @"CURRENT_USER", - @"CURSOR", - @"DATA", - @"DATABASE", - @"DATABASES", - @"DATAFILE", - @"DATE", - @"DATETIME", - @"DAY", - @"DAY_HOUR", - @"DAY_MICROSECOND", - @"DAY_MINUTE", - @"DAY_SECOND", - @"DEALLOCATE", - @"DEALLOCATE PREPARE", - @"DEC", - @"DECIMAL", - @"DECLARE", - @"DEFAULT", - @"DEFINER", - @"DELAYED", - @"DELAY_KEY_WRITE", - @"DELETE", - @"DELIMITER ", - @"DELIMITER ;\n", - @"DELIMITER ;;\n", - @"DESC", - @"DESCRIBE", - @"DES_KEY_FILE", - @"DETERMINISTIC", - @"DIRECTORY", - @"DISABLE", - @"DISCARD", - @"DISK", - @"DISTINCT", - @"DISTINCTROW", - @"DIV", - @"DO", - @"DOUBLE", - @"DROP", - @"DROP DATABASE", - @"DROP EVENT", - @"DROP FOREIGN KEY", - @"DROP FUNCTION", - @"DROP INDEX", - @"DROP LOGFILE GROUP", - @"DROP PREPARE", - @"DROP PRIMARY KEY", - @"DROP PREPARE", - @"DROP PROCEDURE", - @"DROP SCHEMA", - @"DROP SERVER", - @"DROP TABLE", - @"DROP TABLESPACE", - @"DROP TRIGGER", - @"DROP USER", - @"DROP VIEW", - @"DUAL", - @"DUMPFILE", - @"DUPLICATE", - @"DYNAMIC", - @"EACH", - @"ELSE", - @"ELSEIF", - @"ENABLE", - @"ENCLOSED", - @"END", - @"ENDS", - @"ENGINE", - @"ENGINES", - @"ENUM", - @"ERRORS", - @"ESCAPE", - @"ESCAPED", - @"EVENT", - @"EVENTS", - @"EVERY", - @"EXECUTE", - @"EXISTS", - @"EXIT", - @"EXPANSION", - @"EXPLAIN", - @"EXTENDED", - @"EXTENT_SIZE", - @"FALSE", - @"FAST", - @"FETCH", - @"FIELDS", - @"FIELDS TERMINATED BY", - @"FILE", - @"FIRST", - @"FIXED", - @"FLOAT", - @"FLOAT4", - @"FLOAT8", - @"FLUSH", - @"FOR", - @"FOR UPDATE", - @"FORCE", - @"FOREIGN", - @"FOREIGN KEY", - @"FOUND", - @"FRAC_SECOND", - @"FROM", - @"FULL", - @"FULLTEXT", - @"FUNCTION", - @"GEOMETRY", - @"GEOMETRYCOLLECTION", - @"GET_FORMAT", - @"GLOBAL", - @"GRANT", - @"GRANTS", - @"GROUP", - @"GROUP BY", - @"HANDLER", - @"HASH", - @"HAVING", - @"HELP", - @"HIGH_PRIORITY", - @"HOSTS", - @"HOUR", - @"HOUR_MICROSECOND", - @"HOUR_MINUTE", - @"HOUR_SECOND", - @"IDENTIFIED", - @"IF", - @"IGNORE", - @"IMPORT", - @"IN", - @"INDEX", - @"INDEXES", - @"INFILE", - @"INITIAL_SIZE", - @"INNER", - @"INNOBASE", - @"INNODB", - @"INOUT", - @"INSENSITIVE", - @"INSERT", - @"INSERT_METHOD", - @"INSTALL", - @"INSTALL PLUGIN", - @"INT", - @"INT1", - @"INT2", - @"INT3", - @"INT4", - @"INT8", - @"INTEGER", - @"INTERVAL", - @"INTO", - @"INTO DUMPFILE", - @"INTO OUTFILE", - @"INTO TABLE", - @"INVOKER", - @"IO_THREAD", - @"IS", - @"ISOLATION", - @"ISSUER", - @"ITERATE", - @"JOIN", - @"KEY", - @"KEYS", - @"KEY_BLOCK_SIZE", - @"KILL", - @"LANGUAGE", - @"LAST", - @"LEADING", - @"LEAVE", - @"LEAVES", - @"LEFT", - @"LESS", - @"LEVEL", - @"LIKE", - @"LIMIT", - @"LINEAR", - @"LINES", - @"LINES TERMINATED BY", - @"LINESTRING", - @"LIST", - @"LOAD DATA", - @"LOAD INDEX INTO CACHE", - @"LOAD XML", - @"LOCAL", - @"LOCALTIME", - @"LOCALTIMESTAMP", - @"LOCK", - @"LOCK IN SHARE MODE", - @"LOCK TABLES", - @"LOCKS", - @"LOGFILE", - @"LOGS", - @"LONG", - @"LONGBLOB", - @"LONGTEXT", - @"LOOP", - @"LOW_PRIORITY", - @"MASTER", - @"MASTER_CONNECT_RETRY", - @"MASTER_HOST", - @"MASTER_LOG_FILE", - @"MASTER_LOG_POS", - @"MASTER_PASSWORD", - @"MASTER_PORT", - @"MASTER_SERVER_ID", - @"MASTER_SSL", - @"MASTER_SSL_CA", - @"MASTER_SSL_CAPATH", - @"MASTER_SSL_CERT", - @"MASTER_SSL_CIPHER", - @"MASTER_SSL_KEY", - @"MASTER_USER", - @"MATCH", - @"MAXVALUE", - @"MAX_CONNECTIONS_PER_HOUR", - @"MAX_QUERIES_PER_HOUR", - @"MAX_ROWS", - @"MAX_SIZE", - @"MAX_UPDATES_PER_HOUR", - @"MAX_USER_CONNECTIONS", - @"MEDIUM", - @"MEDIUMBLOB", - @"MEDIUMINT", - @"MEDIUMTEXT", - @"MEMORY", - @"MERGE", - @"MICROSECOND", - @"MIDDLEINT", - @"MIGRATE", - @"MINUTE", - @"MINUTE_MICROSECOND", - @"MINUTE_SECOND", - @"MIN_ROWS", - @"MOD", - @"MODE", - @"MODIFIES", - @"MODIFY", - @"MONTH", - @"MULTILINESTRING", - @"MULTIPOINT", - @"MULTIPOLYGON", - @"MUTEX", - @"NAME", - @"NAMES", - @"NATIONAL", - @"NATURAL", - @"NCHAR", - @"NDB", - @"NDBCLUSTER", - @"NEW", - @"NEXT", - @"NO", - @"NODEGROUP", - @"NONE", - @"NOT", - @"NO_WAIT", - @"NO_WRITE_TO_BINLOG", - @"NULL", - @"NUMERIC", - @"NVARCHAR", - @"OFFSET", - @"OLD_PASSWORD", - @"ON", - @"ONE", - @"ONE_SHOT", - @"OPEN", - @"OPTIMIZE", - @"OPTIMIZE TABLE", - @"OPTION", - @"OPTIONALLY", - @"OPTIONALLY ENCLOSED BY", - @"OPTIONS", - @"OR", - @"ORDER", - @"ORDER BY", - @"OUT", - @"OUTER", - @"OUTFILE", - @"PACK_KEYS", - @"PARSER", - @"PARTIAL", - @"PARTITION", - @"PARTITIONING", - @"PARTITIONS", - @"PASSWORD", - @"PHASE", - @"PLUGIN", - @"PLUGINS", - @"POINT", - @"POLYGON", - @"PRECISION", - @"PREPARE", - @"PRESERVE", - @"PREV", - @"PRIMARY", - @"PRIMARY KEY", - @"PRIVILEGES", - @"PROCEDURE", - @"PROCEDURE ANALYSE", - @"PROCESS", - @"PROCESSLIST", - @"PURGE", - @"QUARTER", - @"QUERY", - @"QUICK", - @"RANGE", - @"READ", - @"READS", - @"READ_ONLY", - @"READ_WRITE", - @"REAL", - @"REBUILD", - @"RECOVER", - @"REDOFILE", - @"REDO_BUFFER_SIZE", - @"REDUNDANT", - @"REFERENCES", - @"REGEXP", - @"RELAY_LOG_FILE", - @"RELAY_LOG_POS", - @"RELAY_THREAD", - @"RELEASE", - @"RELOAD", - @"REMOVE", - @"RENAME", - @"RENAME DATABASE", - @"RENAME TABLE", - @"REORGANIZE", - @"REPAIR", - @"REPAIR TABLE", - @"REPEAT", - @"REPEATABLE", - @"REPLACE", - @"REPLICATION", - @"REQUIRE", - @"RESET", - @"RESET MASTER", - @"RESTORE", - @"RESTORE TABLE", - @"RESTRICT", - @"RESUME", - @"RETURN", - @"RETURNS", - @"REVOKE", - @"RIGHT", - @"RLIKE", - @"ROLLBACK", - @"ROLLUP", - @"ROUTINE", - @"ROW", - @"ROWS", - @"ROWS IDENTIFIED BY" - @"ROW_FORMAT", - @"RTREE", - @"SAVEPOINT", - @"SCHEDULE", - @"SCHEDULER", - @"SCHEMA", - @"SCHEMAS", - @"SECOND", - @"SECOND_MICROSECOND", - @"SECURITY", - @"SELECT", - @"SELECT DISTINCT", - @"SENSITIVE", - @"SEPARATOR", - @"SERIAL", - @"SERIALIZABLE", - @"SESSION", - @"SET", - @"SET GLOBAL", - @"SET NAMES", - @"SET PASSWORD", - @"SHARE", - @"SHOW", - @"SHOW BINARY LOGS", - @"SHOW BINLOG EVENTS", - @"SHOW CHARACTER SET", - @"SHOW COLLATION", - @"SHOW COLUMNS", - @"SHOW CONTRIBUTORS", - @"SHOW CREATE DATABASE", - @"SHOW CREATE EVENT", - @"SHOW CREATE FUNCTION", - @"SHOW CREATE PROCEDURE", - @"SHOW CREATE SCHEMA", - @"SHOW CREATE TABLE", - @"SHOW CREATE TRIGGERS", - @"SHOW CREATE VIEW", - @"SHOW DATABASES", - @"SHOW ENGINE", - @"SHOW ENGINES", - @"SHOW ERRORS", - @"SHOW EVENTS", - @"SHOW FIELDS", - @"SHOW FULL PROCESSLIST", - @"SHOW FUNCTION CODE", - @"SHOW FUNCTION STATUS", - @"SHOW GRANTS", - @"SHOW INDEX", - @"SHOW INNODB STATUS", - @"SHOW KEYS", - @"SHOW MASTER LOGS", - @"SHOW MASTER STATUS", - @"SHOW OPEN TABLES", - @"SHOW PLUGINS", - @"SHOW PRIVILEGES", - @"SHOW PROCEDURE CODE", - @"SHOW PROCEDURE STATUS", - @"SHOW PROFILE", - @"SHOW PROFILES", - @"SHOW PROCESSLIST", - @"SHOW SCHEDULER STATUS", - @"SHOW SCHEMAS", - @"SHOW SLAVE HOSTS", - @"SHOW SLAVE STATUS", - @"SHOW STATUS", - @"SHOW STORAGE ENGINES", - @"SHOW TABLE STATUS", - @"SHOW TABLE TYPES", - @"SHOW TABLES", - @"SHOW TRIGGERS", - @"SHOW VARIABLES", - @"SHOW WARNINGS", - @"SHUTDOWN", - @"SIGNED", - @"SIMPLE", - @"SLAVE", - @"SMALLINT", - @"SNAPSHOT", - @"SOME", - @"SONAME", - @"SOUNDS", - @"SPATIAL", - @"SPECIFIC", - @"SQL_AUTO_IS_NULL", - @"SQL_BIG_RESULT", - @"SQL_BIG_SELECTS", - @"SQL_BIG_TABLES", - @"SQL_BUFFER_RESULT", - @"SQL_CACHE", - @"SQL_CALC_FOUND_ROWS", - @"SQL_LOG_BIN", - @"SQL_LOG_OFF", - @"SQL_LOG_UPDATE", - @"SQL_LOW_PRIORITY_UPDATES", - @"SQL_MAX_JOIN_SIZE", - @"SQL_NO_CACHE", - @"SQL_QUOTE_SHOW_CREATE", - @"SQL_SAFE_UPDATES", - @"SQL_SELECT_LIMIT", - @"SQL_SLAVE_SKIP_COUNTER", - @"SQL_SMALL_RESULT", - @"SQL_THREAD", - @"SQL_TSI_DAY", - @"SQL_TSI_FRAC_SECOND", - @"SQL_TSI_HOUR", - @"SQL_TSI_MINUTE", - @"SQL_TSI_MONTH", - @"SQL_TSI_QUARTER", - @"SQL_TSI_SECOND", - @"SQL_TSI_WEEK", - @"SQL_TSI_YEAR", - @"SQL_WARNINGS", - @"SSL", - @"START", - @"START TRANSACTION", - @"STARTING", - @"STARTS", - @"STATUS", - @"STOP", - @"STORAGE", - @"STRAIGHT_JOIN", - @"STRING", - @"SUBJECT", - @"SUBPARTITION", - @"SUBPARTITIONS", - @"SUPER", - @"SUSPEND", - @"TABLE", - @"TABLES", - @"TABLESPACE", - @"TEMPORARY", - @"TEMPTABLE", - @"TERMINATED", - @"TEXT", - @"THAN", - @"THEN", - @"TIME", - @"TIMESTAMP", - @"TIMESTAMPADD", - @"TIMESTAMPDIFF", - @"TINYBLOB", - @"TINYINT", - @"TINYTEXT", - @"TO", - @"TRAILING", - @"TRANSACTION", - @"TRIGGER", - @"TRIGGERS", - @"TRUE", - @"TRUNCATE", - @"TYPE", - @"TYPES", - @"UNCOMMITTED", - @"UNDEFINED", - @"UNDO", - @"UNDOFILE", - @"UNDO_BUFFER_SIZE", - @"UNICODE", - @"UNINSTALL", - @"UNINSTALL PLUGIN", - @"UNION", - @"UNIQUE", - @"UNKNOWN", - @"UNLOCK", - @"UNLOCK TABLES", - @"UNSIGNED", - @"UNTIL", - @"UPDATE", - @"UPGRADE", - @"USAGE", - @"USE", - @"USER", - @"USER_RESOURCES", - @"USE_FRM", - @"USING", - @"UTC_DATE", - @"UTC_TIME", - @"UTC_TIMESTAMP", - @"VALUE", - @"VALUES", - @"VARBINARY", - @"VARCHAR", - @"VARCHARACTER", - @"VARIABLES", - @"VARYING", - @"VIEW", - @"WAIT", - @"WARNINGS", - @"WEEK", - @"WHEN", - @"WHERE", - @"WHILE", - @"WITH", - @"WITH CONSISTENT SNAPSHOT", - @"WORK", - @"WRITE", - @"X509", - @"XA", - @"XOR", - @"YEAR", - @"YEAR_MONTH", - @"ZEROFILL", - - nil]; -} - -/* - * List of fucntions for autocompletion. If you add a keyword here, - * it should also be added to the flex file SPEditorTokens.l - */ --(NSArray *)functions -{ - return [NSArray arrayWithObjects: - @"ABS", - @"ACOS", - @"ADDDATE", - @"ADDTIME", - @"AES_DECRYPT", - @"AES_ENCRYPT", - @"AREA", - @"ASBINARY", - @"ASCII", - @"ASIN", - @"ASTEXT", - @"ATAN", - @"ATAN2", - @"AVG", - @"BDMPOLYFROMTEXT", - @"BDMPOLYFROMWKB", - @"BDPOLYFROMTEXT", - @"BDPOLYFROMWKB", - @"BENCHMARK", - @"BIN", - @"BIT_AND", - @"BIT_COUNT", - @"BIT_LENGTH", - @"BIT_OR", - @"BIT_XOR", - @"BOUNDARY", - @"BUFFER", - @"CAST", - @"CEIL", - @"CEILING", - @"CENTROID", - @"CHAR", - @"CHARACTER_LENGTH", - @"CHARSET", - @"CHAR_LENGTH", - @"COALESCE", - @"COERCIBILITY", - @"COLLATION", - @"COMPRESS", - @"CONCAT", - @"CONCAT_WS", - @"CONNECTION_ID", - @"CONTAINS", - @"CONV", - @"CONVERT", - @"CONVERT_TZ", - @"CONVEXHULL", - @"COS", - @"COT", - @"COUNT", - @"COUNT(*)", - @"CRC32", - @"CROSSES", - @"CURDATE", - @"CURRENT_DATE", - @"CURRENT_TIME", - @"CURRENT_TIMESTAMP", - @"CURRENT_USER", - @"CURTIME", - @"DATABASE", - @"DATE", - @"DATEDIFF", - @"DATE_ADD", - @"DATE_DIFF", - @"DATE_FORMAT", - @"DATE_SUB", - @"DAY", - @"DAYNAME", - @"DAYOFMONTH", - @"DAYOFWEEK", - @"DAYOFYEAR", - @"DECODE", - @"DEFAULT", - @"DEGREES", - @"DES_DECRYPT", - @"DES_ENCRYPT", - @"DIFFERENCE", - @"DIMENSION", - @"DISJOINT", - @"DISTANCE", - @"ELT", - @"ENCODE", - @"ENCRYPT", - @"ENDPOINT", - @"ENVELOPE", - @"EQUALS", - @"EXP", - @"EXPORT_SET", - @"EXTERIORRING", - @"EXTRACT", - @"EXTRACTVALUE", - @"FIELD", - @"FIND_IN_SET", - @"FLOOR", - @"FORMAT", - @"FOUND_ROWS", - @"FROM_DAYS", - @"FROM_UNIXTIME", - @"GEOMCOLLFROMTEXT", - @"GEOMCOLLFROMWKB", - @"GEOMETRYCOLLECTION", - @"GEOMETRYCOLLECTIONFROMTEXT", - @"GEOMETRYCOLLECTIONFROMWKB", - @"GEOMETRYFROMTEXT", - @"GEOMETRYFROMWKB", - @"GEOMETRYN", - @"GEOMETRYTYPE", - @"GEOMFROMTEXT", - @"GEOMFROMWKB", - @"GET_FORMAT", - @"GET_LOCK", - @"GLENGTH", - @"GREATEST", - @"GROUP_CONCAT", - @"GROUP_UNIQUE_USERS", - @"HEX", - @"HOUR", - @"IF", - @"IFNULL", - @"INET_ATON", - @"INET_NTOA", - @"INSERT", - @"INSERT_ID", - @"INSTR", - @"INTERIORRINGN", - @"INTERSECTION", - @"INTERSECTS", - @"INTERVAL", - @"ISCLOSED", - @"ISEMPTY", - @"ISNULL", - @"ISRING", - @"ISSIMPLE", - @"IS_FREE_LOCK", - @"IS_USED_LOCK", - @"LAST_DAY", - @"LAST_INSERT_ID", - @"LCASE", - @"LEAST", - @"LEFT", - @"LENGTH", - @"LINEFROMTEXT", - @"LINEFROMWKB", - @"LINESTRING", - @"LINESTRINGFROMTEXT", - @"LINESTRINGFROMWKB", - @"LN", - @"LOAD_FILE", - @"LOCALTIME", - @"LOCALTIMESTAMP", - @"LOCATE", - @"LOG", - @"LOG10", - @"LOG2", - @"LOWER", - @"LPAD", - @"LTRIM", - @"MAKEDATE", - @"MAKETIME", - @"MAKE_SET", - @"MASTER_POS_WAIT", - @"MAX", - @"MBRCONTAINS", - @"MBRDISJOINT", - @"MBREQUAL", - @"MBRINTERSECTS", - @"MBROVERLAPS", - @"MBRTOUCHES", - @"MBRWITHIN", - @"MD5", - @"MICROSECOND", - @"MID", - @"MIN", - @"MINUTE", - @"MLINEFROMTEXT", - @"MLINEFROMWKB", - @"MOD", - @"MONTH", - @"MONTHNAME", - @"NOW", - @"MPOINTFROMTEXT", - @"MPOINTFROMWKB", - @"MPOLYFROMTEXT", - @"MPOLYFROMWKB", - @"MULTILINESTRING", - @"MULTILINESTRINGFROMTEXT", - @"MULTILINESTRINGFROMWKB", - @"MULTIPOINT", - @"MULTIPOINTFROMTEXT", - @"MULTIPOINTFROMWKB", - @"MULTIPOLYGON", - @"MULTIPOLYGONFROMTEXT", - @"MULTIPOLYGONFROMWKB", - @"NAME_CONST", - @"NOW", - @"NULLIF", - @"NUMGEOMETRIES", - @"NUMINTERIORRINGS", - @"NUMPOINTS", - @"OCT", - @"OCTET_LENGTH", - @"OLD_PASSWORD", - @"ORD", - @"OVERLAPS", - @"PASSWORD", - @"PERIOD_ADD", - @"PERIOD_DIFF", - @"PI", - @"POINT", - @"POINTFROMTEXT", - @"POINTFROMWKB", - @"POINTN", - @"POINTONSURFACE", - @"POLYFROMTEXT", - @"POLYFROMWKB", - @"POLYGON", - @"POLYGONFROMTEXT", - @"POLYGONFROMWKB", - @"POSITION", - @"POW", - @"POWER", - @"QUARTER", - @"QUOTE", - @"RADIANS", - @"RAND", - @"RELATED", - @"RELEASE_LOCK", - @"REPEAT", - @"REPLACE", - @"REVERSE", - @"RIGHT", - @"ROUND", - @"ROW_COUNT", - @"RPAD", - @"RTRIM", - @"SCHEMA", - @"SECOND", - @"SEC_TO_TIME", - @"SESSION_USER", - @"SHA", - @"SHA1", - @"SIGN", - @"SIN", - @"SLEEP", - @"SOUNDEX", - @"SPACE", - @"SQRT", - @"SRID", - @"STARTPOINT", - @"STD", - @"STDDEV", - @"STDDEV_POP", - @"STDDEV_SAMP", - @"STRCMP", - @"STR_TO_DATE", - @"SUBDATE", - @"SUBSTR", - @"SUBSTRING", - @"SUBSTRING_INDEX", - @"SUBTIME", - @"SUM", - @"SYMDIFFERENCE", - @"SYSDATE", - @"SYSTEM_USER", - @"TAN", - @"TIME", - @"TIMEDIFF", - @"TIMESTAMP", - @"TIMESTAMPADD", - @"TIMESTAMPDIFF", - @"TIME_FORMAT", - @"TIME_TO_SEC", - @"TOUCHES", - @"TO_DAYS", - @"TRIM", - @"TRUNCATE", - @"UCASE", - @"UNCOMPRESS", - @"UNCOMPRESSED_LENGTH", - @"UNHEX", - @"UNIQUE_USERS", - @"UNIX_TIMESTAMP", - @"UPDATEXML", - @"UPPER", - @"USER", - @"UTC_DATE", - @"UTC_TIME", - @"UTC_TIMESTAMP", - @"UUID", - @"VARIANCE", - @"VAR_POP", - @"VAR_SAMP", - @"VERSION", - @"WEEK", - @"WEEKDAY", - @"WEEKOFYEAR", - @"WITHIN", - @"YEAR", - @"YEARWEEK", - - nil]; -} - - -/* * Set whether this text view should apply the indentation on the current line to new lines. */ - (void)setAutoindent:(BOOL)enableAutoindent @@ -3410,6 +2460,12 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) // Make sure that the notification is from the correct textStorage object if (textStore!=[self textStorage]) return; + // Cancel autocompletion trigger + if([prefs boolForKey:SPCustomQueryAutoComplete]) + [NSObject cancelPreviousPerformRequestsWithTarget:self + selector:@selector(doAutoCompletion) + object:nil]; + NSInteger editedMask = [textStore editedMask]; // Start autohelp only if the user really changed the text (not e.g. for setting a background color) @@ -3417,14 +2473,8 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) [self performSelector:@selector(autoHelp) withObject:nil afterDelay:[[[prefs valueForKey:SPCustomQueryAutoHelpDelay] retain] doubleValue]]; } - // Cancel autocompletion trigger - if([prefs boolForKey:SPCustomQueryAutoComplete]) - [NSObject cancelPreviousPerformRequestsWithTarget:self - selector:@selector(doAutoCompletion) - object:nil]; - // Start autocompletion if enabled - if([prefs boolForKey:SPCustomQueryAutoComplete] && !completionIsOpen && editedMask != 1) + if([[NSApp keyWindow] firstResponder] == self && [prefs boolForKey:SPCustomQueryAutoComplete] && !completionIsOpen && editedMask != 1) [self performSelector:@selector(doAutoCompletion) withObject:nil afterDelay:[[[prefs valueForKey:SPCustomQueryAutoCompleteDelay] retain] doubleValue]]; // Cancel calling doSyntaxHighlighting for large text diff --git a/Source/SPConstants.h b/Source/SPConstants.h index 83ce6996..c21f6d24 100644 --- a/Source/SPConstants.h +++ b/Source/SPConstants.h @@ -137,6 +137,7 @@ extern NSString *SPCustomQueryHighlightCurrentQuery; extern NSString *SPCustomQueryEditorTabStopWidth; extern NSString *SPCustomQueryAutoComplete; extern NSString *SPCustomQueryAutoCompleteDelay; +extern NSString *SPCustomQueryFunctionCompletionInsertsArguments; // AutoUpdate Prefpane extern NSString *SPLastUsedVersion; diff --git a/Source/SPConstants.m b/Source/SPConstants.m index aa2c3508..2a8822e0 100644 --- a/Source/SPConstants.m +++ b/Source/SPConstants.m @@ -105,6 +105,7 @@ NSString *SPCustomQueryHighlightCurrentQuery = @"CustomQueryHighlightCurrent NSString *SPCustomQueryEditorTabStopWidth = @"CustomQueryEditorTabStopWidth"; NSString *SPCustomQueryAutoComplete = @"CustomQueryAutoComplete"; NSString *SPCustomQueryAutoCompleteDelay = @"CustomQueryAutoCompleteDelay"; +NSString *SPCustomQueryFunctionCompletionInsertsArguments = @"CustomQueryFunctionCompletionInsertsArguments"; // AutoUpdate Prefpane NSString *SPLastUsedVersion = @"LastUsedVersion"; diff --git a/Source/SPNarrowDownCompletion.h b/Source/SPNarrowDownCompletion.h index 6901ffa1..743f7cc5 100644 --- a/Source/SPNarrowDownCompletion.h +++ b/Source/SPNarrowDownCompletion.h @@ -62,6 +62,9 @@ NSInteger spaceCounter; NSMutableCharacterSet* textualInputCharacters; + + NSUserDefaults *prefs; + } - (id)initWithItems:(NSArray*)someSuggestions alreadyTyped:(NSString*)aUserString staticPrefix:(NSString*)aStaticPrefix diff --git a/Source/SPNarrowDownCompletion.m b/Source/SPNarrowDownCompletion.m index 3df3d7b6..10d4c1f7 100644 --- a/Source/SPNarrowDownCompletion.m +++ b/Source/SPNarrowDownCompletion.m @@ -33,6 +33,7 @@ #import "SPStringAdditions.h" #import "ImageAndTextCell.h" #import "SPConstants.h" +#import "SPQueryController.h" #import "RegexKitLite.h" #import "CMTextView.h" #include <tgmath.h> @@ -112,6 +113,8 @@ filtered = nil; spaceCounter = 0; + prefs = [NSUserDefaults standardUserDefaults]; + tableFont = [NSUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] dataForKey:SPCustomQueryEditorFont]]; [self setupInterface]; } @@ -451,11 +454,15 @@ closeMe = YES; return; } else { + if([theView completionWasReinvokedAutomatically]) return; if([[self filterString] hasSuffix:@"."]) { + [theView setCompletionWasReinvokedAutomatically:YES]; [theView doCompletionByUsingSpellChecker:dictMode fuzzyMode:fuzzyMode autoCompleteMode:NO]; closeMe = YES; + return; + } else { + [newFiltered addObject:[NSDictionary dictionaryWithObjectsAndKeys:NSLocalizedString(@"No completions found", @"no completions found message"), @"display", @"", @"noCompletion", nil]]; } - [newFiltered addObject:[NSDictionary dictionaryWithObjectsAndKeys:NSLocalizedString(@"No completions found", @"no completions found message"), @"display", @"", @"noCompletion", nil]]; } } @@ -656,15 +663,15 @@ [commonPrefix setString:tempPrefix]; } - // if(![commonPrefix length]) return; - - NSString* toInsert = [commonPrefix substringFromIndex:[[self filterString] length]]; - [mutablePrefix appendString:toInsert]; - theCharRange.length += [toInsert length]; - theParseRange.length += [toInsert length]; - [theView insertText:[toInsert lowercaseString]]; - [self checkSpaceForAllowedCharacter]; - + // Insert common prefix automatically + if([[self filterString] length] < [commonPrefix length]) { + NSString* toInsert = [commonPrefix substringFromIndex:[[self filterString] length]]; + [mutablePrefix appendString:toInsert]; + theCharRange.length += [toInsert length]; + theParseRange.length += [toInsert length]; + [theView insertText:[toInsert lowercaseString]]; + [self checkSpaceForAllowedCharacter]; + } } - (void)insert_text:(NSString* )aString @@ -675,11 +682,12 @@ // If completion string contains backticks move caret out of the backticks if(backtickMode && !triggerMode) [theView performSelector:@selector(moveRight:)]; - // If it's a function insert () snippet - else if([[[filtered objectAtIndex:[theTableView selectedRow]] objectForKey:@"image"] hasPrefix:@"func"] && ![aString hasSuffix:@")"]) { - [theView insertText:@"()"]; - [theView performSelector:@selector(moveLeft:)]; - // [theView insertAsSnippet:@"(${1:})" atRange:[theView selectedRange]]; + // If it's a function insert () and if given arguments as snippets + else if([prefs boolForKey:SPCustomQueryFunctionCompletionInsertsArguments] && [[[filtered objectAtIndex:[theTableView selectedRow]] objectForKey:@"image"] hasPrefix:@"func"] && ![aString hasSuffix:@")"]) { + NSString *functionArgumentSnippet = [NSString stringWithFormat:@"(%@)", [[SPQueryController sharedQueryController] argumentSnippetForFunction:aString]]; + [theView insertAsSnippet:functionArgumentSnippet atRange:[theView selectedRange]]; + if([functionArgumentSnippet length] == 2) + [theView performSelector:@selector(moveLeft:)]; } } diff --git a/Source/SPQueryController.h b/Source/SPQueryController.h index a1948b4b..797d5b6b 100644 --- a/Source/SPQueryController.h +++ b/Source/SPQueryController.h @@ -51,6 +51,10 @@ NSMutableDictionary *contentFilterContainer; NSUInteger numberOfMaxAllowedHistory; + NSArray *completionKeywordList; + NSArray *completionFunctionList; + NSDictionary *functionArgumentSnippets; + NSUserDefaults *prefs; NSDateFormatter *dateFormatter; } @@ -78,6 +82,11 @@ - (NSUInteger)consoleMessageCount; +// Completion List Controller +- (NSArray*)functionList; +- (NSArray*)keywordList; +- (NSString*)argumentSnippetForFunction:(NSString*)func; + // DocumentsController - (NSURL *)registerDocumentWithFileURL:(NSURL *)fileURL andContextInfo:(NSMutableDictionary *)contextInfo; - (void)removeRegisteredDocumentWithFileURL:(NSURL *)fileURL; diff --git a/Source/SPQueryController.m b/Source/SPQueryController.m index 911923bd..fec04630 100644 --- a/Source/SPQueryController.m +++ b/Source/SPQueryController.m @@ -103,6 +103,44 @@ static SPQueryController *sharedQueryController = nil; favoritesContainer = [[NSMutableDictionary alloc] init]; historyContainer = [[NSMutableDictionary alloc] init]; contentFilterContainer = [[NSMutableDictionary alloc] init]; + completionKeywordList = nil; + completionFunctionList = nil; + functionArgumentSnippets = nil; + + NSError *readError = nil; + NSString *convError = nil; + NSPropertyListFormat format; + NSDictionary *completionPlist; + NSData *completionTokensData = [NSData dataWithContentsOfFile:[NSBundle pathForResource:@"CompletionTokens.plist" ofType:nil inDirectory:[[NSBundle mainBundle] bundlePath]] + options:NSMappedRead error:&readError]; + + + completionPlist = [NSDictionary dictionaryWithDictionary:[NSPropertyListSerialization propertyListFromData:completionTokensData + mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:&convError]]; + + if(completionPlist == nil || readError != nil || convError != nil) { + NSLog(@"Error while reading “CompletionTokens.plist”:\n%@\n%@", [readError localizedDescription], convError); + NSBeep(); + } else { + if([completionPlist objectForKey:@"core_keywords"]) { + completionKeywordList = [[NSArray arrayWithArray:[completionPlist objectForKey:@"core_keywords"]] retain]; + } else { + NSLog(@"No “core_keywords” array found."); + NSBeep(); + } + if([completionPlist objectForKey:@"core_builtin_functions"]) { + completionFunctionList = [[NSArray arrayWithArray:[completionPlist objectForKey:@"core_builtin_functions"]] retain]; + } else { + NSLog(@"No “core_builtin_functions” array found."); + NSBeep(); + } + if([completionPlist objectForKey:@"function_argument_snippets"]) { + functionArgumentSnippets = [[NSDictionary dictionaryWithDictionary:[completionPlist objectForKey:@"function_argument_snippets"]] retain]; + } else { + NSLog(@"No “function_argument_snippets” dictionary found."); + NSBeep(); + } + } } @@ -463,6 +501,30 @@ static SPQueryController *sharedQueryController = nil; } #pragma mark - +#pragma mark Completion List Controller + +- (NSArray*)functionList +{ + if(completionFunctionList != nil && [completionFunctionList count]) + return completionFunctionList; + return [NSArray array]; +} + +- (NSArray*)keywordList +{ + if(completionKeywordList != nil && [completionKeywordList count]) + return completionKeywordList; + return [NSArray array]; +} + +- (NSString*)argumentSnippetForFunction:(NSString*)func +{ + if(functionArgumentSnippets && [functionArgumentSnippets objectForKey:[func uppercaseString]]) + return [functionArgumentSnippets objectForKey:[func uppercaseString]]; + return @""; +} + +#pragma mark - #pragma mark DocumentsController - (NSURL *)registerDocumentWithFileURL:(NSURL *)fileURL andContextInfo:(NSMutableDictionary *)contextInfo @@ -735,7 +797,10 @@ static SPQueryController *sharedQueryController = nil; [favoritesContainer release], favoritesContainer = nil; [historyContainer release], historyContainer = nil; [contentFilterContainer release], contentFilterContainer = nil; - + + if(completionKeywordList) [completionKeywordList release]; + if(completionFunctionList) [completionFunctionList release]; + if(functionArgumentSnippets) [functionArgumentSnippets release]; [super dealloc]; } |