]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/LexTCL.cxx
1 // Scintilla source code edit control
3 ** Lexer for TCL language.
5 // Copyright 1998-2001 by Andre Arpin <arpin@kingston.net>
6 // The License.txt file describes the conditions under which this software may be distributed.
18 #include "StyleContext.h"
20 #include "Scintilla.h"
24 using namespace Scintilla
;
27 // Extended to accept accented characters
28 static inline bool IsAWordChar(int ch
) {
30 (isalnum(ch
) || ch
== '_' || ch
==':' || ch
=='.'); // : name space separator
33 static inline bool IsAWordStart(int ch
) {
34 return ch
>= 0x80 || (ch
==':' || isalpha(ch
) || ch
== '_');
37 static inline bool IsANumberChar(int ch
) {
38 // Not exactly following number definition (several dots are seen as OK, etc.)
39 // but probably enough in most cases.
41 (IsADigit(ch
, 0x10) || toupper(ch
) == 'E' ||
42 ch
== '.' || ch
== '-' || ch
== '+');
45 static void ColouriseTCLDoc(unsigned int startPos
, int length
, int , WordList
*keywordlists
[], Accessor
&styler
) {
46 #define isComment(s) (s==SCE_TCL_COMMENT || s==SCE_TCL_COMMENTLINE || s==SCE_TCL_COMMENT_BOX || s==SCE_TCL_BLOCK_COMMENT)
47 bool foldComment
= styler
.GetPropertyInt("fold.comment") != 0;
48 bool commentLevel
= false;
49 bool subBrace
= false; // substitution begin with a brace ${.....}
50 enum tLineState
{LS_DEFAULT
, LS_OPEN_COMMENT
, LS_OPEN_DOUBLE_QUOTE
, LS_COMMENT_BOX
, LS_MASK_STATE
= 0xf,
51 LS_COMMAND_EXPECTED
= 16, LS_BRACE_ONLY
= 32 } lineState
= LS_DEFAULT
;
52 bool prevSlash
= false;
57 int currentLine
= styler
.GetLine(startPos
);
60 length
+= startPos
- styler
.LineStart(currentLine
);
61 // make sure lines overlap
62 startPos
= styler
.LineStart(currentLine
);
64 WordList
&keywords
= *keywordlists
[0];
65 WordList
&keywords2
= *keywordlists
[1];
66 WordList
&keywords3
= *keywordlists
[2];
67 WordList
&keywords4
= *keywordlists
[3];
68 WordList
&keywords5
= *keywordlists
[4];
69 WordList
&keywords6
= *keywordlists
[5];
70 WordList
&keywords7
= *keywordlists
[6];
71 WordList
&keywords8
= *keywordlists
[7];
72 WordList
&keywords9
= *keywordlists
[8];
74 if (currentLine
> 0) {
75 int ls
= styler
.GetLineState(currentLine
- 1);
76 lineState
= tLineState(ls
& LS_MASK_STATE
);
77 expected
= LS_COMMAND_EXPECTED
== tLineState(ls
& LS_COMMAND_EXPECTED
);
78 subBrace
= LS_BRACE_ONLY
== tLineState(ls
& LS_BRACE_ONLY
);
79 currentLevel
= styler
.LevelAt(currentLine
- 1) >> 17;
80 commentLevel
= (styler
.LevelAt(currentLine
- 1) >> 16) & 1;
82 styler
.SetLevel(0, SC_FOLDLEVELBASE
| SC_FOLDLEVELHEADERFLAG
);
83 bool visibleChars
= false;
85 int previousLevel
= currentLevel
;
86 StyleContext
sc(startPos
, length
, SCE_TCL_DEFAULT
, styler
);
87 for (; ; sc
.Forward()) {
89 if (sc
.ch
=='\r' && sc
.chNext
== '\n') // only ignore \r on PC process on the mac
91 bool atEnd
= !sc
.More(); // make sure we coloured the last word
92 if (lineState
!= LS_DEFAULT
) {
93 sc
.SetState(SCE_TCL_DEFAULT
);
94 if (lineState
== LS_OPEN_COMMENT
)
95 sc
.SetState(SCE_TCL_COMMENTLINE
);
96 else if (lineState
== LS_OPEN_DOUBLE_QUOTE
)
97 sc
.SetState(SCE_TCL_IN_QUOTE
);
98 else if (lineState
== LS_COMMENT_BOX
&& (sc
.ch
== '#' || (sc
.ch
== ' ' && sc
.chNext
=='#')))
99 sc
.SetState(SCE_TCL_COMMENT_BOX
);
100 lineState
= LS_DEFAULT
;
102 if (subBrace
) { // ${ overrides every thing even \ except }
105 sc
.SetState(SCE_TCL_OPERATOR
);
106 sc
.ForwardSetState(SCE_TCL_DEFAULT
);
110 sc
.SetState(SCE_TCL_SUB_BRACE
);
113 } else if (sc
.state
== SCE_TCL_DEFAULT
|| sc
.state
==SCE_TCL_OPERATOR
) {
114 expected
&= isspacechar(static_cast<unsigned char>(sc
.ch
)) || IsAWordStart(sc
.ch
) || sc
.ch
=='#';
115 } else if (sc
.state
== SCE_TCL_SUBSTITUTION
) {
119 sc
.SetState(SCE_TCL_OPERATOR
);
120 sc
.ForwardSetState(SCE_TCL_SUBSTITUTION
);
123 sc
.SetState(SCE_TCL_OPERATOR
);
129 sc
.SetState(SCE_TCL_OPERATOR
);
131 sc
.ForwardSetState(SCE_TCL_SUBSTITUTION
);
134 // maybe spaces should be allowed ???
135 if (!IsAWordChar(sc
.ch
)) { // probably the code is wrong
136 sc
.SetState(SCE_TCL_DEFAULT
);
141 } else if (isComment(sc
.state
)) {
142 } else if (!IsAWordChar(sc
.ch
)) {
143 if ((sc
.state
== SCE_TCL_IDENTIFIER
&& expected
) || sc
.state
== SCE_TCL_MODIFIER
) {
146 sc
.GetCurrent(w
, sizeof(w
));
147 if (w
[strlen(w
)-1]=='\r')
149 while(*s
== ':') // ignore leading : like in ::set a 10
151 bool quote
= sc
.state
== SCE_TCL_IN_QUOTE
;
152 if (commentLevel
|| expected
) {
153 if (keywords
.InList(s
)) {
154 sc
.ChangeState(quote
? SCE_TCL_WORD_IN_QUOTE
: SCE_TCL_WORD
);
155 } else if (keywords2
.InList(s
)) {
156 sc
.ChangeState(quote
? SCE_TCL_WORD_IN_QUOTE
: SCE_TCL_WORD2
);
157 } else if (keywords3
.InList(s
)) {
158 sc
.ChangeState(quote
? SCE_TCL_WORD_IN_QUOTE
: SCE_TCL_WORD3
);
159 } else if (keywords4
.InList(s
)) {
160 sc
.ChangeState(quote
? SCE_TCL_WORD_IN_QUOTE
: SCE_TCL_WORD4
);
161 } else if (sc
.GetRelative(-static_cast<int>(strlen(s
))-1) == '{' &&
162 keywords5
.InList(s
) && sc
.ch
== '}') { // {keyword} exactly no spaces
163 sc
.ChangeState(SCE_TCL_EXPAND
);
165 if (keywords6
.InList(s
)) {
166 sc
.ChangeState(SCE_TCL_WORD5
);
167 } else if (keywords7
.InList(s
)) {
168 sc
.ChangeState(SCE_TCL_WORD6
);
169 } else if (keywords8
.InList(s
)) {
170 sc
.ChangeState(SCE_TCL_WORD7
);
171 } else if (keywords9
.InList(s
)) {
172 sc
.ChangeState(SCE_TCL_WORD8
);
176 sc
.SetState(quote
? SCE_TCL_IN_QUOTE
: SCE_TCL_DEFAULT
);
177 } else if (sc
.state
== SCE_TCL_MODIFIER
|| sc
.state
== SCE_TCL_IDENTIFIER
) {
178 sc
.SetState(SCE_TCL_DEFAULT
);
184 lineState
= LS_DEFAULT
;
185 currentLine
= styler
.GetLine(sc
.currentPos
);
186 if (foldComment
&& sc
.state
!=SCE_TCL_COMMENT
&& isComment(sc
.state
)) {
187 if (currentLevel
== 0) {
192 if (visibleChars
&& commentLevel
) {
195 commentLevel
= false;
200 flag
= SC_FOLDLEVELWHITEFLAG
;
201 if (currentLevel
> previousLevel
)
202 flag
= SC_FOLDLEVELHEADERFLAG
;
203 styler
.SetLevel(currentLine
, flag
+ previousLevel
+ SC_FOLDLEVELBASE
+ (currentLevel
<< 17) + (commentLevel
<< 16));
205 // Update the line state, so it can be seen by next line
206 if (sc
.state
== SCE_TCL_IN_QUOTE
)
207 lineState
= LS_OPEN_DOUBLE_QUOTE
;
210 if (isComment(sc
.state
))
211 lineState
= LS_OPEN_COMMENT
;
212 } else if (sc
.state
== SCE_TCL_COMMENT_BOX
)
213 lineState
= LS_COMMENT_BOX
;
215 styler
.SetLineState(currentLine
,
216 (subBrace
? LS_BRACE_ONLY
: 0) |
217 (expected
? LS_COMMAND_EXPECTED
: 0) | lineState
);
218 if (lineState
== LS_COMMENT_BOX
)
219 sc
.ForwardSetState(SCE_TCL_COMMENT_BOX
);
220 else if (lineState
== LS_OPEN_DOUBLE_QUOTE
)
221 sc
.ForwardSetState(SCE_TCL_IN_QUOTE
);
223 sc
.ForwardSetState(SCE_TCL_DEFAULT
);
225 previousLevel
= currentLevel
;
231 if (sc
.ch
== '#' && IsANumberChar(sc
.chNext
))
232 sc
.ForwardSetState(SCE_TCL_NUMBER
);
235 prevSlash
= sc
.ch
== '\\';
236 if (isComment(sc
.state
))
238 if (sc
.atLineStart
) {
239 visibleChars
= false;
240 if (sc
.state
!=SCE_TCL_IN_QUOTE
&& !isComment(sc
.state
))
242 sc
.SetState(SCE_TCL_DEFAULT
);
243 expected
= IsAWordStart(sc
.ch
)|| isspacechar(static_cast<unsigned char>(sc
.ch
));
249 if (!IsANumberChar(sc
.ch
))
250 sc
.SetState(SCE_TCL_DEFAULT
);
252 case SCE_TCL_IN_QUOTE
:
254 sc
.ForwardSetState(SCE_TCL_DEFAULT
);
255 visibleChars
= true; // necessary if a " is the first and only character on a line
257 } else if (sc
.ch
== '[' || sc
.ch
== ']' || sc
.ch
== '$') {
258 sc
.SetState(SCE_TCL_OPERATOR
);
259 expected
= sc
.ch
== '[';
260 sc
.ForwardSetState(SCE_TCL_IN_QUOTE
);
264 case SCE_TCL_OPERATOR
:
265 sc
.SetState(SCE_TCL_DEFAULT
);
271 if (sc
.state
!= SCE_TCL_IN_QUOTE
&& expected
)
272 sc
.SetState(SCE_TCL_COMMENT
);
274 sc
.SetState(SCE_TCL_COMMENTLINE
);
275 if (sc
.chNext
== '~')
276 sc
.SetState(SCE_TCL_BLOCK_COMMENT
);
277 if (sc
.atLineStart
&& (sc
.chNext
== '#' || sc
.chNext
== '-'))
278 sc
.SetState(SCE_TCL_COMMENT_BOX
);
282 if (!isspacechar(static_cast<unsigned char>(sc
.ch
))) {
291 // Determine if a new state should be entered.
292 if (sc
.state
== SCE_TCL_DEFAULT
) {
293 if (IsAWordStart(sc
.ch
)) {
294 sc
.SetState(SCE_TCL_IDENTIFIER
);
295 } else if (IsADigit(sc
.ch
) && !IsAWordChar(sc
.chPrev
)) {
296 sc
.SetState(SCE_TCL_NUMBER
);
300 sc
.SetState(SCE_TCL_IN_QUOTE
);
303 sc
.SetState(SCE_TCL_OPERATOR
);
308 sc
.SetState(SCE_TCL_OPERATOR
);
316 sc
.SetState(SCE_TCL_OPERATOR
);
323 if (sc
.chNext
!= '{') {
324 sc
.SetState(SCE_TCL_SUBSTITUTION
);
327 sc
.SetState(SCE_TCL_OPERATOR
); // $
329 sc
.ForwardSetState(SCE_TCL_SUB_BRACE
);
334 if ((isspacechar(static_cast<unsigned char>(sc
.chPrev
))||
335 isoperator(static_cast<char>(sc
.chPrev
))) && IsADigit(sc
.chNext
,0x10))
336 sc
.SetState(SCE_TCL_NUMBER
);
339 sc
.SetState(IsADigit(sc
.chNext
)? SCE_TCL_NUMBER
: SCE_TCL_MODIFIER
);
342 if (isoperator(static_cast<char>(sc
.ch
))) {
343 sc
.SetState(SCE_TCL_OPERATOR
);
352 static const char * const tclWordListDesc
[] = {
365 // this code supports folding in the colourizer
366 LexerModule
lmTCL(SCLEX_TCL
, ColouriseTCLDoc
, "tcl", 0, tclWordListDesc
);