Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / editors / scapp / syntaxColorize.M
blobc059a319db9e850ef9538b7eb088d33af92b7881
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <Cocoa/Cocoa.h>
23 #include <SCGeom.h>
26 static int linepos, lineno, charno, yylen;
27 static int textpos, textlen, totallen;
28 static unichar *text;
29 static unichar yytext[256];
31 //initializing to default SC colors, these will get overriden
32 //by CocoaDocument.sc upon lang compilation, defaults are given
33 //here so when lang compilation fails, we still have some colors
34 //over the text to debug.
35 SCColor synColText = SCMakeColor(0, 0, 0, 1),
36 synColClass = SCMakeColor(0, 0, 0.75, 1),
37 synColString = SCMakeColor(0.375, 0.375, 0.375, 1),
38 synColSymbol = SCMakeColor(0, 0.45, 0, 1),
39 synColComment = SCMakeColor(0.75, 0, 0, 1),
40 synColNumber = SCMakeColor(0.0, 0.0, 0.0, 1),
41 synColSpecialVals = SCMakeColor(0.2, 0.2, 0.75, 1), // true false nil inf
42 synColSpecialVars = SCMakeColor(0.4, 0.4, 0.75, 1), // super, thisProcess
43 synColDecl = SCMakeColor(0, 0, 1, 1), // var, const, args
44 synColPunc = SCMakeColor(0.0, 0.0, 0.0, 1), // : ; ' [ ] { } ( )
45 synColEnv = SCMakeColor(1.0, 0.4, 0, 1);
47 static bool streq(const char *cstr, unichar *ustr)
49 while (true) {
50 char c = *cstr++;
51 unichar u = *ustr++;
52 if (u != c) return false;
53 else if (u == 0) return true;
55 return false;
58 static unichar input()
60 unichar c;
61 if (textpos > textlen) {
62 c = 0;
63 } else {
64 c = text[textpos++];
65 charno++;
67 if (c == '\n' || c == '\r') {
68 lineno++;
69 linepos = textpos;
70 charno = 0;
72 if (c != 0) yytext[yylen++] = c;
73 //if (gDebugLexer) post("input '%c' %d\n",c,c);
74 return c;
77 static unichar input0()
79 unichar c;
80 if (textpos > textlen) {
81 c = 0;
82 textpos++; // so unput will work properly
83 } else {
84 c = text[textpos++];
85 charno++;
87 if (c == '\n' || c == '\r') {
88 lineno++;
89 linepos = textpos;
90 charno = 0;
92 //if (gDebugLexer) post("input0 '%c' %d\n",c,c);
93 return c;
96 static void unput(unichar c)
98 if (textpos>0) textpos--;
99 if (c) {
100 if (yylen) --yylen;
101 if (charno) --charno;
102 if (c == '\n' || c == '\r') {
103 --lineno;
108 unichar* startColorizer(NSTextView* textView);
109 unichar* startColorizer(NSTextView* textView)
111 totallen = [[textView textStorage] length];
113 NSRange range = [textView selectedRange];
114 if (range.length == 0) range = NSMakeRange(0, totallen);
116 if (![textView shouldChangeTextInRange: range replacementString: nil]) return 0;
118 textpos = range.location;
119 textlen = textpos + range.length;
121 text = (unichar*)malloc((totallen+1) * sizeof(unichar));
122 [[[textView textStorage] string] getCharacters: text];
123 text[totallen] = 0;
125 linepos = 0;
126 lineno = 1;
127 charno = 0;
129 yylen = 0;
131 return text;
134 void SyntaxColorize(NSTextView* textView)
136 unichar c;
137 long startrun = 0, endrun;
138 NSRange range;
139 int startline, clevel, prevc;
140 NSColor* textColor = [NSColor colorWithCalibratedRed: synColText.red green: synColText.green blue: synColText.blue alpha: synColText.alpha];
141 NSColor* commentColor = [NSColor colorWithCalibratedRed: synColComment.red green: synColComment.green blue: synColComment.blue alpha: synColComment.alpha];
142 NSColor* classColor = [NSColor colorWithCalibratedRed: synColClass.red green: synColClass.green blue: synColClass.blue alpha: synColClass.alpha];
143 NSColor* symbolColor = [NSColor colorWithCalibratedRed: synColSymbol.red green: synColSymbol.green blue: synColSymbol.blue alpha: synColSymbol.alpha];
144 NSColor* stringColor = [NSColor colorWithCalibratedRed: synColString.red green: synColString.green blue: synColString.blue alpha: synColString.alpha];
145 NSColor* numberColor = [NSColor colorWithCalibratedRed: synColNumber.red green: synColNumber.green blue: synColNumber.blue alpha: synColNumber.alpha];
146 NSColor* specialValsColor = [NSColor colorWithCalibratedRed: synColSpecialVals.red green: synColSpecialVals.green blue: synColSpecialVals.blue alpha: synColSpecialVals.alpha];
147 NSColor* specialVarsColor = [NSColor colorWithCalibratedRed: synColSpecialVars.red green: synColSpecialVars.green blue: synColSpecialVars.blue alpha: synColSpecialVars.alpha];
148 NSColor* declColor = [NSColor colorWithCalibratedRed: synColDecl.red green: synColDecl.green blue: synColDecl.blue alpha: synColDecl.alpha];
149 NSColor* puncColor = [NSColor colorWithCalibratedRed: synColPunc.red green: synColPunc.green blue: synColPunc.blue alpha: synColPunc.alpha];
150 NSColor* environColor = [NSColor colorWithCalibratedRed: synColEnv.red green: synColEnv.green blue: synColEnv.blue alpha: synColEnv.alpha];
151 NSTextStorage *textStorage = [textView textStorage];
153 if (!startColorizer(textView)) return;
155 [textStorage beginEditing];
157 // reset to textColor
158 range = NSMakeRange(textpos, textlen - textpos);
159 [textStorage addAttribute:NSForegroundColorAttributeName value: textColor range: range];
161 bool bracket = false;
163 for (;;) {
164 yylen = 0;
165 c = input();
166 if (c == 0 || textpos > textlen) goto leave;
167 else if (c==' ' || c=='\t' || c=='\v' || c=='\f' || c=='\n' || c=='\r') {
168 continue;
171 if (c == '|' && bracket) goto arglist;
172 if (c == '{') { bracket = true; }
173 else bracket = false;
175 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') goto ident;
176 else if (c == '\\') goto symbol1;
177 else if (c == '\'') goto symbol3;
178 else if (c == '"') goto string1;
179 else if (c == '/') {
180 c = input0();
181 if (c == '/') goto comment1;
182 else if (c == '*') goto comment2;
183 else {
184 unput(c);
185 continue;
188 else if (c == '$') {
189 c = input0();
190 if (c == '\\') {
191 c = input0();
193 goto characterLiteral;
195 else if(c == '-') goto negnumber; //might be a negative number
196 else if(c >= '0' && c <= '9') goto number;
197 else if(c==':' || c==';' || c=='.' || c == ',' || c=='(' || c==')' || c=='[' || c==']' || c=='{' || c=='}') goto punct;
198 else if(c=='~') goto environment;
199 else {
200 continue;
202 ident:
203 c = input();
205 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
206 || c == '_' || (c >= '0' && c <= '9')) goto ident;
207 else if (c == ':') {
208 yytext[yylen] = 0;
209 //r = processkeywordbinop(yytext) ;
210 continue;
211 } else {
212 unput(c);
213 yytext[yylen] = 0;
214 endrun = textpos;
215 startrun = textpos - yylen;
216 range = NSMakeRange(startrun, endrun - startrun);
217 if (yytext[0] == '_') {
218 [textStorage addAttribute:NSForegroundColorAttributeName value: classColor range: range];
220 else if (yytext[0] >= 'A' && yytext[0] <= 'Z') {
221 [textStorage addAttribute:NSForegroundColorAttributeName value: classColor range: range];
223 else if ( streq("var",yytext)
224 || streq("arg",yytext)
225 || streq("classvar",yytext)
226 || streq("const",yytext)
228 range = NSMakeRange(startrun, endrun - startrun);
229 [textStorage addAttribute:NSForegroundColorAttributeName value: declColor range: range];
231 else if ( streq("this",yytext)
232 || streq("super",yytext)
233 || streq("thisProcess",yytext)
234 || streq("thisThread",yytext)
235 || streq("thisMethod",yytext)
236 || streq("thisFunctionDef",yytext)
237 || streq("thisFunction",yytext)
239 [textStorage addAttribute:NSForegroundColorAttributeName value: specialVarsColor range: range];
241 else if ( streq("nil",yytext)
242 || streq("false",yytext)
243 || streq("true",yytext)
244 || streq("inf",yytext)
246 [textStorage addAttribute:NSForegroundColorAttributeName value: specialValsColor range: range];
248 continue;
250 symbol1:
251 c = input();
253 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
254 || c == '_') {
255 startrun = textpos - 2;
256 goto symbol2;
257 } else {
258 unput(c);
259 yytext[yylen] = 0;
260 continue;
262 symbol2:
263 c = input();
265 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
266 || c == '_' || (c >= '0' && c <= '9')) goto symbol2;
267 else {
268 unput(c);
269 endrun = textpos;
270 range = NSMakeRange(startrun, endrun - startrun);
271 [textStorage addAttribute:NSForegroundColorAttributeName value: symbolColor range: range];
272 continue;
274 symbol3 : {
275 int startline;
276 unichar endchar;
277 startrun = textpos - 1;
278 startline = lineno;
279 endchar = '\'';
281 c = 0;
282 do {
283 prevc = c;
284 c = input0();
285 } while (!(c == endchar && prevc != '\\') && c != 0);
286 if (c == 0 || textpos > textlen) {
287 //postbuf("Open ended symbol ... started on line %d in file '%s'\n",
288 // startline, curfilename);
289 goto error2;
290 } else {
291 endrun = textpos;
292 range = NSMakeRange(startrun, endrun - startrun);
293 [textStorage addAttribute:NSForegroundColorAttributeName value: symbolColor range: range];
294 continue;
298 string1 : {
299 int startline;
300 unichar endchar;
302 startrun = textpos - 1;
303 startline = lineno;
304 endchar = '\"';
306 c = 0;
307 do {
308 prevc = c;
309 c = input0();
310 if(prevc == '\\' && c == '\\') {
311 prevc = c;
312 c = input0();
313 if(c == endchar) break;
315 } while (!(c == endchar && prevc != '\\') && c != 0);
316 if (c == 0 || textpos > textlen) {
317 //postbuf("Open ended string ... started on line %d in file '%s'\n",
318 // startline, curfilename);
319 goto error2;
320 } else {
321 endrun = textpos;
322 range = NSMakeRange(startrun, endrun - startrun);
323 [textStorage addAttribute:NSForegroundColorAttributeName value: stringColor range: range];
324 continue;
327 arglist:
328 startrun = textpos-1;
329 do {
330 c = input0();
331 } while (c != '|' && c != 0);
332 endrun = textpos;
333 if(c != 0){
334 range = NSMakeRange(startrun, endrun - startrun);
335 [textStorage addAttribute:NSForegroundColorAttributeName value: declColor range: range];
337 continue;
338 comment1: /* comment -- to end of line */
339 startrun = textpos-2;
340 do {
341 c = input0();
342 } while (c != '\n' && c != '\r' && c != 0);
343 endrun = textpos;
344 range = NSMakeRange(startrun, endrun - startrun - 1);
345 [textStorage addAttribute:NSForegroundColorAttributeName value: commentColor range: range];
346 continue;
348 comment2:
349 startrun = textpos-2;
350 startline = lineno;
351 prevc = 0;
352 clevel = 1;
353 do {
354 c = input0();
355 if (c == '/' && prevc == '*') {
356 if (--clevel <= 0) break;
357 } else if (c == '*' && prevc == '/') clevel++;
358 prevc = c;
359 } while (c != 0);
360 if (textpos > textlen) {
361 goto error2;
362 } else {
363 endrun = textpos;
364 range = NSMakeRange(startrun, endrun - startrun);
365 [textStorage addAttribute:NSForegroundColorAttributeName value: commentColor range: range];
366 continue;
368 number:
369 startrun = textpos -1;
370 do {
371 c = input0();
372 if(c == '.') { c = input0(); if(c < '0' || c > '9') { unput(c); break; }; };
373 } while ((c >= '0' && c <= '9') || c == '.' || c == ' ');
374 endrun = textpos - 1;
375 range = NSMakeRange(startrun, endrun - startrun);
376 [textStorage addAttribute:NSForegroundColorAttributeName value: numberColor range: range];
377 unput(c);
378 continue;
379 environment:
380 startrun = textpos -1;
381 do {
382 c = input0();
383 } while ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' || (c >= '0' && c <= '9'));
384 endrun = textpos - 1;
385 range = NSMakeRange(startrun, endrun - startrun);
386 [textStorage addAttribute:NSForegroundColorAttributeName value: environColor range: range];
387 unput(c);
388 continue;
389 characterLiteral:
390 if(c == '\\') {
391 startrun = textpos -3;
392 } else {
393 startrun = textpos -2;
395 endrun = textpos;
396 range = NSMakeRange(startrun, endrun - startrun);
397 [textStorage addAttribute:NSForegroundColorAttributeName value: numberColor range: range];
398 continue;
399 punct:
400 startrun = textpos -1;
401 endrun = textpos;
402 range = NSMakeRange(startrun, endrun - startrun);
403 [textStorage addAttribute:NSForegroundColorAttributeName value: puncColor range: range];
404 continue;
405 negnumber:
406 bool numFound = false; //no digit found yet, after minus sign
407 bool reachedStart = false;
408 int tempTextpos = textpos, tempCharno = charno, tempYylen = yylen, tempLineno = lineno;
409 do { //go backwards until you find stg. other than whitespace and numbers
410 unput(c); unput(c);
411 c = input0();
412 if(textpos <= 1) { //beginning of doc. escape!
413 reachedStart = true;
414 break;
416 } while (c == ' ' || c == '\n' || c == '\t' || c == '\v' || c == '\f' || c == '\r' || c == 0 || (c >= '0' && c <= '9'));
417 textpos = tempTextpos; charno = tempCharno; yylen = tempYylen; lineno = tempLineno; //restore original position
418 if(reachedStart) continue;
419 if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' || c == ')' || c == ']') continue; //it must be a subtraction operator, skip.
420 startrun = textpos - 1;
421 do {
422 c = input0();
423 } while(c == ' ' || c == '\n' || c == '\t' || c == '\v' || c == '\f' || c == '\r');
424 if(c >= '0' && c <= '9') {
425 numFound = true;
426 unput(c);
427 endrun = textpos;
429 if(numFound)
431 range = NSMakeRange(startrun, endrun - startrun);
432 [textStorage addAttribute:NSForegroundColorAttributeName value: numberColor range: range];
433 } else goto punct;
434 continue;
437 error2:
439 leave:
440 free(text);
441 [textStorage endEditing];