]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/lexers/LexCmake.cxx
1 // Scintilla source code edit control
5 // Copyright 2007 by Cristian Adam <cristian [dot] adam [at] gmx [dot] net>
6 // based on the NSIS lexer
7 // The License.txt file describes the conditions under which this software may be distributed.
17 #include "Scintilla.h"
21 #include "LexAccessor.h"
23 #include "StyleContext.h"
24 #include "CharacterSet.h"
25 #include "LexerModule.h"
28 using namespace Scintilla
;
31 static bool isCmakeNumber(char ch
)
33 return(ch
>= '0' && ch
<= '9');
36 static bool isCmakeChar(char ch
)
38 return(ch
== '.' ) || (ch
== '_' ) || isCmakeNumber(ch
) || (ch
>= 'A' && ch
<= 'Z') || (ch
>= 'a' && ch
<= 'z');
41 static bool isCmakeLetter(char ch
)
43 return(ch
>= 'A' && ch
<= 'Z') || (ch
>= 'a' && ch
<= 'z');
46 static bool CmakeNextLineHasElse(unsigned int start
, unsigned int end
, Accessor
&styler
)
49 for ( unsigned int i
= start
; i
< end
; i
++ ) {
50 char cNext
= styler
.SafeGetCharAt( i
);
51 if ( cNext
== '\n' ) {
57 if ( nNextLine
== -1 ) // We never foudn the next line...
60 for ( unsigned int firstChar
= nNextLine
; firstChar
< end
; firstChar
++ ) {
61 char cNext
= styler
.SafeGetCharAt( firstChar
);
66 if ( styler
.Match(firstChar
, "ELSE") || styler
.Match(firstChar
, "else"))
74 static int calculateFoldCmake(unsigned int start
, unsigned int end
, int foldlevel
, Accessor
&styler
, bool bElse
)
76 // If the word is too long, it is not what we are looking for
77 if ( end
- start
> 20 )
80 int newFoldlevel
= foldlevel
;
82 char s
[20]; // The key word we are looking for has atmost 13 characters
83 for (unsigned int i
= 0; i
< end
- start
+ 1 && i
< 19; i
++) {
84 s
[i
] = static_cast<char>( styler
[ start
+ i
] );
88 if ( CompareCaseInsensitive(s
, "IF") == 0 || CompareCaseInsensitive(s
, "WHILE") == 0
89 || CompareCaseInsensitive(s
, "MACRO") == 0 || CompareCaseInsensitive(s
, "FOREACH") == 0
90 || CompareCaseInsensitive(s
, "ELSEIF") == 0 )
92 else if ( CompareCaseInsensitive(s
, "ENDIF") == 0 || CompareCaseInsensitive(s
, "ENDWHILE") == 0
93 || CompareCaseInsensitive(s
, "ENDMACRO") == 0 || CompareCaseInsensitive(s
, "ENDFOREACH") == 0)
95 else if ( bElse
&& CompareCaseInsensitive(s
, "ELSEIF") == 0 )
97 else if ( bElse
&& CompareCaseInsensitive(s
, "ELSE") == 0 )
103 static int classifyWordCmake(unsigned int start
, unsigned int end
, WordList
*keywordLists
[], Accessor
&styler
)
105 char word
[100] = {0};
106 char lowercaseWord
[100] = {0};
108 WordList
&Commands
= *keywordLists
[0];
109 WordList
&Parameters
= *keywordLists
[1];
110 WordList
&UserDefined
= *keywordLists
[2];
112 for (unsigned int i
= 0; i
< end
- start
+ 1 && i
< 99; i
++) {
113 word
[i
] = static_cast<char>( styler
[ start
+ i
] );
114 lowercaseWord
[i
] = static_cast<char>(tolower(word
[i
]));
117 // Check for special words...
118 if ( CompareCaseInsensitive(word
, "MACRO") == 0 || CompareCaseInsensitive(word
, "ENDMACRO") == 0 )
119 return SCE_CMAKE_MACRODEF
;
121 if ( CompareCaseInsensitive(word
, "IF") == 0 || CompareCaseInsensitive(word
, "ENDIF") == 0 )
122 return SCE_CMAKE_IFDEFINEDEF
;
124 if ( CompareCaseInsensitive(word
, "ELSEIF") == 0 || CompareCaseInsensitive(word
, "ELSE") == 0 )
125 return SCE_CMAKE_IFDEFINEDEF
;
127 if ( CompareCaseInsensitive(word
, "WHILE") == 0 || CompareCaseInsensitive(word
, "ENDWHILE") == 0)
128 return SCE_CMAKE_WHILEDEF
;
130 if ( CompareCaseInsensitive(word
, "FOREACH") == 0 || CompareCaseInsensitive(word
, "ENDFOREACH") == 0)
131 return SCE_CMAKE_FOREACHDEF
;
133 if ( Commands
.InList(lowercaseWord
) )
134 return SCE_CMAKE_COMMANDS
;
136 if ( Parameters
.InList(word
) )
137 return SCE_CMAKE_PARAMETERS
;
140 if ( UserDefined
.InList(word
) )
141 return SCE_CMAKE_USERDEFINED
;
143 if ( strlen(word
) > 3 ) {
144 if ( word
[1] == '{' && word
[strlen(word
)-1] == '}' )
145 return SCE_CMAKE_VARIABLE
;
148 // To check for numbers
149 if ( isCmakeNumber( word
[0] ) ) {
150 bool bHasSimpleCmakeNumber
= true;
151 for (unsigned int j
= 1; j
< end
- start
+ 1 && j
< 99; j
++) {
152 if ( !isCmakeNumber( word
[j
] ) ) {
153 bHasSimpleCmakeNumber
= false;
158 if ( bHasSimpleCmakeNumber
)
159 return SCE_CMAKE_NUMBER
;
162 return SCE_CMAKE_DEFAULT
;
165 static void ColouriseCmakeDoc(unsigned int startPos
, int length
, int, WordList
*keywordLists
[], Accessor
&styler
)
167 int state
= SCE_CMAKE_DEFAULT
;
169 state
= styler
.StyleAt(startPos
-1); // Use the style from the previous line, usually default, but could be commentbox
171 styler
.StartAt( startPos
);
172 styler
.GetLine( startPos
);
174 unsigned int nLengthDoc
= startPos
+ length
;
175 styler
.StartSegment( startPos
);
178 bool bVarInString
= false;
179 bool bClassicVarInString
= false;
182 for ( i
= startPos
; i
< nLengthDoc
; i
++ ) {
183 cCurrChar
= styler
.SafeGetCharAt( i
);
184 char cNextChar
= styler
.SafeGetCharAt(i
+1);
187 case SCE_CMAKE_DEFAULT
:
188 if ( cCurrChar
== '#' ) { // we have a comment line
189 styler
.ColourTo(i
-1, state
);
190 state
= SCE_CMAKE_COMMENT
;
193 if ( cCurrChar
== '"' ) {
194 styler
.ColourTo(i
-1, state
);
195 state
= SCE_CMAKE_STRINGDQ
;
196 bVarInString
= false;
197 bClassicVarInString
= false;
200 if ( cCurrChar
== '\'' ) {
201 styler
.ColourTo(i
-1, state
);
202 state
= SCE_CMAKE_STRINGRQ
;
203 bVarInString
= false;
204 bClassicVarInString
= false;
207 if ( cCurrChar
== '`' ) {
208 styler
.ColourTo(i
-1, state
);
209 state
= SCE_CMAKE_STRINGLQ
;
210 bVarInString
= false;
211 bClassicVarInString
= false;
216 if ( cCurrChar
== '$' || isCmakeChar(cCurrChar
)) {
217 styler
.ColourTo(i
-1,state
);
218 state
= SCE_CMAKE_VARIABLE
;
220 // If it is a number, we must check and set style here first...
221 if ( isCmakeNumber(cCurrChar
) && (cNextChar
== '\t' || cNextChar
== ' ' || cNextChar
== '\r' || cNextChar
== '\n' ) )
222 styler
.ColourTo( i
, SCE_CMAKE_NUMBER
);
228 case SCE_CMAKE_COMMENT
:
229 if ( cNextChar
== '\n' || cNextChar
== '\r' ) {
231 if ( cCurrChar
== '\\' ) {
232 styler
.ColourTo(i
-2,state
);
233 styler
.ColourTo(i
,SCE_CMAKE_DEFAULT
);
236 styler
.ColourTo(i
,state
);
237 state
= SCE_CMAKE_DEFAULT
;
241 case SCE_CMAKE_STRINGDQ
:
242 case SCE_CMAKE_STRINGLQ
:
243 case SCE_CMAKE_STRINGRQ
:
245 if ( styler
.SafeGetCharAt(i
-1) == '\\' && styler
.SafeGetCharAt(i
-2) == '$' )
246 break; // Ignore the next character, even if it is a quote of some sort
248 if ( cCurrChar
== '"' && state
== SCE_CMAKE_STRINGDQ
) {
249 styler
.ColourTo(i
,state
);
250 state
= SCE_CMAKE_DEFAULT
;
254 if ( cCurrChar
== '`' && state
== SCE_CMAKE_STRINGLQ
) {
255 styler
.ColourTo(i
,state
);
256 state
= SCE_CMAKE_DEFAULT
;
260 if ( cCurrChar
== '\'' && state
== SCE_CMAKE_STRINGRQ
) {
261 styler
.ColourTo(i
,state
);
262 state
= SCE_CMAKE_DEFAULT
;
266 if ( cNextChar
== '\r' || cNextChar
== '\n' ) {
267 int nCurLine
= styler
.GetLine(i
+1);
269 // We need to check if the previous line has a \ in it...
270 bool bNextLine
= false;
272 while ( nBack
> 0 ) {
273 if ( styler
.GetLine(nBack
) != nCurLine
)
276 char cTemp
= styler
.SafeGetCharAt(nBack
, 'a'); // Letter 'a' is safe here
278 if ( cTemp
== '\\' ) {
282 if ( cTemp
!= '\r' && cTemp
!= '\n' && cTemp
!= '\t' && cTemp
!= ' ' )
289 styler
.ColourTo(i
+1,state
);
291 if ( bNextLine
== false ) {
292 styler
.ColourTo(i
,state
);
293 state
= SCE_CMAKE_DEFAULT
;
298 case SCE_CMAKE_VARIABLE
:
301 if ( cCurrChar
== '$' )
302 state
= SCE_CMAKE_DEFAULT
;
303 else if ( cCurrChar
== '\\' && (cNextChar
== 'n' || cNextChar
== 'r' || cNextChar
== 't' ) )
304 state
= SCE_CMAKE_DEFAULT
;
305 else if ( (isCmakeChar(cCurrChar
) && !isCmakeChar( cNextChar
) && cNextChar
!= '}') || cCurrChar
== '}' ) {
306 state
= classifyWordCmake( styler
.GetStartSegment(), i
, keywordLists
, styler
);
307 styler
.ColourTo( i
, state
);
308 state
= SCE_CMAKE_DEFAULT
;
310 else if ( !isCmakeChar( cCurrChar
) && cCurrChar
!= '{' && cCurrChar
!= '}' ) {
311 if ( classifyWordCmake( styler
.GetStartSegment(), i
-1, keywordLists
, styler
) == SCE_CMAKE_NUMBER
)
312 styler
.ColourTo( i
-1, SCE_CMAKE_NUMBER
);
314 state
= SCE_CMAKE_DEFAULT
;
316 if ( cCurrChar
== '"' ) {
317 state
= SCE_CMAKE_STRINGDQ
;
318 bVarInString
= false;
319 bClassicVarInString
= false;
321 else if ( cCurrChar
== '`' ) {
322 state
= SCE_CMAKE_STRINGLQ
;
323 bVarInString
= false;
324 bClassicVarInString
= false;
326 else if ( cCurrChar
== '\'' ) {
327 state
= SCE_CMAKE_STRINGRQ
;
328 bVarInString
= false;
329 bClassicVarInString
= false;
331 else if ( cCurrChar
== '#' ) {
332 state
= SCE_CMAKE_COMMENT
;
338 if ( state
== SCE_CMAKE_COMMENT
) {
339 styler
.ColourTo(i
,state
);
341 else if ( state
== SCE_CMAKE_STRINGDQ
|| state
== SCE_CMAKE_STRINGLQ
|| state
== SCE_CMAKE_STRINGRQ
) {
342 bool bIngoreNextDollarSign
= false;
344 if ( bVarInString
&& cCurrChar
== '$' ) {
345 bVarInString
= false;
346 bIngoreNextDollarSign
= true;
348 else if ( bVarInString
&& cCurrChar
== '\\' && (cNextChar
== 'n' || cNextChar
== 'r' || cNextChar
== 't' || cNextChar
== '"' || cNextChar
== '`' || cNextChar
== '\'' ) ) {
349 styler
.ColourTo( i
+1, SCE_CMAKE_STRINGVAR
);
350 bVarInString
= false;
351 bIngoreNextDollarSign
= false;
354 else if ( bVarInString
&& !isCmakeChar(cNextChar
) ) {
355 int nWordState
= classifyWordCmake( styler
.GetStartSegment(), i
, keywordLists
, styler
);
356 if ( nWordState
== SCE_CMAKE_VARIABLE
)
357 styler
.ColourTo( i
, SCE_CMAKE_STRINGVAR
);
358 bVarInString
= false;
360 // Covers "${TEST}..."
361 else if ( bClassicVarInString
&& cNextChar
== '}' ) {
362 styler
.ColourTo( i
+1, SCE_CMAKE_STRINGVAR
);
363 bClassicVarInString
= false;
366 // Start of var in string
367 if ( !bIngoreNextDollarSign
&& cCurrChar
== '$' && cNextChar
== '{' ) {
368 styler
.ColourTo( i
-1, state
);
369 bClassicVarInString
= true;
370 bVarInString
= false;
372 else if ( !bIngoreNextDollarSign
&& cCurrChar
== '$' ) {
373 styler
.ColourTo( i
-1, state
);
375 bClassicVarInString
= false;
380 // Colourise remaining document
381 styler
.ColourTo(nLengthDoc
-1,state
);
384 static void FoldCmakeDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
)
386 // No folding enabled, no reason to continue...
387 if ( styler
.GetPropertyInt("fold") == 0 )
390 bool foldAtElse
= styler
.GetPropertyInt("fold.at.else", 0) == 1;
392 int lineCurrent
= styler
.GetLine(startPos
);
393 unsigned int safeStartPos
= styler
.LineStart( lineCurrent
);
398 int levelCurrent
= SC_FOLDLEVELBASE
;
400 levelCurrent
= styler
.LevelAt(lineCurrent
-1) >> 16;
401 int levelNext
= levelCurrent
;
403 for (unsigned int i
= safeStartPos
; i
< startPos
+ length
; i
++) {
404 char chCurr
= styler
.SafeGetCharAt(i
);
407 if ( nWordStart
== -1 && (isCmakeLetter(chCurr
)) ) {
410 else if ( isCmakeLetter(chCurr
) == false && nWordStart
> -1 ) {
411 int newLevel
= calculateFoldCmake( nWordStart
, i
-1, levelNext
, styler
, foldAtElse
);
413 if ( newLevel
== levelNext
) {
415 if ( CmakeNextLineHasElse(i
, startPos
+ length
, styler
) )
420 levelNext
= newLevel
;
425 if ( chCurr
== '\n' ) {
426 if ( bArg1
&& foldAtElse
) {
427 if ( CmakeNextLineHasElse(i
, startPos
+ length
, styler
) )
431 // If we are on a new line...
432 int levelUse
= levelCurrent
;
433 int lev
= levelUse
| levelNext
<< 16;
434 if (levelUse
< levelNext
)
435 lev
|= SC_FOLDLEVELHEADERFLAG
;
436 if (lev
!= styler
.LevelAt(lineCurrent
))
437 styler
.SetLevel(lineCurrent
, lev
);
440 levelCurrent
= levelNext
;
441 bArg1
= true; // New line, lets look at first argument again
446 int levelUse
= levelCurrent
;
447 int lev
= levelUse
| levelNext
<< 16;
448 if (levelUse
< levelNext
)
449 lev
|= SC_FOLDLEVELHEADERFLAG
;
450 if (lev
!= styler
.LevelAt(lineCurrent
))
451 styler
.SetLevel(lineCurrent
, lev
);
454 static const char * const cmakeWordLists
[] = {
461 LexerModule
lmCmake(SCLEX_CMAKE
, ColouriseCmakeDoc
, "cmake", FoldCmakeDoc
, cmakeWordLists
);