]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/LexTCL.cxx
c78214116401570eaf785d9d8780bea699bddd18
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"
23 // Extended to accept accented characters
24 static inline bool IsAWordChar(int ch
) {
26 (isalnum(ch
) || ch
== '_' || ch
==':' || ch
=='.'); // : name space separator
29 static inline bool IsAWordStart(int ch
) {
30 return ch
>= 0x80 || (ch
==':' || isalpha(ch
) || ch
== '_');
33 static inline bool IsANumberChar(int ch
) {
34 // Not exactly following number definition (several dots are seen as OK, etc.)
35 // but probably enough in most cases.
37 (IsADigit(ch
, 0x10) || toupper(ch
) == 'E' ||
38 ch
== '.' || ch
== '-' || ch
== '+');
41 static void ColouriseTCLDoc(unsigned int startPos
, int length
, int , WordList
*keywordlists
[], Accessor
&styler
) {
42 #define isComment(s) (s==SCE_TCL_COMMENT || s==SCE_TCL_COMMENTLINE || s==SCE_TCL_COMMENT_BOX || s==SCE_TCL_BLOCK_COMMENT)
43 bool foldComment
= styler
.GetPropertyInt("fold.comment") != 0;
44 bool commentLevel
= false;
45 bool subBrace
= false; // substitution begin with a brace ${.....}
46 enum tLineState
{LS_DEFAULT
, LS_OPEN_COMMENT
, LS_OPEN_DOUBLE_QUOTE
, LS_COMMENT_BOX
, LS_MASK_STATE
= 0xf,
47 LS_COMMAND_EXPECTED
= 16, LS_BRACE_ONLY
= 32 } lineState
= LS_DEFAULT
;
48 bool prevSlash
= false;
53 int currentLine
= styler
.GetLine(startPos
);
56 length
+= startPos
- styler
.LineStart(currentLine
);
57 // make sure lines overlap
58 startPos
= styler
.LineStart(currentLine
);
60 WordList
&keywords
= *keywordlists
[0];
61 WordList
&keywords2
= *keywordlists
[1];
62 WordList
&keywords3
= *keywordlists
[2];
63 WordList
&keywords4
= *keywordlists
[3];
64 WordList
&keywords5
= *keywordlists
[4];
65 WordList
&keywords6
= *keywordlists
[5];
66 WordList
&keywords7
= *keywordlists
[6];
67 WordList
&keywords8
= *keywordlists
[7];
68 WordList
&keywords9
= *keywordlists
[8];
70 if (currentLine
> 0) {
71 int ls
= styler
.GetLineState(currentLine
- 1);
72 lineState
= tLineState(ls
& LS_MASK_STATE
);
73 expected
= LS_COMMAND_EXPECTED
== tLineState(ls
& LS_COMMAND_EXPECTED
);
74 subBrace
= LS_BRACE_ONLY
== tLineState(ls
& LS_BRACE_ONLY
);
75 currentLevel
= styler
.LevelAt(currentLine
- 1) >> 17;
76 commentLevel
= (styler
.LevelAt(currentLine
- 1) >> 16) & 1;
78 styler
.SetLevel(0, SC_FOLDLEVELBASE
| SC_FOLDLEVELHEADERFLAG
);
79 bool visibleChars
= false;
81 int previousLevel
= currentLevel
;
82 StyleContext
sc(startPos
, length
, SCE_TCL_DEFAULT
, styler
);
83 for (; ; sc
.Forward()) {
85 if (sc
.ch
=='\r' && sc
.chNext
== '\n') // only ignore \r on PC process on the mac
87 bool atEnd
= !sc
.More(); // make sure we coloured the last word
88 if (lineState
!= LS_DEFAULT
) {
89 sc
.SetState(SCE_TCL_DEFAULT
);
90 if (lineState
== LS_OPEN_COMMENT
)
91 sc
.SetState(SCE_TCL_COMMENTLINE
);
92 else if (lineState
== LS_OPEN_DOUBLE_QUOTE
)
93 sc
.SetState(SCE_TCL_IN_QUOTE
);
94 else if (lineState
== LS_COMMENT_BOX
&& (sc
.ch
== '#' || (sc
.ch
== ' ' && sc
.chNext
=='#')))
95 sc
.SetState(SCE_TCL_COMMENT_BOX
);
96 lineState
= LS_DEFAULT
;
98 if (subBrace
) { // ${ overrides every thing even \ except }
101 sc
.SetState(SCE_TCL_OPERATOR
);
102 sc
.ForwardSetState(SCE_TCL_DEFAULT
);
106 sc
.SetState(SCE_TCL_SUB_BRACE
);
109 } else if (sc
.state
== SCE_TCL_DEFAULT
|| sc
.state
==SCE_TCL_OPERATOR
) {
110 expected
&= isspacechar(static_cast<unsigned char>(sc
.ch
)) || IsAWordStart(sc
.ch
) || sc
.ch
=='#';
111 } else if (sc
.state
== SCE_TCL_SUBSTITUTION
) {
115 sc
.SetState(SCE_TCL_OPERATOR
);
116 sc
.ForwardSetState(SCE_TCL_SUBSTITUTION
);
119 sc
.SetState(SCE_TCL_OPERATOR
);
125 sc
.SetState(SCE_TCL_OPERATOR
);
127 sc
.ForwardSetState(SCE_TCL_SUBSTITUTION
);
130 // maybe spaces should be allowed ???
131 if (!IsAWordChar(sc
.ch
)) { // probably the code is wrong
132 sc
.SetState(SCE_TCL_DEFAULT
);
137 } else if (isComment(sc
.state
)) {
138 } else if (!IsAWordChar(sc
.ch
)) {
139 if ((sc
.state
== SCE_TCL_IDENTIFIER
&& expected
) || sc
.state
== SCE_TCL_MODIFIER
) {
142 sc
.GetCurrent(w
, sizeof(w
));
143 if (w
[strlen(w
)-1]=='\r')
145 while(*s
== ':') // ignore leading : like in ::set a 10
147 bool quote
= sc
.state
== SCE_TCL_IN_QUOTE
;
148 if (commentLevel
|| expected
) {
149 if (keywords
.InList(s
)) {
150 sc
.ChangeState(quote
? SCE_TCL_WORD_IN_QUOTE
: SCE_TCL_WORD
);
151 } else if (keywords2
.InList(s
)) {
152 sc
.ChangeState(quote
? SCE_TCL_WORD_IN_QUOTE
: SCE_TCL_WORD2
);
153 } else if (keywords3
.InList(s
)) {
154 sc
.ChangeState(quote
? SCE_TCL_WORD_IN_QUOTE
: SCE_TCL_WORD3
);
155 } else if (keywords4
.InList(s
)) {
156 sc
.ChangeState(quote
? SCE_TCL_WORD_IN_QUOTE
: SCE_TCL_WORD4
);
157 } else if (sc
.GetRelative(-static_cast<int>(strlen(s
))-1) == '{' &&
158 keywords5
.InList(s
) && sc
.ch
== '}') { // {keyword} exactly no spaces
159 sc
.ChangeState(SCE_TCL_EXPAND
);
161 if (keywords6
.InList(s
)) {
162 sc
.ChangeState(SCE_TCL_WORD5
);
163 } else if (keywords7
.InList(s
)) {
164 sc
.ChangeState(SCE_TCL_WORD6
);
165 } else if (keywords8
.InList(s
)) {
166 sc
.ChangeState(SCE_TCL_WORD7
);
167 } else if (keywords9
.InList(s
)) {
168 sc
.ChangeState(SCE_TCL_WORD8
);
172 sc
.SetState(quote
? SCE_TCL_IN_QUOTE
: SCE_TCL_DEFAULT
);
173 } else if (sc
.state
== SCE_TCL_MODIFIER
|| sc
.state
== SCE_TCL_IDENTIFIER
) {
174 sc
.SetState(SCE_TCL_DEFAULT
);
180 lineState
= LS_DEFAULT
;
181 currentLine
= styler
.GetLine(sc
.currentPos
);
182 if (foldComment
&& sc
.state
!=SCE_TCL_COMMENT
&& isComment(sc
.state
)) {
183 if (currentLevel
== 0) {
188 if (visibleChars
&& commentLevel
) {
191 commentLevel
= false;
196 flag
= SC_FOLDLEVELWHITEFLAG
;
197 if (currentLevel
> previousLevel
)
198 flag
= SC_FOLDLEVELHEADERFLAG
;
199 styler
.SetLevel(currentLine
, flag
+ previousLevel
+ SC_FOLDLEVELBASE
+ (currentLevel
<< 17) + (commentLevel
<< 16));
201 // Update the line state, so it can be seen by next line
202 if (sc
.state
== SCE_TCL_IN_QUOTE
)
203 lineState
= LS_OPEN_DOUBLE_QUOTE
;
206 if (isComment(sc
.state
))
207 lineState
= LS_OPEN_COMMENT
;
208 } else if (sc
.state
== SCE_TCL_COMMENT_BOX
)
209 lineState
= LS_COMMENT_BOX
;
211 styler
.SetLineState(currentLine
,
212 (subBrace
? LS_BRACE_ONLY
: 0) |
213 (expected
? LS_COMMAND_EXPECTED
: 0) | lineState
);
214 if (lineState
== LS_COMMENT_BOX
)
215 sc
.ForwardSetState(SCE_TCL_COMMENT_BOX
);
216 else if (lineState
== LS_OPEN_DOUBLE_QUOTE
)
217 sc
.ForwardSetState(SCE_TCL_IN_QUOTE
);
219 sc
.ForwardSetState(SCE_TCL_DEFAULT
);
221 previousLevel
= currentLevel
;
227 if (sc
.ch
== '#' && IsANumberChar(sc
.chNext
))
228 sc
.ForwardSetState(SCE_TCL_NUMBER
);
231 prevSlash
= sc
.ch
== '\\';
232 if (isComment(sc
.state
))
234 if (sc
.atLineStart
) {
235 visibleChars
= false;
236 if (sc
.state
!=SCE_TCL_IN_QUOTE
&& !isComment(sc
.state
))
238 sc
.SetState(SCE_TCL_DEFAULT
);
239 expected
= IsAWordStart(sc
.ch
)|| isspacechar(static_cast<unsigned char>(sc
.ch
));
245 if (!IsANumberChar(sc
.ch
))
246 sc
.SetState(SCE_TCL_DEFAULT
);
248 case SCE_TCL_IN_QUOTE
:
250 sc
.ForwardSetState(SCE_TCL_DEFAULT
);
251 visibleChars
= true; // necessary if a " is the first and only character on a line
253 } else if (sc
.ch
== '[' || sc
.ch
== ']' || sc
.ch
== '$') {
254 sc
.SetState(SCE_TCL_OPERATOR
);
255 expected
= sc
.ch
== '[';
256 sc
.ForwardSetState(SCE_TCL_IN_QUOTE
);
260 case SCE_TCL_OPERATOR
:
261 sc
.SetState(SCE_TCL_DEFAULT
);
267 if (sc
.state
!= SCE_TCL_IN_QUOTE
&& expected
)
268 sc
.SetState(SCE_TCL_COMMENT
);
270 sc
.SetState(SCE_TCL_COMMENTLINE
);
271 if (sc
.chNext
== '~')
272 sc
.SetState(SCE_TCL_BLOCK_COMMENT
);
273 if (sc
.atLineStart
&& (sc
.chNext
== '#' || sc
.chNext
== '-'))
274 sc
.SetState(SCE_TCL_COMMENT_BOX
);
278 if (!isspacechar(static_cast<unsigned char>(sc
.ch
))) {
287 // Determine if a new state should be entered.
288 if (sc
.state
== SCE_TCL_DEFAULT
) {
289 if (IsAWordStart(sc
.ch
)) {
290 sc
.SetState(SCE_TCL_IDENTIFIER
);
291 } else if (IsADigit(sc
.ch
) && !IsAWordChar(sc
.chPrev
)) {
292 sc
.SetState(SCE_TCL_NUMBER
);
296 sc
.SetState(SCE_TCL_IN_QUOTE
);
299 sc
.SetState(SCE_TCL_OPERATOR
);
304 sc
.SetState(SCE_TCL_OPERATOR
);
312 sc
.SetState(SCE_TCL_OPERATOR
);
319 if (sc
.chNext
!= '{') {
320 sc
.SetState(SCE_TCL_SUBSTITUTION
);
323 sc
.SetState(SCE_TCL_OPERATOR
); // $
325 sc
.ForwardSetState(SCE_TCL_SUB_BRACE
);
330 if ((isspacechar(static_cast<unsigned char>(sc
.chPrev
))||
331 isoperator(static_cast<char>(sc
.chPrev
))) && IsADigit(sc
.chNext
,0x10))
332 sc
.SetState(SCE_TCL_NUMBER
);
335 sc
.SetState(IsADigit(sc
.chNext
)? SCE_TCL_NUMBER
: SCE_TCL_MODIFIER
);
338 if (isoperator(static_cast<char>(sc
.ch
))) {
339 sc
.SetState(SCE_TCL_OPERATOR
);
348 static const char * const tclWordListDesc
[] = {
361 // this code supports folding in the colourizer
362 LexerModule
lmTCL(SCLEX_TCL
, ColouriseTCLDoc
, "tcl", 0, tclWordListDesc
);