Fixed issue #2175: TortoiseGitBlame fails to search if line has non-ascii chars and...
[TortoiseGit.git] / ext / scintilla / lexers / LexSTTXT.cxx
blobb0095f7e8770f47baf52683636b4f7965eeffcc2
1 // Scintilla source code edit control
2 /** @file LexSTTXT.cxx
3 ** Lexer for Structured Text language.
4 ** Written by Pavel Bulochkin
5 **/
6 // The License.txt file describes the conditions under which this software may be distributed.
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <assert.h>
14 #include <ctype.h>
16 #include "ILexer.h"
17 #include "Scintilla.h"
18 #include "SciLexer.h"
20 #include "WordList.h"
21 #include "LexAccessor.h"
22 #include "Accessor.h"
23 #include "StyleContext.h"
24 #include "CharacterSet.h"
25 #include "LexerModule.h"
27 #ifdef SCI_NAMESPACE
28 using namespace Scintilla;
29 #endif
31 static void ClassifySTTXTWord(WordList *keywordlists[], StyleContext &sc)
33 char s[256] = { 0 };
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);
80 switch(sc.state)
82 case SCE_STTXT_NUMBER: {
83 if(!setNumber.Contains(sc.ch))
84 sc.SetState(SCE_STTXT_DEFAULT);
85 break;
87 case SCE_STTXT_HEXNUMBER: {
88 if (setHexNumber.Contains(sc.ch))
89 continue;
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);
94 else
95 sc.SetState(SCE_STTXT_DEFAULT);
96 break;
98 case SCE_STTXT_DATETIME: {
99 if (setDataTime.Contains(sc.ch))
100 continue;
101 else if(setWord.Contains(sc.ch))
102 sc.ChangeState(SCE_STTXT_DEFAULT);
103 else
104 sc.SetState(SCE_STTXT_DEFAULT);
105 break;
107 case SCE_STTXT_OPERATOR: {
108 sc.SetState(SCE_STTXT_DEFAULT);
109 break;
111 case SCE_STTXT_PRAGMA: {
112 if (sc.ch == '}')
113 sc.ForwardSetState(SCE_STTXT_DEFAULT);
114 break;
116 case SCE_STTXT_COMMENTLINE: {
117 if (sc.atLineStart)
118 sc.SetState(SCE_STTXT_DEFAULT);
119 break;
121 case SCE_STTXT_COMMENT: {
122 if(sc.Match('*',')'))
124 sc.Forward();
125 sc.ForwardSetState(SCE_STTXT_DEFAULT);
127 break;
129 case SCE_STTXT_STRING1: {
130 if(sc.atLineEnd)
131 sc.SetState(SCE_STTXT_STRINGEOL);
132 else if(sc.ch == '\'' && sc.chPrev != '$')
133 sc.ForwardSetState(SCE_STTXT_DEFAULT);
134 break;
136 case SCE_STTXT_STRING2: {
137 if (sc.atLineEnd)
138 sc.SetState(SCE_STTXT_STRINGEOL);
139 else if(sc.ch == '\"' && sc.chPrev != '$')
140 sc.ForwardSetState(SCE_STTXT_DEFAULT);
141 break;
143 case SCE_STTXT_STRINGEOL: {
144 if(sc.atLineStart)
145 sc.SetState(SCE_STTXT_DEFAULT);
146 break;
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);
154 break;
156 case SCE_STTXT_IDENTIFIER: {
157 if(!setWord.Contains(sc.ch))
158 ClassifySTTXTWord(keywordlists, sc);
159 break;
163 if(sc.state == SCE_STTXT_DEFAULT)
165 if(IsADigit(sc.ch))
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);
189 sc.Complete();
192 static const char * const STTXTWordListDesc[] = {
193 "Keywords",
194 "Types",
195 "Functions",
196 "FB",
197 "Local_Var",
198 "Local_Pragma",
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++)
209 char ch = styler[i];
210 char chNext = styler.SafeGetCharAt(i + 1);
211 int style = styler.StyleAt(i);
213 if(type) {
214 if (ch == '/' && chNext == '/' && style == SCE_STTXT_COMMENTLINE)
215 return true;
217 else if (ch == '(' && chNext == '*' && style == SCE_STTXT_COMMENT)
218 break;
220 if (!IsASpaceOrTab(ch))
221 return false;
224 for (int i = eolPos-2; i>pos; i--)
226 char ch = styler[i];
227 char chPrev = styler.SafeGetCharAt(i-1);
228 int style = styler.StyleAt(i);
230 if(ch == ')' && chPrev == '*' && style == SCE_STTXT_COMMENT)
231 return true;
232 if(!IsASpaceOrTab(ch))
233 return false;
236 return false;
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++)
246 char ch = styler[i];
247 int style = styler.StyleAt(i);
249 if(ch == '{' && style == SCE_STTXT_PRAGMA)
250 return true;
251 else if (!IsASpaceOrTab(ch))
252 return false;
254 return false;
257 static void GetRangeUpper(unsigned int start,unsigned int end,Accessor &styler,char *s,unsigned int len)
259 unsigned int i = 0;
260 while ((i < end - start + 1) && (i < len-1)) {
261 s[i] = static_cast<char>(toupper(styler[start + i]));
262 i++;
264 s[i] = '\0';
267 static void ClassifySTTXTWordFoldPoint(int &levelCurrent,unsigned int lastStart,
268 unsigned int currentPos, Accessor &styler)
270 char s[256];
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") ||
277 !strcmp(s, "FOR") ||
278 !strcmp(s, "FUNCTION") ||
279 !strcmp(s, "FUNCTION_BLOCK") ||
280 !strcmp(s, "IF") ||
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") ||
288 !strcmp(s, "VAR") ||
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") ||
297 !strcmp(s, "WHILE"))
299 levelCurrent++;
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"))
317 levelCurrent--;
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;
337 int lastStart = 0;
339 CharacterSet setWord(CharacterSet::setAlphaNum, "_", 0x80, true);
341 for (unsigned int i = startPos; i < endPos; i++)
343 char ch = chNext;
344 chNext = styler.SafeGetCharAt(i + 1);
345 int stylePrev = style;
346 style = styleNext;
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)
352 levelCurrent++;
353 else if(styleNext != SCE_STTXT_COMMENT && !atEOL)
354 levelCurrent--;
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))
359 levelCurrent++;
360 if (IsCommentLine(lineCurrent-1, styler,true) && !IsCommentLine(lineCurrent+1, styler,true))
361 levelCurrent--;
362 if (!IsCommentLine(lineCurrent-1, styler,false) && IsCommentLine(lineCurrent+1, styler,false))
363 levelCurrent++;
364 if (IsCommentLine(lineCurrent-1, styler,false) && !IsCommentLine(lineCurrent+1, styler,false))
365 levelCurrent--;
367 if(foldPreprocessor && atEOL && IsPragmaLine(lineCurrent, styler)) {
368 if(!IsPragmaLine(lineCurrent-1, styler) && IsPragmaLine(lineCurrent+1, styler ))
369 levelCurrent++;
370 else if(IsPragmaLine(lineCurrent-1, styler) && !IsPragmaLine(lineCurrent+1, styler))
371 levelCurrent--;
373 if (stylePrev != SCE_STTXT_KEYWORD && style == SCE_STTXT_KEYWORD) {
374 lastStart = i;
376 if(stylePrev == SCE_STTXT_KEYWORD) {
377 if(setWord.Contains(ch) && !setWord.Contains(chNext))
378 ClassifySTTXTWordFoldPoint(levelCurrent,lastStart, i, styler);
380 if (!IsASpace(ch)) {
381 visibleChars++;
383 if (atEOL) {
384 int lev = levelPrev;
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);
392 lineCurrent++;
393 levelPrev = levelCurrent;
394 visibleChars = 0;
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...
399 int lev = levelPrev;
400 if (visibleChars == 0 && foldCompact)
401 lev |= SC_FOLDLEVELWHITEFLAG;
402 styler.SetLevel(lineCurrent, lev);
406 LexerModule lmSTTXT(SCLEX_STTXT, ColouriseSTTXTDoc, "fcST", FoldSTTXTDoc, STTXTWordListDesc);