123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498 |
- // Scintilla source code edit control
- // File: LexTeX.cxx - general context conformant tex coloring scheme
- // Author: Hans Hagen - PRAGMA ADE - Hasselt NL - www.pragma-ade.com
- // 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.
- // 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.
- // TeX Folding code added by instanton (soft_share@126.com) with borrowed code from VisualTeX source by Alex Romanenko.
- // Version: June 22, 2007
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <assert.h>
- #include <ctype.h>
- #include "ILexer.h"
- #include "Scintilla.h"
- #include "SciLexer.h"
- #include "WordList.h"
- #include "LexAccessor.h"
- #include "Accessor.h"
- #include "StyleContext.h"
- #include "CharacterSet.h"
- #include "LexerModule.h"
- #ifdef SCI_NAMESPACE
- using namespace Scintilla;
- #endif
- // val SCE_TEX_DEFAULT = 0
- // val SCE_TEX_SPECIAL = 1
- // val SCE_TEX_GROUP = 2
- // val SCE_TEX_SYMBOL = 3
- // val SCE_TEX_COMMAND = 4
- // val SCE_TEX_TEXT = 5
- // Definitions in SciTEGlobal.properties:
- //
- // TeX Highlighting
- //
- // # Default
- // style.tex.0=fore:#7F7F00
- // # Special
- // style.tex.1=fore:#007F7F
- // # Group
- // style.tex.2=fore:#880000
- // # Symbol
- // style.tex.3=fore:#7F7F00
- // # Command
- // style.tex.4=fore:#008800
- // # Text
- // style.tex.5=fore:#000000
- // lexer.tex.interface.default=0
- // lexer.tex.comment.process=0
- // todo: lexer.tex.auto.if
- // Auxiliary functions:
- static inline bool endOfLine(Accessor &styler, Sci_PositionU i) {
- return
- (styler[i] == '\n') || ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n')) ;
- }
- static inline bool isTeXzero(int ch) {
- return
- (ch == '%') ;
- }
- static inline bool isTeXone(int ch) {
- return
- (ch == '[') || (ch == ']') || (ch == '=') || (ch == '#') ||
- (ch == '(') || (ch == ')') || (ch == '<') || (ch == '>') ||
- (ch == '"') ;
- }
- static inline bool isTeXtwo(int ch) {
- return
- (ch == '{') || (ch == '}') || (ch == '$') ;
- }
- static inline bool isTeXthree(int ch) {
- return
- (ch == '~') || (ch == '^') || (ch == '_') || (ch == '&') ||
- (ch == '-') || (ch == '+') || (ch == '\"') || (ch == '`') ||
- (ch == '/') || (ch == '|') || (ch == '%') ;
- }
- static inline bool isTeXfour(int ch) {
- return
- (ch == '\\') ;
- }
- static inline bool isTeXfive(int ch) {
- return
- ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) ||
- (ch == '@') || (ch == '!') || (ch == '?') ;
- }
- static inline bool isTeXsix(int ch) {
- return
- (ch == ' ') ;
- }
- static inline bool isTeXseven(int ch) {
- return
- (ch == '^') ;
- }
- // Interface determination
- static int CheckTeXInterface(
- Sci_PositionU startPos,
- Sci_Position length,
- Accessor &styler,
- int defaultInterface) {
- char lineBuffer[1024] ;
- Sci_PositionU linePos = 0 ;
- // some day we can make something lexer.tex.mapping=(all,0)(nl,1)(en,2)...
- if (styler.SafeGetCharAt(0) == '%') {
- for (Sci_PositionU i = 0; i < startPos + length; i++) {
- lineBuffer[linePos++] = styler.SafeGetCharAt(i) ;
- if (endOfLine(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) {
- lineBuffer[linePos] = '\0';
- if (strstr(lineBuffer, "interface=all")) {
- return 0 ;
- } else if (strstr(lineBuffer, "interface=tex")) {
- return 1 ;
- } else if (strstr(lineBuffer, "interface=nl")) {
- return 2 ;
- } else if (strstr(lineBuffer, "interface=en")) {
- return 3 ;
- } else if (strstr(lineBuffer, "interface=de")) {
- return 4 ;
- } else if (strstr(lineBuffer, "interface=cz")) {
- return 5 ;
- } else if (strstr(lineBuffer, "interface=it")) {
- return 6 ;
- } 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
- return 8 ;
- } else if (styler.SafeGetCharAt(1) == 'D' && strstr(lineBuffer, "%D \\module")) {
- // better would be to limit the search to just one line
- return 3 ;
- } else {
- return defaultInterface ;
- }
- }
- }
- }
- return defaultInterface ;
- }
- static void ColouriseTeXDoc(
- Sci_PositionU startPos,
- Sci_Position length,
- int,
- WordList *keywordlists[],
- Accessor &styler) {
- styler.StartAt(startPos) ;
- styler.StartSegment(startPos) ;
- 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 ;
- int currentInterface = CheckTeXInterface(startPos,length,styler,defaultInterface) ;
- if (currentInterface == 0) {
- useKeywords = false ;
- currentInterface = 1 ;
- }
- WordList &keywords = *keywordlists[currentInterface-1] ;
- StyleContext sc(startPos, length, SCE_TEX_TEXT, styler);
- 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 (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 = static_cast<int>(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);
- if (!endOfLine(styler,sc.currentPos + 1))
- 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();
- }
- static inline bool isNumber(int ch) {
- return
- (ch == '0') || (ch == '1') || (ch == '2') ||
- (ch == '3') || (ch == '4') || (ch == '5') ||
- (ch == '6') || (ch == '7') || (ch == '8') || (ch == '9');
- }
- static inline bool isWordChar(int ch) {
- return ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z'));
- }
- static int ParseTeXCommand(Sci_PositionU pos, Accessor &styler, char *command)
- {
- Sci_Position length=0;
- char ch=styler.SafeGetCharAt(pos+1);
- if(ch==',' || ch==':' || ch==';' || ch=='%'){
- command[0]=ch;
- command[1]=0;
- return 1;
- }
- // find end
- while(isWordChar(ch) && !isNumber(ch) && ch!='_' && ch!='.' && length<100){
- command[length]=ch;
- length++;
- ch=styler.SafeGetCharAt(pos+length+1);
- }
- command[length]='\0';
- if(!length) return 0;
- return length+1;
- }
- static int classifyFoldPointTeXPaired(const char* s) {
- int lev=0;
- if (!(isdigit(s[0]) || (s[0] == '.'))){
- if (strcmp(s, "begin")==0||strcmp(s,"FoldStart")==0||
- strcmp(s,"abstract")==0||strcmp(s,"unprotect")==0||
- strcmp(s,"title")==0||strncmp(s,"start",5)==0||strncmp(s,"Start",5)==0||
- strcmp(s,"documentclass")==0||strncmp(s,"if",2)==0
- )
- lev=1;
- if (strcmp(s, "end")==0||strcmp(s,"FoldStop")==0||
- strcmp(s,"maketitle")==0||strcmp(s,"protect")==0||
- strncmp(s,"stop",4)==0||strncmp(s,"Stop",4)==0||
- strcmp(s,"fi")==0
- )
- lev=-1;
- }
- return lev;
- }
- static int classifyFoldPointTeXUnpaired(const char* s) {
- int lev=0;
- if (!(isdigit(s[0]) || (s[0] == '.'))){
- if (strcmp(s,"part")==0||
- strcmp(s,"chapter")==0||
- strcmp(s,"section")==0||
- strcmp(s,"subsection")==0||
- strcmp(s,"subsubsection")==0||
- strcmp(s,"CJKfamily")==0||
- strcmp(s,"appendix")==0||
- strcmp(s,"Topic")==0||strcmp(s,"topic")==0||
- strcmp(s,"subject")==0||strcmp(s,"subsubject")==0||
- strcmp(s,"def")==0||strcmp(s,"gdef")==0||strcmp(s,"edef")==0||
- strcmp(s,"xdef")==0||strcmp(s,"framed")==0||
- strcmp(s,"frame")==0||
- strcmp(s,"foilhead")==0||strcmp(s,"overlays")==0||strcmp(s,"slide")==0
- ){
- lev=1;
- }
- }
- return lev;
- }
- static bool IsTeXCommentLine(Sci_Position line, Accessor &styler) {
- Sci_Position pos = styler.LineStart(line);
- Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
- Sci_Position startpos = pos;
- while (startpos<eol_pos){
- char ch = styler[startpos];
- if (ch!='%' && ch!=' ') return false;
- else if (ch=='%') return true;
- startpos++;
- }
- return false;
- }
- // FoldTeXDoc: borrowed from VisualTeX with modifications
- static void FoldTexDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[], Accessor &styler)
- {
- bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
- Sci_PositionU endPos = startPos+length;
- int visibleChars=0;
- Sci_Position lineCurrent=styler.GetLine(startPos);
- int levelPrev=styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
- int levelCurrent=levelPrev;
- char chNext=styler[startPos];
- char buffer[100]="";
- for (Sci_PositionU i=startPos; i < endPos; i++) {
- char ch=chNext;
- chNext=styler.SafeGetCharAt(i+1);
- bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
- if(ch=='\\') {
- ParseTeXCommand(i, styler, buffer);
- levelCurrent += classifyFoldPointTeXPaired(buffer)+classifyFoldPointTeXUnpaired(buffer);
- }
- if (levelCurrent > SC_FOLDLEVELBASE && ((ch == '\r' || ch=='\n') && (chNext == '\\'))) {
- ParseTeXCommand(i+1, styler, buffer);
- levelCurrent -= classifyFoldPointTeXUnpaired(buffer);
- }
- char chNext2;
- char chNext3;
- char chNext4;
- char chNext5;
- chNext2=styler.SafeGetCharAt(i+2);
- chNext3=styler.SafeGetCharAt(i+3);
- chNext4=styler.SafeGetCharAt(i+4);
- chNext5=styler.SafeGetCharAt(i+5);
- bool atEOfold = (ch == '%') &&
- (chNext == '%') && (chNext2=='}') &&
- (chNext3=='}')&& (chNext4=='-')&& (chNext5=='-');
- bool atBOfold = (ch == '%') &&
- (chNext == '%') && (chNext2=='-') &&
- (chNext3=='-')&& (chNext4=='{')&& (chNext5=='{');
- if(atBOfold){
- levelCurrent+=1;
- }
- if(atEOfold){
- levelCurrent-=1;
- }
- if(ch=='\\' && chNext=='['){
- levelCurrent+=1;
- }
- if(ch=='\\' && chNext==']'){
- levelCurrent-=1;
- }
- bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
- if (foldComment && atEOL && IsTeXCommentLine(lineCurrent, styler))
- {
- if (lineCurrent==0 && IsTeXCommentLine(lineCurrent + 1, styler)
- )
- levelCurrent++;
- else if (lineCurrent!=0 && !IsTeXCommentLine(lineCurrent - 1, styler)
- && IsTeXCommentLine(lineCurrent + 1, styler)
- )
- levelCurrent++;
- else if (lineCurrent!=0 && IsTeXCommentLine(lineCurrent - 1, styler) &&
- !IsTeXCommentLine(lineCurrent+1, styler))
- levelCurrent--;
- }
- //---------------------------------------------------------------------------------------------
- if (atEOL) {
- int lev = levelPrev;
- if (visibleChars == 0 && foldCompact)
- lev |= SC_FOLDLEVELWHITEFLAG;
- if ((levelCurrent > levelPrev) && (visibleChars > 0))
- lev |= SC_FOLDLEVELHEADERFLAG;
- if (lev != styler.LevelAt(lineCurrent)) {
- styler.SetLevel(lineCurrent, lev);
- }
- lineCurrent++;
- levelPrev = levelCurrent;
- visibleChars = 0;
- }
- if (!isspacechar(ch))
- visibleChars++;
- }
- // Fill in the real level of the next line, keeping the current flags as they will be filled in later
- int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
- styler.SetLevel(lineCurrent, levelPrev | flagsNext);
- }
- static const char * const texWordListDesc[] = {
- "TeX, eTeX, pdfTeX, Omega",
- "ConTeXt Dutch",
- "ConTeXt English",
- "ConTeXt German",
- "ConTeXt Czech",
- "ConTeXt Italian",
- "ConTeXt Romanian",
- 0,
- } ;
- LexerModule lmTeX(SCLEX_TEX, ColouriseTeXDoc, "tex", FoldTexDoc, texWordListDesc);
|