OSDN Git Service

Commit DialogBox compile Okay
[tortoisegit/TortoiseGitJp.git] / ext / scintilla / src / LexTeX.cxx
1 // Scintilla source code edit control\r
2 \r
3 // File: LexTeX.cxx - general context conformant tex coloring scheme\r
4 // Author: Hans Hagen - PRAGMA ADE - Hasselt NL - www.pragma-ade.com\r
5 // Version: September 28, 2003\r
6 \r
7 // Copyright: 1998-2003 by Neil Hodgson <neilh@scintilla.org>\r
8 // The License.txt file describes the conditions under which this software may be distributed.\r
9 \r
10 // This lexer is derived from the one written for the texwork environment (1999++) which in\r
11 // turn is inspired on texedit (1991++) which finds its roots in wdt (1986).\r
12 \r
13 // If you run into strange boundary cases, just tell me and I'll look into it.\r
14 \r
15 \r
16 // TeX Folding code added by instanton (soft_share@126.com) with borrowed code from VisualTeX source by Alex Romanenko.\r
17 // Version: June 22, 2007\r
18 \r
19 #include <stdlib.h>\r
20 #include <string.h>\r
21 #include <ctype.h>\r
22 #include <stdio.h>\r
23 #include <stdarg.h>\r
24 \r
25 #include "Platform.h"\r
26 \r
27 #include "PropSet.h"\r
28 #include "Accessor.h"\r
29 #include "KeyWords.h"\r
30 #include "Scintilla.h"\r
31 #include "SciLexer.h"\r
32 #include "StyleContext.h"\r
33 \r
34 #ifdef SCI_NAMESPACE\r
35 using namespace Scintilla;\r
36 #endif\r
37 \r
38 // val SCE_TEX_DEFAULT = 0\r
39 // val SCE_TEX_SPECIAL = 1\r
40 // val SCE_TEX_GROUP   = 2\r
41 // val SCE_TEX_SYMBOL  = 3\r
42 // val SCE_TEX_COMMAND = 4\r
43 // val SCE_TEX_TEXT    = 5\r
44 \r
45 // Definitions in SciTEGlobal.properties:\r
46 //\r
47 // TeX Highlighting\r
48 //\r
49 // # Default\r
50 // style.tex.0=fore:#7F7F00\r
51 // # Special\r
52 // style.tex.1=fore:#007F7F\r
53 // # Group\r
54 // style.tex.2=fore:#880000\r
55 // # Symbol\r
56 // style.tex.3=fore:#7F7F00\r
57 // # Command\r
58 // style.tex.4=fore:#008800\r
59 // # Text\r
60 // style.tex.5=fore:#000000\r
61 \r
62 // lexer.tex.interface.default=0\r
63 // lexer.tex.comment.process=0\r
64 \r
65 // todo: lexer.tex.auto.if\r
66 \r
67 // Auxiliary functions:\r
68 \r
69 static inline bool endOfLine(Accessor &styler, unsigned int i) {\r
70         return\r
71       (styler[i] == '\n') || ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n')) ;\r
72 }\r
73 \r
74 static inline bool isTeXzero(int ch) {\r
75         return\r
76       (ch == '%') ;\r
77 }\r
78 \r
79 static inline bool isTeXone(int ch) {\r
80         return\r
81       (ch == '[') || (ch == ']') || (ch == '=') || (ch == '#') ||\r
82       (ch == '(') || (ch == ')') || (ch == '<') || (ch == '>') ||\r
83       (ch == '"') ;\r
84 }\r
85 \r
86 static inline bool isTeXtwo(int ch) {\r
87         return\r
88       (ch == '{') || (ch == '}') || (ch == '$') ;\r
89 }\r
90 \r
91 static inline bool isTeXthree(int ch) {\r
92         return\r
93       (ch == '~') || (ch == '^') || (ch == '_') || (ch == '&') ||\r
94       (ch == '-') || (ch == '+') || (ch == '\"') || (ch == '`') ||\r
95       (ch == '/') || (ch == '|') || (ch == '%') ;\r
96 }\r
97 \r
98 static inline bool isTeXfour(int ch) {\r
99         return\r
100       (ch == '\\') ;\r
101 }\r
102 \r
103 static inline bool isTeXfive(int ch) {\r
104         return\r
105       ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) ||\r
106       (ch == '@') || (ch == '!') || (ch == '?') ;\r
107 }\r
108 \r
109 static inline bool isTeXsix(int ch) {\r
110         return\r
111       (ch == ' ') ;\r
112 }\r
113 \r
114 static inline bool isTeXseven(int ch) {\r
115         return\r
116       (ch == '^') ;\r
117 }\r
118 \r
119 // Interface determination\r
120 \r
121 static int CheckTeXInterface(\r
122     unsigned int startPos,\r
123     int length,\r
124     Accessor &styler,\r
125         int defaultInterface) {\r
126 \r
127     char lineBuffer[1024] ;\r
128         unsigned int linePos = 0 ;\r
129 \r
130     // some day we can make something lexer.tex.mapping=(all,0)(nl,1)(en,2)...\r
131 \r
132     if (styler.SafeGetCharAt(0) == '%') {\r
133         for (unsigned int i = 0; i < startPos + length; i++) {\r
134             lineBuffer[linePos++] = styler.SafeGetCharAt(i) ;\r
135             if (endOfLine(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {\r
136                 lineBuffer[linePos] = '\0';\r
137                 if (strstr(lineBuffer, "interface=all")) {\r
138                     return 0 ;\r
139                                 } else if (strstr(lineBuffer, "interface=tex")) {\r
140                     return 1 ;\r
141                 } else if (strstr(lineBuffer, "interface=nl")) {\r
142                     return 2 ;\r
143                 } else if (strstr(lineBuffer, "interface=en")) {\r
144                     return 3 ;\r
145                 } else if (strstr(lineBuffer, "interface=de")) {\r
146                     return 4 ;\r
147                 } else if (strstr(lineBuffer, "interface=cz")) {\r
148                     return 5 ;\r
149                 } else if (strstr(lineBuffer, "interface=it")) {\r
150                     return 6 ;\r
151                 } else if (strstr(lineBuffer, "interface=ro")) {\r
152                     return 7 ;\r
153                 } else if (strstr(lineBuffer, "interface=latex")) {\r
154                                         // we will move latex cum suis up to 91+ when more keyword lists are supported\r
155                     return 8 ;\r
156                                 } else if (styler.SafeGetCharAt(1) == 'D' && strstr(lineBuffer, "%D \\module")) {\r
157                                         // better would be to limit the search to just one line\r
158                                         return 3 ;\r
159                 } else {\r
160                     return defaultInterface ;\r
161                 }\r
162             }\r
163                 }\r
164     }\r
165 \r
166     return defaultInterface ;\r
167 }\r
168 \r
169 static void ColouriseTeXDoc(\r
170     unsigned int startPos,\r
171     int length,\r
172     int,\r
173     WordList *keywordlists[],\r
174     Accessor &styler) {\r
175 \r
176         styler.StartAt(startPos) ;\r
177         styler.StartSegment(startPos) ;\r
178 \r
179         bool processComment   = styler.GetPropertyInt("lexer.tex.comment.process",   0) == 1 ;\r
180         bool useKeywords      = styler.GetPropertyInt("lexer.tex.use.keywords",      1) == 1 ;\r
181         bool autoIf           = styler.GetPropertyInt("lexer.tex.auto.if",           1) == 1 ;\r
182         int  defaultInterface = styler.GetPropertyInt("lexer.tex.interface.default", 1) ;\r
183 \r
184         char key[100] ;\r
185         int  k ;\r
186         bool newifDone = false ;\r
187         bool inComment = false ;\r
188 \r
189         int currentInterface = CheckTeXInterface(startPos,length,styler,defaultInterface) ;\r
190 \r
191     if (currentInterface == 0) {\r
192         useKeywords = false ;\r
193         currentInterface = 1 ;\r
194     }\r
195 \r
196     WordList &keywords = *keywordlists[currentInterface-1] ;\r
197 \r
198         StyleContext sc(startPos, length, SCE_TEX_TEXT, styler);\r
199 \r
200         bool going = sc.More() ; // needed because of a fuzzy end of file state\r
201 \r
202         for (; going; sc.Forward()) {\r
203 \r
204                 if (! sc.More()) { going = false ; } // we need to go one behind the end of text\r
205 \r
206                 if (inComment) {\r
207                         if (sc.atLineEnd) {\r
208                                 sc.SetState(SCE_TEX_TEXT) ;\r
209                                 newifDone = false ;\r
210                                 inComment = false ;\r
211                         }\r
212                 } else {\r
213                         if (! isTeXfive(sc.ch)) {\r
214                                 if (sc.state == SCE_TEX_COMMAND) {\r
215                                         if (sc.LengthCurrent() == 1) { // \<noncstoken>\r
216                                                 if (isTeXseven(sc.ch) && isTeXseven(sc.chNext)) {\r
217                                                         sc.Forward(2) ; // \^^ and \^^<token>\r
218                                                 }\r
219                                                 sc.ForwardSetState(SCE_TEX_TEXT) ;\r
220                                         } else {\r
221                                                 sc.GetCurrent(key, sizeof(key)-1) ;\r
222                                                 k = strlen(key) ;\r
223                                                 memmove(key,key+1,k) ; // shift left over escape token\r
224                                                 key[k] = '\0' ;\r
225                                                 k-- ;\r
226                                                 if (! keywords || ! useKeywords) {\r
227                                                         sc.SetState(SCE_TEX_COMMAND) ;\r
228                                                         newifDone = false ;\r
229                                                 } else if (k == 1) { //\<cstoken>\r
230                                                         sc.SetState(SCE_TEX_COMMAND) ;\r
231                                                         newifDone = false ;\r
232                                                 } else if (keywords.InList(key)) {\r
233                                                 sc.SetState(SCE_TEX_COMMAND) ;\r
234                                                         newifDone = autoIf && (strcmp(key,"newif") == 0) ;\r
235                                                 } else if (autoIf && ! newifDone && (key[0] == 'i') && (key[1] == 'f') && keywords.InList("if")) {\r
236                                                 sc.SetState(SCE_TEX_COMMAND) ;\r
237                                                 } else {\r
238                                                         sc.ChangeState(SCE_TEX_TEXT) ;\r
239                                                         sc.SetState(SCE_TEX_TEXT) ;\r
240                                                         newifDone = false ;\r
241                                                 }\r
242                                         }\r
243                                 }\r
244                                 if (isTeXzero(sc.ch)) {\r
245                                         sc.SetState(SCE_TEX_SYMBOL) ;\r
246                                         sc.ForwardSetState(SCE_TEX_DEFAULT) ;\r
247                                         inComment = ! processComment ;\r
248                                         newifDone = false ;\r
249                                 } else if (isTeXseven(sc.ch) && isTeXseven(sc.chNext)) {\r
250                                         sc.SetState(SCE_TEX_TEXT) ;\r
251                                         sc.ForwardSetState(SCE_TEX_TEXT) ;\r
252                                 } else if (isTeXone(sc.ch)) {\r
253                                         sc.SetState(SCE_TEX_SPECIAL) ;\r
254                                         newifDone = false ;\r
255                                 } else if (isTeXtwo(sc.ch)) {\r
256                                         sc.SetState(SCE_TEX_GROUP) ;\r
257                                         newifDone = false ;\r
258                                 } else if (isTeXthree(sc.ch)) {\r
259                                         sc.SetState(SCE_TEX_SYMBOL) ;\r
260                                         newifDone = false ;\r
261                                 } else if (isTeXfour(sc.ch)) {\r
262                                         sc.SetState(SCE_TEX_COMMAND) ;\r
263                                 } else if (isTeXsix(sc.ch)) {\r
264                                         sc.SetState(SCE_TEX_TEXT) ;\r
265                                 } else if (sc.atLineEnd) {\r
266                                         sc.SetState(SCE_TEX_TEXT) ;\r
267                                         newifDone = false ;\r
268                                         inComment = false ;\r
269                                 } else {\r
270                                         sc.SetState(SCE_TEX_TEXT) ;\r
271                                 }\r
272                         } else if (sc.state != SCE_TEX_COMMAND) {\r
273                                 sc.SetState(SCE_TEX_TEXT) ;\r
274                         }\r
275                 }\r
276         }\r
277         sc.ChangeState(SCE_TEX_TEXT) ;\r
278         sc.Complete();\r
279 \r
280 }\r
281 \r
282 \r
283 static inline bool isNumber(int ch) {\r
284         return\r
285       (ch == '0') || (ch == '1') || (ch == '2') || \r
286       (ch == '3') || (ch == '4') || (ch == '5') || \r
287       (ch == '6') || (ch == '7') || (ch == '8') || (ch == '9');\r
288 }\r
289 \r
290 static inline bool isWordChar(int ch) {\r
291         return ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z'));\r
292 }\r
293 \r
294 static int ParseTeXCommand(unsigned int pos, Accessor &styler, char *command)\r
295 {\r
296   int length=0;\r
297   char ch=styler.SafeGetCharAt(pos+1);\r
298   \r
299   if(ch==',' || ch==':' || ch==';' || ch=='%'){\r
300       command[0]=ch;\r
301       command[1]=0;\r
302           return 1;\r
303   }\r
304 \r
305   // find end\r
306      while(isWordChar(ch) && !isNumber(ch) && ch!='_' && ch!='.' && length<100){\r
307           command[length]=ch;\r
308           length++;\r
309           ch=styler.SafeGetCharAt(pos+length+1);\r
310      }\r
311      \r
312   command[length]='\0';   \r
313   if(!length) return 0;\r
314   return length+1;\r
315 }\r
316 \r
317 static int classifyFoldPointTeXPaired(const char* s) {\r
318         int lev=0; \r
319         if (!(isdigit(s[0]) || (s[0] == '.'))){\r
320                 if (strcmp(s, "begin")==0||strcmp(s,"FoldStart")==0||\r
321                         strcmp(s,"abstract")==0||strcmp(s,"unprotect")==0||\r
322                         strcmp(s,"title")==0||strncmp(s,"start",5)==0||strncmp(s,"Start",5)==0||\r
323                         strcmp(s,"documentclass")==0||strncmp(s,"if",2)==0\r
324                         )\r
325                         lev=1;\r
326                 if (strcmp(s, "end")==0||strcmp(s,"FoldStop")==0||\r
327                         strcmp(s,"maketitle")==0||strcmp(s,"protect")==0||\r
328                         strncmp(s,"stop",4)==0||strncmp(s,"Stop",4)==0||\r
329                         strcmp(s,"fi")==0\r
330                         ) \r
331                 lev=-1;\r
332         }\r
333         return lev;\r
334 }\r
335 \r
336 static int classifyFoldPointTeXUnpaired(const char* s) {\r
337         int lev=0; \r
338         if (!(isdigit(s[0]) || (s[0] == '.'))){\r
339                 if (strcmp(s,"part")==0||\r
340                         strcmp(s,"chapter")==0||\r
341                         strcmp(s,"section")==0||\r
342                         strcmp(s,"subsection")==0||\r
343                         strcmp(s,"subsubsection")==0||\r
344                         strcmp(s,"CJKfamily")==0||\r
345                         strcmp(s,"appendix")==0||\r
346                         strcmp(s,"Topic")==0||strcmp(s,"topic")==0||\r
347                         strcmp(s,"subject")==0||strcmp(s,"subsubject")==0||\r
348                         strcmp(s,"def")==0||strcmp(s,"gdef")==0||strcmp(s,"edef")==0||\r
349                         strcmp(s,"xdef")==0||strcmp(s,"framed")==0||\r
350                         strcmp(s,"frame")==0||\r
351                         strcmp(s,"foilhead")==0||strcmp(s,"overlays")==0||strcmp(s,"slide")==0\r
352                         ){\r
353                             lev=1;\r
354                         }\r
355         }\r
356         return lev;\r
357 }\r
358 \r
359 static bool IsTeXCommentLine(int line, Accessor &styler) {\r
360         int pos = styler.LineStart(line);\r
361         int eol_pos = styler.LineStart(line + 1) - 1;\r
362         \r
363         int startpos = pos;\r
364 \r
365         while (startpos<eol_pos){\r
366                 char ch = styler[startpos];\r
367                 if (ch!='%' && ch!=' ') return false;\r
368                 else if (ch=='%') return true;\r
369                 startpos++;\r
370         }               \r
371 \r
372         return false;\r
373 }\r
374 \r
375 // FoldTeXDoc: borrowed from VisualTeX with modifications\r
376 \r
377 static void FoldTexDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) \r
378 {\r
379         bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;\r
380         unsigned int endPos = startPos+length;\r
381         int visibleChars=0;\r
382         int lineCurrent=styler.GetLine(startPos);\r
383         int levelPrev=styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;\r
384         int levelCurrent=levelPrev;\r
385         char chNext=styler[startPos];\r
386         char buffer[100]="";\r
387         \r
388         for (unsigned int i=startPos; i < endPos; i++) {\r
389                 char ch=chNext;\r
390                 chNext=styler.SafeGetCharAt(i+1);\r
391                 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');\r
392 \r
393         if(ch=='\\') {\r
394             ParseTeXCommand(i, styler, buffer);\r
395                         levelCurrent += classifyFoldPointTeXPaired(buffer)+classifyFoldPointTeXUnpaired(buffer);\r
396                 }\r
397 \r
398                 if (levelCurrent > SC_FOLDLEVELBASE && ((ch == '\r' || ch=='\n') && (chNext == '\\'))) {\r
399             ParseTeXCommand(i+1, styler, buffer);\r
400                         levelCurrent -= classifyFoldPointTeXUnpaired(buffer);\r
401                 }\r
402 \r
403         char chNext2;\r
404         char chNext3;\r
405         char chNext4;\r
406         char chNext5;\r
407         chNext2=styler.SafeGetCharAt(i+2);\r
408         chNext3=styler.SafeGetCharAt(i+3);\r
409         chNext4=styler.SafeGetCharAt(i+4);\r
410         chNext5=styler.SafeGetCharAt(i+5);\r
411 \r
412         bool atEOfold = (ch == '%') && \r
413                         (chNext == '%') && (chNext2=='}') && \r
414                                 (chNext3=='}')&& (chNext4=='-')&& (chNext5=='-');\r
415 \r
416         bool atBOfold = (ch == '%') && \r
417                         (chNext == '%') && (chNext2=='-') && \r
418                                 (chNext3=='-')&& (chNext4=='{')&& (chNext5=='{');\r
419 \r
420         if(atBOfold){\r
421                 levelCurrent+=1;\r
422         }\r
423 \r
424         if(atEOfold){\r
425                 levelCurrent-=1;\r
426         }\r
427         \r
428         if(ch=='\\' && chNext=='['){\r
429                 levelCurrent+=1;\r
430         }\r
431         \r
432         if(ch=='\\' && chNext==']'){\r
433                 levelCurrent-=1;\r
434         }\r
435 \r
436         bool foldComment = styler.GetPropertyInt("fold.comment") != 0;\r
437 \r
438         if (foldComment && atEOL && IsTeXCommentLine(lineCurrent, styler))\r
439         {\r
440             if (lineCurrent==0 && IsTeXCommentLine(lineCurrent + 1, styler)\r
441                                 )\r
442                 levelCurrent++;\r
443             else if (lineCurrent!=0 && !IsTeXCommentLine(lineCurrent - 1, styler)\r
444                && IsTeXCommentLine(lineCurrent + 1, styler)\r
445                                 )\r
446                 levelCurrent++;\r
447             else if (lineCurrent!=0 && IsTeXCommentLine(lineCurrent - 1, styler) &&\r
448                      !IsTeXCommentLine(lineCurrent+1, styler))\r
449                 levelCurrent--;\r
450         }\r
451 \r
452 //--------------------------------------------------------------------------------------------- \r
453                 \r
454                 if (atEOL) {\r
455                         int lev = levelPrev;\r
456                         if (visibleChars == 0 && foldCompact)\r
457                                 lev |= SC_FOLDLEVELWHITEFLAG;\r
458                         if ((levelCurrent > levelPrev) && (visibleChars > 0))\r
459                                 lev |= SC_FOLDLEVELHEADERFLAG;\r
460                         if (lev != styler.LevelAt(lineCurrent)) {\r
461                                 styler.SetLevel(lineCurrent, lev);\r
462                         }\r
463                         lineCurrent++;\r
464                         levelPrev = levelCurrent;\r
465                         visibleChars = 0;\r
466                 }\r
467 \r
468                 if (!isspacechar(ch))\r
469                         visibleChars++;\r
470         }\r
471 \r
472         // Fill in the real level of the next line, keeping the current flags as they will be filled in later\r
473         int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;\r
474         styler.SetLevel(lineCurrent, levelPrev | flagsNext);\r
475 }\r
476 \r
477 \r
478 \r
479 \r
480 static const char * const texWordListDesc[] = {\r
481     "TeX, eTeX, pdfTeX, Omega",\r
482     "ConTeXt Dutch",\r
483     "ConTeXt English",\r
484     "ConTeXt German",\r
485     "ConTeXt Czech",\r
486     "ConTeXt Italian",\r
487     "ConTeXt Romanian",\r
488         0,\r
489 } ;\r
490 \r
491 LexerModule lmTeX(SCLEX_TEX,   ColouriseTeXDoc, "tex", FoldTexDoc, texWordListDesc);\r