Add an UI to enable/disable specific overlay handlers.
[TortoiseGit.git] / ext / scintilla / src / LexMagik.cxx
blobde0d06682fe34cbdf915fce598c4ab86efe20bdd
1 // Scintilla source code edit control
2 /**
3 * @file LexMagik.cxx
4 * Lexer for GE(r) Smallworld(tm) MagikSF
5 */
6 // Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
7 // The License.txt file describes the conditions under which this software may be distributed.
9 #include <stdlib.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <stdio.h>
13 #include <stdarg.h>
15 #include "Platform.h"
17 #include "PropSet.h"
18 #include "Accessor.h"
19 #include "StyleContext.h"
20 #include "KeyWords.h"
21 #include "Scintilla.h"
22 #include "SciLexer.h"
24 #ifdef SCI_NAMESPACE
25 using namespace Scintilla;
26 #endif
28 /**
29 * Is it a core character (C isalpha(), exclamation and question mark)
31 * \param ch The character
32 * \return True if ch is a character, False otherwise
34 static inline bool IsAlphaCore(int ch) {
35 return (isalpha(ch) || ch == '!' || ch == '?');
38 /**
39 * Is it a character (IsAlphaCore() and underscore)
41 * \param ch The character
42 * \return True if ch is a character, False otherwise
44 static inline bool IsAlpha(int ch) {
45 return (IsAlphaCore(ch) || ch == '_');
48 /**
49 * Is it a symbolic character (IsAlpha() and colon)
51 * \param ch The character
52 * \return True if ch is a character, False otherwise
54 static inline bool IsAlphaSym(int ch) {
55 return (IsAlpha(ch) || ch == ':');
58 /**
59 * Is it a numerical character (IsAlpha() and 0 - 9)
61 * \param ch The character
62 * \return True if ch is a character, False otherwise
64 static inline bool IsAlNum(int ch) {
65 return ((ch > '0' && ch < '9') || IsAlpha(ch));
68 /**
69 * Is it a symbolic numerical character (IsAlNum() and colon)
71 * \param ch The character
72 * \return True if ch is a character, False otherwise
74 static inline bool IsAlNumSym(int ch) {
75 return (IsAlNum(ch) || ch == ':');
78 /**
79 * The lexer function
81 * \param startPos Where to start scanning
82 * \param length Where to scan to
83 * \param initStyle The style at the initial point, not used in this folder
84 * \param keywordslists The keywordslists, currently, number 5 is used
85 * \param styler The styler
87 static void ColouriseMagikDoc(unsigned int startPos, int length, int initStyle,
88 WordList *keywordlists[], Accessor &styler) {
89 styler.StartAt(startPos);
91 WordList &keywords = *keywordlists[0];
92 WordList &pragmatics = *keywordlists[1];
93 WordList &containers = *keywordlists[2];
94 WordList &flow = *keywordlists[3];
95 WordList &characters = *keywordlists[4];
97 StyleContext sc(startPos, length, initStyle, styler);
100 for (; sc.More(); sc.Forward()) {
102 repeat:
104 if(sc.ch == '#') {
105 if (sc.chNext == '#') sc.SetState(SCE_MAGIK_HYPER_COMMENT);
106 else sc.SetState(SCE_MAGIK_COMMENT);
107 for(; sc.More() && !(sc.atLineEnd); sc.Forward());
108 sc.SetState(SCE_MAGIK_DEFAULT);
109 goto repeat;
112 if(sc.ch == '"') {
113 sc.SetState(SCE_MAGIK_STRING);
115 if(sc.More())
117 sc.Forward();
118 for(; sc.More() && sc.ch != '"'; sc.Forward());
121 sc.ForwardSetState(SCE_MAGIK_DEFAULT);
122 goto repeat;
125 // The default state
126 if(sc.state == SCE_MAGIK_DEFAULT) {
128 // A certain keyword has been detected
129 if (sc.ch == '_' && (
130 sc.currentPos == 0 || !IsAlNum(sc.chPrev))) {
131 char keyword[50];
132 memset(keyword, '\0', 50);
134 for(
135 int scanPosition = 0;
136 scanPosition < 50;
137 scanPosition++) {
138 char keywordChar = static_cast<char>(
139 tolower(styler.SafeGetCharAt(
140 scanPosition +
141 static_cast<int>(sc.currentPos+1), ' ')));
142 if(IsAlpha(keywordChar)) {
143 keyword[scanPosition] = keywordChar;
144 } else {
145 break;
149 // It is a pragma
150 if(pragmatics.InList(keyword)) {
151 sc.SetState(SCE_MAGIK_PRAGMA);
154 // it is a normal keyword like _local, _self, etc.
155 else if(keywords.InList(keyword)) {
156 sc.SetState(SCE_MAGIK_KEYWORD);
159 // It is a container keyword, such as _method, _proc, etc.
160 else if(containers.InList(keyword)) {
161 sc.SetState(SCE_MAGIK_CONTAINER);
164 // It is a flow keyword, such as _for, _if, _try, etc.
165 else if(flow.InList(keyword)) {
166 sc.SetState(SCE_MAGIK_FLOW);
169 // Interpret as unknown keyword
170 else {
171 sc.SetState(SCE_MAGIK_UNKNOWN_KEYWORD);
175 // Symbolic expression
176 else if(sc.ch == ':' && !IsAlNum(sc.chPrev)) {
177 sc.SetState(SCE_MAGIK_SYMBOL);
178 bool firstTrip = true;
179 for(sc.Forward(); sc.More(); sc.Forward()) {
180 if(firstTrip && IsAlphaSym(sc.ch));
181 else if(!firstTrip && IsAlNumSym(sc.ch));
182 else if(sc.ch == '|') {
183 for(sc.Forward();
184 sc.More() && sc.ch != '|';
185 sc.Forward());
187 else break;
189 firstTrip = false;
191 sc.SetState(SCE_MAGIK_DEFAULT);
192 goto repeat;
195 // Identifier (label) expression
196 else if(sc.ch == '@') {
197 sc.SetState(SCE_MAGIK_IDENTIFIER);
198 bool firstTrip = true;
199 for(sc.Forward(); sc.More(); sc.Forward()) {
200 if(firstTrip && IsAlphaCore(sc.ch)) {
201 firstTrip = false;
203 else if(!firstTrip && IsAlpha(sc.ch));
204 else break;
206 sc.SetState(SCE_MAGIK_DEFAULT);
207 goto repeat;
210 // Start of a character
211 else if(sc.ch == '%') {
212 sc.SetState(SCE_MAGIK_CHARACTER);
213 sc.Forward();
214 char keyword[50];
215 memset(keyword, '\0', 50);
217 for(
218 int scanPosition = 0;
219 scanPosition < 50;
220 scanPosition++) {
221 char keywordChar = static_cast<char>(
222 tolower(styler.SafeGetCharAt(
223 scanPosition +
224 static_cast<int>(sc.currentPos), ' ')));
225 if(IsAlpha(keywordChar)) {
226 keyword[scanPosition] = keywordChar;
227 } else {
228 break;
232 if(characters.InList(keyword)) {
233 sc.Forward(strlen(keyword));
234 } else {
235 sc.Forward();
238 sc.SetState(SCE_MAGIK_DEFAULT);
239 goto repeat;
242 // Operators
243 else if(
244 sc.ch == '>' ||
245 sc.ch == '<' ||
246 sc.ch == '.' ||
247 sc.ch == ',' ||
248 sc.ch == '+' ||
249 sc.ch == '-' ||
250 sc.ch == '/' ||
251 sc.ch == '*' ||
252 sc.ch == '~' ||
253 sc.ch == '$' ||
254 sc.ch == '=') {
255 sc.SetState(SCE_MAGIK_OPERATOR);
258 // Braces
259 else if(sc.ch == '(' || sc.ch == ')') {
260 sc.SetState(SCE_MAGIK_BRACE_BLOCK);
263 // Brackets
264 else if(sc.ch == '{' || sc.ch == '}') {
265 sc.SetState(SCE_MAGIK_BRACKET_BLOCK);
268 // Square Brackets
269 else if(sc.ch == '[' || sc.ch == ']') {
270 sc.SetState(SCE_MAGIK_SQBRACKET_BLOCK);
276 // It is an operator
277 else if(
278 sc.state == SCE_MAGIK_OPERATOR ||
279 sc.state == SCE_MAGIK_BRACE_BLOCK ||
280 sc.state == SCE_MAGIK_BRACKET_BLOCK ||
281 sc.state == SCE_MAGIK_SQBRACKET_BLOCK) {
282 sc.SetState(SCE_MAGIK_DEFAULT);
283 goto repeat;
286 // It is the pragma state
287 else if(sc.state == SCE_MAGIK_PRAGMA) {
288 if(!IsAlpha(sc.ch)) {
289 sc.SetState(SCE_MAGIK_DEFAULT);
290 goto repeat;
294 // It is the keyword state
295 else if(
296 sc.state == SCE_MAGIK_KEYWORD ||
297 sc.state == SCE_MAGIK_CONTAINER ||
298 sc.state == SCE_MAGIK_FLOW ||
299 sc.state == SCE_MAGIK_UNKNOWN_KEYWORD) {
300 if(!IsAlpha(sc.ch)) {
301 sc.SetState(SCE_MAGIK_DEFAULT);
302 goto repeat;
307 sc.Complete();
311 * The word list description
313 static const char * const magikWordListDesc[] = {
314 "Accessors (local, global, self, super, thisthread)",
315 "Pragmatic (pragma, private)",
316 "Containers (method, block, proc)",
317 "Flow (if, then, elif, else)",
318 "Characters (space, tab, newline, return)",
319 "Fold Containers (method, proc, block, if, loop)",
323 * This function detects keywords which are able to have a body. Note that it
324 * uses the Fold Containers word description, not the containers description. It
325 * only works when the style at that particular position is set on Containers
326 * or Flow (number 3 or 4).
328 * \param keywordslist The list of keywords that are scanned, they should only
329 * contain the start keywords, not the end keywords
330 * \param The actual keyword
331 * \return 1 if it is a folding start-keyword, -1 if it is a folding end-keyword
332 * 0 otherwise
334 static inline int IsFoldingContainer(WordList &keywordslist, char * keyword) {
336 strlen(keyword) > 3 &&
337 keyword[0] == 'e' && keyword[1] == 'n' && keyword[2] == 'd') {
338 if (keywordslist.InList(keyword + 3)) {
339 return -1;
342 } else {
343 if(keywordslist.InList(keyword)) {
344 return 1;
348 return 0;
352 * The folding function
354 * \param startPos Where to start scanning
355 * \param length Where to scan to
356 * \param keywordslists The keywordslists, currently, number 5 is used
357 * \param styler The styler
359 static void FoldMagikDoc(unsigned int startPos, int length, int,
360 WordList *keywordslists[], Accessor &styler) {
362 bool compact = styler.GetPropertyInt("fold.compact") != 0;
364 WordList &foldingElements = *keywordslists[5];
365 int endPos = startPos + length;
366 int line = styler.GetLine(startPos);
367 int level = styler.LevelAt(line) & SC_FOLDLEVELNUMBERMASK;
368 int flags = styler.LevelAt(line) & ~SC_FOLDLEVELNUMBERMASK;
370 for(
371 int currentPos = startPos;
372 currentPos < endPos;
373 currentPos++) {
374 char currentState = styler.StyleAt(currentPos);
375 char c = styler.SafeGetCharAt(currentPos, ' ');
376 int prevLine = styler.GetLine(currentPos - 1);
377 line = styler.GetLine(currentPos);
379 // Default situation
380 if(prevLine < line) {
381 styler.SetLevel(line, (level|flags) & ~SC_FOLDLEVELHEADERFLAG);
382 flags = styler.LevelAt(line) & ~SC_FOLDLEVELNUMBERMASK;
387 currentState == SCE_MAGIK_CONTAINER ||
388 currentState == SCE_MAGIK_FLOW
389 ) &&
390 c == '_') {
392 char keyword[50];
393 memset(keyword, '\0', 50);
395 for(
396 int scanPosition = 0;
397 scanPosition < 50;
398 scanPosition++) {
399 char keywordChar = static_cast<char>(
400 tolower(styler.SafeGetCharAt(
401 scanPosition +
402 currentPos + 1, ' ')));
403 if(IsAlpha(keywordChar)) {
404 keyword[scanPosition] = keywordChar;
405 } else {
406 break;
410 if(IsFoldingContainer(foldingElements, keyword) > 0) {
411 styler.SetLevel(
412 line,
413 styler.LevelAt(line) | SC_FOLDLEVELHEADERFLAG);
414 level++;
415 } else if(IsFoldingContainer(foldingElements, keyword) < 0) {
416 styler.SetLevel(line, styler.LevelAt(line));
417 level--;
422 compact && (
423 currentState == SCE_MAGIK_BRACE_BLOCK ||
424 currentState == SCE_MAGIK_BRACKET_BLOCK ||
425 currentState == SCE_MAGIK_SQBRACKET_BLOCK)) {
426 if(c == '{' || c == '[' || c == '(') {
427 styler.SetLevel(
428 line,
429 styler.LevelAt(line) | SC_FOLDLEVELHEADERFLAG);
430 level++;
431 } else if(c == '}' || c == ']' || c == ')') {
432 styler.SetLevel(line, styler.LevelAt(line));
433 level--;
441 * Injecting the module
443 LexerModule lmMagikSF(
444 SCLEX_MAGIK, ColouriseMagikDoc, "magiksf", FoldMagikDoc, magikWordListDesc);