1 // Scintilla source code edit control
2 /** @file LexNsis.cxx
3  ** Lexer for NSIS
4  **/
5 // Copyright 2003 - 2005 by Angelo Mandato <angelo [at] spaceblue [dot] com>
6 // Last Updated: 03/13/2005
7 // The License.txt file describes the conditions under which this software may be distributed.
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13 
14 #include "Platform.h"
15 
16 #include "PropSet.h"
17 #include "Accessor.h"
18 #include "KeyWords.h"
19 #include "Scintilla.h"
20 #include "SciLexer.h"
21 
22 /*
23 // located in SciLexer.h
24 #define SCLEX_NSIS 43
25 
26 #define SCE_NSIS_DEFAULT 0
27 #define SCE_NSIS_COMMENT 1
28 #define SCE_NSIS_STRINGDQ 2
29 #define SCE_NSIS_STRINGLQ 3
30 #define SCE_NSIS_STRINGRQ 4
31 #define SCE_NSIS_FUNCTION 5
32 #define SCE_NSIS_VARIABLE 6
33 #define SCE_NSIS_LABEL 7
34 #define SCE_NSIS_USERDEFINED 8
35 #define SCE_NSIS_SECTIONDEF 9
36 #define SCE_NSIS_SUBSECTIONDEF 10
37 #define SCE_NSIS_IFDEFINEDEF 11
38 #define SCE_NSIS_MACRODEF 12
39 #define SCE_NSIS_STRINGVAR 13
40 #define SCE_NSIS_NUMBER 14
41 // ADDED for Scintilla v1.63
42 #define SCE_NSIS_SECTIONGROUP 15
43 #define SCE_NSIS_PAGEEX 16
44 #define SCE_NSIS_FUNCTIONDEF 17
45 #define SCE_NSIS_COMMENTBOX 18
46 */
47 
isNsisNumber(char ch)48 static bool isNsisNumber(char ch)
49 {
50   return (ch >= '0' && ch <= '9');
51 }
52 
isNsisChar(char ch)53 static bool isNsisChar(char ch)
54 {
55   return (ch == '.' ) || (ch == '_' ) || isNsisNumber(ch) || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
56 }
57 
isNsisLetter(char ch)58 static bool isNsisLetter(char ch)
59 {
60   return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
61 }
62 
NsisNextLineHasElse(unsigned int start,unsigned int end,Accessor & styler)63 static bool NsisNextLineHasElse(unsigned int start, unsigned int end, Accessor &styler)
64 {
65   int nNextLine = -1;
66   for( unsigned int i = start; i < end; i++ )
67   {
68     char cNext = styler.SafeGetCharAt( i );
69     if( cNext == '\n' )
70     {
71       nNextLine = i+1;
72       break;
73     }
74   }
75 
76   if( nNextLine == -1 ) // We never foudn the next line...
77     return false;
78 
79   for( unsigned int firstChar = nNextLine; firstChar < end; firstChar++ )
80   {
81     char cNext = styler.SafeGetCharAt( firstChar );
82     if( cNext == ' ' )
83       continue;
84     if( cNext == '\t' )
85       continue;
86     if( cNext == '!' )
87     {
88       if( styler.Match(firstChar, "!else") )
89         return true;
90     }
91     break;
92   }
93 
94   return false;
95 }
96 
NsisCmp(char * s1,char * s2,bool bIgnoreCase)97 static int NsisCmp( char *s1, char *s2, bool bIgnoreCase )
98 {
99   if( bIgnoreCase )
100      return CompareCaseInsensitive( s1, s2);
101 
102   return strcmp( s1, s2 );
103 }
104 
calculateFoldNsis(unsigned int start,unsigned int end,int foldlevel,Accessor & styler,bool bElse,bool foldUtilityCmd)105 static int calculateFoldNsis(unsigned int start, unsigned int end, int foldlevel, Accessor &styler, bool bElse, bool foldUtilityCmd )
106 {
107   int style = styler.StyleAt(end);
108 
109   // If the word is too long, it is not what we are looking for
110   if( end - start > 20 )
111     return foldlevel;
112 
113   if( foldUtilityCmd )
114   {
115     // Check the style at this point, if it is not valid, then return zero
116     if( style != SCE_NSIS_FUNCTIONDEF && style != SCE_NSIS_SECTIONDEF &&
117         style != SCE_NSIS_SUBSECTIONDEF && style != SCE_NSIS_IFDEFINEDEF &&
118         style != SCE_NSIS_MACRODEF && style != SCE_NSIS_SECTIONGROUP &&
119         style != SCE_NSIS_PAGEEX )
120           return foldlevel;
121   }
122   else
123   {
124     if( style != SCE_NSIS_FUNCTIONDEF && style != SCE_NSIS_SECTIONDEF &&
125         style != SCE_NSIS_SUBSECTIONDEF && style != SCE_NSIS_SECTIONGROUP &&
126         style != SCE_NSIS_PAGEEX )
127           return foldlevel;
128   }
129 
130   int newFoldlevel = foldlevel;
131   bool bIgnoreCase = false;
132   if( styler.GetPropertyInt("nsis.ignorecase") == 1 )
133     bIgnoreCase = true;
134 
135   char s[20]; // The key word we are looking for has atmost 13 characters
136   for (unsigned int i = 0; i < end - start + 1 && i < 19; i++)
137 	{
138 		s[i] = static_cast<char>( styler[ start + i ] );
139 		s[i + 1] = '\0';
140 	}
141 
142   if( s[0] == '!' )
143   {
144     if( NsisCmp(s, "!ifndef", bIgnoreCase) == 0 || NsisCmp(s, "!ifdef", bIgnoreCase ) == 0 || NsisCmp(s, "!macro", bIgnoreCase ) == 0 )
145       newFoldlevel++;
146     else if( NsisCmp(s, "!endif", bIgnoreCase) == 0 || NsisCmp(s, "!macroend", bIgnoreCase ) == 0 )
147       newFoldlevel--;
148     else if( bElse && NsisCmp(s, "!else", bIgnoreCase) == 0 )
149       newFoldlevel++;
150   }
151   else
152   {
153     if( NsisCmp(s, "Section", bIgnoreCase ) == 0 || NsisCmp(s, "SectionGroup", bIgnoreCase ) == 0 || NsisCmp(s, "Function", bIgnoreCase) == 0 || NsisCmp(s, "SubSection", bIgnoreCase ) == 0 || NsisCmp(s, "PageEx", bIgnoreCase ) == 0 )
154       newFoldlevel++;
155     else if( NsisCmp(s, "SectionGroupEnd", bIgnoreCase ) == 0 || NsisCmp(s, "SubSectionEnd", bIgnoreCase ) == 0 || NsisCmp(s, "FunctionEnd", bIgnoreCase) == 0 || NsisCmp(s, "SectionEnd", bIgnoreCase ) == 0 || NsisCmp(s, "PageExEnd", bIgnoreCase ) == 0 )
156       newFoldlevel--;
157   }
158 
159   return newFoldlevel;
160 }
161 
classifyWordNsis(unsigned int start,unsigned int end,WordList * keywordLists[],Accessor & styler)162 static int classifyWordNsis(unsigned int start, unsigned int end, WordList *keywordLists[], Accessor &styler )
163 {
164   bool bIgnoreCase = false;
165   if( styler.GetPropertyInt("nsis.ignorecase") == 1 )
166     bIgnoreCase = true;
167 
168   bool bUserVars = false;
169   if( styler.GetPropertyInt("nsis.uservars") == 1 )
170     bUserVars = true;
171 
172 	char s[100];
173 
174 	WordList &Functions = *keywordLists[0];
175 	WordList &Variables = *keywordLists[1];
176 	WordList &Lables = *keywordLists[2];
177 	WordList &UserDefined = *keywordLists[3];
178 
179 	for (unsigned int i = 0; i < end - start + 1 && i < 99; i++)
180 	{
181     if( bIgnoreCase )
182       s[i] = static_cast<char>( tolower(styler[ start + i ] ) );
183     else
184 		  s[i] = static_cast<char>( styler[ start + i ] );
185 		s[i + 1] = '\0';
186 	}
187 
188 	// Check for special words...
189 	if( NsisCmp(s, "!macro", bIgnoreCase ) == 0 || NsisCmp(s, "!macroend", bIgnoreCase) == 0 ) // Covers !micro and !microend
190 		return SCE_NSIS_MACRODEF;
191 
192 	if( NsisCmp(s, "!ifdef", bIgnoreCase ) == 0 ||  NsisCmp(s, "!ifndef", bIgnoreCase) == 0 ||  NsisCmp(s, "!endif", bIgnoreCase) == 0 )
193 		return SCE_NSIS_IFDEFINEDEF;
194 
195   if( NsisCmp(s, "!else", bIgnoreCase ) == 0 ) // ||  NsisCmp(s, "!ifndef", bIgnoreCase) == 0 ||  NsisCmp(s, "!endif", bIgnoreCase) == 0 )
196 		return SCE_NSIS_IFDEFINEDEF;
197 
198   if( NsisCmp(s, "SectionGroup", bIgnoreCase) == 0 || NsisCmp(s, "SectionGroupEnd", bIgnoreCase) == 0 ) // Covers SectionGroup and SectionGroupEnd
199     return SCE_NSIS_SECTIONGROUP;
200 
201 	if( NsisCmp(s, "Section", bIgnoreCase ) == 0 || NsisCmp(s, "SectionEnd", bIgnoreCase) == 0 ) // Covers Section and SectionEnd
202 		return SCE_NSIS_SECTIONDEF;
203 
204 	if( NsisCmp(s, "SubSection", bIgnoreCase) == 0 || NsisCmp(s, "SubSectionEnd", bIgnoreCase) == 0 ) // Covers SubSection and SubSectionEnd
205 		return SCE_NSIS_SUBSECTIONDEF;
206 
207   if( NsisCmp(s, "PageEx", bIgnoreCase) == 0 || NsisCmp(s, "PageExEnd", bIgnoreCase) == 0 ) // Covers PageEx and PageExEnd
208     return SCE_NSIS_PAGEEX;
209 
210 	if( NsisCmp(s, "Function", bIgnoreCase) == 0 || NsisCmp(s, "FunctionEnd", bIgnoreCase) == 0 ) // Covers Function and FunctionEnd
211 		return SCE_NSIS_FUNCTIONDEF;
212 
213 	if ( Functions.InList(s) )
214 		return SCE_NSIS_FUNCTION;
215 
216 	if ( Variables.InList(s) )
217 		return SCE_NSIS_VARIABLE;
218 
219 	if ( Lables.InList(s) )
220 		return SCE_NSIS_LABEL;
221 
222 	if( UserDefined.InList(s) )
223 		return SCE_NSIS_USERDEFINED;
224 
225 	if( strlen(s) > 3 )
226 	{
227 		if( s[1] == '{' && s[strlen(s)-1] == '}' )
228 			return SCE_NSIS_VARIABLE;
229 	}
230 
231   // See if the variable is a user defined variable
232   if( s[0] == '$' && bUserVars )
233   {
234     bool bHasSimpleNsisChars = true;
235     for (unsigned int j = 1; j < end - start + 1 && j < 99; j++)
236 	  {
237       if( !isNsisChar( s[j] ) )
238       {
239         bHasSimpleNsisChars = false;
240         break;
241       }
242 	  }
243 
244     if( bHasSimpleNsisChars )
245       return SCE_NSIS_VARIABLE;
246   }
247 
248   // To check for numbers
249   if( isNsisNumber( s[0] ) )
250   {
251     bool bHasSimpleNsisNumber = true;
252     for (unsigned int j = 1; j < end - start + 1 && j < 99; j++)
253 	  {
254       if( !isNsisNumber( s[j] ) )
255       {
256         bHasSimpleNsisNumber = false;
257         break;
258       }
259 	  }
260 
261     if( bHasSimpleNsisNumber )
262       return SCE_NSIS_NUMBER;
263   }
264 
265 	return SCE_NSIS_DEFAULT;
266 }
267 
ColouriseNsisDoc(unsigned int startPos,int length,int,WordList * keywordLists[],Accessor & styler)268 static void ColouriseNsisDoc(unsigned int startPos, int length, int, WordList *keywordLists[], Accessor &styler)
269 {
270 	int state = SCE_NSIS_DEFAULT;
271   if( startPos > 0 )
272     state = styler.StyleAt(startPos-1); // Use the style from the previous line, usually default, but could be commentbox
273 
274 	styler.StartAt( startPos );
275 	styler.GetLine( startPos );
276 
277 	unsigned int nLengthDoc = startPos + length;
278 	styler.StartSegment( startPos );
279 
280 	char cCurrChar;
281 	bool bVarInString = false;
282   bool bClassicVarInString = false;
283 
284 	unsigned int i;
285 	for( i = startPos; i < nLengthDoc; i++ )
286 	{
287 		cCurrChar = styler.SafeGetCharAt( i );
288 		char cNextChar = styler.SafeGetCharAt(i+1);
289 
290 		switch(state)
291 		{
292 			case SCE_NSIS_DEFAULT:
293 				if( cCurrChar == ';' || cCurrChar == '#' ) // we have a comment line
294 				{
295 					styler.ColourTo(i-1, state );
296 					state = SCE_NSIS_COMMENT;
297 					break;
298 				}
299 				if( cCurrChar == '"' )
300 				{
301 					styler.ColourTo(i-1, state );
302 					state = SCE_NSIS_STRINGDQ;
303 					bVarInString = false;
304           bClassicVarInString = false;
305 					break;
306 				}
307 				if( cCurrChar == '\'' )
308 				{
309 					styler.ColourTo(i-1, state );
310 					state = SCE_NSIS_STRINGRQ;
311 					bVarInString = false;
312           bClassicVarInString = false;
313 					break;
314 				}
315 				if( cCurrChar == '`' )
316 				{
317 					styler.ColourTo(i-1, state );
318 					state = SCE_NSIS_STRINGLQ;
319 					bVarInString = false;
320           bClassicVarInString = false;
321 					break;
322 				}
323 
324 				// NSIS KeyWord,Function, Variable, UserDefined:
325 				if( cCurrChar == '$' || isNsisChar(cCurrChar) || cCurrChar == '!' )
326 				{
327 					styler.ColourTo(i-1,state);
328 				  state = SCE_NSIS_FUNCTION;
329 
330           // If it is a number, we must check and set style here first...
331           if( isNsisNumber(cCurrChar) && (cNextChar == '\t' || cNextChar == ' ' || cNextChar == '\r' || cNextChar == '\n' ) )
332               styler.ColourTo( i, SCE_NSIS_NUMBER);
333 
334 					break;
335 				}
336 
337         if( cCurrChar == '/' && cNextChar == '*' )
338         {
339           styler.ColourTo(i-1,state);
340           state = SCE_NSIS_COMMENTBOX;
341           break;
342         }
343 
344 				break;
345 			case SCE_NSIS_COMMENT:
346 				if( cNextChar == '\n' || cNextChar == '\r' )
347         {
348           // Special case:
349           if( cCurrChar == '\\' )
350           {
351             styler.ColourTo(i-2,state);
352             styler.ColourTo(i,SCE_NSIS_DEFAULT);
353           }
354           else
355           {
356 				    styler.ColourTo(i,state);
357             state = SCE_NSIS_DEFAULT;
358           }
359         }
360 				break;
361 			case SCE_NSIS_STRINGDQ:
362       case SCE_NSIS_STRINGLQ:
363       case SCE_NSIS_STRINGRQ:
364 
365         if( styler.SafeGetCharAt(i-1) == '\\' && styler.SafeGetCharAt(i-2) == '$' )
366           break; // Ignore the next character, even if it is a quote of some sort
367 
368         if( cCurrChar == '"' && state == SCE_NSIS_STRINGDQ )
369 				{
370 					styler.ColourTo(i,state);
371 				  state = SCE_NSIS_DEFAULT;
372           break;
373 				}
374 
375         if( cCurrChar == '`' && state == SCE_NSIS_STRINGLQ )
376         {
377 					styler.ColourTo(i,state);
378 				  state = SCE_NSIS_DEFAULT;
379           break;
380 				}
381 
382         if( cCurrChar == '\'' && state == SCE_NSIS_STRINGRQ )
383 				{
384 					styler.ColourTo(i,state);
385 				  state = SCE_NSIS_DEFAULT;
386           break;
387 				}
388 
389         if( cNextChar == '\r' || cNextChar == '\n' )
390         {
391           int nCurLine = styler.GetLine(i+1);
392           int nBack = i;
393           // We need to check if the previous line has a \ in it...
394           bool bNextLine = false;
395 
396           while( nBack > 0 )
397           {
398             if( styler.GetLine(nBack) != nCurLine )
399               break;
400 
401             char cTemp = styler.SafeGetCharAt(nBack, 'a'); // Letter 'a' is safe here
402 
403             if( cTemp == '\\' )
404             {
405               bNextLine = true;
406               break;
407             }
408             if( cTemp != '\r' && cTemp != '\n' && cTemp != '\t' && cTemp != ' ' )
409               break;
410 
411             nBack--;
412           }
413 
414           if( bNextLine )
415           {
416             styler.ColourTo(i+1,state);
417           }
418           if( bNextLine == false )
419           {
420             styler.ColourTo(i,state);
421 				    state = SCE_NSIS_DEFAULT;
422           }
423         }
424 				break;
425 
426 			case SCE_NSIS_FUNCTION:
427 
428 				// NSIS KeyWord:
429         if( cCurrChar == '$' )
430           state = SCE_NSIS_DEFAULT;
431         else if( cCurrChar == '\\' && (cNextChar == 'n' || cNextChar == 'r' || cNextChar == 't' ) )
432           state = SCE_NSIS_DEFAULT;
433 				else if( (isNsisChar(cCurrChar) && !isNsisChar( cNextChar) && cNextChar != '}') || cCurrChar == '}' )
434 				{
435 					state = classifyWordNsis( styler.GetStartSegment(), i, keywordLists, styler );
436 					styler.ColourTo( i, state);
437 					state = SCE_NSIS_DEFAULT;
438 				}
439 				else if( !isNsisChar( cCurrChar ) && cCurrChar != '{' && cCurrChar != '}' )
440 				{
441           if( classifyWordNsis( styler.GetStartSegment(), i-1, keywordLists, styler) == SCE_NSIS_NUMBER )
442              styler.ColourTo( i-1, SCE_NSIS_NUMBER );
443 
444 					state = SCE_NSIS_DEFAULT;
445 
446 					if( cCurrChar == '"' )
447 					{
448 						state = SCE_NSIS_STRINGDQ;
449 						bVarInString = false;
450             bClassicVarInString = false;
451 					}
452 					else if( cCurrChar == '`' )
453 					{
454 						state = SCE_NSIS_STRINGLQ;
455 						bVarInString = false;
456             bClassicVarInString = false;
457 					}
458 					else if( cCurrChar == '\'' )
459 					{
460 						state = SCE_NSIS_STRINGRQ;
461 						bVarInString = false;
462             bClassicVarInString = false;
463 					}
464 					else if( cCurrChar == '#' || cCurrChar == ';' )
465           {
466 						state = SCE_NSIS_COMMENT;
467           }
468 				}
469 				break;
470       case SCE_NSIS_COMMENTBOX:
471 
472         if( styler.SafeGetCharAt(i-1) == '*' && cCurrChar == '/' )
473         {
474           styler.ColourTo(i,state);
475           state = SCE_NSIS_DEFAULT;
476         }
477         break;
478 		}
479 
480 		if( state == SCE_NSIS_COMMENT || state == SCE_NSIS_COMMENTBOX )
481 		{
482 			styler.ColourTo(i,state);
483 		}
484 		else if( state == SCE_NSIS_STRINGDQ || state == SCE_NSIS_STRINGLQ || state == SCE_NSIS_STRINGRQ )
485 		{
486       bool bIngoreNextDollarSign = false;
487       bool bUserVars = false;
488       if( styler.GetPropertyInt("nsis.uservars") == 1 )
489         bUserVars = true;
490 
491       if( bVarInString && cCurrChar == '$' )
492       {
493         bVarInString = false;
494         bIngoreNextDollarSign = true;
495       }
496       else if( bVarInString && cCurrChar == '\\' && (cNextChar == 'n' || cNextChar == 'r' || cNextChar == 't' || cNextChar == '"' || cNextChar == '`' || cNextChar == '\'' ) )
497       {
498         styler.ColourTo( i+1, SCE_NSIS_STRINGVAR);
499         bVarInString = false;
500         bIngoreNextDollarSign = false;
501       }
502 
503       // Covers "$INSTDIR and user vars like $MYVAR"
504       else if( bVarInString && !isNsisChar(cNextChar) )
505       {
506         int nWordState = classifyWordNsis( styler.GetStartSegment(), i, keywordLists, styler);
507 				if( nWordState == SCE_NSIS_VARIABLE )
508 					styler.ColourTo( i, SCE_NSIS_STRINGVAR);
509         else if( bUserVars )
510           styler.ColourTo( i, SCE_NSIS_STRINGVAR);
511         bVarInString = false;
512       }
513       // Covers "${TEST}..."
514       else if( bClassicVarInString && cNextChar == '}' )
515       {
516         styler.ColourTo( i+1, SCE_NSIS_STRINGVAR);
517 				bClassicVarInString = false;
518       }
519 
520       // Start of var in string
521 			if( !bIngoreNextDollarSign && cCurrChar == '$' && cNextChar == '{' )
522 			{
523 				styler.ColourTo( i-1, state);
524 				bClassicVarInString = true;
525         bVarInString = false;
526 			}
527       else if( !bIngoreNextDollarSign && cCurrChar == '$' )
528       {
529         styler.ColourTo( i-1, state);
530         bVarInString = true;
531         bClassicVarInString = false;
532       }
533 		}
534 	}
535 
536   // Colourise remaining document
537 	styler.ColourTo(nLengthDoc-1,state);
538 }
539 
FoldNsisDoc(unsigned int startPos,int length,int,WordList * [],Accessor & styler)540 static void FoldNsisDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler)
541 {
542 	// No folding enabled, no reason to continue...
543 	if( styler.GetPropertyInt("fold") == 0 )
544 		return;
545 
546   bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) == 1;
547   bool foldUtilityCmd = styler.GetPropertyInt("nsis.foldutilcmd", 1) == 1;
548   bool blockComment = false;
549 
550   int lineCurrent = styler.GetLine(startPos);
551   unsigned int safeStartPos = styler.LineStart( lineCurrent );
552 
553   bool bArg1 = true;
554   int nWordStart = -1;
555 
556   int levelCurrent = SC_FOLDLEVELBASE;
557 	if (lineCurrent > 0)
558 		levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
559 	int levelNext = levelCurrent;
560   int style = styler.StyleAt(safeStartPos);
561   if( style == SCE_NSIS_COMMENTBOX )
562   {
563     if( styler.SafeGetCharAt(safeStartPos) == '/' && styler.SafeGetCharAt(safeStartPos+1) == '*' )
564       levelNext++;
565     blockComment = true;
566   }
567 
568   for (unsigned int i = safeStartPos; i < startPos + length; i++)
569 	{
570     char chCurr = styler.SafeGetCharAt(i);
571     style = styler.StyleAt(i);
572     if( blockComment && style != SCE_NSIS_COMMENTBOX )
573     {
574       levelNext--;
575       blockComment = false;
576     }
577     else if( !blockComment && style == SCE_NSIS_COMMENTBOX )
578     {
579       levelNext++;
580       blockComment = true;
581     }
582 
583     if( bArg1 && !blockComment)
584     {
585       if( nWordStart == -1 && (isNsisLetter(chCurr) || chCurr == '!') )
586       {
587         nWordStart = i;
588       }
589       else if( isNsisLetter(chCurr) == false && nWordStart > -1 )
590       {
591         int newLevel = calculateFoldNsis( nWordStart, i-1, levelNext, styler, foldAtElse, foldUtilityCmd );
592 
593         if( newLevel == levelNext )
594         {
595           if( foldAtElse && foldUtilityCmd )
596           {
597             if( NsisNextLineHasElse(i, startPos + length, styler) )
598               levelNext--;
599           }
600         }
601         else
602           levelNext = newLevel;
603         bArg1 = false;
604       }
605     }
606 
607     if( chCurr == '\n' )
608     {
609       if( bArg1 && foldAtElse && foldUtilityCmd && !blockComment )
610       {
611         if( NsisNextLineHasElse(i, startPos + length, styler) )
612           levelNext--;
613       }
614 
615       // If we are on a new line...
616       int levelUse = levelCurrent;
617 			int lev = levelUse | levelNext << 16;
618       if (levelUse < levelNext )
619 				lev |= SC_FOLDLEVELHEADERFLAG;
620 			if (lev != styler.LevelAt(lineCurrent))
621 				styler.SetLevel(lineCurrent, lev);
622 
623 			lineCurrent++;
624 			levelCurrent = levelNext;
625       bArg1 = true; // New line, lets look at first argument again
626       nWordStart = -1;
627     }
628   }
629 
630 	int levelUse = levelCurrent;
631 	int lev = levelUse | levelNext << 16;
632 	if (levelUse < levelNext)
633 		lev |= SC_FOLDLEVELHEADERFLAG;
634 	if (lev != styler.LevelAt(lineCurrent))
635 		styler.SetLevel(lineCurrent, lev);
636 }
637 
638 static const char * const nsisWordLists[] = {
639 	"Functions",
640 	"Variables",
641 	"Lables",
642 	"UserDefined",
643 	0, };
644 
645 
646 LexerModule lmNsis(SCLEX_NSIS, ColouriseNsisDoc, "nsis", FoldNsisDoc, nsisWordLists);
647 
648