Add an UI to enable/disable specific overlay handlers.
[TortoiseGit.git] / ext / scintilla / src / LexAbaqus.cxx
blob051a8f4e789817895e507deb568f803b056c7a71
1 // Scintilla source code edit control
2 /** @file LexABAQUS.cxx
3 ** Lexer for ABAQUS. Based on the lexer for APDL by Hadar Raz.
4 ** By Sergio Lucato.
5 ** Sort of completely rewritten by Gertjan Kloosterman
6 **/
7 // The License.txt file describes the conditions under which this software may be distributed.
9 // Code folding copyied and modified from LexBasic.cxx
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include <stdio.h>
15 #include <stdarg.h>
17 #include "Platform.h"
19 #include "PropSet.h"
20 #include "Accessor.h"
21 #include "StyleContext.h"
22 #include "KeyWords.h"
23 #include "Scintilla.h"
24 #include "SciLexer.h"
26 #ifdef SCI_NAMESPACE
27 using namespace Scintilla;
28 #endif
30 static inline bool IsAWordChar(const int ch) {
31 return (ch < 0x80 && (isalnum(ch) || (ch == '_')));
34 static inline bool IsAKeywordChar(const int ch) {
35 return (ch < 0x80 && (isalnum(ch) || (ch == '_') || (ch == ' ')));
38 static inline bool IsASetChar(const int ch) {
39 return (ch < 0x80 && (isalnum(ch) || (ch == '_') || (ch == '.') || (ch == '-')));
42 static inline bool IsAnOperator(char ch) {
43 // '.' left out as it is used to make up numbers
44 if (ch == '*' || ch == '/' || ch == '-' || ch == '+' ||
45 ch == '(' || ch == ')' || ch == '=' || ch == '^' ||
46 ch == '[' || ch == ']' || ch == '<' || ch == '&' ||
47 ch == '>' || ch == ',' || ch == '|' || ch == '~' ||
48 ch == '$' || ch == ':' || ch == '%')
49 return true;
50 return false;
53 static void ColouriseABAQUSDoc(unsigned int startPos, int length, int initStyle, WordList*[] /* *keywordlists[] */,
54 Accessor &styler) {
55 enum localState { KW_LINE_KW, KW_LINE_COMMA, KW_LINE_PAR, KW_LINE_EQ, KW_LINE_VAL, \
56 DAT_LINE_VAL, DAT_LINE_COMMA,\
57 COMMENT_LINE,\
58 ST_ERROR, LINE_END } state ;
60 // Do not leak onto next line
61 state = LINE_END ;
62 initStyle = SCE_ABAQUS_DEFAULT;
63 StyleContext sc(startPos, length, initStyle, styler);
65 // Things are actually quite simple
66 // we have commentlines
67 // keywordlines and datalines
68 // On a data line there will only be colouring of numbers
69 // a keyword line is constructed as
70 // *word,[ paramname[=paramvalue]]*
71 // if the line ends with a , the keyword line continues onto the new line
73 for (; sc.More(); sc.Forward()) {
74 switch ( state ) {
75 case KW_LINE_KW :
76 if ( sc.atLineEnd ) {
77 // finished the line in keyword state, switch to LINE_END
78 sc.SetState(SCE_ABAQUS_DEFAULT) ;
79 state = LINE_END ;
80 } else if ( IsAKeywordChar(sc.ch) ) {
81 // nothing changes
82 state = KW_LINE_KW ;
83 } else if ( sc.ch == ',' ) {
84 // Well well we say a comma, arguments *MUST* follow
85 sc.SetState(SCE_ABAQUS_OPERATOR) ;
86 state = KW_LINE_COMMA ;
87 } else {
88 // Flag an error
89 sc.SetState(SCE_ABAQUS_PROCESSOR) ;
90 state = ST_ERROR ;
92 // Done with processing
93 break ;
94 case KW_LINE_COMMA :
95 // acomma on a keywordline was seen
96 if ( IsAKeywordChar(sc.ch)) {
97 sc.SetState(SCE_ABAQUS_ARGUMENT) ;
98 state = KW_LINE_PAR ;
99 } else if ( sc.atLineEnd || (sc.ch == ',') ) {
100 // we remain in keyword mode
101 state = KW_LINE_COMMA ;
102 } else if ( sc.ch == ' ' ) {
103 sc.SetState(SCE_ABAQUS_DEFAULT) ;
104 state = KW_LINE_COMMA ;
105 } else {
106 // Anything else constitutes an error
107 sc.SetState(SCE_ABAQUS_PROCESSOR) ;
108 state = ST_ERROR ;
110 break ;
111 case KW_LINE_PAR :
112 if ( sc.atLineEnd ) {
113 sc.SetState(SCE_ABAQUS_DEFAULT) ;
114 state = LINE_END ;
115 } else if ( IsAKeywordChar(sc.ch) || (sc.ch == '-') ) {
116 // remain in this state
117 state = KW_LINE_PAR ;
118 } else if ( sc.ch == ',' ) {
119 sc.SetState(SCE_ABAQUS_OPERATOR) ;
120 state = KW_LINE_COMMA ;
121 } else if ( sc.ch == '=' ) {
122 sc.SetState(SCE_ABAQUS_OPERATOR) ;
123 state = KW_LINE_EQ ;
124 } else {
125 // Anything else constitutes an error
126 sc.SetState(SCE_ABAQUS_PROCESSOR) ;
127 state = ST_ERROR ;
129 break ;
130 case KW_LINE_EQ :
131 if ( sc.ch == ' ' ) {
132 sc.SetState(SCE_ABAQUS_DEFAULT) ;
133 // remain in this state
134 state = KW_LINE_EQ ;
135 } else if ( IsADigit(sc.ch) || (sc.ch == '-') || (sc.ch == '.' && IsADigit(sc.chNext)) ) {
136 sc.SetState(SCE_ABAQUS_NUMBER) ;
137 state = KW_LINE_VAL ;
138 } else if ( IsAKeywordChar(sc.ch) ) {
139 sc.SetState(SCE_ABAQUS_DEFAULT) ;
140 state = KW_LINE_VAL ;
141 } else if ( (sc.ch == '\'') || (sc.ch == '\"') ) {
142 sc.SetState(SCE_ABAQUS_STRING) ;
143 state = KW_LINE_VAL ;
144 } else {
145 sc.SetState(SCE_ABAQUS_PROCESSOR) ;
146 state = ST_ERROR ;
148 break ;
149 case KW_LINE_VAL :
150 if ( sc.atLineEnd ) {
151 sc.SetState(SCE_ABAQUS_DEFAULT) ;
152 state = LINE_END ;
153 } else if ( IsASetChar(sc.ch) && (sc.state == SCE_ABAQUS_DEFAULT) ) {
154 // nothing changes
155 state = KW_LINE_VAL ;
156 } else if (( (IsADigit(sc.ch) || sc.ch == '.' || (sc.ch == 'e' || sc.ch == 'E') ||
157 ((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) &&
158 (sc.state == SCE_ABAQUS_NUMBER)) {
159 // remain in number mode
160 state = KW_LINE_VAL ;
161 } else if (sc.state == SCE_ABAQUS_STRING) {
162 // accept everything until a closing quote
163 if ( sc.ch == '\'' || sc.ch == '\"' ) {
164 sc.SetState(SCE_ABAQUS_DEFAULT) ;
165 state = KW_LINE_VAL ;
167 } else if ( sc.ch == ',' ) {
168 sc.SetState(SCE_ABAQUS_OPERATOR) ;
169 state = KW_LINE_COMMA ;
170 } else {
171 // anything else is an error
172 sc.SetState(SCE_ABAQUS_PROCESSOR) ;
173 state = ST_ERROR ;
175 break ;
176 case DAT_LINE_VAL :
177 if ( sc.atLineEnd ) {
178 sc.SetState(SCE_ABAQUS_DEFAULT) ;
179 state = LINE_END ;
180 } else if ( IsASetChar(sc.ch) && (sc.state == SCE_ABAQUS_DEFAULT) ) {
181 // nothing changes
182 state = DAT_LINE_VAL ;
183 } else if (( (IsADigit(sc.ch) || sc.ch == '.' || (sc.ch == 'e' || sc.ch == 'E') ||
184 ((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) &&
185 (sc.state == SCE_ABAQUS_NUMBER)) {
186 // remain in number mode
187 state = DAT_LINE_VAL ;
188 } else if (sc.state == SCE_ABAQUS_STRING) {
189 // accept everything until a closing quote
190 if ( sc.ch == '\'' || sc.ch == '\"' ) {
191 sc.SetState(SCE_ABAQUS_DEFAULT) ;
192 state = DAT_LINE_VAL ;
194 } else if ( sc.ch == ',' ) {
195 sc.SetState(SCE_ABAQUS_OPERATOR) ;
196 state = DAT_LINE_COMMA ;
197 } else {
198 // anything else is an error
199 sc.SetState(SCE_ABAQUS_PROCESSOR) ;
200 state = ST_ERROR ;
202 break ;
203 case DAT_LINE_COMMA :
204 // a comma on a data line was seen
205 if ( sc.atLineEnd ) {
206 sc.SetState(SCE_ABAQUS_DEFAULT) ;
207 state = LINE_END ;
208 } else if ( sc.ch == ' ' ) {
209 sc.SetState(SCE_ABAQUS_DEFAULT) ;
210 state = DAT_LINE_COMMA ;
211 } else if (sc.ch == ',') {
212 sc.SetState(SCE_ABAQUS_OPERATOR) ;
213 state = DAT_LINE_COMMA ;
214 } else if ( IsADigit(sc.ch) || (sc.ch == '-')|| (sc.ch == '.' && IsADigit(sc.chNext)) ) {
215 sc.SetState(SCE_ABAQUS_NUMBER) ;
216 state = DAT_LINE_VAL ;
217 } else if ( IsAKeywordChar(sc.ch) ) {
218 sc.SetState(SCE_ABAQUS_DEFAULT) ;
219 state = DAT_LINE_VAL ;
220 } else if ( (sc.ch == '\'') || (sc.ch == '\"') ) {
221 sc.SetState(SCE_ABAQUS_STRING) ;
222 state = DAT_LINE_VAL ;
223 } else {
224 sc.SetState(SCE_ABAQUS_PROCESSOR) ;
225 state = ST_ERROR ;
227 break ;
228 case COMMENT_LINE :
229 if ( sc.atLineEnd ) {
230 sc.SetState(SCE_ABAQUS_DEFAULT) ;
231 state = LINE_END ;
233 break ;
234 case ST_ERROR :
235 if ( sc.atLineEnd ) {
236 sc.SetState(SCE_ABAQUS_DEFAULT) ;
237 state = LINE_END ;
239 break ;
240 case LINE_END :
241 if ( sc.atLineEnd || sc.ch == ' ' ) {
242 // nothing changes
243 state = LINE_END ;
244 } else if ( sc.ch == '*' ) {
245 if ( sc.chNext == '*' ) {
246 state = COMMENT_LINE ;
247 sc.SetState(SCE_ABAQUS_COMMENT) ;
248 } else {
249 state = KW_LINE_KW ;
250 sc.SetState(SCE_ABAQUS_STARCOMMAND) ;
252 } else {
253 // it must be a data line, things are as if we are in DAT_LINE_COMMA
254 if ( sc.ch == ',' ) {
255 sc.SetState(SCE_ABAQUS_OPERATOR) ;
256 state = DAT_LINE_COMMA ;
257 } else if ( IsADigit(sc.ch) || (sc.ch == '-')|| (sc.ch == '.' && IsADigit(sc.chNext)) ) {
258 sc.SetState(SCE_ABAQUS_NUMBER) ;
259 state = DAT_LINE_VAL ;
260 } else if ( IsAKeywordChar(sc.ch) ) {
261 sc.SetState(SCE_ABAQUS_DEFAULT) ;
262 state = DAT_LINE_VAL ;
263 } else if ( (sc.ch == '\'') || (sc.ch == '\"') ) {
264 sc.SetState(SCE_ABAQUS_STRING) ;
265 state = DAT_LINE_VAL ;
266 } else {
267 sc.SetState(SCE_ABAQUS_PROCESSOR) ;
268 state = ST_ERROR ;
271 break ;
274 sc.Complete();
277 //------------------------------------------------------------------------------
278 // This copyied and modified from LexBasic.cxx
279 //------------------------------------------------------------------------------
281 /* Bits:
282 * 1 - whitespace
283 * 2 - operator
284 * 4 - identifier
285 * 8 - decimal digit
286 * 16 - hex digit
287 * 32 - bin digit
289 static int character_classification[128] =
291 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
292 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
293 1, 2, 0, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2, 2, 10, 6,
294 60, 60, 28, 28, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2, 2, 2,
295 2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,
296 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 4,
297 2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4,
298 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0
301 static bool IsSpace(int c) {
302 return c < 128 && (character_classification[c] & 1);
305 static bool IsIdentifier(int c) {
306 return c < 128 && (character_classification[c] & 4);
309 static int LowerCase(int c)
311 if (c >= 'A' && c <= 'Z')
312 return 'a' + c - 'A';
313 return c;
316 static int LineEnd(int line, Accessor &styler)
318 const int docLines = styler.GetLine(styler.Length() - 1); // Available last line
319 int eol_pos ;
320 // if the line is the last line, the eol_pos is styler.Length()
321 // eol will contain a new line, or a virtual new line
322 if ( docLines == line )
323 eol_pos = styler.Length() ;
324 else
325 eol_pos = styler.LineStart(line + 1) - 1;
326 return eol_pos ;
329 static int LineStart(int line, Accessor &styler)
331 return styler.LineStart(line) ;
334 // LineType
336 // bits determines the line type
337 // 1 : data line
338 // 2 : only whitespace
339 // 3 : data line with only whitespace
340 // 4 : keyword line
341 // 5 : block open keyword line
342 // 6 : block close keyword line
343 // 7 : keyword line in error
344 // 8 : comment line
345 static int LineType(int line, Accessor &styler) {
346 int pos = LineStart(line, styler) ;
347 int eol_pos = LineEnd(line, styler) ;
349 int c ;
350 char ch = ' ';
352 int i = pos ;
353 while ( i < eol_pos ) {
354 c = styler.SafeGetCharAt(i);
355 ch = static_cast<char>(LowerCase(c));
356 // We can say something as soon as no whitespace
357 // was encountered
358 if ( !IsSpace(c) )
359 break ;
360 i++ ;
363 if ( i >= eol_pos ) {
364 // This is a whitespace line, currently
365 // classifies as data line
366 return 3 ;
369 if ( ch != '*' ) {
370 // This is a data line
371 return 1 ;
374 if ( i == eol_pos - 1 ) {
375 // Only a single *, error but make keyword line
376 return 4+3 ;
379 // This means we can have a second character
380 // if that is also a * this means a comment
381 // otherwise it is a keyword.
382 c = styler.SafeGetCharAt(i+1);
383 ch = static_cast<char>(LowerCase(c));
384 if ( ch == '*' ) {
385 return 8 ;
388 // At this point we know this is a keyword line
389 // the character at position i is a *
390 // it is not a comment line
391 char word[256] ;
392 int wlen = 0;
394 word[wlen] = '*' ;
395 wlen++ ;
397 i++ ;
398 while ( (i < eol_pos) && (wlen < 255) ) {
399 c = styler.SafeGetCharAt(i);
400 ch = static_cast<char>(LowerCase(c));
402 if ( (!IsSpace(c)) && (!IsIdentifier(c)) )
403 break ;
405 if ( IsIdentifier(c) ) {
406 word[wlen] = ch ;
407 wlen++ ;
410 i++ ;
413 word[wlen] = 0 ;
415 // Make a comparison
416 if ( !strcmp(word, "*step") ||
417 !strcmp(word, "*part") ||
418 !strcmp(word, "*instance") ||
419 !strcmp(word, "*assembly")) {
420 return 4+1 ;
423 if ( !strcmp(word, "*endstep") ||
424 !strcmp(word, "*endpart") ||
425 !strcmp(word, "*endinstance") ||
426 !strcmp(word, "*endassembly")) {
427 return 4+2 ;
430 return 4 ;
433 static void SafeSetLevel(int line, int level, Accessor &styler)
435 if ( line < 0 )
436 return ;
438 int mask = ((~SC_FOLDLEVELHEADERFLAG) | (~SC_FOLDLEVELWHITEFLAG));
440 if ( (level & mask) < 0 )
441 return ;
443 if ( styler.LevelAt(line) != level )
444 styler.SetLevel(line, level) ;
447 static void FoldABAQUSDoc(unsigned int startPos, int length, int,
448 WordList *[], Accessor &styler) {
449 int startLine = styler.GetLine(startPos) ;
450 int endLine = styler.GetLine(startPos+length-1) ;
452 // bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
453 // We want to deal with all the cases
454 // To know the correct indentlevel, we need to look back to the
455 // previous command line indentation level
456 // order of formatting keyline datalines commentlines
457 int beginData = -1 ;
458 int beginComment = -1 ;
459 int prvKeyLine = startLine ;
460 int prvKeyLineTp = 0 ;
462 // Scan until we find the previous keyword line
463 // this will give us the level reference that we need
464 while ( prvKeyLine > 0 ) {
465 prvKeyLine-- ;
466 prvKeyLineTp = LineType(prvKeyLine, styler) ;
467 if ( prvKeyLineTp & 4 )
468 break ;
471 // Determine the base line level of all lines following
472 // the previous keyword
473 // new keyword lines are placed on this level
474 //if ( prvKeyLineTp & 4 ) {
475 int level = styler.LevelAt(prvKeyLine) & ~SC_FOLDLEVELHEADERFLAG ;
478 // uncomment line below if weird behaviour continues
479 prvKeyLine = -1 ;
481 // Now start scanning over the lines.
482 for ( int line = startLine; line <= endLine; line++ ) {
483 int lineType = LineType(line, styler) ;
485 // Check for comment line
486 if ( lineType == 8 ) {
487 if ( beginComment < 0 ) {
488 beginComment = line ;
492 // Check for data line
493 if ( (lineType == 1) || (lineType == 3) ) {
494 if ( beginData < 0 ) {
495 if ( beginComment >= 0 ) {
496 beginData = beginComment ;
497 } else {
498 beginData = line ;
501 beginComment = -1 ;
504 // Check for keywordline.
505 // As soon as a keyword line is encountered, we can set the
506 // levels of everything from the previous keyword line to this one
507 if ( lineType & 4 ) {
508 // this is a keyword, we can now place the previous keyword
509 // all its data lines and the remainder
511 // Write comments and data line
512 if ( beginComment < 0 ) {
513 beginComment = line ;
516 if ( beginData < 0 ) {
517 beginData = beginComment ;
518 if ( prvKeyLineTp != 5 )
519 SafeSetLevel(prvKeyLine, level, styler) ;
520 else
521 SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ;
522 } else {
523 SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ;
526 int datLevel = level + 1 ;
527 if ( !(prvKeyLineTp & 4) ) {
528 datLevel = level ;
531 for ( int ll = beginData; ll < beginComment; ll++ )
532 SafeSetLevel(ll, datLevel, styler) ;
534 // The keyword we just found is going to be written at another level
535 // if we have a type 5 and type 6
536 if ( prvKeyLineTp == 5 ) {
537 level += 1 ;
540 if ( prvKeyLineTp == 6 ) {
541 level -= 1 ;
542 if ( level < 0 ) {
543 level = 0 ;
547 for ( int lll = beginComment; lll < line; lll++ )
548 SafeSetLevel(lll, level, styler) ;
550 // wrap and reset
551 beginComment = -1 ;
552 beginData = -1 ;
553 prvKeyLine = line ;
554 prvKeyLineTp = lineType ;
559 if ( beginComment < 0 ) {
560 beginComment = endLine + 1 ;
561 } else {
562 // We need to find out whether this comment block is followed by
563 // a data line or a keyword line
564 const int docLines = styler.GetLine(styler.Length() - 1);
566 for ( int line = endLine + 1; line <= docLines; line++ ) {
567 int lineType = LineType(line, styler) ;
569 if ( lineType != 8 ) {
570 if ( !(lineType & 4) ) {
571 beginComment = endLine + 1 ;
573 break ;
578 if ( beginData < 0 ) {
579 beginData = beginComment ;
580 if ( prvKeyLineTp != 5 )
581 SafeSetLevel(prvKeyLine, level, styler) ;
582 else
583 SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ;
584 } else {
585 SafeSetLevel(prvKeyLine, level | SC_FOLDLEVELHEADERFLAG, styler) ;
588 int datLevel = level + 1 ;
589 if ( !(prvKeyLineTp & 4) ) {
590 datLevel = level ;
593 for ( int ll = beginData; ll < beginComment; ll++ )
594 SafeSetLevel(ll, datLevel, styler) ;
596 if ( prvKeyLineTp == 5 ) {
597 level += 1 ;
600 if ( prvKeyLineTp == 6 ) {
601 level -= 1 ;
603 for ( int m = beginComment; m <= endLine; m++ )
604 SafeSetLevel(m, level, styler) ;
607 static const char * const abaqusWordListDesc[] = {
608 "processors",
609 "commands",
610 "slashommands",
611 "starcommands",
612 "arguments",
613 "functions",
617 LexerModule lmAbaqus(SCLEX_ABAQUS, ColouriseABAQUSDoc, "abaqus", FoldABAQUSDoc, abaqusWordListDesc);