*** empty log message ***
[anjuta-git-plugin.git] / scintilla / LexTeX.cxx
bloba5b09467019282f8f7036a94ce7d09bae9aedc73
1 // Scintilla source code edit control
3 // File: LexTeX.cxx - general context conformant tex 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).
13 // If you run into strange boundary cases, just tell me and I'll look into it.
15 #include <stdlib.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <stdio.h>
19 #include <stdarg.h>
21 #include "Platform.h"
23 #include "PropSet.h"
24 #include "Accessor.h"
25 #include "KeyWords.h"
26 #include "Scintilla.h"
27 #include "SciLexer.h"
28 #include "StyleContext.h"
30 // val SCE_TEX_DEFAULT = 0
31 // val SCE_TEX_SPECIAL = 1
32 // val SCE_TEX_GROUP = 2
33 // val SCE_TEX_SYMBOL = 3
34 // val SCE_TEX_COMMAND = 4
35 // val SCE_TEX_TEXT = 5
37 // Definitions in SciTEGlobal.properties:
39 // TeX Highlighting
41 // # Default
42 // style.tex.0=fore:#7F7F00
43 // # Special
44 // style.tex.1=fore:#007F7F
45 // # Group
46 // style.tex.2=fore:#880000
47 // # Symbol
48 // style.tex.3=fore:#7F7F00
49 // # Command
50 // style.tex.4=fore:#008800
51 // # Text
52 // style.tex.5=fore:#000000
54 // lexer.tex.interface.default=0
55 // lexer.tex.comment.process=0
57 // todo: lexer.tex.auto.if
59 // Auxiliary functions:
61 static inline bool endOfLine(Accessor &styler, unsigned int i) {
62 return
63 (styler[i] == '\n') || ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n')) ;
66 static inline bool isTeXzero(int ch) {
67 return
68 (ch == '%') ;
71 static inline bool isTeXone(int ch) {
72 return
73 (ch == '[') || (ch == ']') || (ch == '=') || (ch == '#') ||
74 (ch == '(') || (ch == ')') || (ch == '<') || (ch == '>') ||
75 (ch == '"') ;
78 static inline bool isTeXtwo(int ch) {
79 return
80 (ch == '{') || (ch == '}') || (ch == '$') ;
83 static inline bool isTeXthree(int ch) {
84 return
85 (ch == '~') || (ch == '^') || (ch == '_') || (ch == '&') ||
86 (ch == '-') || (ch == '+') || (ch == '\"') || (ch == '`') ||
87 (ch == '/') || (ch == '|') || (ch == '%') ;
90 static inline bool isTeXfour(int ch) {
91 return
92 (ch == '\\') ;
95 static inline bool isTeXfive(int ch) {
96 return
97 ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) ||
98 (ch == '@') || (ch == '!') || (ch == '?') ;
101 static inline bool isTeXsix(int ch) {
102 return
103 (ch == ' ') ;
106 static inline bool isTeXseven(int ch) {
107 return
108 (ch == '^') ;
111 // Interface determination
113 static int CheckTeXInterface(
114 unsigned int startPos,
115 int length,
116 Accessor &styler,
117 int defaultInterface) {
119 char lineBuffer[1024] ;
120 unsigned int linePos = 0 ;
122 // some day we can make something lexer.tex.mapping=(all,0)(nl,1)(en,2)...
124 if (styler.SafeGetCharAt(0) == '%') {
125 for (unsigned int i = 0; i < startPos + length; i++) {
126 lineBuffer[linePos++] = styler.SafeGetCharAt(i) ;
127 if (endOfLine(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {
128 lineBuffer[linePos] = '\0';
129 if (strstr(lineBuffer, "interface=all")) {
130 return 0 ;
131 } else if (strstr(lineBuffer, "interface=tex")) {
132 return 1 ;
133 } else if (strstr(lineBuffer, "interface=nl")) {
134 return 2 ;
135 } else if (strstr(lineBuffer, "interface=en")) {
136 return 3 ;
137 } else if (strstr(lineBuffer, "interface=de")) {
138 return 4 ;
139 } else if (strstr(lineBuffer, "interface=cz")) {
140 return 5 ;
141 } else if (strstr(lineBuffer, "interface=it")) {
142 return 6 ;
143 } else if (strstr(lineBuffer, "interface=ro")) {
144 return 7 ;
145 } else if (strstr(lineBuffer, "interface=latex")) {
146 // we will move latex cum suis up to 91+ when more keyword lists are supported
147 return 8 ;
148 } else if (styler.SafeGetCharAt(1) == 'D' && strstr(lineBuffer, "%D \\module")) {
149 // better would be to limit the search to just one line
150 return 3 ;
151 } else {
152 return defaultInterface ;
158 return defaultInterface ;
161 static void ColouriseTeXDoc(
162 unsigned int startPos,
163 int length,
164 int,
165 WordList *keywordlists[],
166 Accessor &styler) {
168 styler.StartAt(startPos) ;
169 styler.StartSegment(startPos) ;
171 bool processComment = styler.GetPropertyInt("lexer.tex.comment.process", 0) == 1 ;
172 bool useKeywords = styler.GetPropertyInt("lexer.tex.use.keywords", 1) == 1 ;
173 bool autoIf = styler.GetPropertyInt("lexer.tex.auto.if", 1) == 1 ;
174 int defaultInterface = styler.GetPropertyInt("lexer.tex.interface.default", 1) ;
176 char key[100] ;
177 int k ;
178 bool newifDone = false ;
179 bool inComment = false ;
181 int currentInterface = CheckTeXInterface(startPos,length,styler,defaultInterface) ;
183 if (currentInterface == 0) {
184 useKeywords = false ;
185 currentInterface = 1 ;
188 WordList &keywords = *keywordlists[currentInterface-1] ;
190 StyleContext sc(startPos, length, SCE_TEX_TEXT, styler);
192 bool going = sc.More() ; // needed because of a fuzzy end of file state
194 for (; going; sc.Forward()) {
196 if (! sc.More()) { going = false ; } // we need to go one behind the end of text
198 if (inComment) {
199 if (sc.atLineEnd) {
200 sc.SetState(SCE_TEX_TEXT) ;
201 newifDone = false ;
202 inComment = false ;
204 } else {
205 if (! isTeXfive(sc.ch)) {
206 if (sc.state == SCE_TEX_COMMAND) {
207 if (sc.LengthCurrent() == 1) { // \<noncstoken>
208 if (isTeXseven(sc.ch) && isTeXseven(sc.chNext)) {
209 sc.Forward(2) ; // \^^ and \^^<token>
211 sc.ForwardSetState(SCE_TEX_TEXT) ;
212 } else {
213 sc.GetCurrent(key, sizeof(key)-1) ;
214 k = strlen(key) ;
215 memmove(key,key+1,k) ; // shift left over escape token
216 key[k] = '\0' ;
217 k-- ;
218 if (! keywords || ! useKeywords) {
219 sc.SetState(SCE_TEX_COMMAND) ;
220 newifDone = false ;
221 } else if (k == 1) { //\<cstoken>
222 sc.SetState(SCE_TEX_COMMAND) ;
223 newifDone = false ;
224 } else if (keywords.InList(key)) {
225 sc.SetState(SCE_TEX_COMMAND) ;
226 newifDone = autoIf && (strcmp(key,"newif") == 0) ;
227 } else if (autoIf && ! newifDone && (key[0] == 'i') && (key[1] == 'f') && keywords.InList("if")) {
228 sc.SetState(SCE_TEX_COMMAND) ;
229 } else {
230 sc.ChangeState(SCE_TEX_TEXT) ;
231 sc.SetState(SCE_TEX_TEXT) ;
232 newifDone = false ;
236 if (isTeXzero(sc.ch)) {
237 sc.SetState(SCE_TEX_SYMBOL) ;
238 sc.ForwardSetState(SCE_TEX_DEFAULT) ;
239 inComment = ! processComment ;
240 newifDone = false ;
241 } else if (isTeXseven(sc.ch) && isTeXseven(sc.chNext)) {
242 sc.SetState(SCE_TEX_TEXT) ;
243 sc.ForwardSetState(SCE_TEX_TEXT) ;
244 } else if (isTeXone(sc.ch)) {
245 sc.SetState(SCE_TEX_SPECIAL) ;
246 newifDone = false ;
247 } else if (isTeXtwo(sc.ch)) {
248 sc.SetState(SCE_TEX_GROUP) ;
249 newifDone = false ;
250 } else if (isTeXthree(sc.ch)) {
251 sc.SetState(SCE_TEX_SYMBOL) ;
252 newifDone = false ;
253 } else if (isTeXfour(sc.ch)) {
254 sc.SetState(SCE_TEX_COMMAND) ;
255 } else if (isTeXsix(sc.ch)) {
256 sc.SetState(SCE_TEX_TEXT) ;
257 } else if (sc.atLineEnd) {
258 sc.SetState(SCE_TEX_TEXT) ;
259 newifDone = false ;
260 inComment = false ;
261 } else {
262 sc.SetState(SCE_TEX_TEXT) ;
264 } else if (sc.state != SCE_TEX_COMMAND) {
265 sc.SetState(SCE_TEX_TEXT) ;
269 sc.ChangeState(SCE_TEX_TEXT) ;
270 sc.Complete();
275 // Hooks into the system:
277 static const char * const texWordListDesc[] = {
278 "TeX, eTeX, pdfTeX, Omega"
279 "ConTeXt Dutch",
280 "ConTeXt English",
281 "ConTeXt German",
282 "ConTeXt Czech",
283 "ConTeXt Italian",
284 "ConTeXt Romanian",
288 LexerModule lmTeX(SCLEX_TEX, ColouriseTeXDoc, "tex", 0, texWordListDesc);