]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/LexNsis.cxx
43ddc470619442819c0727b95f18a5c353c5009c
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.
16 #include "CharClassify.h"
20 #include "Scintilla.h"
24 using namespace Scintilla
;
28 // located in SciLexer.h
31 #define SCE_NSIS_DEFAULT 0
32 #define SCE_NSIS_COMMENT 1
33 #define SCE_NSIS_STRINGDQ 2
34 #define SCE_NSIS_STRINGLQ 3
35 #define SCE_NSIS_STRINGRQ 4
36 #define SCE_NSIS_FUNCTION 5
37 #define SCE_NSIS_VARIABLE 6
38 #define SCE_NSIS_LABEL 7
39 #define SCE_NSIS_USERDEFINED 8
40 #define SCE_NSIS_SECTIONDEF 9
41 #define SCE_NSIS_SUBSECTIONDEF 10
42 #define SCE_NSIS_IFDEFINEDEF 11
43 #define SCE_NSIS_MACRODEF 12
44 #define SCE_NSIS_STRINGVAR 13
45 #define SCE_NSIS_NUMBER 14
46 // ADDED for Scintilla v1.63
47 #define SCE_NSIS_SECTIONGROUP 15
48 #define SCE_NSIS_PAGEEX 16
49 #define SCE_NSIS_FUNCTIONDEF 17
50 #define SCE_NSIS_COMMENTBOX 18
53 static bool isNsisNumber(char ch
)
55 return (ch
>= '0' && ch
<= '9');
58 static bool isNsisChar(char ch
)
60 return (ch
== '.' ) || (ch
== '_' ) || isNsisNumber(ch
) || (ch
>= 'A' && ch
<= 'Z') || (ch
>= 'a' && ch
<= 'z');
63 static bool isNsisLetter(char ch
)
65 return (ch
>= 'A' && ch
<= 'Z') || (ch
>= 'a' && ch
<= 'z');
68 static bool NsisNextLineHasElse(unsigned int start
, unsigned int end
, Accessor
&styler
)
71 for( unsigned int i
= start
; i
< end
; i
++ )
73 char cNext
= styler
.SafeGetCharAt( i
);
81 if( nNextLine
== -1 ) // We never found the next line...
84 for( unsigned int firstChar
= nNextLine
; firstChar
< end
; firstChar
++ )
86 char cNext
= styler
.SafeGetCharAt( firstChar
);
93 if( styler
.Match(firstChar
, "!else") )
102 static int NsisCmp( const char *s1
, const char *s2
, bool bIgnoreCase
)
105 return CompareCaseInsensitive( s1
, s2
);
107 return strcmp( s1
, s2
);
110 static int calculateFoldNsis(unsigned int start
, unsigned int end
, int foldlevel
, Accessor
&styler
, bool bElse
, bool foldUtilityCmd
)
112 int style
= styler
.StyleAt(end
);
114 // If the word is too long, it is not what we are looking for
115 if( end
- start
> 20 )
120 // Check the style at this point, if it is not valid, then return zero
121 if( style
!= SCE_NSIS_FUNCTIONDEF
&& style
!= SCE_NSIS_SECTIONDEF
&&
122 style
!= SCE_NSIS_SUBSECTIONDEF
&& style
!= SCE_NSIS_IFDEFINEDEF
&&
123 style
!= SCE_NSIS_MACRODEF
&& style
!= SCE_NSIS_SECTIONGROUP
&&
124 style
!= SCE_NSIS_PAGEEX
)
129 if( style
!= SCE_NSIS_FUNCTIONDEF
&& style
!= SCE_NSIS_SECTIONDEF
&&
130 style
!= SCE_NSIS_SUBSECTIONDEF
&& style
!= SCE_NSIS_SECTIONGROUP
&&
131 style
!= SCE_NSIS_PAGEEX
)
135 int newFoldlevel
= foldlevel
;
136 bool bIgnoreCase
= false;
137 if( styler
.GetPropertyInt("nsis.ignorecase") == 1 )
140 char s
[20]; // The key word we are looking for has atmost 13 characters
141 for (unsigned int i
= 0; i
< end
- start
+ 1 && i
< 19; i
++)
143 s
[i
] = static_cast<char>( styler
[ start
+ i
] );
149 if( NsisCmp(s
, "!ifndef", bIgnoreCase
) == 0 || NsisCmp(s
, "!ifdef", bIgnoreCase
) == 0 || NsisCmp(s
, "!ifmacrodef", bIgnoreCase
) == 0 || NsisCmp(s
, "!ifmacrondef", bIgnoreCase
) == 0 || NsisCmp(s
, "!if", bIgnoreCase
) == 0 || NsisCmp(s
, "!macro", bIgnoreCase
) == 0 )
151 else if( NsisCmp(s
, "!endif", bIgnoreCase
) == 0 || NsisCmp(s
, "!macroend", bIgnoreCase
) == 0 )
153 else if( bElse
&& NsisCmp(s
, "!else", bIgnoreCase
) == 0 )
158 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 )
160 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 )
167 static int classifyWordNsis(unsigned int start
, unsigned int end
, WordList
*keywordLists
[], Accessor
&styler
)
169 bool bIgnoreCase
= false;
170 if( styler
.GetPropertyInt("nsis.ignorecase") == 1 )
173 bool bUserVars
= false;
174 if( styler
.GetPropertyInt("nsis.uservars") == 1 )
179 WordList
&Functions
= *keywordLists
[0];
180 WordList
&Variables
= *keywordLists
[1];
181 WordList
&Lables
= *keywordLists
[2];
182 WordList
&UserDefined
= *keywordLists
[3];
184 for (unsigned int i
= 0; i
< end
- start
+ 1 && i
< 99; i
++)
187 s
[i
] = static_cast<char>( tolower(styler
[ start
+ i
] ) );
189 s
[i
] = static_cast<char>( styler
[ start
+ i
] );
193 // Check for special words...
194 if( NsisCmp(s
, "!macro", bIgnoreCase
) == 0 || NsisCmp(s
, "!macroend", bIgnoreCase
) == 0 ) // Covers !macro and !macroend
195 return SCE_NSIS_MACRODEF
;
197 if( NsisCmp(s
, "!ifdef", bIgnoreCase
) == 0 || NsisCmp(s
, "!ifndef", bIgnoreCase
) == 0 || NsisCmp(s
, "!endif", bIgnoreCase
) == 0 ) // Covers !ifdef, !ifndef and !endif
198 return SCE_NSIS_IFDEFINEDEF
;
200 if( NsisCmp(s
, "!if", bIgnoreCase
) == 0 || NsisCmp(s
, "!else", bIgnoreCase
) == 0 ) // Covers !if and else
201 return SCE_NSIS_IFDEFINEDEF
;
203 if (NsisCmp(s
, "!ifmacrodef", bIgnoreCase
) == 0 || NsisCmp(s
, "!ifmacrondef", bIgnoreCase
) == 0 ) // Covers !ifmacrodef and !ifnmacrodef
204 return SCE_NSIS_IFDEFINEDEF
;
206 if( NsisCmp(s
, "SectionGroup", bIgnoreCase
) == 0 || NsisCmp(s
, "SectionGroupEnd", bIgnoreCase
) == 0 ) // Covers SectionGroup and SectionGroupEnd
207 return SCE_NSIS_SECTIONGROUP
;
209 if( NsisCmp(s
, "Section", bIgnoreCase
) == 0 || NsisCmp(s
, "SectionEnd", bIgnoreCase
) == 0 ) // Covers Section and SectionEnd
210 return SCE_NSIS_SECTIONDEF
;
212 if( NsisCmp(s
, "SubSection", bIgnoreCase
) == 0 || NsisCmp(s
, "SubSectionEnd", bIgnoreCase
) == 0 ) // Covers SubSection and SubSectionEnd
213 return SCE_NSIS_SUBSECTIONDEF
;
215 if( NsisCmp(s
, "PageEx", bIgnoreCase
) == 0 || NsisCmp(s
, "PageExEnd", bIgnoreCase
) == 0 ) // Covers PageEx and PageExEnd
216 return SCE_NSIS_PAGEEX
;
218 if( NsisCmp(s
, "Function", bIgnoreCase
) == 0 || NsisCmp(s
, "FunctionEnd", bIgnoreCase
) == 0 ) // Covers Function and FunctionEnd
219 return SCE_NSIS_FUNCTIONDEF
;
221 if ( Functions
.InList(s
) )
222 return SCE_NSIS_FUNCTION
;
224 if ( Variables
.InList(s
) )
225 return SCE_NSIS_VARIABLE
;
227 if ( Lables
.InList(s
) )
228 return SCE_NSIS_LABEL
;
230 if( UserDefined
.InList(s
) )
231 return SCE_NSIS_USERDEFINED
;
235 if( s
[1] == '{' && s
[strlen(s
)-1] == '}' )
236 return SCE_NSIS_VARIABLE
;
239 // See if the variable is a user defined variable
240 if( s
[0] == '$' && bUserVars
)
242 bool bHasSimpleNsisChars
= true;
243 for (unsigned int j
= 1; j
< end
- start
+ 1 && j
< 99; j
++)
245 if( !isNsisChar( s
[j
] ) )
247 bHasSimpleNsisChars
= false;
252 if( bHasSimpleNsisChars
)
253 return SCE_NSIS_VARIABLE
;
256 // To check for numbers
257 if( isNsisNumber( s
[0] ) )
259 bool bHasSimpleNsisNumber
= true;
260 for (unsigned int j
= 1; j
< end
- start
+ 1 && j
< 99; j
++)
262 if( !isNsisNumber( s
[j
] ) )
264 bHasSimpleNsisNumber
= false;
269 if( bHasSimpleNsisNumber
)
270 return SCE_NSIS_NUMBER
;
273 return SCE_NSIS_DEFAULT
;
276 static void ColouriseNsisDoc(unsigned int startPos
, int length
, int, WordList
*keywordLists
[], Accessor
&styler
)
278 int state
= SCE_NSIS_DEFAULT
;
280 state
= styler
.StyleAt(startPos
-1); // Use the style from the previous line, usually default, but could be commentbox
282 styler
.StartAt( startPos
);
283 styler
.GetLine( startPos
);
285 unsigned int nLengthDoc
= startPos
+ length
;
286 styler
.StartSegment( startPos
);
289 bool bVarInString
= false;
290 bool bClassicVarInString
= false;
293 for( i
= startPos
; i
< nLengthDoc
; i
++ )
295 cCurrChar
= styler
.SafeGetCharAt( i
);
296 char cNextChar
= styler
.SafeGetCharAt(i
+1);
300 case SCE_NSIS_DEFAULT
:
301 if( cCurrChar
== ';' || cCurrChar
== '#' ) // we have a comment line
303 styler
.ColourTo(i
-1, state
);
304 state
= SCE_NSIS_COMMENT
;
307 if( cCurrChar
== '"' )
309 styler
.ColourTo(i
-1, state
);
310 state
= SCE_NSIS_STRINGDQ
;
311 bVarInString
= false;
312 bClassicVarInString
= false;
315 if( cCurrChar
== '\'' )
317 styler
.ColourTo(i
-1, state
);
318 state
= SCE_NSIS_STRINGRQ
;
319 bVarInString
= false;
320 bClassicVarInString
= false;
323 if( cCurrChar
== '`' )
325 styler
.ColourTo(i
-1, state
);
326 state
= SCE_NSIS_STRINGLQ
;
327 bVarInString
= false;
328 bClassicVarInString
= false;
332 // NSIS KeyWord,Function, Variable, UserDefined:
333 if( cCurrChar
== '$' || isNsisChar(cCurrChar
) || cCurrChar
== '!' )
335 styler
.ColourTo(i
-1,state
);
336 state
= SCE_NSIS_FUNCTION
;
338 // If it is a number, we must check and set style here first...
339 if( isNsisNumber(cCurrChar
) && (cNextChar
== '\t' || cNextChar
== ' ' || cNextChar
== '\r' || cNextChar
== '\n' ) )
340 styler
.ColourTo( i
, SCE_NSIS_NUMBER
);
345 if( cCurrChar
== '/' && cNextChar
== '*' )
347 styler
.ColourTo(i
-1,state
);
348 state
= SCE_NSIS_COMMENTBOX
;
353 case SCE_NSIS_COMMENT
:
354 if( cNextChar
== '\n' || cNextChar
== '\r' )
357 if( cCurrChar
== '\\' )
359 styler
.ColourTo(i
-2,state
);
360 styler
.ColourTo(i
,SCE_NSIS_DEFAULT
);
364 styler
.ColourTo(i
,state
);
365 state
= SCE_NSIS_DEFAULT
;
369 case SCE_NSIS_STRINGDQ
:
370 case SCE_NSIS_STRINGLQ
:
371 case SCE_NSIS_STRINGRQ
:
373 if( styler
.SafeGetCharAt(i
-1) == '\\' && styler
.SafeGetCharAt(i
-2) == '$' )
374 break; // Ignore the next character, even if it is a quote of some sort
376 if( cCurrChar
== '"' && state
== SCE_NSIS_STRINGDQ
)
378 styler
.ColourTo(i
,state
);
379 state
= SCE_NSIS_DEFAULT
;
383 if( cCurrChar
== '`' && state
== SCE_NSIS_STRINGLQ
)
385 styler
.ColourTo(i
,state
);
386 state
= SCE_NSIS_DEFAULT
;
390 if( cCurrChar
== '\'' && state
== SCE_NSIS_STRINGRQ
)
392 styler
.ColourTo(i
,state
);
393 state
= SCE_NSIS_DEFAULT
;
397 if( cNextChar
== '\r' || cNextChar
== '\n' )
399 int nCurLine
= styler
.GetLine(i
+1);
401 // We need to check if the previous line has a \ in it...
402 bool bNextLine
= false;
406 if( styler
.GetLine(nBack
) != nCurLine
)
409 char cTemp
= styler
.SafeGetCharAt(nBack
, 'a'); // Letter 'a' is safe here
416 if( cTemp
!= '\r' && cTemp
!= '\n' && cTemp
!= '\t' && cTemp
!= ' ' )
424 styler
.ColourTo(i
+1,state
);
426 if( bNextLine
== false )
428 styler
.ColourTo(i
,state
);
429 state
= SCE_NSIS_DEFAULT
;
434 case SCE_NSIS_FUNCTION
:
437 if( cCurrChar
== '$' )
438 state
= SCE_NSIS_DEFAULT
;
439 else if( cCurrChar
== '\\' && (cNextChar
== 'n' || cNextChar
== 'r' || cNextChar
== 't' ) )
440 state
= SCE_NSIS_DEFAULT
;
441 else if( (isNsisChar(cCurrChar
) && !isNsisChar( cNextChar
) && cNextChar
!= '}') || cCurrChar
== '}' )
443 state
= classifyWordNsis( styler
.GetStartSegment(), i
, keywordLists
, styler
);
444 styler
.ColourTo( i
, state
);
445 state
= SCE_NSIS_DEFAULT
;
447 else if( !isNsisChar( cCurrChar
) && cCurrChar
!= '{' && cCurrChar
!= '}' )
449 if( classifyWordNsis( styler
.GetStartSegment(), i
-1, keywordLists
, styler
) == SCE_NSIS_NUMBER
)
450 styler
.ColourTo( i
-1, SCE_NSIS_NUMBER
);
452 state
= SCE_NSIS_DEFAULT
;
454 if( cCurrChar
== '"' )
456 state
= SCE_NSIS_STRINGDQ
;
457 bVarInString
= false;
458 bClassicVarInString
= false;
460 else if( cCurrChar
== '`' )
462 state
= SCE_NSIS_STRINGLQ
;
463 bVarInString
= false;
464 bClassicVarInString
= false;
466 else if( cCurrChar
== '\'' )
468 state
= SCE_NSIS_STRINGRQ
;
469 bVarInString
= false;
470 bClassicVarInString
= false;
472 else if( cCurrChar
== '#' || cCurrChar
== ';' )
474 state
= SCE_NSIS_COMMENT
;
478 case SCE_NSIS_COMMENTBOX
:
480 if( styler
.SafeGetCharAt(i
-1) == '*' && cCurrChar
== '/' )
482 styler
.ColourTo(i
,state
);
483 state
= SCE_NSIS_DEFAULT
;
488 if( state
== SCE_NSIS_COMMENT
|| state
== SCE_NSIS_COMMENTBOX
)
490 styler
.ColourTo(i
,state
);
492 else if( state
== SCE_NSIS_STRINGDQ
|| state
== SCE_NSIS_STRINGLQ
|| state
== SCE_NSIS_STRINGRQ
)
494 bool bIngoreNextDollarSign
= false;
495 bool bUserVars
= false;
496 if( styler
.GetPropertyInt("nsis.uservars") == 1 )
499 if( bVarInString
&& cCurrChar
== '$' )
501 bVarInString
= false;
502 bIngoreNextDollarSign
= true;
504 else if( bVarInString
&& cCurrChar
== '\\' && (cNextChar
== 'n' || cNextChar
== 'r' || cNextChar
== 't' || cNextChar
== '"' || cNextChar
== '`' || cNextChar
== '\'' ) )
506 styler
.ColourTo( i
+1, SCE_NSIS_STRINGVAR
);
507 bVarInString
= false;
508 bIngoreNextDollarSign
= false;
511 // Covers "$INSTDIR and user vars like $MYVAR"
512 else if( bVarInString
&& !isNsisChar(cNextChar
) )
514 int nWordState
= classifyWordNsis( styler
.GetStartSegment(), i
, keywordLists
, styler
);
515 if( nWordState
== SCE_NSIS_VARIABLE
)
516 styler
.ColourTo( i
, SCE_NSIS_STRINGVAR
);
518 styler
.ColourTo( i
, SCE_NSIS_STRINGVAR
);
519 bVarInString
= false;
521 // Covers "${TEST}..."
522 else if( bClassicVarInString
&& cNextChar
== '}' )
524 styler
.ColourTo( i
+1, SCE_NSIS_STRINGVAR
);
525 bClassicVarInString
= false;
528 // Start of var in string
529 if( !bIngoreNextDollarSign
&& cCurrChar
== '$' && cNextChar
== '{' )
531 styler
.ColourTo( i
-1, state
);
532 bClassicVarInString
= true;
533 bVarInString
= false;
535 else if( !bIngoreNextDollarSign
&& cCurrChar
== '$' )
537 styler
.ColourTo( i
-1, state
);
539 bClassicVarInString
= false;
544 // Colourise remaining document
545 styler
.ColourTo(nLengthDoc
-1,state
);
548 static void FoldNsisDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
)
550 // No folding enabled, no reason to continue...
551 if( styler
.GetPropertyInt("fold") == 0 )
554 bool foldAtElse
= styler
.GetPropertyInt("fold.at.else", 0) == 1;
555 bool foldUtilityCmd
= styler
.GetPropertyInt("nsis.foldutilcmd", 1) == 1;
556 bool blockComment
= false;
558 int lineCurrent
= styler
.GetLine(startPos
);
559 unsigned int safeStartPos
= styler
.LineStart( lineCurrent
);
564 int levelCurrent
= SC_FOLDLEVELBASE
;
566 levelCurrent
= styler
.LevelAt(lineCurrent
-1) >> 16;
567 int levelNext
= levelCurrent
;
568 int style
= styler
.StyleAt(safeStartPos
);
569 if( style
== SCE_NSIS_COMMENTBOX
)
571 if( styler
.SafeGetCharAt(safeStartPos
) == '/' && styler
.SafeGetCharAt(safeStartPos
+1) == '*' )
576 for (unsigned int i
= safeStartPos
; i
< startPos
+ length
; i
++)
578 char chCurr
= styler
.SafeGetCharAt(i
);
579 style
= styler
.StyleAt(i
);
580 if( blockComment
&& style
!= SCE_NSIS_COMMENTBOX
)
583 blockComment
= false;
585 else if( !blockComment
&& style
== SCE_NSIS_COMMENTBOX
)
591 if( bArg1
&& !blockComment
)
593 if( nWordStart
== -1 && (isNsisLetter(chCurr
) || chCurr
== '!') )
597 else if( isNsisLetter(chCurr
) == false && nWordStart
> -1 )
599 int newLevel
= calculateFoldNsis( nWordStart
, i
-1, levelNext
, styler
, foldAtElse
, foldUtilityCmd
);
601 if( newLevel
== levelNext
)
603 if( foldAtElse
&& foldUtilityCmd
)
605 if( NsisNextLineHasElse(i
, startPos
+ length
, styler
) )
610 levelNext
= newLevel
;
617 if( bArg1
&& foldAtElse
&& foldUtilityCmd
&& !blockComment
)
619 if( NsisNextLineHasElse(i
, startPos
+ length
, styler
) )
623 // If we are on a new line...
624 int levelUse
= levelCurrent
;
625 int lev
= levelUse
| levelNext
<< 16;
626 if (levelUse
< levelNext
)
627 lev
|= SC_FOLDLEVELHEADERFLAG
;
628 if (lev
!= styler
.LevelAt(lineCurrent
))
629 styler
.SetLevel(lineCurrent
, lev
);
632 levelCurrent
= levelNext
;
633 bArg1
= true; // New line, lets look at first argument again
638 int levelUse
= levelCurrent
;
639 int lev
= levelUse
| levelNext
<< 16;
640 if (levelUse
< levelNext
)
641 lev
|= SC_FOLDLEVELHEADERFLAG
;
642 if (lev
!= styler
.LevelAt(lineCurrent
))
643 styler
.SetLevel(lineCurrent
, lev
);
646 static const char * const nsisWordLists
[] = {
654 LexerModule
lmNsis(SCLEX_NSIS
, ColouriseNsisDoc
, "nsis", FoldNsisDoc
, nsisWordLists
);