diff options
-rw-r--r-- | src/LexTeX.cxx | 270 |
1 files changed, 110 insertions, 160 deletions
diff --git a/src/LexTeX.cxx b/src/LexTeX.cxx index 21a4d3944..a5b094670 100644 --- a/src/LexTeX.cxx +++ b/src/LexTeX.cxx @@ -2,7 +2,7 @@ // File: LexTeX.cxx - general context conformant tex coloring scheme // Author: Hans Hagen - PRAGMA ADE - Hasselt NL - www.pragma-ade.com -// Version: August 18, 2003 +// Version: September 28, 2003 // Copyright: 1998-2003 by Neil Hodgson <neilh@scintilla.org> // The License.txt file describes the conditions under which this software may be distributed. @@ -10,6 +10,8 @@ // This lexer is derived from the one written for the texwork environment (1999++) which in // turn is inspired on texedit (1991++) which finds its roots in wdt (1986). +// If you run into strange boundary cases, just tell me and I'll look into it. + #include <stdlib.h> #include <string.h> #include <ctype.h> @@ -52,6 +54,8 @@ // lexer.tex.interface.default=0 // lexer.tex.comment.process=0 +// todo: lexer.tex.auto.if + // Auxiliary functions: static inline bool endOfLine(Accessor &styler, unsigned int i) { @@ -59,187 +63,67 @@ static inline bool endOfLine(Accessor &styler, unsigned int i) { (styler[i] == '\n') || ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n')) ; } -static inline bool isTeXzero(char ch) { +static inline bool isTeXzero(int ch) { return (ch == '%') ; } -static inline bool isTeXone(char ch) { +static inline bool isTeXone(int ch) { return (ch == '[') || (ch == ']') || (ch == '=') || (ch == '#') || (ch == '(') || (ch == ')') || (ch == '<') || (ch == '>') || (ch == '"') ; } -static inline bool isTeXtwo(char ch) { +static inline bool isTeXtwo(int ch) { return (ch == '{') || (ch == '}') || (ch == '$') ; } -static inline bool isTeXthree(char ch) { +static inline bool isTeXthree(int ch) { return (ch == '~') || (ch == '^') || (ch == '_') || (ch == '&') || (ch == '-') || (ch == '+') || (ch == '\"') || (ch == '`') || (ch == '/') || (ch == '|') || (ch == '%') ; } -static inline bool isTeXfour(char ch) { +static inline bool isTeXfour(int ch) { return (ch == '\\') ; } -static inline bool isTeXfive(char ch) { +static inline bool isTeXfive(int ch) { return ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) || (ch == '@') || (ch == '!') || (ch == '?') ; } -static inline bool isTeXsix(char ch) { +static inline bool isTeXsix(int ch) { return (ch == ' ') ; } - -// Coloring functions: - -bool newifDone = false ; - -static void ColourTeXRange( - unsigned int texMode, - char *key, - unsigned int endPos, - WordList &keywords, - bool useKeywords, - Accessor &styler) { - - bool autoIf = true ; - - switch (texMode) { - case 0 : - styler.ColourTo(endPos, SCE_TEX_DEFAULT) ; - newifDone = false ; - break ; - case 1 : - styler.ColourTo(endPos, SCE_TEX_SPECIAL) ; - newifDone = false ; - break ; - case 2 : - styler.ColourTo(endPos, SCE_TEX_GROUP) ; - newifDone = false ; - break ; - case 3 : - styler.ColourTo(endPos, SCE_TEX_SYMBOL) ; - newifDone = false ; - break ; - case 4 : - if (! keywords || ! useKeywords) { - styler.ColourTo(endPos, SCE_TEX_COMMAND) ; - newifDone = false ; - } else if (key[1] == '\0') { - styler.ColourTo(endPos, SCE_TEX_COMMAND) ; - newifDone = false ; - } else if (keywords.InList(key)) { - styler.ColourTo(endPos, SCE_TEX_COMMAND) ; - newifDone = autoIf && (strcmp(key,"newif") == 0) ; - } else if (autoIf && ! newifDone && (key[0] == 'i') && (key[1] == 'f') && keywords.InList("if")) { - styler.ColourTo(endPos, SCE_TEX_COMMAND) ; - } else { - styler.ColourTo(endPos, SCE_TEX_TEXT) ; - newifDone = false ; - } - break ; - case 5 : - styler.ColourTo(endPos, SCE_TEX_TEXT) ; - newifDone = newifDone || (strspn(key," ") == strlen(key)) ; - break ; - } - +static inline bool isTeXseven(int ch) { + return + (ch == '^') ; } -static void ColouriseTeXLine( - char *lineBuffer, - unsigned int lengthLine, - unsigned int startPos, - WordList &keywords, - bool useKeywords, - Accessor &styler) { - - char ch; - bool cs = false ; - unsigned int offset = 0 ; - unsigned int mode = 5 ; - unsigned int k = 0 ; - char key[1024] ; // length check in calling routine - unsigned int start = startPos-1 ; - - bool comment = (styler.GetPropertyInt("lexer.tex.comment.process", 0) == 0) ; - - // we use a cheap append to key method, ugly, but fast and ok - - while (offset < lengthLine) { - - ch = lineBuffer[offset] ; - - if (cs) { - cs = false ; - key[k] = ch ; ++k ; key[k] = '\0' ; // ugly but ok - } else if ((comment) && ((mode == 0) || (isTeXzero(ch)))) { - ColourTeXRange(mode,key,start,keywords,useKeywords,styler) ; k = 0 ; - mode = 0 ; - } else if (isTeXone(ch)) { - if (mode != 1) { ColourTeXRange(mode,key,start,keywords,useKeywords,styler) ; k = 0 ; } - mode = 1 ; - } else if (isTeXtwo(ch)) { - if (mode != 2) { ColourTeXRange(mode,key,start,keywords,useKeywords,styler) ; k = 0 ; } - mode = 2 ; - } else if (isTeXthree(ch)) { - if (mode != 3) { ColourTeXRange(mode,key,start,keywords,useKeywords,styler) ; k = 0 ; } - mode = 3 ; - } else if (isTeXfour(ch)) { - if (keywords || (mode != 4)) { - ColourTeXRange(mode,key,start,keywords,useKeywords,styler) ; k = 0 ; cs = true ; - } - mode = 4 ; - } else if (isTeXfive(ch)) { - if (mode < 4) { - ColourTeXRange(mode,key,start,keywords,useKeywords,styler) ; k = 0 ; mode = 5 ; - key[k] = ch ; ++k ; key[k] = '\0' ; // ugly but ok - } else if ((mode == 4) && (k == 1) && isTeXfour(key[0])) { - ColourTeXRange(mode,key,start,keywords,useKeywords,styler) ; k = 0 ; mode = 5 ; - } else { - key[k] = ch ; ++k ; key[k] = '\0' ; // ugly but ok - } - } else if (isTeXsix(ch)) { - if (mode != 5) { ColourTeXRange(mode,key,start,keywords,useKeywords,styler) ; k = 0 ; } - mode = 5 ; - } else if (mode != 5) { - ColourTeXRange(mode,key,start,keywords,useKeywords,styler) ; k = 0 ; mode = 5 ; - } - - ++offset ; - ++start ; - - } - - ColourTeXRange(mode,key,start,keywords,useKeywords,styler) ; - -} +// Interface determination static int CheckTeXInterface( unsigned int startPos, int length, - Accessor &styler) { + Accessor &styler, + int defaultInterface) { char lineBuffer[1024] ; unsigned int linePos = 0 ; - int defaultInterface = styler.GetPropertyInt("lexer.tex.interface.default", 1) ; - // some day we can make something lexer.tex.mapping=(all,0)(nl,1)(en,2)... if (styler.SafeGetCharAt(0) == '%') { for (unsigned int i = 0; i < startPos + length; i++) { - lineBuffer[linePos++] = styler[i]; + lineBuffer[linePos++] = styler.SafeGetCharAt(i) ; if (endOfLine(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { lineBuffer[linePos] = '\0'; if (strstr(lineBuffer, "interface=all")) { @@ -259,7 +143,7 @@ static int CheckTeXInterface( } else if (strstr(lineBuffer, "interface=ro")) { return 7 ; } else if (strstr(lineBuffer, "interface=latex")) { - // we will move latex cum suis up to 91+ when more keyword lists are supported + // we will move latex cum suis up to 91+ when more keyword lists are supported return 8 ; } else if (styler.SafeGetCharAt(1) == 'D' && strstr(lineBuffer, "%D \\module")) { // better would be to limit the search to just one line @@ -274,26 +158,27 @@ static int CheckTeXInterface( return defaultInterface ; } -// Main handler: -// -// The lexer works on a per line basis. I'm not familiar with the internals of scintilla, but -// since the lexer does not look back or forward beyond the current view, some optimization can -// be accomplished by providing just the viewport. The following code is more or less copied -// from the LexOthers.cxx file. - static void ColouriseTeXDoc( unsigned int startPos, int length, - int /*initStyle*/, + int, WordList *keywordlists[], Accessor &styler) { styler.StartAt(startPos) ; styler.StartSegment(startPos) ; - int currentInterface = CheckTeXInterface(startPos,length,styler) ; + bool processComment = styler.GetPropertyInt("lexer.tex.comment.process", 0) == 1 ; + bool useKeywords = styler.GetPropertyInt("lexer.tex.use.keywords", 1) == 1 ; + bool autoIf = styler.GetPropertyInt("lexer.tex.auto.if", 1) == 1 ; + int defaultInterface = styler.GetPropertyInt("lexer.tex.interface.default", 1) ; + + char key[100] ; + int k ; + bool newifDone = false ; + bool inComment = false ; - bool useKeywords = true ; + int currentInterface = CheckTeXInterface(startPos,length,styler,defaultInterface) ; if (currentInterface == 0) { useKeywords = false ; @@ -302,26 +187,91 @@ static void ColouriseTeXDoc( WordList &keywords = *keywordlists[currentInterface-1] ; - char lineBuffer[1024] ; - unsigned int linePos = 0 ; + StyleContext sc(startPos, length, SCE_TEX_TEXT, styler); - for (unsigned int i = startPos; i < startPos + length; i++) { - lineBuffer[linePos++] = styler[i] ; - if (endOfLine(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { - // End of line (or of line buffer) met, colourise it - lineBuffer[linePos] = '\0' ; - ColouriseTeXLine(lineBuffer, linePos, i-linePos+1, keywords, useKeywords, styler) ; - linePos = 0 ; - } - } + bool going = sc.More() ; // needed because of a fuzzy end of file state + + for (; going; sc.Forward()) { + + if (! sc.More()) { going = false ; } // we need to go one behind the end of text - if (linePos > 0) { - // Last line does not have ending characters - ColouriseTeXLine(lineBuffer, linePos, startPos+length-linePos, keywords, useKeywords, styler) ; + if (inComment) { + if (sc.atLineEnd) { + sc.SetState(SCE_TEX_TEXT) ; + newifDone = false ; + inComment = false ; + } + } else { + if (! isTeXfive(sc.ch)) { + if (sc.state == SCE_TEX_COMMAND) { + if (sc.LengthCurrent() == 1) { // \<noncstoken> + if (isTeXseven(sc.ch) && isTeXseven(sc.chNext)) { + sc.Forward(2) ; // \^^ and \^^<token> + } + sc.ForwardSetState(SCE_TEX_TEXT) ; + } else { + sc.GetCurrent(key, sizeof(key)-1) ; + k = strlen(key) ; + memmove(key,key+1,k) ; // shift left over escape token + key[k] = '\0' ; + k-- ; + if (! keywords || ! useKeywords) { + sc.SetState(SCE_TEX_COMMAND) ; + newifDone = false ; + } else if (k == 1) { //\<cstoken> + sc.SetState(SCE_TEX_COMMAND) ; + newifDone = false ; + } else if (keywords.InList(key)) { + sc.SetState(SCE_TEX_COMMAND) ; + newifDone = autoIf && (strcmp(key,"newif") == 0) ; + } else if (autoIf && ! newifDone && (key[0] == 'i') && (key[1] == 'f') && keywords.InList("if")) { + sc.SetState(SCE_TEX_COMMAND) ; + } else { + sc.ChangeState(SCE_TEX_TEXT) ; + sc.SetState(SCE_TEX_TEXT) ; + newifDone = false ; + } + } + } + if (isTeXzero(sc.ch)) { + sc.SetState(SCE_TEX_SYMBOL) ; + sc.ForwardSetState(SCE_TEX_DEFAULT) ; + inComment = ! processComment ; + newifDone = false ; + } else if (isTeXseven(sc.ch) && isTeXseven(sc.chNext)) { + sc.SetState(SCE_TEX_TEXT) ; + sc.ForwardSetState(SCE_TEX_TEXT) ; + } else if (isTeXone(sc.ch)) { + sc.SetState(SCE_TEX_SPECIAL) ; + newifDone = false ; + } else if (isTeXtwo(sc.ch)) { + sc.SetState(SCE_TEX_GROUP) ; + newifDone = false ; + } else if (isTeXthree(sc.ch)) { + sc.SetState(SCE_TEX_SYMBOL) ; + newifDone = false ; + } else if (isTeXfour(sc.ch)) { + sc.SetState(SCE_TEX_COMMAND) ; + } else if (isTeXsix(sc.ch)) { + sc.SetState(SCE_TEX_TEXT) ; + } else if (sc.atLineEnd) { + sc.SetState(SCE_TEX_TEXT) ; + newifDone = false ; + inComment = false ; + } else { + sc.SetState(SCE_TEX_TEXT) ; + } + } else if (sc.state != SCE_TEX_COMMAND) { + sc.SetState(SCE_TEX_TEXT) ; + } + } } + sc.ChangeState(SCE_TEX_TEXT) ; + sc.Complete(); } + // Hooks into the system: static const char * const texWordListDesc[] = { |