]> git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/lexers/LexMetapost.cxx
Allow unsetting wxMenuItem as start of radio group too.
[wxWidgets.git] / src / stc / scintilla / lexers / LexMetapost.cxx
1 // Scintilla source code edit control
2
3 // File: LexMetapost.cxx - general context conformant metapost coloring scheme
4 // Author: Hans Hagen - PRAGMA ADE - Hasselt NL - www.pragma-ade.com
5 // Version: September 28, 2003
6 // Modified by instanton: July 10, 2007
7 // Folding based on keywordlists[]
8
9 // Copyright: 1998-2003 by Neil Hodgson <neilh@scintilla.org>
10 // The License.txt file describes the conditions under which this software may be distributed.
11
12 // This lexer is derived from the one written for the texwork environment (1999++) which in
13 // turn is inspired on texedit (1991++) which finds its roots in wdt (1986).
14
15 #include <stdlib.h>
16 #include <string.h>
17 #include <stdio.h>
18 #include <stdarg.h>
19 #include <assert.h>
20 #include <ctype.h>
21
22 #include "ILexer.h"
23 #include "Scintilla.h"
24 #include "SciLexer.h"
25
26 #include "WordList.h"
27 #include "LexAccessor.h"
28 #include "Accessor.h"
29 #include "StyleContext.h"
30 #include "CharacterSet.h"
31 #include "LexerModule.h"
32
33 #ifdef SCI_NAMESPACE
34 using namespace Scintilla;
35 #endif
36
37 // val SCE_METAPOST_DEFAULT = 0
38 // val SCE_METAPOST_SPECIAL = 1
39 // val SCE_METAPOST_GROUP = 2
40 // val SCE_METAPOST_SYMBOL = 3
41 // val SCE_METAPOST_COMMAND = 4
42 // val SCE_METAPOST_TEXT = 5
43
44 // Definitions in SciTEGlobal.properties:
45 //
46 // Metapost Highlighting
47 //
48 // # Default
49 // style.metapost.0=fore:#7F7F00
50 // # Special
51 // style.metapost.1=fore:#007F7F
52 // # Group
53 // style.metapost.2=fore:#880000
54 // # Symbol
55 // style.metapost.3=fore:#7F7F00
56 // # Command
57 // style.metapost.4=fore:#008800
58 // # Text
59 // style.metapost.5=fore:#000000
60
61 // lexer.tex.comment.process=0
62
63 // Auxiliary functions:
64
65 static inline bool endOfLine(Accessor &styler, unsigned int i) {
66 return
67 (styler[i] == '\n') || ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n')) ;
68 }
69
70 static inline bool isMETAPOSTcomment(int ch) {
71 return
72 (ch == '%') ;
73 }
74
75 static inline bool isMETAPOSTone(int ch) {
76 return
77 (ch == '[') || (ch == ']') || (ch == '(') || (ch == ')') ||
78 (ch == ':') || (ch == '=') || (ch == '<') || (ch == '>') ||
79 (ch == '{') || (ch == '}') || (ch == '\'') || (ch == '\"') ;
80 }
81
82 static inline bool isMETAPOSTtwo(int ch) {
83 return
84 (ch == ';') || (ch == '$') || (ch == '@') || (ch == '#');
85 }
86
87 static inline bool isMETAPOSTthree(int ch) {
88 return
89 (ch == '.') || (ch == '-') || (ch == '+') || (ch == '/') ||
90 (ch == '*') || (ch == ',') || (ch == '|') || (ch == '`') ||
91 (ch == '!') || (ch == '?') || (ch == '^') || (ch == '&') ||
92 (ch == '%') ;
93 }
94
95 static inline bool isMETAPOSTidentifier(int ch) {
96 return
97 ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) ||
98 (ch == '_') ;
99 }
100
101 static inline bool isMETAPOSTnumber(int ch) {
102 return
103 (ch >= '0') && (ch <= '9') ;
104 }
105
106 static inline bool isMETAPOSTstring(int ch) {
107 return
108 (ch == '\"') ;
109 }
110
111 static inline bool isMETAPOSTcolon(int ch) {
112 return
113 (ch == ':') ;
114 }
115
116 static inline bool isMETAPOSTequal(int ch) {
117 return
118 (ch == '=') ;
119 }
120
121 static int CheckMETAPOSTInterface(
122 unsigned int startPos,
123 int length,
124 Accessor &styler,
125 int defaultInterface) {
126
127 char lineBuffer[1024] ;
128 unsigned int linePos = 0 ;
129
130 // some day we can make something lexer.metapost.mapping=(none,0)(metapost,1)(mp,1)(metafun,2)...
131
132 if (styler.SafeGetCharAt(0) == '%') {
133 for (unsigned int i = 0; i < startPos + length; i++) {
134 lineBuffer[linePos++] = styler.SafeGetCharAt(i) ;
135 if (endOfLine(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {
136 lineBuffer[linePos] = '\0';
137 if (strstr(lineBuffer, "interface=none")) {
138 return 0 ;
139 } else if (strstr(lineBuffer, "interface=metapost") || strstr(lineBuffer, "interface=mp")) {
140 return 1 ;
141 } else if (strstr(lineBuffer, "interface=metafun")) {
142 return 2 ;
143 } else if (styler.SafeGetCharAt(1) == 'D' && strstr(lineBuffer, "%D \\module")) {
144 // better would be to limit the search to just one line
145 return 2 ;
146 } else {
147 return defaultInterface ;
148 }
149 }
150 }
151 }
152
153 return defaultInterface ;
154 }
155
156 static void ColouriseMETAPOSTDoc(
157 unsigned int startPos,
158 int length,
159 int,
160 WordList *keywordlists[],
161 Accessor &styler) {
162
163 styler.StartAt(startPos) ;
164 styler.StartSegment(startPos) ;
165
166 bool processComment = styler.GetPropertyInt("lexer.metapost.comment.process", 0) == 1 ;
167 int defaultInterface = styler.GetPropertyInt("lexer.metapost.interface.default", 1) ;
168
169 int currentInterface = CheckMETAPOSTInterface(startPos,length,styler,defaultInterface) ;
170
171 // 0 no keyword highlighting
172 // 1 metapost keyword hightlighting
173 // 2+ metafun keyword hightlighting
174
175 int extraInterface = 0 ;
176
177 if (currentInterface != 0) {
178 extraInterface = currentInterface ;
179 }
180
181 WordList &keywords = *keywordlists[0] ;
182 WordList &keywords2 = *keywordlists[extraInterface-1] ;
183
184 StyleContext sc(startPos, length, SCE_METAPOST_TEXT, styler) ;
185
186 char key[100] ;
187
188 bool inTeX = false ;
189 bool inComment = false ;
190 bool inString = false ;
191 bool inClause = false ;
192
193 bool going = sc.More() ; // needed because of a fuzzy end of file state
194
195 for (; going; sc.Forward()) {
196
197 if (! sc.More()) { going = false ; } // we need to go one behind the end of text
198
199 if (inClause) {
200 sc.SetState(SCE_METAPOST_TEXT) ;
201 inClause = false ;
202 }
203
204 if (inComment) {
205 if (sc.atLineEnd) {
206 sc.SetState(SCE_METAPOST_TEXT) ;
207 inTeX = false ;
208 inComment = false ;
209 inClause = false ;
210 inString = false ; // not correct but we want to stimulate one-lines
211 }
212 } else if (inString) {
213 if (isMETAPOSTstring(sc.ch)) {
214 sc.SetState(SCE_METAPOST_SPECIAL) ;
215 sc.ForwardSetState(SCE_METAPOST_TEXT) ;
216 inString = false ;
217 } else if (sc.atLineEnd) {
218 sc.SetState(SCE_METAPOST_TEXT) ;
219 inTeX = false ;
220 inComment = false ;
221 inClause = false ;
222 inString = false ; // not correct but we want to stimulate one-lines
223 }
224 } else {
225 if ((! isMETAPOSTidentifier(sc.ch)) && (sc.LengthCurrent() > 0)) {
226 if (sc.state == SCE_METAPOST_COMMAND) {
227 sc.GetCurrent(key, sizeof(key)) ;
228 if ((strcmp(key,"btex") == 0) || (strcmp(key,"verbatimtex") == 0)) {
229 sc.ChangeState(SCE_METAPOST_GROUP) ;
230 inTeX = true ;
231 } else if (inTeX) {
232 if (strcmp(key,"etex") == 0) {
233 sc.ChangeState(SCE_METAPOST_GROUP) ;
234 inTeX = false ;
235 } else {
236 sc.ChangeState(SCE_METAPOST_TEXT) ;
237 }
238 } else {
239 if (keywords && keywords.InList(key)) {
240 sc.ChangeState(SCE_METAPOST_COMMAND) ;
241 } else if (keywords2 && keywords2.InList(key)) {
242 sc.ChangeState(SCE_METAPOST_EXTRA) ;
243 } else {
244 sc.ChangeState(SCE_METAPOST_TEXT) ;
245 }
246 }
247 }
248 }
249 if (isMETAPOSTcomment(sc.ch)) {
250 if (! inTeX) {
251 sc.SetState(SCE_METAPOST_SYMBOL) ;
252 sc.ForwardSetState(SCE_METAPOST_DEFAULT) ;
253 inComment = ! processComment ;
254 } else {
255 sc.SetState(SCE_METAPOST_TEXT) ;
256 }
257 } else if (isMETAPOSTstring(sc.ch)) {
258 if (! inTeX) {
259 sc.SetState(SCE_METAPOST_SPECIAL) ;
260 if (! isMETAPOSTstring(sc.chNext)) {
261 sc.ForwardSetState(SCE_METAPOST_TEXT) ;
262 }
263 inString = true ;
264 } else {
265 sc.SetState(SCE_METAPOST_TEXT) ;
266 }
267 } else if (isMETAPOSTcolon(sc.ch)) {
268 if (! inTeX) {
269 if (! isMETAPOSTequal(sc.chNext)) {
270 sc.SetState(SCE_METAPOST_COMMAND) ;
271 inClause = true ;
272 } else {
273 sc.SetState(SCE_METAPOST_SPECIAL) ;
274 }
275 } else {
276 sc.SetState(SCE_METAPOST_TEXT) ;
277 }
278 } else if (isMETAPOSTone(sc.ch)) {
279 if (! inTeX) {
280 sc.SetState(SCE_METAPOST_SPECIAL) ;
281 } else {
282 sc.SetState(SCE_METAPOST_TEXT) ;
283 }
284 } else if (isMETAPOSTtwo(sc.ch)) {
285 if (! inTeX) {
286 sc.SetState(SCE_METAPOST_GROUP) ;
287 } else {
288 sc.SetState(SCE_METAPOST_TEXT) ;
289 }
290 } else if (isMETAPOSTthree(sc.ch)) {
291 if (! inTeX) {
292 sc.SetState(SCE_METAPOST_SYMBOL) ;
293 } else {
294 sc.SetState(SCE_METAPOST_TEXT) ;
295 }
296 } else if (isMETAPOSTidentifier(sc.ch)) {
297 if (sc.state != SCE_METAPOST_COMMAND) {
298 sc.SetState(SCE_METAPOST_TEXT) ;
299 sc.ChangeState(SCE_METAPOST_COMMAND) ;
300 }
301 } else if (isMETAPOSTnumber(sc.ch)) {
302 // rather redundant since for the moment we don't handle numbers
303 sc.SetState(SCE_METAPOST_TEXT) ;
304 } else if (sc.atLineEnd) {
305 sc.SetState(SCE_METAPOST_TEXT) ;
306 inTeX = false ;
307 inComment = false ;
308 inClause = false ;
309 inString = false ;
310 } else {
311 sc.SetState(SCE_METAPOST_TEXT) ;
312 }
313 }
314
315 }
316
317 sc.Complete();
318
319 }
320
321 // Hooks info the system:
322
323 static const char * const metapostWordListDesc[] = {
324 "MetaPost",
325 "MetaFun",
326 0
327 } ;
328
329 static int classifyFoldPointMetapost(const char* s,WordList *keywordlists[]) {
330 WordList& keywordsStart=*keywordlists[3];
331 WordList& keywordsStop1=*keywordlists[4];
332
333 if (keywordsStart.InList(s)) {return 1;}
334 else if (keywordsStop1.InList(s)) {return -1;}
335 return 0;
336
337 }
338
339 static int ParseMetapostWord(unsigned int pos, Accessor &styler, char *word)
340 {
341 int length=0;
342 char ch=styler.SafeGetCharAt(pos);
343 *word=0;
344
345 while(isMETAPOSTidentifier(ch) && isalpha(ch) && length<100){
346 word[length]=ch;
347 length++;
348 ch=styler.SafeGetCharAt(pos+length);
349 }
350 word[length]=0;
351 return length;
352 }
353
354 static void FoldMetapostDoc(unsigned int startPos, int length, int, WordList *keywordlists[], Accessor &styler)
355 {
356 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
357 unsigned int endPos = startPos+length;
358 int visibleChars=0;
359 int lineCurrent=styler.GetLine(startPos);
360 int levelPrev=styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
361 int levelCurrent=levelPrev;
362 char chNext=styler[startPos];
363
364 char buffer[100]="";
365
366 for (unsigned int i=startPos; i < endPos; i++) {
367 char ch=chNext;
368 chNext=styler.SafeGetCharAt(i+1);
369 char chPrev=styler.SafeGetCharAt(i-1);
370 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
371
372 if(i==0 || chPrev == '\r' || chPrev=='\n'|| chPrev==' '|| chPrev=='(' || chPrev=='$')
373 {
374 ParseMetapostWord(i, styler, buffer);
375 levelCurrent += classifyFoldPointMetapost(buffer,keywordlists);
376 }
377
378 if (atEOL) {
379 int lev = levelPrev;
380 if (visibleChars == 0 && foldCompact)
381 lev |= SC_FOLDLEVELWHITEFLAG;
382 if ((levelCurrent > levelPrev) && (visibleChars > 0))
383 lev |= SC_FOLDLEVELHEADERFLAG;
384 if (lev != styler.LevelAt(lineCurrent)) {
385 styler.SetLevel(lineCurrent, lev);
386 }
387 lineCurrent++;
388 levelPrev = levelCurrent;
389 visibleChars = 0;
390 }
391
392 if (!isspacechar(ch))
393 visibleChars++;
394 }
395 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
396 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
397 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
398
399 }
400
401
402 LexerModule lmMETAPOST(SCLEX_METAPOST, ColouriseMETAPOSTDoc, "metapost", FoldMetapostDoc, metapostWordListDesc);