aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/CMTextView.m82
-rw-r--r--Source/tokens.h15
-rw-r--r--Source/tokens.l323
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