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