Scintilla 4.0.3
[TortoiseGit.git] / ext / scintilla / lexers / LexMetapost.cxx
bloba4d5d16070b6ae31b193d9426c863d74c69b7a09
1 // Scintilla source code edit control
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[]
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.
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).
15 #include <stdlib.h>
16 #include <string.h>
17 #include <stdio.h>
18 #include <stdarg.h>
19 #include <assert.h>
20 #include <ctype.h>
22 #include "ILexer.h"
23 #include "Scintilla.h"
24 #include "SciLexer.h"
26 #include "WordList.h"
27 #include "LexAccessor.h"
28 #include "Accessor.h"
29 #include "StyleContext.h"
30 #include "CharacterSet.h"
31 #include "LexerModule.h"
33 using namespace Scintilla;
35 // val SCE_METAPOST_DEFAULT = 0
36 // val SCE_METAPOST_SPECIAL = 1
37 // val SCE_METAPOST_GROUP = 2
38 // val SCE_METAPOST_SYMBOL = 3
39 // val SCE_METAPOST_COMMAND = 4
40 // val SCE_METAPOST_TEXT = 5
42 // Definitions in SciTEGlobal.properties:
44 // Metapost Highlighting
46 // # Default
47 // style.metapost.0=fore:#7F7F00
48 // # Special
49 // style.metapost.1=fore:#007F7F
50 // # Group
51 // style.metapost.2=fore:#880000
52 // # Symbol
53 // style.metapost.3=fore:#7F7F00
54 // # Command
55 // style.metapost.4=fore:#008800
56 // # Text
57 // style.metapost.5=fore:#000000
59 // lexer.tex.comment.process=0
61 // Auxiliary functions:
63 static inline bool endOfLine(Accessor &styler, Sci_PositionU i) {
64 return
65 (styler[i] == '\n') || ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n')) ;
68 static inline bool isMETAPOSTcomment(int ch) {
69 return
70 (ch == '%') ;
73 static inline bool isMETAPOSTone(int ch) {
74 return
75 (ch == '[') || (ch == ']') || (ch == '(') || (ch == ')') ||
76 (ch == ':') || (ch == '=') || (ch == '<') || (ch == '>') ||
77 (ch == '{') || (ch == '}') || (ch == '\'') || (ch == '\"') ;
80 static inline bool isMETAPOSTtwo(int ch) {
81 return
82 (ch == ';') || (ch == '$') || (ch == '@') || (ch == '#');
85 static inline bool isMETAPOSTthree(int ch) {
86 return
87 (ch == '.') || (ch == '-') || (ch == '+') || (ch == '/') ||
88 (ch == '*') || (ch == ',') || (ch == '|') || (ch == '`') ||
89 (ch == '!') || (ch == '?') || (ch == '^') || (ch == '&') ||
90 (ch == '%') ;
93 static inline bool isMETAPOSTidentifier(int ch) {
94 return
95 ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) ||
96 (ch == '_') ;
99 static inline bool isMETAPOSTnumber(int ch) {
100 return
101 (ch >= '0') && (ch <= '9') ;
104 static inline bool isMETAPOSTstring(int ch) {
105 return
106 (ch == '\"') ;
109 static inline bool isMETAPOSTcolon(int ch) {
110 return
111 (ch == ':') ;
114 static inline bool isMETAPOSTequal(int ch) {
115 return
116 (ch == '=') ;
119 static int CheckMETAPOSTInterface(
120 Sci_PositionU startPos,
121 Sci_Position length,
122 Accessor &styler,
123 int defaultInterface) {
125 char lineBuffer[1024] ;
126 Sci_PositionU linePos = 0 ;
128 // some day we can make something lexer.metapost.mapping=(none,0)(metapost,1)(mp,1)(metafun,2)...
130 if (styler.SafeGetCharAt(0) == '%') {
131 for (Sci_PositionU i = 0; i < startPos + length; i++) {
132 lineBuffer[linePos++] = styler.SafeGetCharAt(i) ;
133 if (endOfLine(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {
134 lineBuffer[linePos] = '\0';
135 if (strstr(lineBuffer, "interface=none")) {
136 return 0 ;
137 } else if (strstr(lineBuffer, "interface=metapost") || strstr(lineBuffer, "interface=mp")) {
138 return 1 ;
139 } else if (strstr(lineBuffer, "interface=metafun")) {
140 return 2 ;
141 } else if (styler.SafeGetCharAt(1) == 'D' && strstr(lineBuffer, "%D \\module")) {
142 // better would be to limit the search to just one line
143 return 2 ;
144 } else {
145 return defaultInterface ;
151 return defaultInterface ;
154 static void ColouriseMETAPOSTDoc(
155 Sci_PositionU startPos,
156 Sci_Position length,
157 int,
158 WordList *keywordlists[],
159 Accessor &styler) {
161 styler.StartAt(startPos) ;
162 styler.StartSegment(startPos) ;
164 bool processComment = styler.GetPropertyInt("lexer.metapost.comment.process", 0) == 1 ;
165 int defaultInterface = styler.GetPropertyInt("lexer.metapost.interface.default", 1) ;
167 int currentInterface = CheckMETAPOSTInterface(startPos,length,styler,defaultInterface) ;
169 // 0 no keyword highlighting
170 // 1 metapost keyword hightlighting
171 // 2+ metafun keyword hightlighting
173 int extraInterface = 0 ;
175 if (currentInterface != 0) {
176 extraInterface = currentInterface ;
179 WordList &keywords = *keywordlists[0] ;
180 WordList &keywords2 = *keywordlists[extraInterface-1] ;
182 StyleContext sc(startPos, length, SCE_METAPOST_TEXT, styler) ;
184 char key[100] ;
186 bool inTeX = false ;
187 bool inComment = false ;
188 bool inString = false ;
189 bool inClause = false ;
191 bool going = sc.More() ; // needed because of a fuzzy end of file state
193 for (; going; sc.Forward()) {
195 if (! sc.More()) { going = false ; } // we need to go one behind the end of text
197 if (inClause) {
198 sc.SetState(SCE_METAPOST_TEXT) ;
199 inClause = false ;
202 if (inComment) {
203 if (sc.atLineEnd) {
204 sc.SetState(SCE_METAPOST_TEXT) ;
205 inTeX = false ;
206 inComment = false ;
207 inClause = false ;
208 inString = false ; // not correct but we want to stimulate one-lines
210 } else if (inString) {
211 if (isMETAPOSTstring(sc.ch)) {
212 sc.SetState(SCE_METAPOST_SPECIAL) ;
213 sc.ForwardSetState(SCE_METAPOST_TEXT) ;
214 inString = false ;
215 } else if (sc.atLineEnd) {
216 sc.SetState(SCE_METAPOST_TEXT) ;
217 inTeX = false ;
218 inComment = false ;
219 inClause = false ;
220 inString = false ; // not correct but we want to stimulate one-lines
222 } else {
223 if ((! isMETAPOSTidentifier(sc.ch)) && (sc.LengthCurrent() > 0)) {
224 if (sc.state == SCE_METAPOST_COMMAND) {
225 sc.GetCurrent(key, sizeof(key)) ;
226 if ((strcmp(key,"btex") == 0) || (strcmp(key,"verbatimtex") == 0)) {
227 sc.ChangeState(SCE_METAPOST_GROUP) ;
228 inTeX = true ;
229 } else if (inTeX) {
230 if (strcmp(key,"etex") == 0) {
231 sc.ChangeState(SCE_METAPOST_GROUP) ;
232 inTeX = false ;
233 } else {
234 sc.ChangeState(SCE_METAPOST_TEXT) ;
236 } else {
237 if (keywords && keywords.InList(key)) {
238 sc.ChangeState(SCE_METAPOST_COMMAND) ;
239 } else if (keywords2 && keywords2.InList(key)) {
240 sc.ChangeState(SCE_METAPOST_EXTRA) ;
241 } else {
242 sc.ChangeState(SCE_METAPOST_TEXT) ;
247 if (isMETAPOSTcomment(sc.ch)) {
248 if (! inTeX) {
249 sc.SetState(SCE_METAPOST_SYMBOL) ;
250 sc.ForwardSetState(SCE_METAPOST_DEFAULT) ;
251 inComment = ! processComment ;
252 } else {
253 sc.SetState(SCE_METAPOST_TEXT) ;
255 } else if (isMETAPOSTstring(sc.ch)) {
256 if (! inTeX) {
257 sc.SetState(SCE_METAPOST_SPECIAL) ;
258 if (! isMETAPOSTstring(sc.chNext)) {
259 sc.ForwardSetState(SCE_METAPOST_TEXT) ;
261 inString = true ;
262 } else {
263 sc.SetState(SCE_METAPOST_TEXT) ;
265 } else if (isMETAPOSTcolon(sc.ch)) {
266 if (! inTeX) {
267 if (! isMETAPOSTequal(sc.chNext)) {
268 sc.SetState(SCE_METAPOST_COMMAND) ;
269 inClause = true ;
270 } else {
271 sc.SetState(SCE_METAPOST_SPECIAL) ;
273 } else {
274 sc.SetState(SCE_METAPOST_TEXT) ;
276 } else if (isMETAPOSTone(sc.ch)) {
277 if (! inTeX) {
278 sc.SetState(SCE_METAPOST_SPECIAL) ;
279 } else {
280 sc.SetState(SCE_METAPOST_TEXT) ;
282 } else if (isMETAPOSTtwo(sc.ch)) {
283 if (! inTeX) {
284 sc.SetState(SCE_METAPOST_GROUP) ;
285 } else {
286 sc.SetState(SCE_METAPOST_TEXT) ;
288 } else if (isMETAPOSTthree(sc.ch)) {
289 if (! inTeX) {
290 sc.SetState(SCE_METAPOST_SYMBOL) ;
291 } else {
292 sc.SetState(SCE_METAPOST_TEXT) ;
294 } else if (isMETAPOSTidentifier(sc.ch)) {
295 if (sc.state != SCE_METAPOST_COMMAND) {
296 sc.SetState(SCE_METAPOST_TEXT) ;
297 sc.ChangeState(SCE_METAPOST_COMMAND) ;
299 } else if (isMETAPOSTnumber(sc.ch)) {
300 // rather redundant since for the moment we don't handle numbers
301 sc.SetState(SCE_METAPOST_TEXT) ;
302 } else if (sc.atLineEnd) {
303 sc.SetState(SCE_METAPOST_TEXT) ;
304 inTeX = false ;
305 inComment = false ;
306 inClause = false ;
307 inString = false ;
308 } else {
309 sc.SetState(SCE_METAPOST_TEXT) ;
315 sc.Complete();
319 // Hooks info the system:
321 static const char * const metapostWordListDesc[] = {
322 "MetaPost",
323 "MetaFun",
327 static int classifyFoldPointMetapost(const char* s,WordList *keywordlists[]) {
328 WordList& keywordsStart=*keywordlists[3];
329 WordList& keywordsStop1=*keywordlists[4];
331 if (keywordsStart.InList(s)) {return 1;}
332 else if (keywordsStop1.InList(s)) {return -1;}
333 return 0;
337 static int ParseMetapostWord(Sci_PositionU pos, Accessor &styler, char *word)
339 int length=0;
340 char ch=styler.SafeGetCharAt(pos);
341 *word=0;
343 while(isMETAPOSTidentifier(ch) && isalpha(ch) && length<100){
344 word[length]=ch;
345 length++;
346 ch=styler.SafeGetCharAt(pos+length);
348 word[length]=0;
349 return length;
352 static void FoldMetapostDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *keywordlists[], Accessor &styler)
354 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
355 Sci_PositionU endPos = startPos+length;
356 int visibleChars=0;
357 Sci_Position lineCurrent=styler.GetLine(startPos);
358 int levelPrev=styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
359 int levelCurrent=levelPrev;
360 char chNext=styler[startPos];
362 char buffer[100]="";
364 for (Sci_PositionU i=startPos; i < endPos; i++) {
365 char ch=chNext;
366 chNext=styler.SafeGetCharAt(i+1);
367 char chPrev=styler.SafeGetCharAt(i-1);
368 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
370 if(i==0 || chPrev == '\r' || chPrev=='\n'|| chPrev==' '|| chPrev=='(' || chPrev=='$')
372 ParseMetapostWord(i, styler, buffer);
373 levelCurrent += classifyFoldPointMetapost(buffer,keywordlists);
376 if (atEOL) {
377 int lev = levelPrev;
378 if (visibleChars == 0 && foldCompact)
379 lev |= SC_FOLDLEVELWHITEFLAG;
380 if ((levelCurrent > levelPrev) && (visibleChars > 0))
381 lev |= SC_FOLDLEVELHEADERFLAG;
382 if (lev != styler.LevelAt(lineCurrent)) {
383 styler.SetLevel(lineCurrent, lev);
385 lineCurrent++;
386 levelPrev = levelCurrent;
387 visibleChars = 0;
390 if (!isspacechar(ch))
391 visibleChars++;
393 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
394 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
395 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
400 LexerModule lmMETAPOST(SCLEX_METAPOST, ColouriseMETAPOSTDoc, "metapost", FoldMetapostDoc, metapostWordListDesc);