OSDN Git Service

Commit DialogBox compile Okay
[tortoisegit/TortoiseGitJp.git] / ext / scintilla / src / LexCmake.cxx
1 // Scintilla source code edit control\r
2 /** @file LexCmake.cxx\r
3  ** Lexer for Cmake\r
4  **/\r
5 // Copyright 2007 by Cristian Adam <cristian [dot] adam [at] gmx [dot] net>\r
6 // based on the NSIS lexer\r
7 // The License.txt file describes the conditions under which this software may be distributed.\r
8 #include <stdlib.h>\r
9 #include <string.h>\r
10 #include <ctype.h>\r
11 #include <stdio.h>\r
12 #include <stdarg.h>\r
13 \r
14 #include "Platform.h"\r
15 \r
16 #include "PropSet.h"\r
17 #include "Accessor.h"\r
18 #include "KeyWords.h"\r
19 #include "Scintilla.h"\r
20 #include "SciLexer.h"\r
21 \r
22 #ifdef SCI_NAMESPACE\r
23 using namespace Scintilla;\r
24 #endif\r
25 \r
26 static bool isCmakeNumber(char ch)\r
27 {\r
28     return(ch >= '0' && ch <= '9');\r
29 }\r
30 \r
31 static bool isCmakeChar(char ch)\r
32 {\r
33     return(ch == '.' ) || (ch == '_' ) || isCmakeNumber(ch) || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');\r
34 }\r
35 \r
36 static bool isCmakeLetter(char ch)\r
37 {\r
38     return(ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');\r
39 }\r
40 \r
41 static bool CmakeNextLineHasElse(unsigned int start, unsigned int end, Accessor &styler)\r
42 {\r
43     int nNextLine = -1;\r
44     for ( unsigned int i = start; i < end; i++ ) {\r
45         char cNext = styler.SafeGetCharAt( i );\r
46         if ( cNext == '\n' ) {\r
47             nNextLine = i+1;\r
48             break;\r
49         }\r
50     }\r
51 \r
52     if ( nNextLine == -1 ) // We never foudn the next line...\r
53         return false;\r
54 \r
55     for ( unsigned int firstChar = nNextLine; firstChar < end; firstChar++ ) {\r
56         char cNext = styler.SafeGetCharAt( firstChar );\r
57         if ( cNext == ' ' )\r
58             continue;\r
59         if ( cNext == '\t' )\r
60             continue;\r
61         if ( styler.Match(firstChar, "ELSE")  || styler.Match(firstChar, "else"))\r
62             return true;\r
63         break;\r
64     }\r
65 \r
66     return false;\r
67 }\r
68 \r
69 static int calculateFoldCmake(unsigned int start, unsigned int end, int foldlevel, Accessor &styler, bool bElse)\r
70 {\r
71     // If the word is too long, it is not what we are looking for\r
72     if ( end - start > 20 )\r
73         return foldlevel;\r
74 \r
75     int newFoldlevel = foldlevel;\r
76 \r
77     char s[20]; // The key word we are looking for has atmost 13 characters\r
78     for (unsigned int i = 0; i < end - start + 1 && i < 19; i++) {\r
79         s[i] = static_cast<char>( styler[ start + i ] );\r
80         s[i + 1] = '\0';\r
81     }\r
82 \r
83     if ( CompareCaseInsensitive(s, "IF") == 0 || CompareCaseInsensitive(s, "WHILE") == 0\r
84          || CompareCaseInsensitive(s, "MACRO") == 0 || CompareCaseInsensitive(s, "FOREACH") == 0\r
85          || CompareCaseInsensitive(s, "ELSEIF") == 0 )\r
86         newFoldlevel++;\r
87     else if ( CompareCaseInsensitive(s, "ENDIF") == 0 || CompareCaseInsensitive(s, "ENDWHILE") == 0\r
88               || CompareCaseInsensitive(s, "ENDMACRO") == 0 || CompareCaseInsensitive(s, "ENDFOREACH") == 0)\r
89         newFoldlevel--;\r
90     else if ( bElse && CompareCaseInsensitive(s, "ELSEIF") == 0 )\r
91         newFoldlevel++;\r
92     else if ( bElse && CompareCaseInsensitive(s, "ELSE") == 0 )\r
93         newFoldlevel++;\r
94 \r
95     return newFoldlevel;\r
96 }\r
97 \r
98 static int classifyWordCmake(unsigned int start, unsigned int end, WordList *keywordLists[], Accessor &styler )\r
99 {\r
100     char word[100] = {0};\r
101     char lowercaseWord[100] = {0};\r
102 \r
103     WordList &Commands = *keywordLists[0];\r
104     WordList &Parameters = *keywordLists[1];\r
105     WordList &UserDefined = *keywordLists[2];\r
106 \r
107     for (unsigned int i = 0; i < end - start + 1 && i < 99; i++) {\r
108         word[i] = static_cast<char>( styler[ start + i ] );\r
109         lowercaseWord[i] = static_cast<char>(tolower(word[i]));\r
110     }\r
111 \r
112     // Check for special words...\r
113     if ( CompareCaseInsensitive(word, "MACRO") == 0 || CompareCaseInsensitive(word, "ENDMACRO") == 0 )\r
114         return SCE_CMAKE_MACRODEF;\r
115 \r
116     if ( CompareCaseInsensitive(word, "IF") == 0 ||  CompareCaseInsensitive(word, "ENDIF") == 0 )\r
117         return SCE_CMAKE_IFDEFINEDEF;\r
118 \r
119     if ( CompareCaseInsensitive(word, "ELSEIF") == 0  || CompareCaseInsensitive(word, "ELSE") == 0 )\r
120         return SCE_CMAKE_IFDEFINEDEF;\r
121 \r
122     if ( CompareCaseInsensitive(word, "WHILE") == 0 || CompareCaseInsensitive(word, "ENDWHILE") == 0)\r
123         return SCE_CMAKE_WHILEDEF;\r
124 \r
125     if ( CompareCaseInsensitive(word, "FOREACH") == 0 || CompareCaseInsensitive(word, "ENDFOREACH") == 0)\r
126         return SCE_CMAKE_FOREACHDEF;\r
127 \r
128     if ( Commands.InList(lowercaseWord) )\r
129         return SCE_CMAKE_COMMANDS;\r
130 \r
131     if ( Parameters.InList(word) )\r
132         return SCE_CMAKE_PARAMETERS;\r
133 \r
134 \r
135     if ( UserDefined.InList(word) )\r
136         return SCE_CMAKE_USERDEFINED;\r
137 \r
138     if ( strlen(word) > 3 ) {\r
139         if ( word[1] == '{' && word[strlen(word)-1] == '}' )\r
140             return SCE_CMAKE_VARIABLE;\r
141     }\r
142 \r
143     // To check for numbers\r
144     if ( isCmakeNumber( word[0] ) ) {\r
145         bool bHasSimpleCmakeNumber = true;\r
146         for (unsigned int j = 1; j < end - start + 1 && j < 99; j++) {\r
147             if ( !isCmakeNumber( word[j] ) ) {\r
148                 bHasSimpleCmakeNumber = false;\r
149                 break;\r
150             }\r
151         }\r
152 \r
153         if ( bHasSimpleCmakeNumber )\r
154             return SCE_CMAKE_NUMBER;\r
155     }\r
156 \r
157     return SCE_CMAKE_DEFAULT;\r
158 }\r
159 \r
160 static void ColouriseCmakeDoc(unsigned int startPos, int length, int, WordList *keywordLists[], Accessor &styler)\r
161 {\r
162     int state = SCE_CMAKE_DEFAULT;\r
163     if ( startPos > 0 )\r
164         state = styler.StyleAt(startPos-1); // Use the style from the previous line, usually default, but could be commentbox\r
165 \r
166     styler.StartAt( startPos );\r
167     styler.GetLine( startPos );\r
168 \r
169     unsigned int nLengthDoc = startPos + length;\r
170     styler.StartSegment( startPos );\r
171 \r
172     char cCurrChar;\r
173     bool bVarInString = false;\r
174     bool bClassicVarInString = false;\r
175 \r
176     unsigned int i;\r
177     for ( i = startPos; i < nLengthDoc; i++ ) {\r
178         cCurrChar = styler.SafeGetCharAt( i );\r
179         char cNextChar = styler.SafeGetCharAt(i+1);\r
180 \r
181         switch (state) {\r
182         case SCE_CMAKE_DEFAULT:\r
183             if ( cCurrChar == '#' ) { // we have a comment line\r
184                 styler.ColourTo(i-1, state );\r
185                 state = SCE_CMAKE_COMMENT;\r
186                 break;\r
187             }\r
188             if ( cCurrChar == '"' ) {\r
189                 styler.ColourTo(i-1, state );\r
190                 state = SCE_CMAKE_STRINGDQ;\r
191                 bVarInString = false;\r
192                 bClassicVarInString = false;\r
193                 break;\r
194             }\r
195             if ( cCurrChar == '\'' ) {\r
196                 styler.ColourTo(i-1, state );\r
197                 state = SCE_CMAKE_STRINGRQ;\r
198                 bVarInString = false;\r
199                 bClassicVarInString = false;\r
200                 break;\r
201             }\r
202             if ( cCurrChar == '`' ) {\r
203                 styler.ColourTo(i-1, state );\r
204                 state = SCE_CMAKE_STRINGLQ;\r
205                 bVarInString = false;\r
206                 bClassicVarInString = false;\r
207                 break;\r
208             }\r
209 \r
210             // CMake Variable\r
211             if ( cCurrChar == '$' || isCmakeChar(cCurrChar)) {\r
212                 styler.ColourTo(i-1,state);\r
213                 state = SCE_CMAKE_VARIABLE;\r
214 \r
215                 // If it is a number, we must check and set style here first...\r
216                 if ( isCmakeNumber(cCurrChar) && (cNextChar == '\t' || cNextChar == ' ' || cNextChar == '\r' || cNextChar == '\n' ) )\r
217                     styler.ColourTo( i, SCE_CMAKE_NUMBER);\r
218 \r
219                 break;\r
220             }\r
221 \r
222             break;\r
223         case SCE_CMAKE_COMMENT:\r
224             if ( cNextChar == '\n' || cNextChar == '\r' ) {\r
225                 // Special case:\r
226                 if ( cCurrChar == '\\' ) {\r
227                     styler.ColourTo(i-2,state);\r
228                     styler.ColourTo(i,SCE_CMAKE_DEFAULT);\r
229                 }\r
230                 else {\r
231                     styler.ColourTo(i,state);\r
232                     state = SCE_CMAKE_DEFAULT;\r
233                 }\r
234             }\r
235             break;\r
236         case SCE_CMAKE_STRINGDQ:\r
237         case SCE_CMAKE_STRINGLQ:\r
238         case SCE_CMAKE_STRINGRQ:\r
239 \r
240             if ( styler.SafeGetCharAt(i-1) == '\\' && styler.SafeGetCharAt(i-2) == '$' )\r
241                 break; // Ignore the next character, even if it is a quote of some sort\r
242 \r
243             if ( cCurrChar == '"' && state == SCE_CMAKE_STRINGDQ ) {\r
244                 styler.ColourTo(i,state);\r
245                 state = SCE_CMAKE_DEFAULT;\r
246                 break;\r
247             }\r
248 \r
249             if ( cCurrChar == '`' && state == SCE_CMAKE_STRINGLQ ) {\r
250                 styler.ColourTo(i,state);\r
251                 state = SCE_CMAKE_DEFAULT;\r
252                 break;\r
253             }\r
254 \r
255             if ( cCurrChar == '\'' && state == SCE_CMAKE_STRINGRQ ) {\r
256                 styler.ColourTo(i,state);\r
257                 state = SCE_CMAKE_DEFAULT;\r
258                 break;\r
259             }\r
260 \r
261             if ( cNextChar == '\r' || cNextChar == '\n' ) {\r
262                 int nCurLine = styler.GetLine(i+1);\r
263                 int nBack = i;\r
264                 // We need to check if the previous line has a \ in it...\r
265                 bool bNextLine = false;\r
266 \r
267                 while ( nBack > 0 ) {\r
268                     if ( styler.GetLine(nBack) != nCurLine )\r
269                         break;\r
270 \r
271                     char cTemp = styler.SafeGetCharAt(nBack, 'a'); // Letter 'a' is safe here\r
272 \r
273                     if ( cTemp == '\\' ) {\r
274                         bNextLine = true;\r
275                         break;\r
276                     }\r
277                     if ( cTemp != '\r' && cTemp != '\n' && cTemp != '\t' && cTemp != ' ' )\r
278                         break;\r
279 \r
280                     nBack--;\r
281                 }\r
282 \r
283                 if ( bNextLine ) {\r
284                     styler.ColourTo(i+1,state);\r
285                 }\r
286                 if ( bNextLine == false ) {\r
287                     styler.ColourTo(i,state);\r
288                     state = SCE_CMAKE_DEFAULT;\r
289                 }\r
290             }\r
291             break;\r
292 \r
293         case SCE_CMAKE_VARIABLE:\r
294 \r
295             // CMake Variable:\r
296             if ( cCurrChar == '$' )\r
297                 state = SCE_CMAKE_DEFAULT;\r
298             else if ( cCurrChar == '\\' && (cNextChar == 'n' || cNextChar == 'r' || cNextChar == 't' ) )\r
299                 state = SCE_CMAKE_DEFAULT;\r
300             else if ( (isCmakeChar(cCurrChar) && !isCmakeChar( cNextChar) && cNextChar != '}') || cCurrChar == '}' ) {\r
301                 state = classifyWordCmake( styler.GetStartSegment(), i, keywordLists, styler );\r
302                 styler.ColourTo( i, state);\r
303                 state = SCE_CMAKE_DEFAULT;\r
304             }\r
305             else if ( !isCmakeChar( cCurrChar ) && cCurrChar != '{' && cCurrChar != '}' ) {\r
306                 if ( classifyWordCmake( styler.GetStartSegment(), i-1, keywordLists, styler) == SCE_CMAKE_NUMBER )\r
307                     styler.ColourTo( i-1, SCE_CMAKE_NUMBER );\r
308 \r
309                 state = SCE_CMAKE_DEFAULT;\r
310 \r
311                 if ( cCurrChar == '"' ) {\r
312                     state = SCE_CMAKE_STRINGDQ;\r
313                     bVarInString = false;\r
314                     bClassicVarInString = false;\r
315                 }\r
316                 else if ( cCurrChar == '`' ) {\r
317                     state = SCE_CMAKE_STRINGLQ;\r
318                     bVarInString = false;\r
319                     bClassicVarInString = false;\r
320                 }\r
321                 else if ( cCurrChar == '\'' ) {\r
322                     state = SCE_CMAKE_STRINGRQ;\r
323                     bVarInString = false;\r
324                     bClassicVarInString = false;\r
325                 }\r
326                 else if ( cCurrChar == '#' ) {\r
327                     state = SCE_CMAKE_COMMENT;\r
328                 }\r
329             }\r
330             break;\r
331         }\r
332 \r
333         if ( state == SCE_CMAKE_COMMENT) {\r
334             styler.ColourTo(i,state);\r
335         }\r
336         else if ( state == SCE_CMAKE_STRINGDQ || state == SCE_CMAKE_STRINGLQ || state == SCE_CMAKE_STRINGRQ ) {\r
337             bool bIngoreNextDollarSign = false;\r
338 \r
339             if ( bVarInString && cCurrChar == '$' ) {\r
340                 bVarInString = false;\r
341                 bIngoreNextDollarSign = true;\r
342             }\r
343             else if ( bVarInString && cCurrChar == '\\' && (cNextChar == 'n' || cNextChar == 'r' || cNextChar == 't' || cNextChar == '"' || cNextChar == '`' || cNextChar == '\'' ) ) {\r
344                 styler.ColourTo( i+1, SCE_CMAKE_STRINGVAR);\r
345                 bVarInString = false;\r
346                 bIngoreNextDollarSign = false;\r
347             }\r
348 \r
349             else if ( bVarInString && !isCmakeChar(cNextChar) ) {\r
350                 int nWordState = classifyWordCmake( styler.GetStartSegment(), i, keywordLists, styler);\r
351                 if ( nWordState == SCE_CMAKE_VARIABLE )\r
352                     styler.ColourTo( i, SCE_CMAKE_STRINGVAR);\r
353                 bVarInString = false;\r
354             }\r
355             // Covers "${TEST}..."\r
356             else if ( bClassicVarInString && cNextChar == '}' ) {\r
357                 styler.ColourTo( i+1, SCE_CMAKE_STRINGVAR);\r
358                 bClassicVarInString = false;\r
359             }\r
360 \r
361             // Start of var in string\r
362             if ( !bIngoreNextDollarSign && cCurrChar == '$' && cNextChar == '{' ) {\r
363                 styler.ColourTo( i-1, state);\r
364                 bClassicVarInString = true;\r
365                 bVarInString = false;\r
366             }\r
367             else if ( !bIngoreNextDollarSign && cCurrChar == '$' ) {\r
368                 styler.ColourTo( i-1, state);\r
369                 bVarInString = true;\r
370                 bClassicVarInString = false;\r
371             }\r
372         }\r
373     }\r
374 \r
375     // Colourise remaining document\r
376     styler.ColourTo(nLengthDoc-1,state);\r
377 }\r
378 \r
379 static void FoldCmakeDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler)\r
380 {\r
381     // No folding enabled, no reason to continue...\r
382     if ( styler.GetPropertyInt("fold") == 0 )\r
383         return;\r
384 \r
385     bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) == 1;\r
386 \r
387     int lineCurrent = styler.GetLine(startPos);\r
388     unsigned int safeStartPos = styler.LineStart( lineCurrent );\r
389 \r
390     bool bArg1 = true;\r
391     int nWordStart = -1;\r
392 \r
393     int levelCurrent = SC_FOLDLEVELBASE;\r
394     if (lineCurrent > 0)\r
395         levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;\r
396     int levelNext = levelCurrent;\r
397 \r
398     for (unsigned int i = safeStartPos; i < startPos + length; i++) {\r
399         char chCurr = styler.SafeGetCharAt(i);\r
400 \r
401         if ( bArg1 ) {\r
402             if ( nWordStart == -1 && (isCmakeLetter(chCurr)) ) {\r
403                 nWordStart = i;\r
404             }\r
405             else if ( isCmakeLetter(chCurr) == false && nWordStart > -1 ) {\r
406                 int newLevel = calculateFoldCmake( nWordStart, i-1, levelNext, styler, foldAtElse);\r
407 \r
408                 if ( newLevel == levelNext ) {\r
409                     if ( foldAtElse ) {\r
410                         if ( CmakeNextLineHasElse(i, startPos + length, styler) )\r
411                             levelNext--;\r
412                     }\r
413                 }\r
414                 else\r
415                     levelNext = newLevel;\r
416                 bArg1 = false;\r
417             }\r
418         }\r
419 \r
420         if ( chCurr == '\n' ) {\r
421             if ( bArg1 && foldAtElse) {\r
422                 if ( CmakeNextLineHasElse(i, startPos + length, styler) )\r
423                     levelNext--;\r
424             }\r
425 \r
426             // If we are on a new line...\r
427             int levelUse = levelCurrent;\r
428             int lev = levelUse | levelNext << 16;\r
429             if (levelUse < levelNext )\r
430                 lev |= SC_FOLDLEVELHEADERFLAG;\r
431             if (lev != styler.LevelAt(lineCurrent))\r
432                 styler.SetLevel(lineCurrent, lev);\r
433 \r
434             lineCurrent++;\r
435             levelCurrent = levelNext;\r
436             bArg1 = true; // New line, lets look at first argument again\r
437             nWordStart = -1;\r
438         }\r
439     }\r
440 \r
441     int levelUse = levelCurrent;\r
442     int lev = levelUse | levelNext << 16;\r
443     if (levelUse < levelNext)\r
444         lev |= SC_FOLDLEVELHEADERFLAG;\r
445     if (lev != styler.LevelAt(lineCurrent))\r
446         styler.SetLevel(lineCurrent, lev);\r
447 }\r
448 \r
449 static const char * const cmakeWordLists[] = {\r
450     "Commands",\r
451     "Parameters",\r
452     "UserDefined",\r
453     0,\r
454     0,};\r
455 \r
456 LexerModule lmCmake(SCLEX_CMAKE, ColouriseCmakeDoc, "cmake", FoldCmakeDoc, cmakeWordLists);\r