OSDN Git Service

Commit DialogBox compile Okay
[tortoisegit/TortoiseGitJp.git] / ext / scintilla / src / LexTCL.cxx
1 // Scintilla source code edit control\r
2 /** @file LexTCL.cxx\r
3  ** Lexer for TCL language.\r
4  **/\r
5 // Copyright 1998-2001 by Andre Arpin <arpin@kingston.net>\r
6 // The License.txt file describes the conditions under which this software may be distributed.\r
7 \r
8 #include <stdlib.h>\r
9 #include <string.h>\r
10 #include <ctype.h>\r
11 #include <stdarg.h>\r
12 #include <stdio.h>\r
13 \r
14 #include "Platform.h"\r
15 \r
16 #include "PropSet.h"\r
17 #include "Accessor.h"\r
18 #include "StyleContext.h"\r
19 #include "KeyWords.h"\r
20 #include "Scintilla.h"\r
21 #include "SciLexer.h"\r
22 \r
23 #ifdef SCI_NAMESPACE\r
24 using namespace Scintilla;\r
25 #endif\r
26 \r
27 // Extended to accept accented characters\r
28 static inline bool IsAWordChar(int ch) {\r
29         return ch >= 0x80 ||\r
30         (isalnum(ch) || ch == '_' || ch ==':' || ch=='.'); // : name space separator\r
31 }\r
32 \r
33 static inline bool IsAWordStart(int ch) {\r
34         return ch >= 0x80 || (ch ==':' || isalpha(ch) || ch == '_');\r
35 }\r
36 \r
37 static inline bool IsANumberChar(int ch) {\r
38         // Not exactly following number definition (several dots are seen as OK, etc.)\r
39         // but probably enough in most cases.\r
40         return (ch < 0x80) &&\r
41                (IsADigit(ch, 0x10) || toupper(ch) == 'E' ||\r
42                 ch == '.' || ch == '-' || ch == '+');\r
43 }\r
44 \r
45 static void ColouriseTCLDoc(unsigned int startPos, int length, int , WordList *keywordlists[], Accessor &styler) {\r
46 #define  isComment(s) (s==SCE_TCL_COMMENT || s==SCE_TCL_COMMENTLINE || s==SCE_TCL_COMMENT_BOX || s==SCE_TCL_BLOCK_COMMENT)\r
47         bool foldComment = styler.GetPropertyInt("fold.comment") != 0;\r
48         bool commentLevel = false;\r
49     bool subBrace = false; // substitution begin with a brace ${.....}\r
50         enum tLineState {LS_DEFAULT, LS_OPEN_COMMENT, LS_OPEN_DOUBLE_QUOTE, LS_COMMENT_BOX, LS_MASK_STATE = 0xf, \r
51         LS_COMMAND_EXPECTED = 16, LS_BRACE_ONLY = 32 } lineState = LS_DEFAULT;\r
52         bool prevSlash = false;\r
53         int currentLevel = 0;\r
54     bool expected = 0;\r
55     bool subParen = 0;\r
56 \r
57         int currentLine = styler.GetLine(startPos);\r
58     if (currentLine > 0)\r
59         currentLine--;\r
60         length += startPos - styler.LineStart(currentLine);\r
61         // make sure lines overlap\r
62         startPos = styler.LineStart(currentLine);\r
63 \r
64         WordList &keywords = *keywordlists[0];\r
65         WordList &keywords2 = *keywordlists[1];\r
66         WordList &keywords3 = *keywordlists[2];\r
67         WordList &keywords4 = *keywordlists[3];\r
68         WordList &keywords5 = *keywordlists[4];\r
69         WordList &keywords6 = *keywordlists[5];\r
70         WordList &keywords7 = *keywordlists[6];\r
71     WordList &keywords8 = *keywordlists[7];\r
72     WordList &keywords9 = *keywordlists[8];\r
73 \r
74         if (currentLine > 0) {\r
75         int ls = styler.GetLineState(currentLine - 1);\r
76                 lineState = tLineState(ls & LS_MASK_STATE);\r
77                 expected = LS_COMMAND_EXPECTED == tLineState(ls & LS_COMMAND_EXPECTED);\r
78         subBrace = LS_BRACE_ONLY == tLineState(ls & LS_BRACE_ONLY);\r
79                 currentLevel = styler.LevelAt(currentLine - 1) >> 17;\r
80                 commentLevel = (styler.LevelAt(currentLine - 1) >> 16) & 1;\r
81         } else\r
82                 styler.SetLevel(0, SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG);\r
83         bool visibleChars = false;\r
84 \r
85         int previousLevel = currentLevel;\r
86     StyleContext sc(startPos, length, SCE_TCL_DEFAULT, styler);\r
87         for (; ; sc.Forward()) {\r
88 next:\r
89         if (sc.ch=='\r' && sc.chNext == '\n') // only ignore \r on PC process on the mac \r
90             continue;\r
91         bool atEnd = !sc.More();  // make sure we coloured the last word\r
92         if (lineState != LS_DEFAULT) {\r
93             sc.SetState(SCE_TCL_DEFAULT);\r
94             if (lineState == LS_OPEN_COMMENT)\r
95                 sc.SetState(SCE_TCL_COMMENTLINE);\r
96             else if (lineState == LS_OPEN_DOUBLE_QUOTE)\r
97                 sc.SetState(SCE_TCL_IN_QUOTE);\r
98             else if (lineState == LS_COMMENT_BOX && (sc.ch == '#' || (sc.ch == ' ' && sc.chNext=='#')))\r
99                 sc.SetState(SCE_TCL_COMMENT_BOX);\r
100             lineState = LS_DEFAULT;\r
101         }\r
102         if (subBrace) { // ${ overrides every thing even \ except }\r
103             if (sc.ch == '}') {\r
104                 subBrace = false;\r
105                 sc.SetState(SCE_TCL_OPERATOR);\r
106                 sc.ForwardSetState(SCE_TCL_DEFAULT);\r
107                 goto next;\r
108             }\r
109             else\r
110                 sc.SetState(SCE_TCL_SUB_BRACE);\r
111             if (!sc.atLineEnd)\r
112                 continue;\r
113         } else if (sc.state == SCE_TCL_DEFAULT || sc.state ==SCE_TCL_OPERATOR) {\r
114             expected &= isspacechar(static_cast<unsigned char>(sc.ch)) || IsAWordStart(sc.ch) || sc.ch =='#';\r
115         } else if (sc.state == SCE_TCL_SUBSTITUTION) {\r
116             switch(sc.ch) {\r
117             case '(':\r
118                 subParen=true;\r
119                 sc.SetState(SCE_TCL_OPERATOR);\r
120                 sc.ForwardSetState(SCE_TCL_SUBSTITUTION);\r
121                 continue;\r
122             case ')':\r
123                 sc.SetState(SCE_TCL_OPERATOR);\r
124                 subParen=false;\r
125                 continue;\r
126             case '$':\r
127                 continue;\r
128             case ',':\r
129                 sc.SetState(SCE_TCL_OPERATOR);\r
130                 if (subParen)\r
131                     sc.ForwardSetState(SCE_TCL_SUBSTITUTION);\r
132                 continue;\r
133             default :\r
134                 // maybe spaces should be allowed ???\r
135                 if (!IsAWordChar(sc.ch)) { // probably the code is wrong\r
136                     sc.SetState(SCE_TCL_DEFAULT);\r
137                     subParen = 0;\r
138                 }\r
139                 break;\r
140             }\r
141         } else if (isComment(sc.state)) {\r
142         } else if (!IsAWordChar(sc.ch)) {\r
143             if ((sc.state == SCE_TCL_IDENTIFIER && expected) ||  sc.state == SCE_TCL_MODIFIER) {\r
144                 char w[100];\r
145                 char *s=w;\r
146                 sc.GetCurrent(w, sizeof(w));\r
147                 if (w[strlen(w)-1]=='\r')\r
148                     w[strlen(w)-1]=0;\r
149                 while(*s == ':') // ignore leading : like in ::set a 10\r
150                     ++s;\r
151                 bool quote = sc.state == SCE_TCL_IN_QUOTE;\r
152                 if (commentLevel  || expected) {\r
153                     if (keywords.InList(s)) {\r
154                         sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD);\r
155                     } else if (keywords2.InList(s)) {\r
156                         sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD2);\r
157                     } else if (keywords3.InList(s)) {\r
158                         sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD3);\r
159                     } else if (keywords4.InList(s)) {\r
160                         sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD4);\r
161                     } else if (sc.GetRelative(-static_cast<int>(strlen(s))-1) == '{' &&\r
162                         keywords5.InList(s) && sc.ch == '}') { // {keyword} exactly no spaces\r
163                             sc.ChangeState(SCE_TCL_EXPAND);\r
164                     }\r
165                     if (keywords6.InList(s)) {\r
166                         sc.ChangeState(SCE_TCL_WORD5);\r
167                     } else if (keywords7.InList(s)) {\r
168                         sc.ChangeState(SCE_TCL_WORD6);\r
169                     } else if (keywords8.InList(s)) {\r
170                         sc.ChangeState(SCE_TCL_WORD7);\r
171                     } else if (keywords9.InList(s)) {\r
172                         sc.ChangeState(SCE_TCL_WORD8);\r
173                     } \r
174                 }\r
175                 expected = false;\r
176                 sc.SetState(quote ? SCE_TCL_IN_QUOTE : SCE_TCL_DEFAULT);\r
177             } else if (sc.state == SCE_TCL_MODIFIER || sc.state == SCE_TCL_IDENTIFIER) {\r
178                 sc.SetState(SCE_TCL_DEFAULT);\r
179             }\r
180         }\r
181                 if (atEnd)\r
182                         break;\r
183         if (sc.atLineEnd) {\r
184             lineState = LS_DEFAULT;\r
185                         currentLine = styler.GetLine(sc.currentPos);\r
186                         if (foldComment && sc.state!=SCE_TCL_COMMENT && isComment(sc.state)) {\r
187                                 if (currentLevel == 0) {\r
188                                         ++currentLevel;\r
189                                         commentLevel = true;\r
190                                 }\r
191                         } else {\r
192                                 if (visibleChars && commentLevel) {\r
193                                         --currentLevel;\r
194                                         --previousLevel;\r
195                                         commentLevel = false;\r
196                                 }\r
197                         }\r
198                         int flag = 0;\r
199                         if (!visibleChars)\r
200                                 flag = SC_FOLDLEVELWHITEFLAG;\r
201                         if (currentLevel > previousLevel)\r
202                                 flag = SC_FOLDLEVELHEADERFLAG;\r
203                         styler.SetLevel(currentLine, flag + previousLevel + SC_FOLDLEVELBASE + (currentLevel << 17) + (commentLevel << 16));\r
204 \r
205                         // Update the line state, so it can be seen by next line\r
206                         if (sc.state == SCE_TCL_IN_QUOTE)\r
207                                 lineState = LS_OPEN_DOUBLE_QUOTE;\r
208                         else {\r
209                              if (prevSlash) {\r
210                                     if (isComment(sc.state))\r
211                                             lineState = LS_OPEN_COMMENT;\r
212                 } else if (sc.state == SCE_TCL_COMMENT_BOX)\r
213                     lineState = LS_COMMENT_BOX;\r
214                         }\r
215             styler.SetLineState(currentLine, \r
216                 (subBrace ? LS_BRACE_ONLY : 0) |\r
217                 (expected ? LS_COMMAND_EXPECTED : 0)  | lineState);\r
218             if (lineState == LS_COMMENT_BOX)\r
219                 sc.ForwardSetState(SCE_TCL_COMMENT_BOX);\r
220             else if (lineState == LS_OPEN_DOUBLE_QUOTE)\r
221                 sc.ForwardSetState(SCE_TCL_IN_QUOTE);\r
222             else\r
223                 sc.ForwardSetState(SCE_TCL_DEFAULT);\r
224                         prevSlash = false;\r
225                         previousLevel = currentLevel;\r
226                         goto next;\r
227                 }\r
228 \r
229                 if (prevSlash) {\r
230             prevSlash = false;\r
231             if (sc.ch == '#' && IsANumberChar(sc.chNext))\r
232                 sc.ForwardSetState(SCE_TCL_NUMBER);\r
233             continue;\r
234                 }\r
235         prevSlash = sc.ch == '\\';\r
236         if (isComment(sc.state))\r
237             continue;\r
238                 if (sc.atLineStart) {\r
239                         visibleChars = false;\r
240                         if (sc.state!=SCE_TCL_IN_QUOTE && !isComment(sc.state))\r
241             {\r
242                                 sc.SetState(SCE_TCL_DEFAULT);\r
243                 expected = IsAWordStart(sc.ch)|| isspacechar(static_cast<unsigned char>(sc.ch));\r
244             }\r
245                 }\r
246 \r
247                 switch (sc.state) {\r
248                 case SCE_TCL_NUMBER:\r
249                         if (!IsANumberChar(sc.ch))\r
250                                 sc.SetState(SCE_TCL_DEFAULT);\r
251                         break;\r
252                 case SCE_TCL_IN_QUOTE:\r
253                         if (sc.ch == '"') {\r
254                                 sc.ForwardSetState(SCE_TCL_DEFAULT);\r
255                                 visibleChars = true; // necessary if a " is the first and only character on a line\r
256                                 goto next;\r
257                         } else if (sc.ch == '[' || sc.ch == ']' || sc.ch == '$') {\r
258                                 sc.SetState(SCE_TCL_OPERATOR);\r
259                 expected = sc.ch == '[';\r
260                 sc.ForwardSetState(SCE_TCL_IN_QUOTE);\r
261                                 goto next;\r
262                         }\r
263             continue;\r
264         case SCE_TCL_OPERATOR:\r
265                         sc.SetState(SCE_TCL_DEFAULT);\r
266                         break;\r
267                 }\r
268 \r
269                 if (sc.ch == '#') {\r
270                         if (visibleChars) {\r
271                 if (sc.state != SCE_TCL_IN_QUOTE && expected)\r
272                                         sc.SetState(SCE_TCL_COMMENT);\r
273                         } else {\r
274                 sc.SetState(SCE_TCL_COMMENTLINE);\r
275                 if (sc.chNext == '~')\r
276                     sc.SetState(SCE_TCL_BLOCK_COMMENT);\r
277                 if (sc.atLineStart && (sc.chNext == '#' || sc.chNext == '-'))\r
278                         sc.SetState(SCE_TCL_COMMENT_BOX);\r
279             }\r
280         }\r
281 \r
282                 if (!isspacechar(static_cast<unsigned char>(sc.ch))) {\r
283                         visibleChars = true;\r
284                 }\r
285 \r
286                 if (sc.ch == '\\') {\r
287                         prevSlash = true;\r
288                         continue;               \r
289                 }\r
290 \r
291                 // Determine if a new state should be entered.\r
292                 if (sc.state == SCE_TCL_DEFAULT) {\r
293             if (IsAWordStart(sc.ch)) {\r
294                                 sc.SetState(SCE_TCL_IDENTIFIER);\r
295                         } else if (IsADigit(sc.ch) && !IsAWordChar(sc.chPrev)) {\r
296                                 sc.SetState(SCE_TCL_NUMBER);\r
297                         } else {\r
298                                 switch (sc.ch) {\r
299                                 case '\"':\r
300                                         sc.SetState(SCE_TCL_IN_QUOTE);\r
301                                         break;\r
302                                 case '{':\r
303                                         sc.SetState(SCE_TCL_OPERATOR);\r
304                                         expected = true;\r
305                                         ++currentLevel;\r
306                                         break;\r
307                                 case '}':\r
308                                         sc.SetState(SCE_TCL_OPERATOR);\r
309                                         --currentLevel;\r
310                                         break;\r
311                                 case '[':\r
312                     expected = true;\r
313                                 case ']':\r
314                                 case '(':\r
315                                 case ')':\r
316                                         sc.SetState(SCE_TCL_OPERATOR);\r
317                                         break;\r
318                                 case ';':\r
319                     expected = true;\r
320                                         break;\r
321                 case '$':\r
322                     subParen = 0;\r
323                     if (sc.chNext != '{') {\r
324                         sc.SetState(SCE_TCL_SUBSTITUTION);\r
325                     } \r
326                     else {\r
327                         sc.SetState(SCE_TCL_OPERATOR);  // $\r
328                         sc.Forward();  // {\r
329                         sc.ForwardSetState(SCE_TCL_SUB_BRACE);\r
330                         subBrace = true;\r
331                     }\r
332                     break;\r
333                 case '#':\r
334                     if ((isspacechar(static_cast<unsigned char>(sc.chPrev))||\r
335                             isoperator(static_cast<char>(sc.chPrev))) && IsADigit(sc.chNext,0x10))\r
336                         sc.SetState(SCE_TCL_NUMBER);\r
337                     break;\r
338                 case '-':\r
339                     sc.SetState(IsADigit(sc.chNext)? SCE_TCL_NUMBER: SCE_TCL_MODIFIER);\r
340                     break;\r
341                 default:\r
342                     if (isoperator(static_cast<char>(sc.ch))) {\r
343                         sc.SetState(SCE_TCL_OPERATOR);\r
344                     }\r
345                                 }\r
346                         }\r
347                 }\r
348         }\r
349         sc.Complete();\r
350 }\r
351 \r
352 static const char * const tclWordListDesc[] = {\r
353             "TCL Keywords",\r
354             "TK Keywords",\r
355             "iTCL Keywords",\r
356             "tkCommands",\r
357             "expand"\r
358             "user1",\r
359             "user2",\r
360             "user3",\r
361             "user4",\r
362             0\r
363         };\r
364 \r
365 // this code supports folding in the colourizer\r
366 LexerModule lmTCL(SCLEX_TCL, ColouriseTCLDoc, "tcl", 0, tclWordListDesc);\r