]> git.saurik.com Git - wxWidgets.git/blame - src/stc/scintilla/lexers/LexPowerPro.cxx
Add missing WXK constants for the control keys
[wxWidgets.git] / src / stc / scintilla / lexers / LexPowerPro.cxx
CommitLineData
9e96e16f
RD
1// Scintilla source code edit control
2// @file LexPowerPro.cxx
3// PowerPro utility, written by Bruce Switzer, is available from http://powerpro.webeddie.com
4// PowerPro lexer is written by Christopher Bean (cbean@cb-software.net)
5//
1dcf666d 6// Lexer code heavily borrowed from:
9e96e16f
RD
7// LexAU3.cxx by Jos van der Zande
8// LexCPP.cxx by Neil Hodgson
9// LexVB.cxx by Neil Hodgson
10//
11// Changes:
12// 2008-10-25 - Initial release
1dcf666d 13// 2008-10-26 - Changed how <name> is hilighted in 'function <name>' so that
9e96e16f 14// local isFunction = "" and local functions = "" don't get falsely highlighted
1dcf666d 15// 2008-12-14 - Added bounds checking for szFirstWord and szDo
9e96e16f
RD
16// - Replaced SetOfCharacters with CharacterSet
17// - Made sure that CharacterSet::Contains is passed only positive values
1dcf666d
RD
18// - Made sure that the return value of Accessor::SafeGetCharAt is positive before
19// passing to functions that require positive values like isspacechar()
9e96e16f 20// - Removed unused visibleChars processing from ColourisePowerProDoc()
1dcf666d 21// - Fixed bug with folding logic where line continuations didn't end where
9e96e16f
RD
22// they were supposed to
23// - Moved all helper functions to the top of the file
1dcf666d
RD
24// 2010-06-03 - Added onlySpaces variable to allow the @function and ;comment styles to be indented
25// - Modified HasFunction function to be a bit more robust
26// - Renamed HasFunction function to IsFunction
27// - Cleanup
9e96e16f
RD
28// Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
29// The License.txt file describes the conditions under which this software may be distributed.
30
9e96e16f 31#include <string.h>
1dcf666d
RD
32#include <assert.h>
33#include <ctype.h>
9e96e16f 34
1dcf666d 35#include "ILexer.h"
9e96e16f
RD
36#include "Scintilla.h"
37#include "SciLexer.h"
1dcf666d
RD
38
39#include "WordList.h"
40#include "LexAccessor.h"
41#include "Accessor.h"
42#include "StyleContext.h"
9e96e16f 43#include "CharacterSet.h"
1dcf666d 44#include "LexerModule.h"
9e96e16f
RD
45
46#ifdef SCI_NAMESPACE
47using namespace Scintilla;
48#endif
49
50static inline bool IsStreamCommentStyle(int style) {
51 return style == SCE_POWERPRO_COMMENTBLOCK;
52}
53
1dcf666d
RD
54static inline bool IsLineEndChar(unsigned char ch) {
55 return ch == 0x0a //LF
56 || ch == 0x0c //FF
57 || ch == 0x0d; //CR
58}
59
9e96e16f
RD
60static bool IsContinuationLine(unsigned int szLine, Accessor &styler)
61{
1dcf666d
RD
62 int startPos = styler.LineStart(szLine);
63 int endPos = styler.LineStart(szLine + 1) - 2;
64 while (startPos < endPos)
9e96e16f 65 {
1dcf666d 66 char stylech = styler.StyleAt(startPos);
9e96e16f 67 if (!(stylech == SCE_POWERPRO_COMMENTBLOCK)) {
1dcf666d
RD
68 char ch = styler.SafeGetCharAt(endPos);
69 char chPrev = styler.SafeGetCharAt(endPos - 1);
70 char chPrevPrev = styler.SafeGetCharAt(endPos - 2);
71 if (ch > 0 && chPrev > 0 && chPrevPrev > 0 && !isspacechar(ch) && !isspacechar(chPrev) && !isspacechar(chPrevPrev) )
72 return (chPrevPrev == ';' && chPrev == ';' && ch == '+');
9e96e16f 73 }
1dcf666d 74 endPos--; // skip to next char
9e96e16f
RD
75 }
76 return false;
77}
78
79// Routine to find first none space on the current line and return its Style
1dcf666d
RD
80// needed for comment lines not starting on pos 1
81static int GetStyleFirstWord(int szLine, Accessor &styler)
9e96e16f 82{
1dcf666d
RD
83 int startPos = styler.LineStart(szLine);
84 int endPos = styler.LineStart(szLine + 1) - 1;
85 char ch = styler.SafeGetCharAt(startPos);
9e96e16f 86
1dcf666d
RD
87 while (ch > 0 && isspacechar(ch) && startPos < endPos)
88 {
89 startPos++; // skip to next char
90 ch = styler.SafeGetCharAt(startPos);
9e96e16f 91 }
1dcf666d 92 return styler.StyleAt(startPos);
9e96e16f
RD
93}
94
95//returns true if there is a function to highlight
96//used to highlight <name> in 'function <name>'
1dcf666d
RD
97//note:
98// sample line (without quotes): "\tfunction asdf()
99// currentPos will be the position of 'a'
100static bool IsFunction(Accessor &styler, unsigned int currentPos) {
101
102 const char function[10] = "function "; //10 includes \0
103 unsigned int numberOfCharacters = sizeof(function) - 1;
104 unsigned int position = currentPos - numberOfCharacters;
105
106 //compare each character with the letters in the function array
107 //return false if ALL don't match
108 for (unsigned int i = 0; i < numberOfCharacters; i++) {
109 char c = styler.SafeGetCharAt(position++);
110 if (c != function[i])
111 return false;
112 }
113
114 //make sure that there are only spaces (or tabs) between the beginning
115 //of the line and the function declaration
116 position = currentPos - numberOfCharacters - 1; //-1 to move to char before 'function'
117 for (unsigned int j = 0; j < 16; j++) { //check up to 16 preceeding characters
118 char c = styler.SafeGetCharAt(position--, '\0'); //if can't read char, return NUL (past beginning of document)
119 if (c <= 0) //reached beginning of document
120 return true;
121 if (c > 0 && IsLineEndChar(c))
122 return true;
123 else if (c > 0 && !IsASpaceOrTab(c))
124 return false;
125 }
126
127 //fall-through
128 return false;
9e96e16f
RD
129}
130
131static void ColourisePowerProDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
132 Accessor &styler, bool caseSensitive) {
133
134 WordList &keywords = *keywordlists[0];
135 WordList &keywords2 = *keywordlists[1];
136 WordList &keywords3 = *keywordlists[2];
137 WordList &keywords4 = *keywordlists[3];
1dcf666d
RD
138
139 //define the character sets
9e96e16f
RD
140 CharacterSet setWordStart(CharacterSet::setAlpha, "_@", 0x80, true);
141 CharacterSet setWord(CharacterSet::setAlphaNum, "._", 0x80, true);
142
143 StyleContext sc(startPos, length, initStyle, styler);
144 char s_save[100]; //for last line highlighting
1dcf666d
RD
145
146 //are there only spaces between the first letter of the line and the beginning of the line
147 bool onlySpaces = true;
148
9e96e16f 149 for (; sc.More(); sc.Forward()) {
1dcf666d 150
9e96e16f
RD
151 // save the total current word for eof processing
152 char s[100];
153 sc.GetCurrentLowered(s, sizeof(s));
1dcf666d
RD
154
155 if ((sc.ch > 0) && setWord.Contains(sc.ch))
9e96e16f
RD
156 {
157 strcpy(s_save,s);
1dcf666d 158 int tp = static_cast<int>(strlen(s_save));
9e96e16f
RD
159 if (tp < 99) {
160 s_save[tp] = static_cast<char>(tolower(sc.ch));
161 s_save[tp+1] = '\0';
162 }
163 }
9e96e16f
RD
164
165 if (sc.atLineStart) {
166 if (sc.state == SCE_POWERPRO_DOUBLEQUOTEDSTRING) {
167 // Prevent SCE_POWERPRO_STRINGEOL from leaking back to previous line which
168 // ends with a line continuation by locking in the state upto this position.
169 sc.SetState(SCE_POWERPRO_DOUBLEQUOTEDSTRING);
170 }
171 }
172
173 // Determine if the current state should terminate.
174 switch (sc.state) {
175 case SCE_POWERPRO_OPERATOR:
176 sc.SetState(SCE_POWERPRO_DEFAULT);
177 break;
1dcf666d 178
9e96e16f
RD
179 case SCE_POWERPRO_NUMBER:
180
181 if (!IsADigit(sc.ch))
182 sc.SetState(SCE_POWERPRO_DEFAULT);
1dcf666d 183
9e96e16f
RD
184 break;
185
186 case SCE_POWERPRO_IDENTIFIER:
187 //if ((sc.ch > 0) && !setWord.Contains(sc.ch) || (sc.ch == '.')) { // use this line if don't want to match keywords with . in them. ie: win.debug will match both win and debug so win debug will also be colorized
188 if ((sc.ch > 0) && !setWord.Contains(sc.ch)){ // || (sc.ch == '.')) { // use this line if you want to match keywords with a . ie: win.debug will only match win.debug neither win nor debug will be colorized separately
189 char s[1000];
190 if (caseSensitive) {
191 sc.GetCurrent(s, sizeof(s));
192 } else {
193 sc.GetCurrentLowered(s, sizeof(s));
194 }
1dcf666d 195
9e96e16f
RD
196 if (keywords.InList(s)) {
197 sc.ChangeState(SCE_POWERPRO_WORD);
198 } else if (keywords2.InList(s)) {
199 sc.ChangeState(SCE_POWERPRO_WORD2);
200 } else if (keywords3.InList(s)) {
201 sc.ChangeState(SCE_POWERPRO_WORD3);
202 } else if (keywords4.InList(s)) {
203 sc.ChangeState(SCE_POWERPRO_WORD4);
204 }
205 sc.SetState(SCE_POWERPRO_DEFAULT);
206 }
207 break;
208
209 case SCE_POWERPRO_LINECONTINUE:
210 if (sc.atLineStart) {
211 sc.SetState(SCE_POWERPRO_DEFAULT);
212 } else if (sc.Match('/', '*') || sc.Match('/', '/')) {
213 sc.SetState(SCE_POWERPRO_DEFAULT);
214 }
215 break;
216
217 case SCE_POWERPRO_COMMENTBLOCK:
218 if (sc.Match('*', '/')) {
219 sc.Forward();
220 sc.ForwardSetState(SCE_POWERPRO_DEFAULT);
221 }
222 break;
223
224 case SCE_POWERPRO_COMMENTLINE:
225 if (sc.atLineStart) {
226 sc.SetState(SCE_POWERPRO_DEFAULT);
227 }
228 break;
229
230 case SCE_POWERPRO_DOUBLEQUOTEDSTRING:
231 if (sc.atLineEnd) {
232 sc.ChangeState(SCE_POWERPRO_STRINGEOL);
233 } else if (sc.ch == '\\') {
234 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
235 sc.Forward();
236 }
237 } else if (sc.ch == '\"') {
238 sc.ForwardSetState(SCE_POWERPRO_DEFAULT);
239 }
240 break;
241
242 case SCE_POWERPRO_SINGLEQUOTEDSTRING:
243 if (sc.atLineEnd) {
244 sc.ChangeState(SCE_POWERPRO_STRINGEOL);
245 } else if (sc.ch == '\\') {
246 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
247 sc.Forward();
248 }
249 } else if (sc.ch == '\'') {
250 sc.ForwardSetState(SCE_POWERPRO_DEFAULT);
251 }
252 break;
253
254 case SCE_POWERPRO_STRINGEOL:
255 if (sc.atLineStart) {
256 sc.SetState(SCE_POWERPRO_DEFAULT);
257 }
258 break;
259
260 case SCE_POWERPRO_VERBATIM:
261 if (sc.ch == '\"') {
262 if (sc.chNext == '\"') {
263 sc.Forward();
264 } else {
265 sc.ForwardSetState(SCE_POWERPRO_DEFAULT);
266 }
267 }
268 break;
269
270 case SCE_POWERPRO_ALTQUOTE:
271 if (sc.ch == '#') {
272 if (sc.chNext == '#') {
273 sc.Forward();
274 } else {
275 sc.ForwardSetState(SCE_POWERPRO_DEFAULT);
276 }
277 }
278 break;
1dcf666d 279
9e96e16f 280 case SCE_POWERPRO_FUNCTION:
1dcf666d 281 if (isspacechar(sc.ch) || sc.ch == '(') {
9e96e16f
RD
282 sc.SetState(SCE_POWERPRO_DEFAULT);
283 }
284 break;
285 }
286
287 // Determine if a new state should be entered.
288 if (sc.state == SCE_POWERPRO_DEFAULT) {
289 if (sc.Match('?', '\"')) {
290 sc.SetState(SCE_POWERPRO_VERBATIM);
291 sc.Forward();
292 } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
293 sc.SetState(SCE_POWERPRO_NUMBER);
294 }else if (sc.Match('?','#')) {
295 if (sc.ch == '?' && sc.chNext == '#') {
296 sc.SetState(SCE_POWERPRO_ALTQUOTE);
297 sc.Forward();
298 }
1dcf666d
RD
299 } else if (IsFunction(styler, sc.currentPos)) { //highlight <name> in 'function <name>'
300 sc.SetState(SCE_POWERPRO_FUNCTION);
301 } else if (onlySpaces && sc.ch == '@') { //alternate function definition [label]
9e96e16f
RD
302 sc.SetState(SCE_POWERPRO_FUNCTION);
303 } else if ((sc.ch > 0) && (setWordStart.Contains(sc.ch) || (sc.ch == '?'))) {
304 sc.SetState(SCE_POWERPRO_IDENTIFIER);
1dcf666d 305 } else if (sc.Match(";;+")) {
9e96e16f
RD
306 sc.SetState(SCE_POWERPRO_LINECONTINUE);
307 } else if (sc.Match('/', '*')) {
308 sc.SetState(SCE_POWERPRO_COMMENTBLOCK);
309 sc.Forward(); // Eat the * so it isn't used for the end of the comment
310 } else if (sc.Match('/', '/')) {
311 sc.SetState(SCE_POWERPRO_COMMENTLINE);
1dcf666d 312 } else if (onlySpaces && sc.ch == ';') { //legacy comment that can only have blank space in front of it
9e96e16f
RD
313 sc.SetState(SCE_POWERPRO_COMMENTLINE);
314 } else if (sc.Match(";;")) {
315 sc.SetState(SCE_POWERPRO_COMMENTLINE);
316 } else if (sc.ch == '\"') {
317 sc.SetState(SCE_POWERPRO_DOUBLEQUOTEDSTRING);
318 } else if (sc.ch == '\'') {
319 sc.SetState(SCE_POWERPRO_SINGLEQUOTEDSTRING);
320 } else if (isoperator(static_cast<char>(sc.ch))) {
321 sc.SetState(SCE_POWERPRO_OPERATOR);
322 }
323 }
1dcf666d
RD
324
325 //maintain a record of whether or not all the preceding characters on
326 //a line are space characters
327 if (onlySpaces && !IsASpaceOrTab(sc.ch))
328 onlySpaces = false;
329
330 //reset when starting a new line
331 if (sc.atLineEnd)
332 onlySpaces = true;
9e96e16f
RD
333 }
334
335 //*************************************
1dcf666d 336 // Colourize the last word correctly
9e96e16f
RD
337 //*************************************
338 if (sc.state == SCE_POWERPRO_IDENTIFIER)
339 {
340 if (keywords.InList(s_save)) {
341 sc.ChangeState(SCE_POWERPRO_WORD);
342 sc.SetState(SCE_POWERPRO_DEFAULT);
343 }
344 else if (keywords2.InList(s_save)) {
345 sc.ChangeState(SCE_POWERPRO_WORD2);
346 sc.SetState(SCE_POWERPRO_DEFAULT);
347 }
348 else if (keywords3.InList(s_save)) {
349 sc.ChangeState(SCE_POWERPRO_WORD3);
350 sc.SetState(SCE_POWERPRO_DEFAULT);
351 }
352 else if (keywords4.InList(s_save)) {
353 sc.ChangeState(SCE_POWERPRO_WORD4);
354 sc.SetState(SCE_POWERPRO_DEFAULT);
355 }
356 else {
357 sc.SetState(SCE_POWERPRO_DEFAULT);
358 }
359 }
360 sc.Complete();
361}
362
363static void FoldPowerProDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler)
364{
365 //define the character sets
366 CharacterSet setWordStart(CharacterSet::setAlpha, "_@", 0x80, true);
367 CharacterSet setWord(CharacterSet::setAlphaNum, "._", 0x80, true);
368
1dcf666d
RD
369 //used to tell if we're recursively folding the whole document, or just a small piece (ie: if statement or 1 function)
370 bool isFoldingAll = true;
371
9e96e16f
RD
372 int endPos = startPos + length;
373 int lastLine = styler.GetLine(styler.Length()); //used to help fold the last line correctly
374
375 // get settings from the config files for folding comments and preprocessor lines
376 bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
377 bool foldInComment = styler.GetPropertyInt("fold.comment") == 2;
378 bool foldCompact = true;
1dcf666d 379
9e96e16f
RD
380 // Backtrack to previous line in case need to fix its fold status
381 int lineCurrent = styler.GetLine(startPos);
382 if (startPos > 0) {
383 isFoldingAll = false;
384 if (lineCurrent > 0) {
385 lineCurrent--;
386 startPos = styler.LineStart(lineCurrent);
387 }
388 }
1dcf666d 389 // vars for style of previous/current/next lines
9e96e16f
RD
390 int style = GetStyleFirstWord(lineCurrent,styler);
391 int stylePrev = 0;
1dcf666d 392
9e96e16f 393 // find the first previous line without continuation character at the end
1dcf666d
RD
394 while ((lineCurrent > 0 && IsContinuationLine(lineCurrent, styler))
395 || (lineCurrent > 1 && IsContinuationLine(lineCurrent - 1, styler))) {
9e96e16f
RD
396 lineCurrent--;
397 startPos = styler.LineStart(lineCurrent);
398 }
1dcf666d 399
9e96e16f
RD
400 if (lineCurrent > 0) {
401 stylePrev = GetStyleFirstWord(lineCurrent-1,styler);
402 }
1dcf666d 403
9e96e16f 404 // vars for getting first word to check for keywords
1dcf666d
RD
405 bool isFirstWordStarted = false;
406 bool isFirstWordEnded = false;
407
408 const unsigned int FIRST_WORD_MAX_LEN = 10;
409 char szFirstWord[FIRST_WORD_MAX_LEN] = "";
410 unsigned int firstWordLen = 0;
411
9e96e16f
RD
412 char szDo[3]="";
413 int szDolen = 0;
1dcf666d
RD
414 bool isDoLastWord = false;
415
9e96e16f
RD
416 // var for indentlevel
417 int levelCurrent = SC_FOLDLEVELBASE;
1dcf666d 418 if (lineCurrent > 0)
9e96e16f 419 levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
9e96e16f 420 int levelNext = levelCurrent;
1dcf666d 421
9e96e16f
RD
422 int visibleChars = 0;
423 int functionCount = 0;
1dcf666d 424
9e96e16f
RD
425 char chNext = styler.SafeGetCharAt(startPos);
426 char chPrev = '\0';
427 char chPrevPrev = '\0';
428 char chPrevPrevPrev = '\0';
1dcf666d 429
9e96e16f
RD
430 for (int i = startPos; i < endPos; i++) {
431
432 char ch = chNext;
433 chNext = styler.SafeGetCharAt(i + 1);
1dcf666d
RD
434
435 if ((ch > 0) && setWord.Contains(ch))
9e96e16f 436 visibleChars++;
1dcf666d 437
9e96e16f
RD
438 // get the syle for the current character neede to check in comment
439 int stylech = styler.StyleAt(i);
1dcf666d
RD
440
441 // start the capture of the first word
442 if (!isFirstWordStarted && (ch > 0)) {
443 if (setWord.Contains(ch) || setWordStart.Contains(ch) || ch == ';' || ch == '/') {
444 isFirstWordStarted = true;
445 if (firstWordLen < FIRST_WORD_MAX_LEN - 1) {
446 szFirstWord[firstWordLen++] = static_cast<char>(tolower(ch));
447 szFirstWord[firstWordLen] = '\0';
448 }
9e96e16f 449 }
1dcf666d
RD
450 } // continue capture of the first word on the line
451 else if (isFirstWordStarted && !isFirstWordEnded && (ch > 0)) {
452 if (!setWord.Contains(ch)) {
453 isFirstWordEnded = true;
9e96e16f 454 }
1dcf666d
RD
455 else if (firstWordLen < (FIRST_WORD_MAX_LEN - 1)) {
456 szFirstWord[firstWordLen++] = static_cast<char>(tolower(ch));
457 szFirstWord[firstWordLen] = '\0';
9e96e16f
RD
458 }
459 }
1dcf666d 460
9e96e16f 461 if (stylech != SCE_POWERPRO_COMMENTLINE) {
1dcf666d
RD
462
463 //reset isDoLastWord if we find a character(ignoring spaces) after 'do'
464 if (isDoLastWord && (ch > 0) && setWord.Contains(ch))
465 isDoLastWord = false;
466
467 // --find out if the word "do" is the last on a "if" line--
468 // collect each letter and put it into a buffer 2 chars long
469 // if we end up with "do" in the buffer when we reach the end of
470 // the line, "do" was the last word on the line
471 if ((ch > 0) && isFirstWordEnded && strcmp(szFirstWord, "if") == 0) {
9e96e16f
RD
472 if (szDolen == 2) {
473 szDo[0] = szDo[1];
474 szDo[1] = static_cast<char>(tolower(ch));
475 szDo[2] = '\0';
1dcf666d
RD
476
477 if (strcmp(szDo, "do") == 0)
478 isDoLastWord = true;
479
480 } else if (szDolen < 2) {
9e96e16f
RD
481 szDo[szDolen++] = static_cast<char>(tolower(ch));
482 szDo[szDolen] = '\0';
483 }
484 }
485 }
486
1dcf666d
RD
487 // End of Line found so process the information
488 if ((ch == '\r' && chNext != '\n') // \r\n
489 || ch == '\n' // \n
490 || i == endPos) { // end of selection
491
9e96e16f
RD
492 // **************************
493 // Folding logic for Keywords
494 // **************************
1dcf666d 495
9e96e16f
RD
496 // if a keyword is found on the current line and the line doesn't end with ;;+ (continuation)
497 // and we are not inside a commentblock.
1dcf666d
RD
498 if (firstWordLen > 0
499 && chPrev != '+' && chPrevPrev != ';' && chPrevPrevPrev !=';'
500 && (!IsStreamCommentStyle(style) || foldInComment) ) {
501
9e96e16f 502 // only fold "if" last keyword is "then" (else its a one line if)
1dcf666d 503 if (strcmp(szFirstWord, "if") == 0 && isDoLastWord)
9e96e16f 504 levelNext++;
1dcf666d
RD
505
506 // create new fold for these words
507 if (strcmp(szFirstWord, "for") == 0)
9e96e16f 508 levelNext++;
1dcf666d 509
9e96e16f
RD
510 //handle folding for functions/labels
511 //Note: Functions and labels don't have an explicit end like [end function]
512 // 1. functions/labels end at the start of another function
513 // 2. functions/labels end at the end of the file
1dcf666d 514 if ((strcmp(szFirstWord, "function") == 0) || (firstWordLen > 0 && szFirstWord[0] == '@')) {
9e96e16f 515 if (isFoldingAll) { //if we're folding the whole document (recursivly by lua script)
1dcf666d 516
9e96e16f
RD
517 if (functionCount > 0) {
518 levelCurrent--;
519 } else {
520 levelNext++;
521 }
1dcf666d
RD
522 functionCount++;
523
9e96e16f
RD
524 } else { //if just folding a small piece (by clicking on the minus sign next to the word)
525 levelCurrent--;
526 }
527 }
1dcf666d 528
9e96e16f 529 // end the fold for these words before the current line
1dcf666d 530 if (strcmp(szFirstWord, "endif") == 0 || strcmp(szFirstWord, "endfor") == 0) {
9e96e16f
RD
531 levelNext--;
532 levelCurrent--;
533 }
1dcf666d
RD
534
535 // end the fold for these words before the current line and Start new fold
536 if (strcmp(szFirstWord, "else") == 0 || strcmp(szFirstWord, "elseif") == 0 )
9e96e16f 537 levelCurrent--;
1dcf666d 538
9e96e16f
RD
539 }
540 // Preprocessor and Comment folding
541 int styleNext = GetStyleFirstWord(lineCurrent + 1,styler);
542
543 // *********************************
544 // Folding logic for Comment blocks
545 // *********************************
546 if (foldComment && IsStreamCommentStyle(style)) {
1dcf666d 547
9e96e16f 548 // Start of a comment block
1dcf666d 549 if (stylePrev != style && IsStreamCommentStyle(styleNext) && styleNext == style) {
9e96e16f 550 levelNext++;
1dcf666d
RD
551 } // fold till the last line for normal comment lines
552 else if (IsStreamCommentStyle(stylePrev)
553 && styleNext != SCE_POWERPRO_COMMENTLINE
554 && stylePrev == SCE_POWERPRO_COMMENTLINE
9e96e16f
RD
555 && style == SCE_POWERPRO_COMMENTLINE) {
556 levelNext--;
1dcf666d
RD
557 } // fold till the one but last line for Blockcomment lines
558 else if (IsStreamCommentStyle(stylePrev)
559 && styleNext != SCE_POWERPRO_COMMENTBLOCK
9e96e16f
RD
560 && style == SCE_POWERPRO_COMMENTBLOCK) {
561 levelNext--;
562 levelCurrent--;
563 }
564 }
565
566 int levelUse = levelCurrent;
567 int lev = levelUse | levelNext << 16;
568 if (visibleChars == 0 && foldCompact)
569 lev |= SC_FOLDLEVELWHITEFLAG;
1dcf666d 570 if (levelUse < levelNext)
9e96e16f 571 lev |= SC_FOLDLEVELHEADERFLAG;
1dcf666d 572 if (lev != styler.LevelAt(lineCurrent))
9e96e16f 573 styler.SetLevel(lineCurrent, lev);
9e96e16f
RD
574
575 // reset values for the next line
576 lineCurrent++;
577 stylePrev = style;
578 style = styleNext;
579 levelCurrent = levelNext;
580 visibleChars = 0;
1dcf666d 581
9e96e16f 582 // if the last characters are ;;+ then don't reset since the line continues on the next line.
1dcf666d
RD
583 if (chPrev != '+' && chPrevPrev != ';' && chPrevPrevPrev != ';') {
584 firstWordLen = 0;
9e96e16f 585 szDolen = 0;
1dcf666d
RD
586 isFirstWordStarted = false;
587 isFirstWordEnded = false;
588 isDoLastWord = false;
589
590 //blank out first word
591 for (unsigned int i = 0; i < FIRST_WORD_MAX_LEN; i++)
592 szFirstWord[i] = '\0';
9e96e16f
RD
593 }
594 }
595
596 // save the last processed characters
597 if ((ch > 0) && !isspacechar(ch)) {
598 chPrevPrevPrev = chPrevPrev;
599 chPrevPrev = chPrev;
600 chPrev = ch;
9e96e16f
RD
601 }
602 }
603
1dcf666d 604 //close folds on the last line - without this a 'phantom'
9e96e16f
RD
605 //fold can appear when an open fold is on the last line
606 //this can occur because functions and labels don't have an explicit end
607 if (lineCurrent >= lastLine) {
608 int lev = 0;
609 lev |= SC_FOLDLEVELWHITEFLAG;
610 styler.SetLevel(lineCurrent, lev);
611 }
612
613}
614
615static const char * const powerProWordLists[] = {
616 "Keyword list 1",
617 "Keyword list 2",
618 "Keyword list 3",
619 "Keyword list 4",
620 0,
621 };
622
623static void ColourisePowerProDocWrapper(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
624 Accessor &styler) {
625 ColourisePowerProDoc(startPos, length, initStyle, keywordlists, styler, false);
626}
627
628LexerModule lmPowerPro(SCLEX_POWERPRO, ColourisePowerProDocWrapper, "powerpro", FoldPowerProDoc, powerProWordLists);
1dcf666d
RD
629
630