*** empty log message ***
[anjuta-git-plugin.git] / scintilla / LexNsis.cxx
blob0f969bbfb8c4d3c9b711dd8cc0bd66cc4de36f9b
1 // Scintilla source code edit control
2 /** @file LexNsis.cxx
3 ** Lexer for NSIS
4 **/
5 // Copyright 2003, 2004 by Angelo Mandato <angelo [at] spaceblue [dot] com>
6 // Last Updated: 02/22/2004
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>
14 #include "Platform.h"
16 #include "PropSet.h"
17 #include "Accessor.h"
18 #include "KeyWords.h"
19 #include "Scintilla.h"
20 #include "SciLexer.h"
23 // located in SciLexer.h
24 #define SCLEX_NSIS 43
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
43 static bool isNsisNumber(char ch)
45 return (ch >= '0' && ch <= '9');
48 static bool isNsisChar(char ch)
50 return (ch == '.' ) || (ch == '_' ) || isNsisNumber(ch) || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
53 static bool isNsisLetter(char ch)
55 return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
58 static int NsisCmp( char *s1, char *s2, bool bIgnoreCase )
60 if( bIgnoreCase )
61 return CompareCaseInsensitive( s1, s2);
63 return strcmp( s1, s2 );
66 static int calculateFoldNsis(unsigned int start, unsigned int end, int foldlevel, Accessor &styler )
68 // If the word is too long, it is not what we are looking for
69 if( end - start > 13 )
70 return foldlevel;
72 // Check the style at this point, if it is not valid, then return zero
73 if( styler.StyleAt(end) != SCE_NSIS_FUNCTION && styler.StyleAt(end) != SCE_NSIS_SECTIONDEF &&
74 styler.StyleAt(end) != SCE_NSIS_SUBSECTIONDEF && styler.StyleAt(end) != SCE_NSIS_IFDEFINEDEF &&
75 styler.StyleAt(end) != SCE_NSIS_MACRODEF )
76 return foldlevel;
78 int newFoldlevel = foldlevel;
79 bool bIgnoreCase = false;
80 if( styler.GetPropertyInt("nsis.ignorecase") == 1 )
81 bIgnoreCase = true;
83 char s[15]; // The key word we are looking for has atmost 13 characters
84 for (unsigned int i = 0; i < end - start + 1 && i < 14; i++)
86 s[i] = static_cast<char>( styler[ start + i ] );
87 s[i + 1] = '\0';
90 if( s[0] == '!' )
92 if( NsisCmp(s, "!ifndef", bIgnoreCase) == 0 || NsisCmp(s, "!ifdef", bIgnoreCase ) == 0 || NsisCmp(s, "!macro", bIgnoreCase ) == 0 )
93 newFoldlevel++;
94 else if( NsisCmp(s, "!endif", bIgnoreCase) == 0 || NsisCmp(s, "!macroend", bIgnoreCase ) == 0 )
95 newFoldlevel--;
97 else
99 if( NsisCmp(s, "Function", bIgnoreCase) == 0 || NsisCmp(s, "Section", bIgnoreCase ) == 0 || NsisCmp(s, "SubSection", bIgnoreCase ) == 0 )
100 newFoldlevel++;
101 else if( NsisCmp(s, "FunctionEnd", bIgnoreCase) == 0 || NsisCmp(s, "SectionEnd", bIgnoreCase ) == 0 || NsisCmp(s, "SubSectionEnd", bIgnoreCase ) == 0 )
102 newFoldlevel--;
105 return newFoldlevel;
108 static int classifyWordNsis(unsigned int start, unsigned int end, WordList *keywordLists[], Accessor &styler )
110 bool bIgnoreCase = false;
111 if( styler.GetPropertyInt("nsis.ignorecase") == 1 )
112 bIgnoreCase = true;
114 bool bUserVars = false;
115 if( styler.GetPropertyInt("nsis.uservars") == 1 )
116 bUserVars = true;
118 char s[100];
120 WordList &Functions = *keywordLists[0];
121 WordList &Variables = *keywordLists[1];
122 WordList &Lables = *keywordLists[2];
123 WordList &UserDefined = *keywordLists[3];
125 for (unsigned int i = 0; i < end - start + 1 && i < 99; i++)
127 if( bIgnoreCase )
128 s[i] = static_cast<char>( tolower(styler[ start + i ] ) );
129 else
130 s[i] = static_cast<char>( styler[ start + i ] );
131 s[i + 1] = '\0';
134 // Check for special words...
135 if( NsisCmp(s, "!macro", bIgnoreCase ) == 0 || NsisCmp(s, "!macroend", bIgnoreCase) == 0 ) // Covers !micro and !microend
136 return SCE_NSIS_MACRODEF;
138 if( NsisCmp(s, "!ifdef", bIgnoreCase ) == 0 || NsisCmp(s, "!ifndef", bIgnoreCase) == 0 || NsisCmp(s, "!endif", bIgnoreCase) == 0 )
139 return SCE_NSIS_IFDEFINEDEF;
141 if( NsisCmp(s, "Section", bIgnoreCase ) == 0 || NsisCmp(s, "SectionEnd", bIgnoreCase) == 0 ) // Covers Section and SectionEnd
142 return SCE_NSIS_SECTIONDEF;
144 if( NsisCmp(s, "SubSection", bIgnoreCase) == 0 || NsisCmp(s, "SubSectionEnd", bIgnoreCase) == 0 ) // Covers SubSection and SubSectionEnd
145 return SCE_NSIS_SUBSECTIONDEF;
147 if( NsisCmp(s, "Function", bIgnoreCase) == 0 || NsisCmp(s, "FunctionEnd", bIgnoreCase) == 0 ) // Covers SubSection and SubSectionEnd
148 return SCE_NSIS_FUNCTION;
150 if ( Functions.InList(s) )
151 return SCE_NSIS_FUNCTION;
153 if ( Variables.InList(s) )
154 return SCE_NSIS_VARIABLE;
156 if ( Lables.InList(s) )
157 return SCE_NSIS_LABEL;
159 if( UserDefined.InList(s) )
160 return SCE_NSIS_USERDEFINED;
162 if( strlen(s) > 3 )
164 if( s[1] == '{' && s[strlen(s)-1] == '}' )
165 return SCE_NSIS_VARIABLE;
168 // See if the variable is a user defined variable
169 if( s[0] == '$' && bUserVars )
171 bool bHasSimpleNsisChars = true;
172 for (unsigned int j = 1; j < end - start + 1 && j < 99; j++)
174 if( !isNsisChar( s[j] ) )
176 bHasSimpleNsisChars = false;
177 break;
181 if( bHasSimpleNsisChars )
182 return SCE_NSIS_VARIABLE;
185 // To check for numbers
186 if( isNsisNumber( s[0] ) )
188 bool bHasSimpleNsisNumber = true;
189 for (unsigned int j = 1; j < end - start + 1 && j < 99; j++)
191 if( s[j] == '\0' || s[j] == '\r' || s[j] == '\n' )
192 break;
194 if( !isNsisNumber( s[j] ) )
196 bHasSimpleNsisNumber = false;
197 break;
201 if( bHasSimpleNsisNumber )
202 return SCE_NSIS_NUMBER;
205 return SCE_NSIS_DEFAULT;
208 static void ColouriseNsisDoc(unsigned int startPos, int length, int, WordList *keywordLists[], Accessor &styler)
210 int state = SCE_NSIS_DEFAULT;
211 styler.StartAt( startPos );
212 styler.GetLine( startPos );
214 unsigned int nLengthDoc = startPos + length;
215 styler.StartSegment( startPos );
217 char cCurrChar;
218 bool bVarInString = false;
219 bool bClassicVarInString = false;
221 unsigned int i;
222 for( i = startPos; i < nLengthDoc; i++ )
224 cCurrChar = styler.SafeGetCharAt( i );
225 char cNextChar = styler.SafeGetCharAt(i+1);
227 switch(state)
229 case SCE_NSIS_DEFAULT:
230 if( cCurrChar == ';' || cCurrChar == '#' ) // we have a comment line
232 styler.ColourTo(i-1, state );
233 state = SCE_NSIS_COMMENT;
234 break;
236 if( cCurrChar == '"' )
238 styler.ColourTo(i-1, state );
239 state = SCE_NSIS_STRINGDQ;
240 bVarInString = false;
241 bClassicVarInString = false;
242 break;
244 if( cCurrChar == '\'' )
246 styler.ColourTo(i-1, state );
247 state = SCE_NSIS_STRINGRQ;
248 bVarInString = false;
249 bClassicVarInString = false;
250 break;
252 if( cCurrChar == '`' )
254 styler.ColourTo(i-1, state );
255 state = SCE_NSIS_STRINGLQ;
256 bVarInString = false;
257 bClassicVarInString = false;
258 break;
261 // NSIS KeyWord,Function, Variable, UserDefined:
262 if( cCurrChar == '$' || isNsisChar(cCurrChar) || cCurrChar == '!' )
264 styler.ColourTo(i-1,state);
265 state = SCE_NSIS_FUNCTION;
267 // If it is a number, we must check and set style here first...
268 if( isNsisNumber(cCurrChar) && (cNextChar == '\t' || cNextChar == ' ' || cNextChar == '\r' || cNextChar == '\n' ) )
269 styler.ColourTo( i, SCE_NSIS_NUMBER);
271 break;
273 break;
274 case SCE_NSIS_COMMENT:
275 if( cNextChar == '\n' || cNextChar == '\r' )
277 styler.ColourTo(i,state);
278 state = SCE_NSIS_DEFAULT;
280 break;
281 case SCE_NSIS_STRINGDQ:
282 if( cCurrChar == '"' || cNextChar == '\r' || cNextChar == '\n' )
284 styler.ColourTo(i,SCE_NSIS_STRINGDQ);
285 state = SCE_NSIS_DEFAULT;
287 break;
288 case SCE_NSIS_STRINGLQ:
289 if( cCurrChar == '`' || cNextChar == '\r' || cNextChar == '\n' )
291 styler.ColourTo(i,SCE_NSIS_STRINGLQ);
292 state = SCE_NSIS_DEFAULT;
294 break;
295 case SCE_NSIS_STRINGRQ:
296 if( cCurrChar == '\'' || cNextChar == '\r' || cNextChar == '\n' )
298 styler.ColourTo(i,SCE_NSIS_STRINGRQ);
299 state = SCE_NSIS_DEFAULT;
301 break;
302 case SCE_NSIS_FUNCTION:
304 // NSIS KeyWord:
305 if( cCurrChar == '$' )
306 state = SCE_NSIS_DEFAULT;
307 else if( cCurrChar == '\\' && (cNextChar == 'n' || cNextChar == 'r' || cNextChar == 't' ) )
308 state = SCE_NSIS_DEFAULT;
309 else if( (isNsisChar(cCurrChar) && !isNsisChar( cNextChar) && cNextChar != '}') || cCurrChar == '}' )
311 state = classifyWordNsis( styler.GetStartSegment(), i, keywordLists, styler);
312 styler.ColourTo( i, state);
313 state = SCE_NSIS_DEFAULT;
315 else if( !isNsisChar( cCurrChar ) && cCurrChar != '{' && cCurrChar != '}' )
317 if( classifyWordNsis( styler.GetStartSegment(), i-1, keywordLists, styler) == SCE_NSIS_NUMBER )
318 styler.ColourTo( i-1, SCE_NSIS_NUMBER );
320 state = SCE_NSIS_DEFAULT;
322 if( cCurrChar == '"' )
324 state = SCE_NSIS_STRINGDQ;
325 bVarInString = false;
326 bClassicVarInString = false;
328 else if( cCurrChar == '`' )
330 state = SCE_NSIS_STRINGLQ;
331 bVarInString = false;
332 bClassicVarInString = false;
334 else if( cCurrChar == '\'' )
336 state = SCE_NSIS_STRINGRQ;
337 bVarInString = false;
338 bClassicVarInString = false;
340 else if( cCurrChar == '#' || cCurrChar == ';' )
342 state = SCE_NSIS_COMMENT;
345 break;
348 if( state == SCE_NSIS_COMMENT )
350 styler.ColourTo(i,state);
352 else if( state == SCE_NSIS_STRINGDQ || state == SCE_NSIS_STRINGLQ || state == SCE_NSIS_STRINGRQ )
354 bool bIngoreNextDollarSign = false;
355 bool bUserVars = false;
356 if( styler.GetPropertyInt("nsis.uservars") == 1 )
357 bUserVars = true;
359 if( bVarInString && cCurrChar == '$' )
361 bVarInString = false;
362 bIngoreNextDollarSign = true;
364 else if( bVarInString && cCurrChar == '\\' && (cNextChar == 'n' || cNextChar == 'r' || cNextChar == 't' ) )
366 bVarInString = false;
367 bIngoreNextDollarSign = true;
370 // Covers "$INSTDIR and user vars like $MYVAR"
371 else if( bVarInString && !isNsisChar(cNextChar) )
373 int nWordState = classifyWordNsis( styler.GetStartSegment(), i, keywordLists, styler);
374 if( nWordState == SCE_NSIS_VARIABLE )
375 styler.ColourTo( i, SCE_NSIS_STRINGVAR);
376 else if( bUserVars )
377 styler.ColourTo( i, SCE_NSIS_STRINGVAR);
378 bVarInString = false;
380 // Covers "${TEST}..."
381 else if( bClassicVarInString && cNextChar == '}' )
383 styler.ColourTo( i+1, SCE_NSIS_STRINGVAR);
384 bClassicVarInString = false;
387 // Start of var in string
388 if( !bIngoreNextDollarSign && cCurrChar == '$' && cNextChar == '{' )
390 styler.ColourTo( i-1, state);
391 bClassicVarInString = true;
392 bVarInString = false;
394 else if( !bIngoreNextDollarSign && cCurrChar == '$' )
396 styler.ColourTo( i-1, state);
397 bVarInString = true;
398 bClassicVarInString = false;
403 // Colourise remaining document
404 switch( state )
406 case SCE_NSIS_COMMENT:
407 case SCE_NSIS_STRINGDQ:
408 case SCE_NSIS_STRINGLQ:
409 case SCE_NSIS_STRINGRQ:
410 case SCE_NSIS_VARIABLE:
411 case SCE_NSIS_STRINGVAR:
412 styler.ColourTo(nLengthDoc-1,state); break;
414 default:
415 styler.ColourTo(nLengthDoc-1,SCE_NSIS_DEFAULT); break;
419 static void FoldNsisDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler)
421 // No folding enabled, no reason to continue...
422 if( styler.GetPropertyInt("fold") == 0 )
423 return;
425 int lineCurrent = styler.GetLine(startPos);
426 unsigned int safeStartPos = styler.LineStart( lineCurrent );
428 bool bArg1 = true;
429 int nWordStart = -1;
431 int levelCurrent = SC_FOLDLEVELBASE;
432 if (lineCurrent > 0)
433 levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
434 int levelNext = levelCurrent;
436 for (unsigned int i = safeStartPos; i < startPos + length; i++)
438 char chCurr = styler.SafeGetCharAt(i);
440 if( bArg1 ) //&& chCurr != '\n' )
442 if( nWordStart == -1 && (isNsisLetter(chCurr) || chCurr == '!') )
443 nWordStart = i;
444 else if( !isNsisLetter(chCurr) && nWordStart > -1 )
446 int newLevel = calculateFoldNsis( nWordStart, i-1, levelNext, styler );
447 if( newLevel != levelNext )
448 levelNext = newLevel;
449 bArg1 = false;
453 if( chCurr == '\n' )
455 // If we are on a new line...
456 int levelUse = levelCurrent;
457 int lev = levelUse | levelNext << 16;
458 if (levelUse < levelNext)
459 lev |= SC_FOLDLEVELHEADERFLAG;
460 if (lev != styler.LevelAt(lineCurrent))
461 styler.SetLevel(lineCurrent, lev);
463 lineCurrent++;
464 levelCurrent = levelNext;
465 bArg1 = true; // New line, lets look at first argument again
466 nWordStart = -1;
470 int levelUse = levelCurrent;
471 int lev = levelUse | levelNext << 16;
472 if (levelUse < levelNext)
473 lev |= SC_FOLDLEVELHEADERFLAG;
474 if (lev != styler.LevelAt(lineCurrent))
475 styler.SetLevel(lineCurrent, lev);
478 static const char * const nsisWordLists[] = {
479 "Functions",
480 "Variables",
481 "Lables",
482 "UserDefined",
483 0, };
486 LexerModule lmNsis(SCLEX_NSIS, ColouriseNsisDoc, "nsis", FoldNsisDoc, nsisWordLists);