1 // Scintilla source code edit control
3 ** Lexer for Structured Text language.
4 ** Written by Pavel Bulochkin
6 // The License.txt file describes the conditions under which this software may be distributed.
17 #include "Scintilla.h"
21 #include "LexAccessor.h"
23 #include "StyleContext.h"
24 #include "CharacterSet.h"
25 #include "LexerModule.h"
28 using namespace Scintilla
;
31 static void ClassifySTTXTWord(WordList
*keywordlists
[], StyleContext
&sc
)
34 sc
.GetCurrentLowered(s
, sizeof(s
));
36 if ((*keywordlists
[0]).InList(s
)) {
37 sc
.ChangeState(SCE_STTXT_KEYWORD
);
40 else if ((*keywordlists
[1]).InList(s
)) {
41 sc
.ChangeState(SCE_STTXT_TYPE
);
44 else if ((*keywordlists
[2]).InList(s
)) {
45 sc
.ChangeState(SCE_STTXT_FUNCTION
);
48 else if ((*keywordlists
[3]).InList(s
)) {
49 sc
.ChangeState(SCE_STTXT_FB
);
52 else if ((*keywordlists
[4]).InList(s
)) {
53 sc
.ChangeState(SCE_STTXT_VARS
);
56 else if ((*keywordlists
[5]).InList(s
)) {
57 sc
.ChangeState(SCE_STTXT_PRAGMAS
);
60 sc
.SetState(SCE_STTXT_DEFAULT
);
63 static void ColouriseSTTXTDoc (unsigned int startPos
, int length
, int initStyle
,
64 WordList
*keywordlists
[], Accessor
&styler
)
66 StyleContext
sc(startPos
, length
, initStyle
, styler
);
68 CharacterSet
setWord(CharacterSet::setAlphaNum
, "_", 0x80, true);
69 CharacterSet
setWordStart(CharacterSet::setAlpha
, "_", 0x80, true);
70 CharacterSet
setNumber(CharacterSet::setDigits
, "_.eE");
71 CharacterSet
setHexNumber(CharacterSet::setDigits
, "_abcdefABCDEF");
72 CharacterSet
setOperator(CharacterSet::setNone
,",.+-*/:;<=>[]()%&");
73 CharacterSet
setDataTime(CharacterSet::setDigits
,"_.-:dmshDMSH");
75 for ( ; sc
.More() ; sc
.Forward())
77 if(sc
.atLineStart
&& sc
.state
!= SCE_STTXT_COMMENT
)
78 sc
.SetState(SCE_STTXT_DEFAULT
);
82 case SCE_STTXT_NUMBER
: {
83 if(!setNumber
.Contains(sc
.ch
))
84 sc
.SetState(SCE_STTXT_DEFAULT
);
87 case SCE_STTXT_HEXNUMBER
: {
88 if (setHexNumber
.Contains(sc
.ch
))
90 else if(setDataTime
.Contains(sc
.ch
))
91 sc
.ChangeState(SCE_STTXT_DATETIME
);
92 else if(setWord
.Contains(sc
.ch
))
93 sc
.ChangeState(SCE_STTXT_DEFAULT
);
95 sc
.SetState(SCE_STTXT_DEFAULT
);
98 case SCE_STTXT_DATETIME
: {
99 if (setDataTime
.Contains(sc
.ch
))
101 else if(setWord
.Contains(sc
.ch
))
102 sc
.ChangeState(SCE_STTXT_DEFAULT
);
104 sc
.SetState(SCE_STTXT_DEFAULT
);
107 case SCE_STTXT_OPERATOR
: {
108 sc
.SetState(SCE_STTXT_DEFAULT
);
111 case SCE_STTXT_PRAGMA
: {
113 sc
.ForwardSetState(SCE_STTXT_DEFAULT
);
116 case SCE_STTXT_COMMENTLINE
: {
118 sc
.SetState(SCE_STTXT_DEFAULT
);
121 case SCE_STTXT_COMMENT
: {
122 if(sc
.Match('*',')'))
125 sc
.ForwardSetState(SCE_STTXT_DEFAULT
);
129 case SCE_STTXT_STRING1
: {
131 sc
.SetState(SCE_STTXT_STRINGEOL
);
132 else if(sc
.ch
== '\'' && sc
.chPrev
!= '$')
133 sc
.ForwardSetState(SCE_STTXT_DEFAULT
);
136 case SCE_STTXT_STRING2
: {
138 sc
.SetState(SCE_STTXT_STRINGEOL
);
139 else if(sc
.ch
== '\"' && sc
.chPrev
!= '$')
140 sc
.ForwardSetState(SCE_STTXT_DEFAULT
);
143 case SCE_STTXT_STRINGEOL
: {
145 sc
.SetState(SCE_STTXT_DEFAULT
);
148 case SCE_STTXT_CHARACTER
: {
149 if(setHexNumber
.Contains(sc
.ch
))
150 sc
.SetState(SCE_STTXT_HEXNUMBER
);
151 else if(setDataTime
.Contains(sc
.ch
))
152 sc
.SetState(SCE_STTXT_DATETIME
);
153 else sc
.SetState(SCE_STTXT_DEFAULT
);
156 case SCE_STTXT_IDENTIFIER
: {
157 if(!setWord
.Contains(sc
.ch
))
158 ClassifySTTXTWord(keywordlists
, sc
);
163 if(sc
.state
== SCE_STTXT_DEFAULT
)
166 sc
.SetState(SCE_STTXT_NUMBER
);
167 else if (setWordStart
.Contains(sc
.ch
))
168 sc
.SetState(SCE_STTXT_IDENTIFIER
);
169 else if (sc
.Match('/', '/'))
170 sc
.SetState(SCE_STTXT_COMMENTLINE
);
171 else if(sc
.Match('(', '*'))
172 sc
.SetState(SCE_STTXT_COMMENT
);
173 else if (sc
.ch
== '{')
174 sc
.SetState(SCE_STTXT_PRAGMA
);
175 else if (sc
.ch
== '\'')
176 sc
.SetState(SCE_STTXT_STRING1
);
177 else if (sc
.ch
== '\"')
178 sc
.SetState(SCE_STTXT_STRING2
);
179 else if(sc
.ch
== '#')
180 sc
.SetState(SCE_STTXT_CHARACTER
);
181 else if (setOperator
.Contains(sc
.ch
))
182 sc
.SetState(SCE_STTXT_OPERATOR
);
186 if (sc
.state
== SCE_STTXT_IDENTIFIER
&& setWord
.Contains(sc
.chPrev
))
187 ClassifySTTXTWord(keywordlists
, sc
);
192 static const char * const STTXTWordListDesc
[] = {
202 static bool IsCommentLine(int line
, Accessor
&styler
, bool type
)
204 int pos
= styler
.LineStart(line
);
205 int eolPos
= styler
.LineStart(line
+ 1) - 1;
207 for (int i
= pos
; i
< eolPos
; i
++)
210 char chNext
= styler
.SafeGetCharAt(i
+ 1);
211 int style
= styler
.StyleAt(i
);
214 if (ch
== '/' && chNext
== '/' && style
== SCE_STTXT_COMMENTLINE
)
217 else if (ch
== '(' && chNext
== '*' && style
== SCE_STTXT_COMMENT
)
220 if (!IsASpaceOrTab(ch
))
224 for (int i
= eolPos
-2; i
>pos
; i
--)
227 char chPrev
= styler
.SafeGetCharAt(i
-1);
228 int style
= styler
.StyleAt(i
);
230 if(ch
== ')' && chPrev
== '*' && style
== SCE_STTXT_COMMENT
)
232 if(!IsASpaceOrTab(ch
))
239 static bool IsPragmaLine(int line
, Accessor
&styler
)
241 int pos
= styler
.LineStart(line
);
242 int eolPos
= styler
.LineStart(line
+1) - 1;
244 for (int i
= pos
; i
< eolPos
; i
++)
247 int style
= styler
.StyleAt(i
);
249 if(ch
== '{' && style
== SCE_STTXT_PRAGMA
)
251 else if (!IsASpaceOrTab(ch
))
257 static void GetRangeUpper(unsigned int start
,unsigned int end
,Accessor
&styler
,char *s
,unsigned int len
)
260 while ((i
< end
- start
+ 1) && (i
< len
-1)) {
261 s
[i
] = static_cast<char>(toupper(styler
[start
+ i
]));
267 static void ClassifySTTXTWordFoldPoint(int &levelCurrent
,unsigned int lastStart
,
268 unsigned int currentPos
, Accessor
&styler
)
271 GetRangeUpper(lastStart
, currentPos
, styler
, s
, sizeof(s
));
273 // See Table C.2 - Keywords
274 if (!strcmp(s
, "ACTION") ||
275 !strcmp(s
, "CASE") ||
276 !strcmp(s
, "CONFIGURATION") ||
278 !strcmp(s
, "FUNCTION") ||
279 !strcmp(s
, "FUNCTION_BLOCK") ||
281 !strcmp(s
, "INITIAL_STEP") ||
282 !strcmp(s
, "REPEAT") ||
283 !strcmp(s
, "RESOURCE") ||
284 !strcmp(s
, "STEP") ||
285 !strcmp(s
, "STRUCT") ||
286 !strcmp(s
, "TRANSITION") ||
287 !strcmp(s
, "TYPE") ||
289 !strcmp(s
, "VAR_INPUT") ||
290 !strcmp(s
, "VAR_OUTPUT") ||
291 !strcmp(s
, "VAR_IN_OUT") ||
292 !strcmp(s
, "VAR_TEMP") ||
293 !strcmp(s
, "VAR_EXTERNAL") ||
294 !strcmp(s
, "VAR_ACCESS") ||
295 !strcmp(s
, "VAR_CONFIG") ||
296 !strcmp(s
, "VAR_GLOBAL") ||
301 else if (!strcmp(s
, "END_ACTION") ||
302 !strcmp(s
, "END_CASE") ||
303 !strcmp(s
, "END_CONFIGURATION") ||
304 !strcmp(s
, "END_FOR") ||
305 !strcmp(s
, "END_FUNCTION") ||
306 !strcmp(s
, "END_FUNCTION_BLOCK") ||
307 !strcmp(s
, "END_IF") ||
308 !strcmp(s
, "END_REPEAT") ||
309 !strcmp(s
, "END_RESOURCE") ||
310 !strcmp(s
, "END_STEP") ||
311 !strcmp(s
, "END_STRUCT") ||
312 !strcmp(s
, "END_TRANSITION") ||
313 !strcmp(s
, "END_TYPE") ||
314 !strcmp(s
, "END_VAR") ||
315 !strcmp(s
, "END_WHILE"))
318 if (levelCurrent
< SC_FOLDLEVELBASE
) {
319 levelCurrent
= SC_FOLDLEVELBASE
;
324 static void FoldSTTXTDoc(unsigned int startPos
, int length
, int initStyle
, WordList
*[],Accessor
&styler
)
326 bool foldComment
= styler
.GetPropertyInt("fold.comment") != 0;
327 bool foldPreprocessor
= styler
.GetPropertyInt("fold.preprocessor") != 0;
328 bool foldCompact
= styler
.GetPropertyInt("fold.compact", 1) != 0;
329 unsigned int endPos
= startPos
+ length
;
330 int visibleChars
= 0;
331 int lineCurrent
= styler
.GetLine(startPos
);
332 int levelPrev
= styler
.LevelAt(lineCurrent
) & SC_FOLDLEVELNUMBERMASK
;
333 int levelCurrent
= levelPrev
;
334 char chNext
= styler
[startPos
];
335 int styleNext
= styler
.StyleAt(startPos
);
336 int style
= initStyle
;
339 CharacterSet
setWord(CharacterSet::setAlphaNum
, "_", 0x80, true);
341 for (unsigned int i
= startPos
; i
< endPos
; i
++)
344 chNext
= styler
.SafeGetCharAt(i
+ 1);
345 int stylePrev
= style
;
347 styleNext
= styler
.StyleAt(i
+ 1);
348 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
350 if (foldComment
&& style
== SCE_STTXT_COMMENT
) {
351 if(stylePrev
!= SCE_STTXT_COMMENT
)
353 else if(styleNext
!= SCE_STTXT_COMMENT
&& !atEOL
)
356 if ( foldComment
&& atEOL
&& ( IsCommentLine(lineCurrent
, styler
,false)
357 || IsCommentLine(lineCurrent
,styler
,true))) {
358 if(!IsCommentLine(lineCurrent
-1, styler
,true) && IsCommentLine(lineCurrent
+1, styler
,true))
360 if (IsCommentLine(lineCurrent
-1, styler
,true) && !IsCommentLine(lineCurrent
+1, styler
,true))
362 if (!IsCommentLine(lineCurrent
-1, styler
,false) && IsCommentLine(lineCurrent
+1, styler
,false))
364 if (IsCommentLine(lineCurrent
-1, styler
,false) && !IsCommentLine(lineCurrent
+1, styler
,false))
367 if(foldPreprocessor
&& atEOL
&& IsPragmaLine(lineCurrent
, styler
)) {
368 if(!IsPragmaLine(lineCurrent
-1, styler
) && IsPragmaLine(lineCurrent
+1, styler
))
370 else if(IsPragmaLine(lineCurrent
-1, styler
) && !IsPragmaLine(lineCurrent
+1, styler
))
373 if (stylePrev
!= SCE_STTXT_KEYWORD
&& style
== SCE_STTXT_KEYWORD
) {
376 if(stylePrev
== SCE_STTXT_KEYWORD
) {
377 if(setWord
.Contains(ch
) && !setWord
.Contains(chNext
))
378 ClassifySTTXTWordFoldPoint(levelCurrent
,lastStart
, i
, styler
);
385 if (visibleChars
== 0 && foldCompact
)
386 lev
|= SC_FOLDLEVELWHITEFLAG
;
387 if ((levelCurrent
> levelPrev
) && (visibleChars
> 0))
388 lev
|= SC_FOLDLEVELHEADERFLAG
;
389 if (lev
!= styler
.LevelAt(lineCurrent
))
390 styler
.SetLevel(lineCurrent
, lev
);
393 levelPrev
= levelCurrent
;
397 // If we didn't reach the EOL in previous loop, store line level and whitespace information.
398 // The rest will be filled in later...
400 if (visibleChars
== 0 && foldCompact
)
401 lev
|= SC_FOLDLEVELWHITEFLAG
;
402 styler
.SetLevel(lineCurrent
, lev
);
406 LexerModule
lmSTTXT(SCLEX_STTXT
, ColouriseSTTXTDoc
, "fcST", FoldSTTXTDoc
, STTXTWordListDesc
);