]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/LexNsis.cxx
93f0cd4d62b72c06a4a61ee18e5cb8e9fd44d658
1 // Scintilla source code edit control
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.
19 #include "Scintilla.h"
23 using namespace Scintilla
;
27 // located in SciLexer.h
30 #define SCE_NSIS_DEFAULT 0
31 #define SCE_NSIS_COMMENT 1
32 #define SCE_NSIS_STRINGDQ 2
33 #define SCE_NSIS_STRINGLQ 3
34 #define SCE_NSIS_STRINGRQ 4
35 #define SCE_NSIS_FUNCTION 5
36 #define SCE_NSIS_VARIABLE 6
37 #define SCE_NSIS_LABEL 7
38 #define SCE_NSIS_USERDEFINED 8
39 #define SCE_NSIS_SECTIONDEF 9
40 #define SCE_NSIS_SUBSECTIONDEF 10
41 #define SCE_NSIS_IFDEFINEDEF 11
42 #define SCE_NSIS_MACRODEF 12
43 #define SCE_NSIS_STRINGVAR 13
44 #define SCE_NSIS_NUMBER 14
45 // ADDED for Scintilla v1.63
46 #define SCE_NSIS_SECTIONGROUP 15
47 #define SCE_NSIS_PAGEEX 16
48 #define SCE_NSIS_FUNCTIONDEF 17
49 #define SCE_NSIS_COMMENTBOX 18
52 static bool isNsisNumber(char ch
)
54 return (ch
>= '0' && ch
<= '9');
57 static bool isNsisChar(char ch
)
59 return (ch
== '.' ) || (ch
== '_' ) || isNsisNumber(ch
) || (ch
>= 'A' && ch
<= 'Z') || (ch
>= 'a' && ch
<= 'z');
62 static bool isNsisLetter(char ch
)
64 return (ch
>= 'A' && ch
<= 'Z') || (ch
>= 'a' && ch
<= 'z');
67 static bool NsisNextLineHasElse(unsigned int start
, unsigned int end
, Accessor
&styler
)
70 for( unsigned int i
= start
; i
< end
; i
++ )
72 char cNext
= styler
.SafeGetCharAt( i
);
80 if( nNextLine
== -1 ) // We never foudn the next line...
83 for( unsigned int firstChar
= nNextLine
; firstChar
< end
; firstChar
++ )
85 char cNext
= styler
.SafeGetCharAt( firstChar
);
92 if( styler
.Match(firstChar
, "!else") )
101 static int NsisCmp( char *s1
, char *s2
, bool bIgnoreCase
)
104 return CompareCaseInsensitive( s1
, s2
);
106 return strcmp( s1
, s2
);
109 static int calculateFoldNsis(unsigned int start
, unsigned int end
, int foldlevel
, Accessor
&styler
, bool bElse
, bool foldUtilityCmd
)
111 int style
= styler
.StyleAt(end
);
113 // If the word is too long, it is not what we are looking for
114 if( end
- start
> 20 )
119 // Check the style at this point, if it is not valid, then return zero
120 if( style
!= SCE_NSIS_FUNCTIONDEF
&& style
!= SCE_NSIS_SECTIONDEF
&&
121 style
!= SCE_NSIS_SUBSECTIONDEF
&& style
!= SCE_NSIS_IFDEFINEDEF
&&
122 style
!= SCE_NSIS_MACRODEF
&& style
!= SCE_NSIS_SECTIONGROUP
&&
123 style
!= SCE_NSIS_PAGEEX
)
128 if( style
!= SCE_NSIS_FUNCTIONDEF
&& style
!= SCE_NSIS_SECTIONDEF
&&
129 style
!= SCE_NSIS_SUBSECTIONDEF
&& style
!= SCE_NSIS_SECTIONGROUP
&&
130 style
!= SCE_NSIS_PAGEEX
)
134 int newFoldlevel
= foldlevel
;
135 bool bIgnoreCase
= false;
136 if( styler
.GetPropertyInt("nsis.ignorecase") == 1 )
139 char s
[20]; // The key word we are looking for has atmost 13 characters
140 for (unsigned int i
= 0; i
< end
- start
+ 1 && i
< 19; i
++)
142 s
[i
] = static_cast<char>( styler
[ start
+ i
] );
148 if( NsisCmp(s
, "!ifndef", bIgnoreCase
) == 0 || NsisCmp(s
, "!ifdef", bIgnoreCase
) == 0 || NsisCmp(s
, "!if", bIgnoreCase
) == 0 || NsisCmp(s
, "!macro", bIgnoreCase
) == 0 )
150 else if( NsisCmp(s
, "!endif", bIgnoreCase
) == 0 || NsisCmp(s
, "!macroend", bIgnoreCase
) == 0 )
152 else if( bElse
&& NsisCmp(s
, "!else", bIgnoreCase
) == 0 )
157 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 )
159 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 )
166 static int classifyWordNsis(unsigned int start
, unsigned int end
, WordList
*keywordLists
[], Accessor
&styler
)
168 bool bIgnoreCase
= false;
169 if( styler
.GetPropertyInt("nsis.ignorecase") == 1 )
172 bool bUserVars
= false;
173 if( styler
.GetPropertyInt("nsis.uservars") == 1 )
178 WordList
&Functions
= *keywordLists
[0];
179 WordList
&Variables
= *keywordLists
[1];
180 WordList
&Lables
= *keywordLists
[2];
181 WordList
&UserDefined
= *keywordLists
[3];
183 for (unsigned int i
= 0; i
< end
- start
+ 1 && i
< 99; i
++)
186 s
[i
] = static_cast<char>( tolower(styler
[ start
+ i
] ) );
188 s
[i
] = static_cast<char>( styler
[ start
+ i
] );
192 // Check for special words...
193 if( NsisCmp(s
, "!macro", bIgnoreCase
) == 0 || NsisCmp(s
, "!macroend", bIgnoreCase
) == 0 ) // Covers !micro and !microend
194 return SCE_NSIS_MACRODEF
;
196 if( NsisCmp(s
, "!ifdef", bIgnoreCase
) == 0 || NsisCmp(s
, "!ifndef", bIgnoreCase
) == 0 || NsisCmp(s
, "!endif", bIgnoreCase
) == 0 )
197 return SCE_NSIS_IFDEFINEDEF
;
199 if( NsisCmp(s
, "!else", bIgnoreCase
) == 0 ) // || NsisCmp(s, "!ifndef", bIgnoreCase) == 0 || NsisCmp(s, "!endif", bIgnoreCase) == 0 )
200 return SCE_NSIS_IFDEFINEDEF
;
202 if( NsisCmp(s
, "!if", bIgnoreCase
) == 0 )
203 return SCE_NSIS_IFDEFINEDEF
;
205 if( NsisCmp(s
, "SectionGroup", bIgnoreCase
) == 0 || NsisCmp(s
, "SectionGroupEnd", bIgnoreCase
) == 0 ) // Covers SectionGroup and SectionGroupEnd
206 return SCE_NSIS_SECTIONGROUP
;
208 if( NsisCmp(s
, "Section", bIgnoreCase
) == 0 || NsisCmp(s
, "SectionEnd", bIgnoreCase
) == 0 ) // Covers Section and SectionEnd
209 return SCE_NSIS_SECTIONDEF
;
211 if( NsisCmp(s
, "SubSection", bIgnoreCase
) == 0 || NsisCmp(s
, "SubSectionEnd", bIgnoreCase
) == 0 ) // Covers SubSection and SubSectionEnd
212 return SCE_NSIS_SUBSECTIONDEF
;
214 if( NsisCmp(s
, "PageEx", bIgnoreCase
) == 0 || NsisCmp(s
, "PageExEnd", bIgnoreCase
) == 0 ) // Covers PageEx and PageExEnd
215 return SCE_NSIS_PAGEEX
;
217 if( NsisCmp(s
, "Function", bIgnoreCase
) == 0 || NsisCmp(s
, "FunctionEnd", bIgnoreCase
) == 0 ) // Covers Function and FunctionEnd
218 return SCE_NSIS_FUNCTIONDEF
;
220 if ( Functions
.InList(s
) )
221 return SCE_NSIS_FUNCTION
;
223 if ( Variables
.InList(s
) )
224 return SCE_NSIS_VARIABLE
;
226 if ( Lables
.InList(s
) )
227 return SCE_NSIS_LABEL
;
229 if( UserDefined
.InList(s
) )
230 return SCE_NSIS_USERDEFINED
;
234 if( s
[1] == '{' && s
[strlen(s
)-1] == '}' )
235 return SCE_NSIS_VARIABLE
;
238 // See if the variable is a user defined variable
239 if( s
[0] == '$' && bUserVars
)
241 bool bHasSimpleNsisChars
= true;
242 for (unsigned int j
= 1; j
< end
- start
+ 1 && j
< 99; j
++)
244 if( !isNsisChar( s
[j
] ) )
246 bHasSimpleNsisChars
= false;
251 if( bHasSimpleNsisChars
)
252 return SCE_NSIS_VARIABLE
;
255 // To check for numbers
256 if( isNsisNumber( s
[0] ) )
258 bool bHasSimpleNsisNumber
= true;
259 for (unsigned int j
= 1; j
< end
- start
+ 1 && j
< 99; j
++)
261 if( !isNsisNumber( s
[j
] ) )
263 bHasSimpleNsisNumber
= false;
268 if( bHasSimpleNsisNumber
)
269 return SCE_NSIS_NUMBER
;
272 return SCE_NSIS_DEFAULT
;
275 static void ColouriseNsisDoc(unsigned int startPos
, int length
, int, WordList
*keywordLists
[], Accessor
&styler
)
277 int state
= SCE_NSIS_DEFAULT
;
279 state
= styler
.StyleAt(startPos
-1); // Use the style from the previous line, usually default, but could be commentbox
281 styler
.StartAt( startPos
);
282 styler
.GetLine( startPos
);
284 unsigned int nLengthDoc
= startPos
+ length
;
285 styler
.StartSegment( startPos
);
288 bool bVarInString
= false;
289 bool bClassicVarInString
= false;
292 for( i
= startPos
; i
< nLengthDoc
; i
++ )
294 cCurrChar
= styler
.SafeGetCharAt( i
);
295 char cNextChar
= styler
.SafeGetCharAt(i
+1);
299 case SCE_NSIS_DEFAULT
:
300 if( cCurrChar
== ';' || cCurrChar
== '#' ) // we have a comment line
302 styler
.ColourTo(i
-1, state
);
303 state
= SCE_NSIS_COMMENT
;
306 if( cCurrChar
== '"' )
308 styler
.ColourTo(i
-1, state
);
309 state
= SCE_NSIS_STRINGDQ
;
310 bVarInString
= false;
311 bClassicVarInString
= false;
314 if( cCurrChar
== '\'' )
316 styler
.ColourTo(i
-1, state
);
317 state
= SCE_NSIS_STRINGRQ
;
318 bVarInString
= false;
319 bClassicVarInString
= false;
322 if( cCurrChar
== '`' )
324 styler
.ColourTo(i
-1, state
);
325 state
= SCE_NSIS_STRINGLQ
;
326 bVarInString
= false;
327 bClassicVarInString
= false;
331 // NSIS KeyWord,Function, Variable, UserDefined:
332 if( cCurrChar
== '$' || isNsisChar(cCurrChar
) || cCurrChar
== '!' )
334 styler
.ColourTo(i
-1,state
);
335 state
= SCE_NSIS_FUNCTION
;
337 // If it is a number, we must check and set style here first...
338 if( isNsisNumber(cCurrChar
) && (cNextChar
== '\t' || cNextChar
== ' ' || cNextChar
== '\r' || cNextChar
== '\n' ) )
339 styler
.ColourTo( i
, SCE_NSIS_NUMBER
);
344 if( cCurrChar
== '/' && cNextChar
== '*' )
346 styler
.ColourTo(i
-1,state
);
347 state
= SCE_NSIS_COMMENTBOX
;
352 case SCE_NSIS_COMMENT
:
353 if( cNextChar
== '\n' || cNextChar
== '\r' )
356 if( cCurrChar
== '\\' )
358 styler
.ColourTo(i
-2,state
);
359 styler
.ColourTo(i
,SCE_NSIS_DEFAULT
);
363 styler
.ColourTo(i
,state
);
364 state
= SCE_NSIS_DEFAULT
;
368 case SCE_NSIS_STRINGDQ
:
369 case SCE_NSIS_STRINGLQ
:
370 case SCE_NSIS_STRINGRQ
:
372 if( styler
.SafeGetCharAt(i
-1) == '\\' && styler
.SafeGetCharAt(i
-2) == '$' )
373 break; // Ignore the next character, even if it is a quote of some sort
375 if( cCurrChar
== '"' && state
== SCE_NSIS_STRINGDQ
)
377 styler
.ColourTo(i
,state
);
378 state
= SCE_NSIS_DEFAULT
;
382 if( cCurrChar
== '`' && state
== SCE_NSIS_STRINGLQ
)
384 styler
.ColourTo(i
,state
);
385 state
= SCE_NSIS_DEFAULT
;
389 if( cCurrChar
== '\'' && state
== SCE_NSIS_STRINGRQ
)
391 styler
.ColourTo(i
,state
);
392 state
= SCE_NSIS_DEFAULT
;
396 if( cNextChar
== '\r' || cNextChar
== '\n' )
398 int nCurLine
= styler
.GetLine(i
+1);
400 // We need to check if the previous line has a \ in it...
401 bool bNextLine
= false;
405 if( styler
.GetLine(nBack
) != nCurLine
)
408 char cTemp
= styler
.SafeGetCharAt(nBack
, 'a'); // Letter 'a' is safe here
415 if( cTemp
!= '\r' && cTemp
!= '\n' && cTemp
!= '\t' && cTemp
!= ' ' )
423 styler
.ColourTo(i
+1,state
);
425 if( bNextLine
== false )
427 styler
.ColourTo(i
,state
);
428 state
= SCE_NSIS_DEFAULT
;
433 case SCE_NSIS_FUNCTION
:
436 if( cCurrChar
== '$' )
437 state
= SCE_NSIS_DEFAULT
;
438 else if( cCurrChar
== '\\' && (cNextChar
== 'n' || cNextChar
== 'r' || cNextChar
== 't' ) )
439 state
= SCE_NSIS_DEFAULT
;
440 else if( (isNsisChar(cCurrChar
) && !isNsisChar( cNextChar
) && cNextChar
!= '}') || cCurrChar
== '}' )
442 state
= classifyWordNsis( styler
.GetStartSegment(), i
, keywordLists
, styler
);
443 styler
.ColourTo( i
, state
);
444 state
= SCE_NSIS_DEFAULT
;
446 else if( !isNsisChar( cCurrChar
) && cCurrChar
!= '{' && cCurrChar
!= '}' )
448 if( classifyWordNsis( styler
.GetStartSegment(), i
-1, keywordLists
, styler
) == SCE_NSIS_NUMBER
)
449 styler
.ColourTo( i
-1, SCE_NSIS_NUMBER
);
451 state
= SCE_NSIS_DEFAULT
;
453 if( cCurrChar
== '"' )
455 state
= SCE_NSIS_STRINGDQ
;
456 bVarInString
= false;
457 bClassicVarInString
= false;
459 else if( cCurrChar
== '`' )
461 state
= SCE_NSIS_STRINGLQ
;
462 bVarInString
= false;
463 bClassicVarInString
= false;
465 else if( cCurrChar
== '\'' )
467 state
= SCE_NSIS_STRINGRQ
;
468 bVarInString
= false;
469 bClassicVarInString
= false;
471 else if( cCurrChar
== '#' || cCurrChar
== ';' )
473 state
= SCE_NSIS_COMMENT
;
477 case SCE_NSIS_COMMENTBOX
:
479 if( styler
.SafeGetCharAt(i
-1) == '*' && cCurrChar
== '/' )
481 styler
.ColourTo(i
,state
);
482 state
= SCE_NSIS_DEFAULT
;
487 if( state
== SCE_NSIS_COMMENT
|| state
== SCE_NSIS_COMMENTBOX
)
489 styler
.ColourTo(i
,state
);
491 else if( state
== SCE_NSIS_STRINGDQ
|| state
== SCE_NSIS_STRINGLQ
|| state
== SCE_NSIS_STRINGRQ
)
493 bool bIngoreNextDollarSign
= false;
494 bool bUserVars
= false;
495 if( styler
.GetPropertyInt("nsis.uservars") == 1 )
498 if( bVarInString
&& cCurrChar
== '$' )
500 bVarInString
= false;
501 bIngoreNextDollarSign
= true;
503 else if( bVarInString
&& cCurrChar
== '\\' && (cNextChar
== 'n' || cNextChar
== 'r' || cNextChar
== 't' || cNextChar
== '"' || cNextChar
== '`' || cNextChar
== '\'' ) )
505 styler
.ColourTo( i
+1, SCE_NSIS_STRINGVAR
);
506 bVarInString
= false;
507 bIngoreNextDollarSign
= false;
510 // Covers "$INSTDIR and user vars like $MYVAR"
511 else if( bVarInString
&& !isNsisChar(cNextChar
) )
513 int nWordState
= classifyWordNsis( styler
.GetStartSegment(), i
, keywordLists
, styler
);
514 if( nWordState
== SCE_NSIS_VARIABLE
)
515 styler
.ColourTo( i
, SCE_NSIS_STRINGVAR
);
517 styler
.ColourTo( i
, SCE_NSIS_STRINGVAR
);
518 bVarInString
= false;
520 // Covers "${TEST}..."
521 else if( bClassicVarInString
&& cNextChar
== '}' )
523 styler
.ColourTo( i
+1, SCE_NSIS_STRINGVAR
);
524 bClassicVarInString
= false;
527 // Start of var in string
528 if( !bIngoreNextDollarSign
&& cCurrChar
== '$' && cNextChar
== '{' )
530 styler
.ColourTo( i
-1, state
);
531 bClassicVarInString
= true;
532 bVarInString
= false;
534 else if( !bIngoreNextDollarSign
&& cCurrChar
== '$' )
536 styler
.ColourTo( i
-1, state
);
538 bClassicVarInString
= false;
543 // Colourise remaining document
544 styler
.ColourTo(nLengthDoc
-1,state
);
547 static void FoldNsisDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
)
549 // No folding enabled, no reason to continue...
550 if( styler
.GetPropertyInt("fold") == 0 )
553 bool foldAtElse
= styler
.GetPropertyInt("fold.at.else", 0) == 1;
554 bool foldUtilityCmd
= styler
.GetPropertyInt("nsis.foldutilcmd", 1) == 1;
555 bool blockComment
= false;
557 int lineCurrent
= styler
.GetLine(startPos
);
558 unsigned int safeStartPos
= styler
.LineStart( lineCurrent
);
563 int levelCurrent
= SC_FOLDLEVELBASE
;
565 levelCurrent
= styler
.LevelAt(lineCurrent
-1) >> 16;
566 int levelNext
= levelCurrent
;
567 int style
= styler
.StyleAt(safeStartPos
);
568 if( style
== SCE_NSIS_COMMENTBOX
)
570 if( styler
.SafeGetCharAt(safeStartPos
) == '/' && styler
.SafeGetCharAt(safeStartPos
+1) == '*' )
575 for (unsigned int i
= safeStartPos
; i
< startPos
+ length
; i
++)
577 char chCurr
= styler
.SafeGetCharAt(i
);
578 style
= styler
.StyleAt(i
);
579 if( blockComment
&& style
!= SCE_NSIS_COMMENTBOX
)
582 blockComment
= false;
584 else if( !blockComment
&& style
== SCE_NSIS_COMMENTBOX
)
590 if( bArg1
&& !blockComment
)
592 if( nWordStart
== -1 && (isNsisLetter(chCurr
) || chCurr
== '!') )
596 else if( isNsisLetter(chCurr
) == false && nWordStart
> -1 )
598 int newLevel
= calculateFoldNsis( nWordStart
, i
-1, levelNext
, styler
, foldAtElse
, foldUtilityCmd
);
600 if( newLevel
== levelNext
)
602 if( foldAtElse
&& foldUtilityCmd
)
604 if( NsisNextLineHasElse(i
, startPos
+ length
, styler
) )
609 levelNext
= newLevel
;
616 if( bArg1
&& foldAtElse
&& foldUtilityCmd
&& !blockComment
)
618 if( NsisNextLineHasElse(i
, startPos
+ length
, styler
) )
622 // If we are on a new line...
623 int levelUse
= levelCurrent
;
624 int lev
= levelUse
| levelNext
<< 16;
625 if (levelUse
< levelNext
)
626 lev
|= SC_FOLDLEVELHEADERFLAG
;
627 if (lev
!= styler
.LevelAt(lineCurrent
))
628 styler
.SetLevel(lineCurrent
, lev
);
631 levelCurrent
= levelNext
;
632 bArg1
= true; // New line, lets look at first argument again
637 int levelUse
= levelCurrent
;
638 int lev
= levelUse
| levelNext
<< 16;
639 if (levelUse
< levelNext
)
640 lev
|= SC_FOLDLEVELHEADERFLAG
;
641 if (lev
!= styler
.LevelAt(lineCurrent
))
642 styler
.SetLevel(lineCurrent
, lev
);
645 static const char * const nsisWordLists
[] = {
653 LexerModule
lmNsis(SCLEX_NSIS
, ColouriseNsisDoc
, "nsis", FoldNsisDoc
, nsisWordLists
);