diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/CMTextView.m | 82 | ||||
-rw-r--r-- | Source/tokens.h | 15 | ||||
-rw-r--r-- | Source/tokens.l | 323 |
3 files changed, 420 insertions, 0 deletions
diff --git a/Source/CMTextView.m b/Source/CMTextView.m index 7ca2f782..12b253da 100644 --- a/Source/CMTextView.m +++ b/Source/CMTextView.m @@ -24,6 +24,17 @@ #import "CMTextView.h" #import "SPStringAdditions.h" +/* +all the extern variables and prototypes required for flex (syntax highlighting) +*/ +#import "tokens.h" +extern int yylex(); +extern int yyuoffset, yyuleng; +typedef struct yy_buffer_state *YY_BUFFER_STATE; +void yy_switch_to_buffer(YY_BUFFER_STATE); +YY_BUFFER_STATE yy_scan_string (const char *); + + @implementation CMTextView - (NSArray *)completionsForPartialWordRange:(NSRange)charRange indexOfSelectedItem:(int *)index @@ -350,4 +361,75 @@ nil]; } +/******************* +SYNTAX HIGHLIGHTING! +*******************/ +- (void)awakeFromNib +/* +sets self as delegate for the textView's textStorage to enable syntax highlighting +*/ +{ + [[self textStorage] setDelegate:self]; +} + +- (void)textStorageDidProcessEditing:(NSNotification *)notification +/* +performs syntax highlighting +this method recolors the entire text on every keypress. for a single sql query, +that should be no problem, but it could be a nuisance when editing large sql queries +*/ +{ + NSTextStorage *textStore = [notification object]; + + //make sure that the notification is from the correct textStorage object + if (textStore==[self textStorage]) + { + + NSColor *reservedColor = [NSColor blueColor]; + NSColor *quoteColor = [NSColor grayColor]; + NSColor *commentColor = [NSColor redColor ]; + + NSString *string = [textStore string]; + unsigned int length = [string length]; + int token; + NSRange textRange, tokenRange; + + textRange = NSMakeRange(0, length); + + //first remove the old colors + [textStore removeAttribute:NSForegroundColorAttributeName range:textRange]; + + //initialise flex + yyuoffset = 0; yyuleng = 0; + yy_switch_to_buffer(yy_scan_string([[textStore string] UTF8String])); + + //now loop through all the tokens + while (token=yylex()){ + tokenRange = NSMakeRange(yyuoffset, yyuleng); //convert the result from flex to an NSRange + tokenRange = NSIntersectionRange(tokenRange, textRange); // make sure that tokenRange is valid (and therefore within textRange) + // otherwise a bug in the lex code could cause the the TextView to crash + + switch (token) { + case SPT_SINGLE_QUOTED_TEXT: + case SPT_DOUBLE_QUOTED_TEXT: + [textStore addAttribute: NSForegroundColorAttributeName + value: quoteColor + range: tokenRange ]; + break; + case SPT_RESERVED_WORD: + [textStore addAttribute: NSForegroundColorAttributeName + value: reservedColor + range: tokenRange ]; + break; + case SPT_COMMENT: + [textStore addAttribute: NSForegroundColorAttributeName + value: commentColor + range: tokenRange ]; + break; + }} + + } +} + + @end diff --git a/Source/tokens.h b/Source/tokens.h new file mode 100644 index 00000000..81ea830f --- /dev/null +++ b/Source/tokens.h @@ -0,0 +1,15 @@ +/* + * tokens.h + * sequel-pro + * + * Created by Jakob on 3/15/09. + * + * This file defines all the tokens used for parsing the source code + */ + +#define SPT_DOUBLE_QUOTED_TEXT 1 +#define SPT_SINGLE_QUOTED_TEXT 2 +#define SPT_BACKTICK_QUOTED_TEXT 3 +#define SPT_RESERVED_WORD 4 +#define SPT_COMMENT 5 +#define SPT_OTHER 6
\ No newline at end of file diff --git a/Source/tokens.l b/Source/tokens.l new file mode 100644 index 00000000..941378c3 --- /dev/null +++ b/Source/tokens.l @@ -0,0 +1,323 @@ +%{ +#import "tokens.h" +int utf8strlen(const char *s); + +#define YY_NO_UNPUT + +int yyuoffset, yyuleng; + +#define YY_USER_ACTION { yyuoffset += yyuleng; yyuleng = utf8strlen(yytext); } +%} +%option noyywrap +%option case-insensitive +s [ \t\n]+ +word [a-z_0-9] +nonword [^a-z_0-9#] +%x comment +%% +\"([^"\\]|\\(.|\n))*\"? { return SPT_DOUBLE_QUOTED_TEXT; } /* double quoted strings */ +'([^'\\]|\\(.|\n))*'? { return SPT_SINGLE_QUOTED_TEXT; } /* single quoted strings */ +`[^`]*`? { return SPT_BACKTICK_QUOTED_TEXT; } /* identifier quoting */ +"/*" { BEGIN(comment); return SPT_COMMENT; } +<comment>[^*]* { return SPT_COMMENT; } +<comment>"*"+ { return SPT_COMMENT; } +<comment>"*"+"/" { BEGIN(INITIAL); return SPT_COMMENT; } + +#[^\n]*\n? | +--[ \t][^\n]*\n? { return SPT_COMMENT; } /* -- Comments */ +{s} { return SPT_OTHER; } /* ignore spaces */ +ADD | +ALL | +ALTER{s}TABLE | +ALTER{s}VIEW | +ALTER{s}SCHEMA | +ALTER{s}SCHEMA | +ALTER{s}FUNCTION | +ALTER{s}COLUMN | +ALTER{s}DATABASE | +ALTER{s}PROCEDURE | +ANALYZE | +AND | +ASC | +ASENSITIVE | +BEFORE | +BETWEEN | +BIGINT | +BINARY | +BLOB | +BOTH | +CALL | +CASCADE | +CASE | +CHANGE | +CHAR | +CHARACTER | +CHECK | +COLLATE | +COLUMN | +COLUMNS | +CONDITION | +CONNECTION | +CONSTRAINT | +CONTINUE | +CONVERT | +CREATE{s}VIEW | +CREATE{s}INDEX | +CREATE{s}FUNCTION | +CREATE{s}DATABASE | +CREATE{s}PROCEDURE | +CREATE{s}SCHEMA | +CREATE{s}TRIGGER | +CREATE{s}TABLE | +CREATE{s}USER | +CROSS | +CURRENT_DATE | +CURRENT_TIME | +CURRENT_TIMESTAMP | +CURRENT_USER | +CURSOR | +DATABASE | +DATABASES | +DAY_HOUR | +DAY_MICROSECOND | +DAY_MINUTE | +DAY_SECOND | +DEC | +DECIMAL | +DECLARE | +DEFAULT | +DELAYED | +DELETE | +DESC | +DESCRIBE | +DETERMINISTIC | +DISTINCT | +DISTINCTROW | +DIV | +DOUBLE | +DROP{s}TABLE | +DROP{s}TRIGGER | +DROP{s}VIEW | +DROP{s}SCHEMA | +DROP{s}USER | +DROP{s}PROCEDURE | +DROP{s}FUNCTION | +DROP{s}FOREIGN{s}KEY | +DROP{s}INDEX | +DROP{s}PREPARE | +DROP{s}PRIMARY{s}KEY | +DROP{s}DATABASE | +DUAL | +EACH | +ELSE | +ELSEIF | +ENCLOSED | +ESCAPED | +EXISTS | +EXIT | +EXPLAIN | +FALSE | +FETCH | +FIELDS | +FLOAT | +FOR | +FORCE | +FOREIGN{s}KEY | +FOUND | +FROM | +FULLTEXT | +GOTO | +GRANT | +GROUP | +HAVING | +HIGH_PRIORITY | +HOUR_MICROSECOND | +HOUR_MINUTE | +HOUR_SECOND | +IGNORE | +INDEX | +INFILE | +INNER | +INOUT | +INSENSITIVE | +INSERT | +INT | +INTEGER | +INTERVAL | +INTO | +ITERATE | +JOIN | +KEY | +KEYS | +KILL | +LEADING | +LEAVE | +LEFT | +LIKE | +LIMIT | +LINES | +LOAD | +LOCALTIME | +LOCALTIMESTAMP | +LOCK | +LONG | +LONGBLOB | +LONGTEXT | +LOOP | +LOW_PRIORITY | +MATCH | +MEDIUMBLOB | +MEDIUMINT | +MEDIUMTEXT | +MIDDLEINT | +MINUTE_MICROSECOND | +MINUTE_SECOND | +MOD | +NATURAL | +NOT | +NO_WRITE_TO_BINLOG | +NULL | +NUMERIC | +ON | +OPTIMIZE | +OPTION | +OPTIONALLY | +ORDER | +OUT | +OUTER | +OUTFILE | +PRECISION | +PRIMARY | +PRIVILEGES | +PROCEDURE | +PURGE | +READ | +REAL | +REFERENCES | +REGEXP | +RENAME | +REPEAT | +REPLACE | +REQUIRE | +RESTRICT | +RETURN | +REVOKE | +RIGHT | +RLIKE | +SECOND_MICROSECOND | +SELECT | +SENSITIVE | +SEPARATOR | +SET | +SHOW{s}PROCEDURE{s}STATUS | +SHOW{s}PROCESSLIST | +SHOW{s}SCHEMAS | +SHOW{s}SLAVE{s}HOSTS | +SHOW{s}PRIVILEGES | +SHOW{s}OPEN{s}TABLES | +SHOW{s}MASTER{s}STATUS | +SHOW{s}SLAVE{s}STATUS | +SHOW{s}PLUGIN | +SHOW{s}STORAGE{s}ENGINES | +SHOW{s}VARIABLES | +SHOW{s}WARNINGS | +SHOW{s}TRIGGERS | +SHOW{s}TABLES | +SHOW{s}MASTER{s}LOGS | +SHOW{s}TABLE{s}STATUS | +SHOW{s}TABLE{s}TYPES | +SHOW{s}STATUS | +SHOW{s}INNODB{s}STATUS | +SHOW{s}CREATE{s}DATABASE | +SHOW{s}CREATE{s}FUNCTION | +SHOW{s}CREATE{s}PROCEDURE | +SHOW{s}CREATE{s}SCHEMA | +SHOW{s}COLUMNS | +SHOW{s}COLLATION | +SHOW{s}BINARY{s}LOGS | +SHOW{s}BINLOG{s}EVENTS | +SHOW{s}CHARACTER{s}SET | +SHOW{s}CREATE{s}TABLE | +SHOW{s}CREATE{s}VIEW | +SHOW{s}FUNCTION{s}STATUS | +SHOW{s}GRANTS | +SHOW{s}INDEX | +SHOW{s}FIELDS | +SHOW{s}ERRORS | +SHOW{s}DATABASES | +SHOW{s}ENGINE | +SHOW{s}ENGINES | +SHOW{s}KEYS | +SMALLINT | +SONAME | +SPATIAL | +SPECIFIC | +SQL | +SQLEXCEPTION | +SQLSTATE | +SQLWARNING | +SQL_BIG_RESULT | +SQL_CALC_FOUND_ROWS | +SQL_SMALL_RESULT | +SSL | +STARTING | +STRAIGHT_JOIN | +TABLE | +TABLES | +TERMINATED | +THEN | +TINYBLOB | +TINYINT | +TINYTEXT | +TRAILING | +TRIGGER | +TRUE | +UNDO | +UNION | +UNIQUE | +UNLOCK | +UNSIGNED | +UPDATE | +USAGE | +USE | +USING | +UTC_DATE | +UTC_TIME | +UTC_TIMESTAMP | +VALUES | +VARBINARY | +VARCHAR | +VARCHARACTER | +VARYING | +WHEN | +WHERE | +WHILE | +WITH | +WRITE | +XOR | +YEAR_MONTH | +ZEROFILL { return SPT_RESERVED_WORD; } /* all the mysql reserved words */ +{word}+ { return SPT_OTHER; } /* return any word */ +{nonword} { return SPT_OTHER; } /* return anything else */ + +<<EOF>> { + BEGIN(INITIAL); + yy_delete_buffer(YY_CURRENT_BUFFER); + return 0; + } +%% + +int utf8strlen(const char *s) +/* +This simple function calculates the length of an UTF8 string in characters (not bytes) +It's not especially fast, but it's easy to comprehend +*/ +{ + int j=0; + while (*s) + { + if ((*s & 0xC0) != 0x80) j++; + s++; + } + return (j); +}
\ No newline at end of file |