]> git.saurik.com Git - wxWidgets.git/blob - utils/wxPython/modules/lseditor/sourcepainter.cpp
code cleanup
[wxWidgets.git] / utils / wxPython / modules / lseditor / sourcepainter.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: No names yet.
3 // Purpose: Contrib. demo
4 // Author: Aleksandras Gluchovas
5 // Modified by:
6 // Created: 22/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Aleksandars Gluchovas
9 // Licence: GNU General Public License
10 /////////////////////////////////////////////////////////////////////////////
11 //
12 // This program is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 2 of the License, or
15 // (at your option) any later version.
16 //
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 /////////////////////////////////////////////////////////////////////////////
26
27
28 // For compilers that support precompilation, includes "wx/wx.h".
29 #include "wx/wxprec.h"
30
31 #ifdef __BORLANDC__
32 #pragma hdrstop
33 #endif
34
35 #ifndef WX_PRECOMP
36 #include "wx/wx.h"
37 #endif
38
39 #include "config.h"
40
41 #if defined( wxUSE_TEMPLATE_STL )
42
43 #include <map>
44 using namespace std;
45 #else
46
47 #include <wxstlac.h>
48
49 #endif
50
51 #include "sourcepainter.h"
52
53 const int MAX_KEYWORD_LEN = 16;
54
55 struct KeywordT
56 {
57 char keyWord[MAX_KEYWORD_LEN];
58 int rank;
59 };
60
61 // source fragment ranks :
62
63 // 0 - nomral text
64 // 1 - basic types
65 // 2 - reserved words
66
67 // multil-language keywords map
68
69 static KeywordT __gKeyWords[] =
70 {
71 { "for", 1 },
72 { "FOR", 1 },
73 { "For", 1 },
74
75 { "next", 1 },
76 { "Next", 1 },
77 { "NEXT", 1 },
78
79 { "if", 1 },
80 { "If", 1 },
81 { "IF", 1 },
82
83 { "then", 1 },
84 { "Then", 1 },
85 { "THEN", 1 },
86
87 { "else", 1 },
88 { "Else", 1 },
89 { "ELSE", 1 },
90
91 { "do", 1 },
92 { "Do", 1 },
93 { "DO", 1 },
94
95
96 { "break", 1 },
97 { "Break", 1 },
98 { "BREAK", 1 },
99
100 { "continue", 1 },
101
102 { "goto", 1 },
103 { "Goto", 1 },
104 { "GOTO", 1 },
105
106 { "switch", 1 },
107 { "default", 1 },
108 { "case", 1 },
109
110 { "repeat", 1 },
111 { "Repeat", 1 },
112 { "REPEAT", 1 },
113
114 { "until", 1 },
115 { "Until", 1 },
116 { "UNTIL", 1 },
117
118 { "return", 1 },
119 { "Return", 1 },
120 { "RETURN", 1 },
121
122 { "unit", 1 },
123 { "Unit", 1 },
124 { "UNIT", 1 },
125
126 { "procedure", 1 },
127 { "Procedure", 1 },
128 { "PROCEDURE", 1 },
129
130 { "function", 1 },
131 { "Function", 1 },
132 { "FUNCTION", 1 },
133
134 { "begin", 1 },
135 { "Begin", 1 },
136 { "BEGIN", 1 },
137
138 { "End", 1 },
139 { "END", 1 },
140
141 ////////////////////////////////////////////////////
142
143 { "enum", 1 },
144 { "static", 1 },
145 { "const", 1 },
146 { "mutable", 1 },
147 { "volatile", 1 },
148 { "__asm", 1 },
149 { "asm", 1 },
150
151 { "typeid", 1 },
152 { "sizeof", 1 },
153 { "typeof", 1 },
154
155
156 { "native", 1 },
157
158 { "#include", 1 },
159 { "#define", 1 },
160 { "#def", 1 },
161 { "#undef", 1 },
162 { "#ifdef", 1 },
163 { "#ifndef", 1 },
164 { "#if", 1 },
165 { "#endif", 1 },
166 { "#elif", 1 },
167 { "#else", 1 },
168 { "#pragma", 1 },
169 { "#line", 1 },
170
171 { "package", 1 },
172 { "import", 1 },
173 { "export", 1 },
174
175 ////////////////////////////////////////////////////
176
177 { "dynamic_cast", 1 },
178 { "const_cast", 1 },
179
180 //////// some hacks for VB /////////
181
182 { "sub", 1 },
183 { "Sub", 1 },
184 { "SUB", 1 },
185 { "as", 1 },
186 { "As", 1 },
187 { "AS", 1 },
188
189 /////// data types ///////
190
191 { "int" , 1 },
192 { "integer", 1 },
193 { "Integer", 1 },
194 { "INTEGER", 1 },
195
196 { "real", 1 },
197 { "Real", 1 },
198 { "REAL", 1 },
199
200 { "float", 1 },
201 { "Float", 1 },
202 { "FLOAT", 1 },
203
204 { "char", 1 },
205 { "Char", 1 },
206 { "CHAR", 1 },
207
208 { "register", 1 },
209
210 { "string", 1 },
211 { "String", 1 },
212 { "STRING", 1 },
213
214 { "array", 1 },
215 { "Array", 1 },
216 { "ARRAY", 1 },
217
218 { "packed", 1 },
219 { "Packed", 1 },
220 { "PACKED", 1 },
221
222 { "property", 1 },
223 { "Property", 1 },
224 { "PROPERTY", 1 },
225
226 { "unsigned", 1 },
227
228 { "long", 1 },
229 { "double", 1 },
230 { "short", 1 },
231 { "bool", 1 },
232
233 { "longint", 1 },
234 { "Longint", 1 },
235 { "LONGINT", 1 },
236
237 { "extended", 1 },
238 { "Extended", 1 },
239 { "EXTENTED", 1 },
240
241 { "pointer", 1 },
242 { "Pointer", 1 },
243 { "POINTER", 1 },
244
245 { "and", 1 },
246 { "And", 1 },
247 { "AND", 1 },
248 { "or", 1 },
249 { "Or", 1 },
250 { "OR", 1 },
251 { "xor", 1 },
252 { "Xor", 1 },
253 { "XOR", 1 },
254
255 { "void", 1 },
256 { "__stdcall", 1 },
257 { "__declspec", 1 },
258 { "extern", 1 },
259 { "stdcall", 1 },
260 { "dllimport", 1 },
261 { "dllexport", 1 },
262 { "__cdecl", 1 },
263 { "cdecl", 1 },
264 { "template", 1 },
265 { "typedef", 1 },
266 { "naked", 1 },
267
268 { "try", 1 },
269 { "catch", 1 },
270 { "throw", 2 }, // C++
271 { "throws", 1 }, // Java
272
273
274 { "finalize", 1 },
275
276 // "STL-suport"
277
278 { "size_t", 1 },
279 { "NPOS", 1 },
280 { "vector", 1 },
281 { "list", 1 },
282 { "map", 1 },
283 { "multimap", 1 },
284
285 { "external", 1 },
286 { "External", 1 },
287 { "EXTERNAL", 1 },
288
289 //////////// meta-information //////////////
290
291 { "virtual", 2 },
292 { "Virtual", 2 },
293
294 { "override", 2 },
295 { "Override", 2 },
296
297 { "class", 2 },
298 { "Class", 2 },
299 { "CLASS", 2 },
300
301 { "struct", 2 },
302 { "union", 2 },
303
304 { "record", 2 },
305 { "Record", 2 },
306 { "RECORD", 2 },
307
308 { "form", 1 },
309 { "Form", 1 },
310 { "FORM", 1 },
311
312 { "namespace", 2 },
313
314 { "interface" , 2 },
315 { "abstract", 2 },
316
317 { "Interface" , 2 },
318 { "INTERFACE" , 2 },
319
320 { "implementation", 2 },
321 { "Implementation", 2 },
322 { "IMPLEMENTATION", 2 },
323
324 { "label", 2 },
325 { "Label", 2 },
326 { "LABEL", 2 },
327
328 { "implements", 2 },
329 { "extends", 2 },
330
331 { "public", 2 },
332 { "private", 2 },
333 { "protected", 2 },
334
335 { "this", 1 },
336 { "This", 1 },
337 { "THIS", 1 },
338
339 { "new", 1 },
340 { "New", 1 },
341 { "NEW", 1 },
342
343 { "delete", 2 },
344 { "inline", 2 },
345
346 { "operator", 1 },
347
348 { "Inherited", 2 },
349 { "Inherited", 2 },
350
351 { "final", 2 },
352 { "implements", 2 },
353 { "super", 2 },
354
355 // even more...
356 { "java", 2 },
357 { "Java", 2 },
358 { "JAVA", 2 },
359 { "delphi", 2 },
360 { "Delphi", 2 },
361 { "SmallTalk", 2 },
362 { "Smalltalk", 2 },
363 { "smalltalk", 2 },
364 { "assembler", 2 },
365 { "Assembler", 2 },
366 { "Basic", 2 },
367 { "BASIC", 2 },
368 { "basic", 2 },
369 { "CORBA", 2 },
370 { "COBOL", 2 },
371 { "ADA", 2 },
372 { "LISP", 2 },
373
374 // just for fun...
375 { "life", 2 },
376 { "sucks", 2 },
377 { "rules", 2 },
378 { "Quake", 2 },
379 { "QuakeWorld", 2 },
380 { "[ag_slammer]",2 },
381 { "Aleksandras", 2 },
382 { "Gluchovas" , 2 },
383 { "Alex", 2 },
384 { "alex", 2 },
385 { "aleks", 2 },
386 { "aleksas", 3 },
387 { "AlexSoft", 2 },
388 { "Alexsoft", 2 },
389 { "SpringSky", 2 },
390 { "SK_Team", 2 },
391 { "soften", 2 },
392 { "UB40", 2 },
393 { "U96", 2 }
394 };
395
396 struct less_c_str
397 {
398 inline bool operator()( char* x, char* y) const
399 { return ( strcmp( x,y ) < 0 );
400 }
401 };
402
403 #if defined( wxUSE_TEMPLATE_STL )
404
405 typedef map< char*, char*, less_c_str > KeywordMapT;
406
407 #else
408
409 typedef char* CharPtrT;
410 typedef WXSTL_MAP( CharPtrT, CharPtrT ,less_c_str) KeywordMapT;
411
412 #endif
413
414 static KeywordMapT __gMultiLangMap;
415 static int __gMapReady = 0;
416
417 void check_keyword_map( int keywordMapNr )
418 {
419 if ( !__gMapReady )
420 {
421 __gMapReady = 1;
422
423 // "make sure" the address of the first member of non-polimorphic class
424 // coinsides with the address of the instance
425
426 KeywordT dummy;
427
428 if ( (char*)& dummy != &dummy.keyWord[0] )
429 throw;
430
431 int size = sizeof(__gKeyWords) / sizeof( KeywordT );
432
433 for( int i = 0; i != size; ++i )
434
435 __gMultiLangMap.insert(
436 KeywordMapT::value_type( (char*)&__gKeyWords[i],
437 (char*)&__gKeyWords[i]
438 )
439 );
440 }
441 }
442
443 int get_rank( char* start, char* end )
444 {
445 // FIXME:: what if end is no longer leagal adress?
446
447 char tmp = *end;
448 *end = '\0'; // put temporary terminator
449
450 KeywordMapT::iterator i;
451
452 if ( (i = __gMultiLangMap.find( start ) ) != __gMultiLangMap.end() )
453 {
454 KeywordT* pKey = (KeywordT*)(*i).second;
455
456 *end = tmp;
457
458 return pKey->rank;
459 }
460 else
461 {
462 *end = tmp;
463 return 0;
464 }
465 }
466
467 static inline void store_range( IntListT& results, int rank, int range_len )
468 {
469 if ( !range_len ) return;
470
471 results.push_back ( ( rank << 16 ) | ( range_len ) );
472 }
473
474
475 #define STORE_RANGE store_range( results, cur_rank, cur_range_len );\
476 cur_rank = cur_range_len = 0;
477
478 #define NEXT_CHAR cur_range_len++; \
479 ++cur; \
480 continue;
481
482 static inline int is_alpha( char ch )
483 {
484 return ( (( ch >= '_' ) && ( ch <= 'z' )) ||
485 (( ch >= 'A' ) && ( ch <= 'Z' ))
486 );
487 }
488
489 // _ . .
490 // Ziema atEjo netikEtai
491
492 static void heighlight_syntax( char* str, int strLen,
493 IntListT& results, bool& isComment )
494 {
495 bool isMultiline = 0;
496 char* cur = str;
497 char* end = str + strLen;
498
499 int cur_rank = ( isComment == 1 ) ? RANK_GREEN : RANK_BLACK;
500 int cur_range_len = 0;
501
502 while ( cur != end )
503 {
504 int has_next = ( cur+1 != end );
505
506 if ( isComment )
507 {
508 if ( *cur == '*' )
509 if ( has_next && *(cur+1) == '/' )
510 {
511 // turn off multiline comment mode
512 cur += 2;
513 cur_range_len += 2;
514 isComment = 0;
515 isMultiline = 0;
516 STORE_RANGE;
517
518 continue;
519 }
520
521 ++cur_range_len;
522 ++cur;
523 continue;
524 }
525
526 /*
527 if ( *cur == 10 )
528 if ( isComment )
529 if ( isMultiline )
530 {
531 cur_rank = RANK_GREEN;
532 cur_range_len = end - cur;
533 STORE_RANGE;
534 isComment = 0;
535 isMultiline = 0;
536 continue;
537 }*/
538
539 if ( *cur == '/' )
540 {
541 if ( has_next )
542 {
543 if ( *(cur+1) == '/' )
544 {
545 STORE_RANGE;
546
547 char* eol = cur;
548 while ( eol < end && *eol != 10 )
549 ++eol;
550
551 cur_rank = RANK_GREEN;
552 cur_range_len = eol - cur;
553 cur = eol;
554 STORE_RANGE;
555
556 continue;
557 }
558
559 if ( *(cur+1) == '*' )
560 {
561 STORE_RANGE;
562 cur_rank = RANK_GREEN;
563 cur_range_len = 2;
564 isComment = 1;
565 cur += 2;
566 isMultiline = 1;
567 continue;
568 }
569 }
570
571 NEXT_CHAR;
572 }
573
574 if ( ( is_alpha( *cur ) || *(cur) == '#' )
575 && has_next
576 )
577 {
578 if ( is_alpha( *(cur+1) ) )
579 {
580 char* start = cur;
581 cur += 2;
582
583 while ( cur != end && is_alpha(*cur) ) ++cur;
584
585 int wordRank;
586
587 if ( (wordRank = get_rank( start, cur )) > 0 )
588 {
589 STORE_RANGE;
590
591 store_range( results, wordRank, int(cur-start) );
592 cur_rank = cur_range_len = 0;
593 continue;
594 }
595
596 cur_range_len += ( cur-start );
597 continue;
598 }
599 else
600 NEXT_CHAR;
601 }
602
603 NEXT_CHAR;
604 }
605
606 if ( cur_range_len > 0 ) STORE_RANGE;
607 }
608
609 /***** Implementation for class SourcePainter ******/
610
611 SourcePainter::SourcePainter( bool assembleResultString )
612 : mCollectResultsOn( assembleResultString ),
613 mIsInComment( FALSE ),
614 mCommentIsMultiline( FALSE )
615 {
616 check_keyword_map(0);
617 }
618
619 void SourcePainter::ProcessSource( char* src, int srcLen )
620 {
621 // TBD:: multilne state...
622
623 heighlight_syntax( src, srcLen, mBlocks, mIsInComment );
624
625 if ( mCollectResultsOn )
626
627 mResultStr += string( src, srcLen );
628 }
629
630 void SourcePainter::SetState( bool isInComment,
631 bool commentIsMultiline )
632 {
633 mIsInComment = isInComment;
634 mCommentIsMultiline = commentIsMultiline;
635 }
636
637 void SourcePainter::Init(bool assembleResultString)
638 {
639 mIsInComment = 0;
640 mCommentIsMultiline = 0;
641 mCollectResultsOn = assembleResultString;
642
643 mResultStr = "";
644
645 mBlocks.erase( mBlocks.begin(), mBlocks.end() );
646 }
647
648 static int rank_tags_map[] =
649 {
650 TAG_BLACK_FONT,
651 TAG_BLUE_FONT,
652 TAG_RED_FONT,
653 TAG_GREEN_FONT
654 };
655
656 void SourcePainter::GetResultString(string& result, MarkupTagsT tags)
657 {
658 // this method works, only if results of processing
659 // are collected
660 ASSERT( mCollectResultsOn );
661 result = "";
662
663 int pos = 0;
664
665 for( size_t i = 0; i != mBlocks.size(); ++i )
666 {
667 int desc = mBlocks[i];
668
669 int len = desc & 0xFFFF;
670 int rank = (desc >> 16) & 0xFFFF;
671
672 result += tags[ rank_tags_map[rank] ].start;
673
674 for( int n = 0; n != len; ++n )
675
676 result += mResultStr[pos+n];
677
678 pos += len;
679
680 result += tags[ rank_tags_map[rank] ].end;
681 }
682 }
683
684 IntListT& SourcePainter::GetBlocks()
685 {
686 return mBlocks;
687 }
688
689 bool SourcePainter::IsKeyword( char* word, int wordLen )
690 {
691 check_keyword_map(0);
692
693 int rank = get_rank( word, word + wordLen );
694
695 return ( rank == RANK_BLUE || rank == RANK_RED );
696 }