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
7 // Copyright: 1998-2003 by Neil Hodgson <neilh@scintilla.org>
8 // The License.txt file describes the conditions under which this software may be distributed.
10 // This lexer is derived from the one written for the texwork environment (1999++) which in
11 // turn is inspired on texedit (1991++) which finds its roots in wdt (1986).
24 #include "Scintilla.h"
26 #include "StyleContext.h"
28 // val SCE_METAPOST_DEFAULT = 0
29 // val SCE_METAPOST_SPECIAL = 1
30 // val SCE_METAPOST_GROUP = 2
31 // val SCE_METAPOST_SYMBOL = 3
32 // val SCE_METAPOST_COMMAND = 4
33 // val SCE_METAPOST_TEXT = 5
35 // Definitions in SciTEGlobal.properties:
37 // Metapost Highlighting
40 // style.metapost.0=fore:#7F7F00
42 // style.metapost.1=fore:#007F7F
44 // style.metapost.2=fore:#880000
46 // style.metapost.3=fore:#7F7F00
48 // style.metapost.4=fore:#008800
50 // style.metapost.5=fore:#000000
52 // lexer.tex.comment.process=0
54 // Auxiliary functions:
56 static inline bool endOfLine(Accessor
&styler
, unsigned int i
) {
58 (styler
[i
] == '\n') || ((styler
[i
] == '\r') && (styler
.SafeGetCharAt(i
+ 1) != '\n')) ;
61 static inline bool isMETAPOSTcomment(int ch
) {
66 static inline bool isMETAPOSTone(int ch
) {
68 (ch
== '[') || (ch
== ']') || (ch
== '(') || (ch
== ')') ||
69 (ch
== ':') || (ch
== '=') || (ch
== '<') || (ch
== '>') ||
70 (ch
== '{') || (ch
== '}') || (ch
== '\'') || (ch
== '\"') ;
73 static inline bool isMETAPOSTtwo(int ch
) {
75 (ch
== ';') || (ch
== '$') || (ch
== '@') || (ch
== '#');
78 static inline bool isMETAPOSTthree(int ch
) {
80 (ch
== '.') || (ch
== '-') || (ch
== '+') || (ch
== '/') ||
81 (ch
== '*') || (ch
== ',') || (ch
== '|') || (ch
== '`') ||
82 (ch
== '!') || (ch
== '?') || (ch
== '^') || (ch
== '&') ||
86 static inline bool isMETAPOSTidentifier(int ch
) {
88 ((ch
>= 'a') && (ch
<= 'z')) || ((ch
>= 'A') && (ch
<= 'Z')) ||
92 static inline bool isMETAPOSTnumber(int ch
) {
94 (ch
>= '0') && (ch
<= '9') ;
97 static inline bool isMETAPOSTstring(int ch
) {
102 static inline bool isMETAPOSTcolon(int ch
) {
107 static inline bool isMETAPOSTequal(int ch
) {
112 static int CheckMETAPOSTInterface(
113 unsigned int startPos
,
116 int defaultInterface
) {
118 char lineBuffer
[1024] ;
119 unsigned int linePos
= 0 ;
121 // some day we can make something lexer.metapost.mapping=(none,0)(metapost,1)(mp,1)(metafun,2)...
123 if (styler
.SafeGetCharAt(0) == '%') {
124 for (unsigned int i
= 0; i
< startPos
+ length
; i
++) {
125 lineBuffer
[linePos
++] = styler
.SafeGetCharAt(i
) ;
126 if (endOfLine(styler
, i
) || (linePos
>= sizeof(lineBuffer
) - 1)) {
127 lineBuffer
[linePos
] = '\0';
128 if (strstr(lineBuffer
, "interface=none")) {
130 } else if (strstr(lineBuffer
, "interface=metapost") || strstr(lineBuffer
, "interface=mp")) {
132 } else if (strstr(lineBuffer
, "interface=metafun")) {
134 } else if (styler
.SafeGetCharAt(1) == 'D' && strstr(lineBuffer
, "%D \\module")) {
135 // better would be to limit the search to just one line
138 return defaultInterface
;
144 return defaultInterface
;
147 static void ColouriseMETAPOSTDoc(
148 unsigned int startPos
,
151 WordList
*keywordlists
[],
154 styler
.StartAt(startPos
) ;
155 styler
.StartSegment(startPos
) ;
157 bool processComment
= styler
.GetPropertyInt("lexer.metapost.comment.process", 0) == 1 ;
158 int defaultInterface
= styler
.GetPropertyInt("lexer.metapost.interface.default", 1) ;
160 int currentInterface
= CheckMETAPOSTInterface(startPos
,length
,styler
,defaultInterface
) ;
162 // 0 no keyword highlighting
163 // 1 metapost keyword hightlighting
164 // 2+ metafun keyword hightlighting
166 int extraInterface
= 0 ;
168 if (currentInterface
!= 0) {
169 extraInterface
= currentInterface
;
172 WordList
&keywords
= *keywordlists
[0] ;
173 WordList
&keywords2
= *keywordlists
[extraInterface
-1] ;
175 StyleContext
sc(startPos
, length
, SCE_METAPOST_TEXT
, styler
) ;
180 bool inComment
= false ;
181 bool inString
= false ;
182 bool inClause
= false ;
184 bool going
= sc
.More() ; // needed because of a fuzzy end of file state
186 for (; going
; sc
.Forward()) {
188 if (! sc
.More()) { going
= false ; } // we need to go one behind the end of text
191 sc
.SetState(SCE_METAPOST_TEXT
) ;
197 sc
.SetState(SCE_METAPOST_TEXT
) ;
201 inString
= false ; // not correct but we want to stimulate one-lines
203 } else if (inString
) {
204 if (isMETAPOSTstring(sc
.ch
)) {
205 sc
.SetState(SCE_METAPOST_SPECIAL
) ;
206 sc
.ForwardSetState(SCE_METAPOST_TEXT
) ;
208 } else if (sc
.atLineEnd
) {
209 sc
.SetState(SCE_METAPOST_TEXT
) ;
213 inString
= false ; // not correct but we want to stimulate one-lines
216 if ((! isMETAPOSTidentifier(sc
.ch
)) && (sc
.LengthCurrent() > 0)) {
217 if (sc
.state
== SCE_METAPOST_COMMAND
) {
218 sc
.GetCurrent(key
, sizeof(key
)) ;
219 if ((strcmp(key
,"btex") == 0) || (strcmp(key
,"verbatimtex") == 0)) {
220 sc
.ChangeState(SCE_METAPOST_GROUP
) ;
223 if (strcmp(key
,"etex") == 0) {
224 sc
.ChangeState(SCE_METAPOST_GROUP
) ;
227 sc
.ChangeState(SCE_METAPOST_TEXT
) ;
230 if (keywords
&& keywords
.InList(key
)) {
231 sc
.ChangeState(SCE_METAPOST_COMMAND
) ;
232 } else if (keywords2
&& keywords2
.InList(key
)) {
233 sc
.ChangeState(SCE_METAPOST_EXTRA
) ;
235 sc
.ChangeState(SCE_METAPOST_TEXT
) ;
240 if (isMETAPOSTcomment(sc
.ch
)) {
242 sc
.SetState(SCE_METAPOST_SYMBOL
) ;
243 sc
.ForwardSetState(SCE_METAPOST_DEFAULT
) ;
244 inComment
= ! processComment
;
246 sc
.SetState(SCE_METAPOST_TEXT
) ;
248 } else if (isMETAPOSTstring(sc
.ch
)) {
250 sc
.SetState(SCE_METAPOST_SPECIAL
) ;
251 if (! isMETAPOSTstring(sc
.chNext
)) {
252 sc
.ForwardSetState(SCE_METAPOST_TEXT
) ;
256 sc
.SetState(SCE_METAPOST_TEXT
) ;
258 } else if (isMETAPOSTcolon(sc
.ch
)) {
260 if (! isMETAPOSTequal(sc
.chNext
)) {
261 sc
.SetState(SCE_METAPOST_COMMAND
) ;
264 sc
.SetState(SCE_METAPOST_SPECIAL
) ;
267 sc
.SetState(SCE_METAPOST_TEXT
) ;
269 } else if (isMETAPOSTone(sc
.ch
)) {
271 sc
.SetState(SCE_METAPOST_SPECIAL
) ;
273 sc
.SetState(SCE_METAPOST_TEXT
) ;
275 } else if (isMETAPOSTtwo(sc
.ch
)) {
277 sc
.SetState(SCE_METAPOST_GROUP
) ;
279 sc
.SetState(SCE_METAPOST_TEXT
) ;
281 } else if (isMETAPOSTthree(sc
.ch
)) {
283 sc
.SetState(SCE_METAPOST_SYMBOL
) ;
285 sc
.SetState(SCE_METAPOST_TEXT
) ;
287 } else if (isMETAPOSTidentifier(sc
.ch
)) {
288 if (sc
.state
!= SCE_METAPOST_COMMAND
) {
289 sc
.SetState(SCE_METAPOST_TEXT
) ;
290 sc
.ChangeState(SCE_METAPOST_COMMAND
) ;
292 } else if (isMETAPOSTnumber(sc
.ch
)) {
293 // rather redundant since for the moment we don't handle numbers
294 sc
.SetState(SCE_METAPOST_TEXT
) ;
295 } else if (sc
.atLineEnd
) {
296 sc
.SetState(SCE_METAPOST_TEXT
) ;
302 sc
.SetState(SCE_METAPOST_TEXT
) ;
312 // Hooks info the system:
314 static const char * const metapostWordListDesc
[] = {
320 LexerModule
lmMETAPOST(SCLEX_METAPOST
, ColouriseMETAPOSTDoc
, "metapost", 0, metapostWordListDesc
);