]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/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.
19 #include "Scintilla.h"
23 using namespace Scintilla
;
26 static bool isCmakeNumber(char ch
)
28 return(ch
>= '0' && ch
<= '9');
31 static bool isCmakeChar(char ch
)
33 return(ch
== '.' ) || (ch
== '_' ) || isCmakeNumber(ch
) || (ch
>= 'A' && ch
<= 'Z') || (ch
>= 'a' && ch
<= 'z');
36 static bool isCmakeLetter(char ch
)
38 return(ch
>= 'A' && ch
<= 'Z') || (ch
>= 'a' && ch
<= 'z');
41 static bool CmakeNextLineHasElse(unsigned int start
, unsigned int end
, Accessor
&styler
)
44 for ( unsigned int i
= start
; i
< end
; i
++ ) {
45 char cNext
= styler
.SafeGetCharAt( i
);
46 if ( cNext
== '\n' ) {
52 if ( nNextLine
== -1 ) // We never foudn the next line...
55 for ( unsigned int firstChar
= nNextLine
; firstChar
< end
; firstChar
++ ) {
56 char cNext
= styler
.SafeGetCharAt( firstChar
);
61 if ( styler
.Match(firstChar
, "ELSE") || styler
.Match(firstChar
, "else"))
69 static int calculateFoldCmake(unsigned int start
, unsigned int end
, int foldlevel
, Accessor
&styler
, bool bElse
)
71 // If the word is too long, it is not what we are looking for
72 if ( end
- start
> 20 )
75 int newFoldlevel
= foldlevel
;
77 char s
[20]; // The key word we are looking for has atmost 13 characters
78 for (unsigned int i
= 0; i
< end
- start
+ 1 && i
< 19; i
++) {
79 s
[i
] = static_cast<char>( styler
[ start
+ i
] );
83 if ( CompareCaseInsensitive(s
, "IF") == 0 || CompareCaseInsensitive(s
, "WHILE") == 0
84 || CompareCaseInsensitive(s
, "MACRO") == 0 || CompareCaseInsensitive(s
, "FOREACH") == 0
85 || CompareCaseInsensitive(s
, "ELSEIF") == 0 )
87 else if ( CompareCaseInsensitive(s
, "ENDIF") == 0 || CompareCaseInsensitive(s
, "ENDWHILE") == 0
88 || CompareCaseInsensitive(s
, "ENDMACRO") == 0 || CompareCaseInsensitive(s
, "ENDFOREACH") == 0)
90 else if ( bElse
&& CompareCaseInsensitive(s
, "ELSEIF") == 0 )
92 else if ( bElse
&& CompareCaseInsensitive(s
, "ELSE") == 0 )
98 static int classifyWordCmake(unsigned int start
, unsigned int end
, WordList
*keywordLists
[], Accessor
&styler
)
100 char word
[100] = {0};
101 char lowercaseWord
[100] = {0};
103 WordList
&Commands
= *keywordLists
[0];
104 WordList
&Parameters
= *keywordLists
[1];
105 WordList
&UserDefined
= *keywordLists
[2];
107 for (unsigned int i
= 0; i
< end
- start
+ 1 && i
< 99; i
++) {
108 word
[i
] = static_cast<char>( styler
[ start
+ i
] );
109 lowercaseWord
[i
] = static_cast<char>(tolower(word
[i
]));
112 // Check for special words...
113 if ( CompareCaseInsensitive(word
, "MACRO") == 0 || CompareCaseInsensitive(word
, "ENDMACRO") == 0 )
114 return SCE_CMAKE_MACRODEF
;
116 if ( CompareCaseInsensitive(word
, "IF") == 0 || CompareCaseInsensitive(word
, "ENDIF") == 0 )
117 return SCE_CMAKE_IFDEFINEDEF
;
119 if ( CompareCaseInsensitive(word
, "ELSEIF") == 0 || CompareCaseInsensitive(word
, "ELSE") == 0 )
120 return SCE_CMAKE_IFDEFINEDEF
;
122 if ( CompareCaseInsensitive(word
, "WHILE") == 0 || CompareCaseInsensitive(word
, "ENDWHILE") == 0)
123 return SCE_CMAKE_WHILEDEF
;
125 if ( CompareCaseInsensitive(word
, "FOREACH") == 0 || CompareCaseInsensitive(word
, "ENDFOREACH") == 0)
126 return SCE_CMAKE_FOREACHDEF
;
128 if ( Commands
.InList(lowercaseWord
) )
129 return SCE_CMAKE_COMMANDS
;
131 if ( Parameters
.InList(word
) )
132 return SCE_CMAKE_PARAMETERS
;
135 if ( UserDefined
.InList(word
) )
136 return SCE_CMAKE_USERDEFINED
;
138 if ( strlen(word
) > 3 ) {
139 if ( word
[1] == '{' && word
[strlen(word
)-1] == '}' )
140 return SCE_CMAKE_VARIABLE
;
143 // To check for numbers
144 if ( isCmakeNumber( word
[0] ) ) {
145 bool bHasSimpleCmakeNumber
= true;
146 for (unsigned int j
= 1; j
< end
- start
+ 1 && j
< 99; j
++) {
147 if ( !isCmakeNumber( word
[j
] ) ) {
148 bHasSimpleCmakeNumber
= false;
153 if ( bHasSimpleCmakeNumber
)
154 return SCE_CMAKE_NUMBER
;
157 return SCE_CMAKE_DEFAULT
;
160 static void ColouriseCmakeDoc(unsigned int startPos
, int length
, int, WordList
*keywordLists
[], Accessor
&styler
)
162 int state
= SCE_CMAKE_DEFAULT
;
164 state
= styler
.StyleAt(startPos
-1); // Use the style from the previous line, usually default, but could be commentbox
166 styler
.StartAt( startPos
);
167 styler
.GetLine( startPos
);
169 unsigned int nLengthDoc
= startPos
+ length
;
170 styler
.StartSegment( startPos
);
173 bool bVarInString
= false;
174 bool bClassicVarInString
= false;
177 for ( i
= startPos
; i
< nLengthDoc
; i
++ ) {
178 cCurrChar
= styler
.SafeGetCharAt( i
);
179 char cNextChar
= styler
.SafeGetCharAt(i
+1);
182 case SCE_CMAKE_DEFAULT
:
183 if ( cCurrChar
== '#' ) { // we have a comment line
184 styler
.ColourTo(i
-1, state
);
185 state
= SCE_CMAKE_COMMENT
;
188 if ( cCurrChar
== '"' ) {
189 styler
.ColourTo(i
-1, state
);
190 state
= SCE_CMAKE_STRINGDQ
;
191 bVarInString
= false;
192 bClassicVarInString
= false;
195 if ( cCurrChar
== '\'' ) {
196 styler
.ColourTo(i
-1, state
);
197 state
= SCE_CMAKE_STRINGRQ
;
198 bVarInString
= false;
199 bClassicVarInString
= false;
202 if ( cCurrChar
== '`' ) {
203 styler
.ColourTo(i
-1, state
);
204 state
= SCE_CMAKE_STRINGLQ
;
205 bVarInString
= false;
206 bClassicVarInString
= false;
211 if ( cCurrChar
== '$' || isCmakeChar(cCurrChar
)) {
212 styler
.ColourTo(i
-1,state
);
213 state
= SCE_CMAKE_VARIABLE
;
215 // If it is a number, we must check and set style here first...
216 if ( isCmakeNumber(cCurrChar
) && (cNextChar
== '\t' || cNextChar
== ' ' || cNextChar
== '\r' || cNextChar
== '\n' ) )
217 styler
.ColourTo( i
, SCE_CMAKE_NUMBER
);
223 case SCE_CMAKE_COMMENT
:
224 if ( cNextChar
== '\n' || cNextChar
== '\r' ) {
226 if ( cCurrChar
== '\\' ) {
227 styler
.ColourTo(i
-2,state
);
228 styler
.ColourTo(i
,SCE_CMAKE_DEFAULT
);
231 styler
.ColourTo(i
,state
);
232 state
= SCE_CMAKE_DEFAULT
;
236 case SCE_CMAKE_STRINGDQ
:
237 case SCE_CMAKE_STRINGLQ
:
238 case SCE_CMAKE_STRINGRQ
:
240 if ( styler
.SafeGetCharAt(i
-1) == '\\' && styler
.SafeGetCharAt(i
-2) == '$' )
241 break; // Ignore the next character, even if it is a quote of some sort
243 if ( cCurrChar
== '"' && state
== SCE_CMAKE_STRINGDQ
) {
244 styler
.ColourTo(i
,state
);
245 state
= SCE_CMAKE_DEFAULT
;
249 if ( cCurrChar
== '`' && state
== SCE_CMAKE_STRINGLQ
) {
250 styler
.ColourTo(i
,state
);
251 state
= SCE_CMAKE_DEFAULT
;
255 if ( cCurrChar
== '\'' && state
== SCE_CMAKE_STRINGRQ
) {
256 styler
.ColourTo(i
,state
);
257 state
= SCE_CMAKE_DEFAULT
;
261 if ( cNextChar
== '\r' || cNextChar
== '\n' ) {
262 int nCurLine
= styler
.GetLine(i
+1);
264 // We need to check if the previous line has a \ in it...
265 bool bNextLine
= false;
267 while ( nBack
> 0 ) {
268 if ( styler
.GetLine(nBack
) != nCurLine
)
271 char cTemp
= styler
.SafeGetCharAt(nBack
, 'a'); // Letter 'a' is safe here
273 if ( cTemp
== '\\' ) {
277 if ( cTemp
!= '\r' && cTemp
!= '\n' && cTemp
!= '\t' && cTemp
!= ' ' )
284 styler
.ColourTo(i
+1,state
);
286 if ( bNextLine
== false ) {
287 styler
.ColourTo(i
,state
);
288 state
= SCE_CMAKE_DEFAULT
;
293 case SCE_CMAKE_VARIABLE
:
296 if ( cCurrChar
== '$' )
297 state
= SCE_CMAKE_DEFAULT
;
298 else if ( cCurrChar
== '\\' && (cNextChar
== 'n' || cNextChar
== 'r' || cNextChar
== 't' ) )
299 state
= SCE_CMAKE_DEFAULT
;
300 else if ( (isCmakeChar(cCurrChar
) && !isCmakeChar( cNextChar
) && cNextChar
!= '}') || cCurrChar
== '}' ) {
301 state
= classifyWordCmake( styler
.GetStartSegment(), i
, keywordLists
, styler
);
302 styler
.ColourTo( i
, state
);
303 state
= SCE_CMAKE_DEFAULT
;
305 else if ( !isCmakeChar( cCurrChar
) && cCurrChar
!= '{' && cCurrChar
!= '}' ) {
306 if ( classifyWordCmake( styler
.GetStartSegment(), i
-1, keywordLists
, styler
) == SCE_CMAKE_NUMBER
)
307 styler
.ColourTo( i
-1, SCE_CMAKE_NUMBER
);
309 state
= SCE_CMAKE_DEFAULT
;
311 if ( cCurrChar
== '"' ) {
312 state
= SCE_CMAKE_STRINGDQ
;
313 bVarInString
= false;
314 bClassicVarInString
= false;
316 else if ( cCurrChar
== '`' ) {
317 state
= SCE_CMAKE_STRINGLQ
;
318 bVarInString
= false;
319 bClassicVarInString
= false;
321 else if ( cCurrChar
== '\'' ) {
322 state
= SCE_CMAKE_STRINGRQ
;
323 bVarInString
= false;
324 bClassicVarInString
= false;
326 else if ( cCurrChar
== '#' ) {
327 state
= SCE_CMAKE_COMMENT
;
333 if ( state
== SCE_CMAKE_COMMENT
) {
334 styler
.ColourTo(i
,state
);
336 else if ( state
== SCE_CMAKE_STRINGDQ
|| state
== SCE_CMAKE_STRINGLQ
|| state
== SCE_CMAKE_STRINGRQ
) {
337 bool bIngoreNextDollarSign
= false;
339 if ( bVarInString
&& cCurrChar
== '$' ) {
340 bVarInString
= false;
341 bIngoreNextDollarSign
= true;
343 else if ( bVarInString
&& cCurrChar
== '\\' && (cNextChar
== 'n' || cNextChar
== 'r' || cNextChar
== 't' || cNextChar
== '"' || cNextChar
== '`' || cNextChar
== '\'' ) ) {
344 styler
.ColourTo( i
+1, SCE_CMAKE_STRINGVAR
);
345 bVarInString
= false;
346 bIngoreNextDollarSign
= false;
349 else if ( bVarInString
&& !isCmakeChar(cNextChar
) ) {
350 int nWordState
= classifyWordCmake( styler
.GetStartSegment(), i
, keywordLists
, styler
);
351 if ( nWordState
== SCE_CMAKE_VARIABLE
)
352 styler
.ColourTo( i
, SCE_CMAKE_STRINGVAR
);
353 bVarInString
= false;
355 // Covers "${TEST}..."
356 else if ( bClassicVarInString
&& cNextChar
== '}' ) {
357 styler
.ColourTo( i
+1, SCE_CMAKE_STRINGVAR
);
358 bClassicVarInString
= false;
361 // Start of var in string
362 if ( !bIngoreNextDollarSign
&& cCurrChar
== '$' && cNextChar
== '{' ) {
363 styler
.ColourTo( i
-1, state
);
364 bClassicVarInString
= true;
365 bVarInString
= false;
367 else if ( !bIngoreNextDollarSign
&& cCurrChar
== '$' ) {
368 styler
.ColourTo( i
-1, state
);
370 bClassicVarInString
= false;
375 // Colourise remaining document
376 styler
.ColourTo(nLengthDoc
-1,state
);
379 static void FoldCmakeDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
)
381 // No folding enabled, no reason to continue...
382 if ( styler
.GetPropertyInt("fold") == 0 )
385 bool foldAtElse
= styler
.GetPropertyInt("fold.at.else", 0) == 1;
387 int lineCurrent
= styler
.GetLine(startPos
);
388 unsigned int safeStartPos
= styler
.LineStart( lineCurrent
);
393 int levelCurrent
= SC_FOLDLEVELBASE
;
395 levelCurrent
= styler
.LevelAt(lineCurrent
-1) >> 16;
396 int levelNext
= levelCurrent
;
398 for (unsigned int i
= safeStartPos
; i
< startPos
+ length
; i
++) {
399 char chCurr
= styler
.SafeGetCharAt(i
);
402 if ( nWordStart
== -1 && (isCmakeLetter(chCurr
)) ) {
405 else if ( isCmakeLetter(chCurr
) == false && nWordStart
> -1 ) {
406 int newLevel
= calculateFoldCmake( nWordStart
, i
-1, levelNext
, styler
, foldAtElse
);
408 if ( newLevel
== levelNext
) {
410 if ( CmakeNextLineHasElse(i
, startPos
+ length
, styler
) )
415 levelNext
= newLevel
;
420 if ( chCurr
== '\n' ) {
421 if ( bArg1
&& foldAtElse
) {
422 if ( CmakeNextLineHasElse(i
, startPos
+ length
, styler
) )
426 // If we are on a new line...
427 int levelUse
= levelCurrent
;
428 int lev
= levelUse
| levelNext
<< 16;
429 if (levelUse
< levelNext
)
430 lev
|= SC_FOLDLEVELHEADERFLAG
;
431 if (lev
!= styler
.LevelAt(lineCurrent
))
432 styler
.SetLevel(lineCurrent
, lev
);
435 levelCurrent
= levelNext
;
436 bArg1
= true; // New line, lets look at first argument again
441 int levelUse
= levelCurrent
;
442 int lev
= levelUse
| levelNext
<< 16;
443 if (levelUse
< levelNext
)
444 lev
|= SC_FOLDLEVELHEADERFLAG
;
445 if (lev
!= styler
.LevelAt(lineCurrent
))
446 styler
.SetLevel(lineCurrent
, lev
);
449 static const char * const cmakeWordLists
[] = {
456 LexerModule
lmCmake(SCLEX_CMAKE
, ColouriseCmakeDoc
, "cmake", FoldCmakeDoc
, cmakeWordLists
);